Properly implement Chloroblast recoil (#9648)

This commit is contained in:
Karthik 2023-07-15 15:54:49 -04:00 committed by GitHub
parent d947b82322
commit e218cb9dbb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 68 additions and 22 deletions

View File

@ -302,7 +302,7 @@ export const Scripts: ModdedBattleScriptsData = {
}
if (move.recoil && move.totalDamage) {
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move), pokemon, target, 'recoil');
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, target, 'recoil');
}
return damage;
},

View File

@ -239,7 +239,7 @@ export const Scripts: ModdedBattleScriptsData = {
// If a pokemon caused the other to faint with a recoil move and only one pokemon remains on both sides,
// recoil damage will not be taken.
if (move.recoil && move.totalDamage && (pokemon.side.pokemonLeft > 1 || target.side.pokemonLeft > 1 || target.hp)) {
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move), pokemon, target, 'recoil');
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, target, 'recoil');
}
return damage;
},

View File

@ -451,7 +451,7 @@ export const Scripts: ModdedBattleScriptsData = {
}
if (move.recoil && move.totalDamage) {
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move), pokemon, target, 'recoil');
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, target, 'recoil');
}
if (target && pokemon !== target) target.gotAttacked(move, damage, pokemon);

View File

@ -1513,7 +1513,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-activate', target, 'Substitute', '[damage]');
}
if (move.recoil && damage) {
this.damage(this.actions.calcRecoilDamage(damage, move), source, target, 'recoil');
this.damage(this.actions.calcRecoilDamage(damage, move, source), source, target, 'recoil');
}
if (move.drain) {
this.heal(Math.ceil(damage * move.drain[0] / move.drain[1]), source, target, 'drain');

View File

@ -890,7 +890,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
this.add('-activate', target, 'Substitute', '[damage]');
}
if (move.recoil && damage) {
this.damage(this.actions.calcRecoilDamage(damage, move), source, target, 'recoil');
this.damage(this.actions.calcRecoilDamage(damage, move, source), source, target, 'recoil');
}
if (move.drain) {
this.heal(Math.ceil(damage * move.drain[0] / move.drain[1]), source, target, 'drain');

View File

@ -527,7 +527,7 @@ export const Scripts: ModdedBattleScriptsData = {
}
if (move.recoil && move.totalDamage) {
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move), pokemon, pokemon, 'recoil');
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, pokemon, 'recoil');
}
if (move.struggleRecoil) {

View File

@ -2396,16 +2396,7 @@ export const Moves: {[moveid: string]: MoveData} = {
pp: 5,
priority: 0,
flags: {protect: 1, mirror: 1},
mindBlownRecoil: true,
onAfterMove(pokemon, target, move) {
if (move.mindBlownRecoil && !move.multihit) {
const hpBeforeRecoil = pokemon.hp;
this.damage(Math.round(pokemon.maxhp / 2), pokemon, pokemon, this.dex.conditions.get('Chloroblast'), true);
if (pokemon.hp <= pokemon.maxhp / 2 && hpBeforeRecoil > pokemon.maxhp / 2) {
this.runEvent('EmergencyExit', pokemon, pokemon);
}
}
},
// Recoil implemented in battle-actions.ts
secondary: null,
target: "normal",
type: "Grass",
@ -18788,8 +18779,8 @@ export const Moves: {[moveid: string]: MoveData} = {
} else {
this.add('-activate', target, 'move: Substitute', '[damage]');
}
if (move.recoil) {
this.damage(this.actions.calcRecoilDamage(damage, move), source, target, 'recoil');
if (move.recoil || move.id === 'chloroblast') {
this.damage(this.actions.calcRecoilDamage(damage, move, source), source, target, 'recoil');
}
if (move.drain) {
this.heal(Math.ceil(damage * move.drain[0] / move.drain[1]), source, target, 'drain');

View File

@ -945,9 +945,9 @@ export class BattleActions {
this.battle.add('-hitcount', targets[0], hit - 1);
}
if (move.recoil && move.totalDamage) {
if ((move.recoil || move.id === 'chloroblast') && move.totalDamage) {
const hpBeforeRecoil = pokemon.hp;
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move), pokemon, pokemon, 'recoil');
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, pokemon, 'recoil');
if (pokemon.hp <= pokemon.maxhp / 2 && hpBeforeRecoil > pokemon.maxhp / 2) {
this.battle.runEvent('EmergencyExit', pokemon, pokemon);
}
@ -1359,7 +1359,8 @@ export class BattleActions {
return retVal === true ? undefined : retVal;
}
calcRecoilDamage(damageDealt: number, move: Move): number {
calcRecoilDamage(damageDealt: number, move: Move, pokemon: Pokemon): number {
if (move.id === 'chloroblast') return Math.round(pokemon.maxhp / 2);
return this.battle.clampIntRange(Math.round(damageDealt * move.recoil![0] / move.recoil![1]), 1);
}

View File

@ -214,7 +214,7 @@ interface BattleScriptsData {
interface ModdedBattleActions {
inherit?: true;
afterMoveSecondaryEvent?: (this: BattleActions, targets: Pokemon[], pokemon: Pokemon, move: ActiveMove) => undefined;
calcRecoilDamage?: (this: BattleActions, damageDealt: number, move: Move) => number;
calcRecoilDamage?: (this: BattleActions, damageDealt: number, move: Move, pokemon: Pokemon) => number;
canMegaEvo?: (this: BattleActions, pokemon: Pokemon) => string | undefined | null;
canUltraBurst?: (this: BattleActions, pokemon: Pokemon) => string | null;
canZMove?: (this: BattleActions, pokemon: Pokemon) => ZMoveOptions | void;

View File

@ -0,0 +1,54 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe('Chloroblast', function () {
afterEach(function () {
battle.destroy();
});
it('should deal recoil damage to the user equal to half its max HP, rounded up', function () {
battle = common.createBattle([[
{species: "Electrode-Hisui", item: 'widelens', moves: ['chloroblast']},
], [
{species: "Blissey", moves: ['sleeptalk']},
]]);
assert.hurtsBy(battle.p1.active[0], Math.round(battle.p1.active[0].maxhp / 2), () => battle.makeChoices());
});
it('should not deal recoil damage to the user if it misses or is blocked by Protect', function () {
battle = common.createBattle([[
{species: "Electrode-Hisui", item: 'widelens', moves: ['chloroblast', 'protect']},
], [
{species: "Talonflame", ability: 'galewings', moves: ['fly', 'protect']},
]]);
battle.makeChoices('move chloroblast', 'move fly');
battle.makeChoices('move protect', 'auto');
battle.makeChoices('move chloroblast', 'move protect');
assert.fullHP(battle.p1.active[0]);
});
it('should have its recoil damage negated by Rock Head', function () {
battle = common.createBattle([[
{species: "Electrode-Hisui", ability: 'rockhead', item: 'widelens', moves: ['chloroblast']},
], [
{species: "Blissey", moves: ['sleeptalk']},
]]);
battle.makeChoices();
assert.fullHP(battle.p1.active[0]);
});
it('should not have its base power boosted by Reckless', function () {
battle = common.createBattle([[
{species: "Electrode-Hisui", ability: 'reckless', item: 'widelens', moves: ['chloroblast']},
], [
{species: "Blissey", ability: 'shellarmor', moves: ['sleeptalk']},
]]);
battle.makeChoices();
const damage = battle.p2.active[0].maxhp - battle.p2.active[0].hp;
assert.bounded(damage, [103, 123]);
});
});