Update abattr callsites in move-phase

This commit is contained in:
Sirz Benjie 2025-06-14 16:44:58 -05:00
parent 8f66dbe69b
commit 1deb74e926
No known key found for this signature in database
GPG Key ID: 38AC42D68CF5E138
8 changed files with 70 additions and 58 deletions

View File

@ -67,7 +67,7 @@ import { modifierTypes } from "./data/data-lists";
import { getModifierPoolForType } from "./utils/modifier-utils"; import { getModifierPoolForType } from "./utils/modifier-utils";
import { ModifierPoolType } from "#enums/modifier-pool-type"; import { ModifierPoolType } from "#enums/modifier-pool-type";
import AbilityBar from "#app/ui/ability-bar"; import AbilityBar from "#app/ui/ability-bar";
import { applyAbAttrs, applyPostBattleInitAbAttrs, applyPostItemLostAbAttrs } from "./data/abilities/apply-ab-attrs"; import { applyAbAttrs } from "./data/abilities/apply-ab-attrs";
import { allAbilities } from "./data/data-lists"; import { allAbilities } from "./data/data-lists";
import type { FixedBattleConfig } from "#app/battle"; import type { FixedBattleConfig } from "#app/battle";
import Battle from "#app/battle"; import Battle from "#app/battle";
@ -1256,7 +1256,7 @@ export default class BattleScene extends SceneBase {
const doubleChance = new NumberHolder(newWaveIndex % 10 === 0 ? 32 : 8); const doubleChance = new NumberHolder(newWaveIndex % 10 === 0 ? 32 : 8);
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
for (const p of playerField) { for (const p of playerField) {
applyAbAttrs("DoubleBattleChanceAbAttr", p, null, false, doubleChance); applyAbAttrs("DoubleBattleChanceAbAttr", { pokemon: p, chance: doubleChance });
} }
return Math.max(doubleChance.value, 1); return Math.max(doubleChance.value, 1);
} }
@ -1461,7 +1461,7 @@ export default class BattleScene extends SceneBase {
for (const pokemon of this.getPlayerParty()) { for (const pokemon of this.getPlayerParty()) {
pokemon.resetBattleAndWaveData(); pokemon.resetBattleAndWaveData();
pokemon.resetTera(); pokemon.resetTera();
applyPostBattleInitAbAttrs("PostBattleInitAbAttr", pokemon); applyAbAttrs("PostBattleInitAbAttr", { pokemon });
if ( if (
pokemon.hasSpecies(SpeciesId.TERAPAGOS) || pokemon.hasSpecies(SpeciesId.TERAPAGOS) ||
(this.gameMode.isClassic && this.currentBattle.waveIndex > 180 && this.currentBattle.waveIndex <= 190) (this.gameMode.isClassic && this.currentBattle.waveIndex > 180 && this.currentBattle.waveIndex <= 190)
@ -2743,7 +2743,7 @@ export default class BattleScene extends SceneBase {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
if (source && source.isPlayer() !== target.isPlayer()) { if (source && source.isPlayer() !== target.isPlayer()) {
applyAbAttrs("BlockItemTheftAbAttr", source, cancelled); applyAbAttrs("BlockItemTheftAbAttr", { pokemon: source, cancelled });
} }
if (cancelled.value) { if (cancelled.value) {
@ -2783,13 +2783,13 @@ export default class BattleScene extends SceneBase {
if (target.isPlayer()) { if (target.isPlayer()) {
this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant); this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant);
if (source && itemLost) { if (source && itemLost) {
applyPostItemLostAbAttrs("PostItemLostAbAttr", source, false); applyAbAttrs("PostItemLostAbAttr", { pokemon: source });
} }
return true; return true;
} }
this.addEnemyModifier(newItemModifier, ignoreUpdate, instant); this.addEnemyModifier(newItemModifier, ignoreUpdate, instant);
if (source && itemLost) { if (source && itemLost) {
applyPostItemLostAbAttrs("PostItemLostAbAttr", source, false); applyAbAttrs("PostItemLostAbAttr", { pokemon: source });
} }
return true; return true;
} }
@ -2812,7 +2812,7 @@ export default class BattleScene extends SceneBase {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
if (source && source.isPlayer() !== target.isPlayer()) { if (source && source.isPlayer() !== target.isPlayer()) {
applyAbAttrs("BlockItemTheftAbAttr", source, cancelled); applyAbAttrs("BlockItemTheftAbAttr", { pokemon: source, cancelled });
} }
if (cancelled.value) { if (cancelled.value) {

View File

@ -202,7 +202,7 @@ export class WeakenMoveScreenTag extends ArenaTag {
): boolean { ): boolean {
if (this.weakenedCategories.includes(moveCategory)) { if (this.weakenedCategories.includes(moveCategory)) {
const bypassed = new BooleanHolder(false); const bypassed = new BooleanHolder(false);
applyAbAttrs("InfiltratorAbAttr", attacker, null, false, bypassed); applyAbAttrs("InfiltratorAbAttr", { pokemon: attacker, bypassed });
if (bypassed.value) { if (bypassed.value) {
return false; return false;
} }

View File

@ -35,28 +35,28 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
case BerryType.APICOT: case BerryType.APICOT:
case BerryType.SALAC: case BerryType.SALAC:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new NumberHolder(0.25); const hpRatioReq = new NumberHolder(0.25);
// Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth // Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth
const stat: BattleStat = berryType - BerryType.ENIGMA; const stat: BattleStat = berryType - BerryType.ENIGMA;
applyAbAttrs("ReduceBerryUseThresholdAbAttr", { pokemon, stat}); applyAbAttrs("ReduceBerryUseThresholdAbAttr", { pokemon, hpRatioReq });
return pokemon.getHpRatio() < threshold.value && pokemon.getStatStage(stat) < 6; return pokemon.getHpRatio() < hpRatioReq.value && pokemon.getStatStage(stat) < 6;
}; };
case BerryType.LANSAT: case BerryType.LANSAT:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new NumberHolder(0.25); const hpRatioReq = new NumberHolder(0.25);
applyAbAttrs("ReduceBerryUseThresholdAbAttr", pokemon, null, false, threshold); applyAbAttrs("ReduceBerryUseThresholdAbAttr", { pokemon, hpRatioReq });
return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST); return pokemon.getHpRatio() < 0.25 && !pokemon.getTag(BattlerTagType.CRIT_BOOST);
}; };
case BerryType.STARF: case BerryType.STARF:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new NumberHolder(0.25); const hpRatioReq = new NumberHolder(0.25);
applyAbAttrs("ReduceBerryUseThresholdAbAttr", pokemon, null, false, threshold); applyAbAttrs("ReduceBerryUseThresholdAbAttr", { pokemon, hpRatioReq });
return pokemon.getHpRatio() < 0.25; return pokemon.getHpRatio() < 0.25;
}; };
case BerryType.LEPPA: case BerryType.LEPPA:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new NumberHolder(0.25); const hpRatioReq = new NumberHolder(0.25);
applyAbAttrs("ReduceBerryUseThresholdAbAttr", pokemon, null, false, threshold); applyAbAttrs("ReduceBerryUseThresholdAbAttr", { pokemon, hpRatioReq });
return !!pokemon.getMoveset().find(m => !m.getPpRatio()); return !!pokemon.getMoveset().find(m => !m.getPpRatio());
}; };
} }
@ -72,7 +72,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
case BerryType.ENIGMA: case BerryType.ENIGMA:
{ {
const hpHealed = new NumberHolder(toDmgValue(consumer.getMaxHp() / 4)); const hpHealed = new NumberHolder(toDmgValue(consumer.getMaxHp() / 4));
applyAbAttrs("DoubleBerryEffectAbAttr", { pokemon: consumer, effectValue: hpHealed, cancelled: null}); applyAbAttrs("DoubleBerryEffectAbAttr", { pokemon: consumer, effectValue: hpHealed });
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew(
"PokemonHealPhase", "PokemonHealPhase",
consumer.getBattlerIndex(), consumer.getBattlerIndex(),
@ -105,7 +105,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
// Offset BerryType such that LIECHI --> Stat.ATK = 1, GANLON --> Stat.DEF = 2, etc etc. // Offset BerryType such that LIECHI --> Stat.ATK = 1, GANLON --> Stat.DEF = 2, etc etc.
const stat: BattleStat = berryType - BerryType.ENIGMA; const stat: BattleStat = berryType - BerryType.ENIGMA;
const statStages = new NumberHolder(1); const statStages = new NumberHolder(1);
applyAbAttrs("DoubleBerryEffectAbAttr", consumer, null, false, statStages); applyAbAttrs("DoubleBerryEffectAbAttr", { pokemon: consumer, effectValue: statStages });
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew(
"StatStageChangePhase", "StatStageChangePhase",
consumer.getBattlerIndex(), consumer.getBattlerIndex(),
@ -126,7 +126,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
{ {
const randStat = randSeedInt(Stat.SPD, Stat.ATK); const randStat = randSeedInt(Stat.SPD, Stat.ATK);
const stages = new NumberHolder(2); const stages = new NumberHolder(2);
applyAbAttrs("DoubleBerryEffectAbAttr", consumer, null, false, stages); applyAbAttrs("DoubleBerryEffectAbAttr", { pokemon: consumer, effectValue: stages });
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew(
"StatStageChangePhase", "StatStageChangePhase",
consumer.getBattlerIndex(), consumer.getBattlerIndex(),

View File

@ -42,7 +42,7 @@ import type {
import { getModifierType } from "#app/utils/modifier-utils"; import { getModifierType } from "#app/utils/modifier-utils";
import { Color, ShadowColor } from "#enums/color"; import { Color, ShadowColor } from "#enums/color";
import { FRIENDSHIP_GAIN_FROM_RARE_CANDY } from "#app/data/balance/starters"; import { FRIENDSHIP_GAIN_FROM_RARE_CANDY } from "#app/data/balance/starters";
import { applyAbAttrs, applyPostItemLostAbAttrs } from "#app/data/abilities/apply-ab-attrs"; import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { ModifierInstanceMap, ModifierString } from "#app/@types/modifier-types"; import type { ModifierInstanceMap, ModifierString } from "#app/@types/modifier-types";
@ -1879,7 +1879,7 @@ export class BerryModifier extends PokemonHeldItemModifier {
// munch the berry and trigger unburden-like effects // munch the berry and trigger unburden-like effects
getBerryEffectFunc(this.berryType)(pokemon); getBerryEffectFunc(this.berryType)(pokemon);
applyPostItemLostAbAttrs("PostItemLostAbAttr", pokemon, false); applyAbAttrs("PostItemLostAbAttr", { pokemon });
// Update berry eaten trackers for Belch, Harvest, Cud Chew, etc. // Update berry eaten trackers for Belch, Harvest, Cud Chew, etc.
// Don't recover it if we proc berry pouch (no item duplication) // Don't recover it if we proc berry pouch (no item duplication)
@ -1967,7 +1967,7 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier {
// Reapply Commander on the Pokemon's side of the field, if applicable // Reapply Commander on the Pokemon's side of the field, if applicable
const field = pokemon.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField(); const field = pokemon.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
for (const p of field) { for (const p of field) {
applyAbAttrs("CommanderAbAttr", p, null, false); applyAbAttrs("CommanderAbAttr", { pokemon: p });
} }
return true; return true;
} }

View File

@ -42,7 +42,7 @@ export class BerryPhase extends FieldPhase {
// TODO: If both opponents on field have unnerve, which one displays its message? // TODO: If both opponents on field have unnerve, which one displays its message?
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
pokemon.getOpponents().forEach(opp => applyAbAttrs("PreventBerryUseAbAttr", opp, cancelled)); pokemon.getOpponents().forEach(opp => applyAbAttrs("PreventBerryUseAbAttr", { pokemon: opp, cancelled }));
if (cancelled.value) { if (cancelled.value) {
globalScene.phaseManager.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:preventBerryUse", { i18next.t("abilityTriggers:preventBerryUse", {
@ -70,6 +70,6 @@ export class BerryPhase extends FieldPhase {
globalScene.updateModifiers(pokemon.isPlayer()); globalScene.updateModifiers(pokemon.isPlayer());
// AbilityId.CHEEK_POUCH only works once per round of nom noms // AbilityId.CHEEK_POUCH only works once per round of nom noms
applyAbAttrs("HealFromBerryUseAbAttr", pokemon, new BooleanHolder(false)); applyAbAttrs("HealFromBerryUseAbAttr", { pokemon });
} }
} }

View File

@ -2,7 +2,7 @@ import { BattlerIndex } from "#enums/battler-index";
import { BattleType } from "#enums/battle-type"; import { BattleType } from "#enums/battle-type";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
import { applyAbAttrs, applyPreSummonAbAttrs } from "#app/data/abilities/apply-ab-attrs"; import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
import { initEncounterAnims, loadEncounterAnimAssets } from "#app/data/battle-anims"; import { initEncounterAnims, loadEncounterAnimAssets } from "#app/data/battle-anims";
import { getCharVariantFromDialogue } from "#app/data/dialogue"; import { getCharVariantFromDialogue } from "#app/data/dialogue";
import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
@ -128,7 +128,7 @@ export class EncounterPhase extends BattlePhase {
.slice(0, !battle.double ? 1 : 2) .slice(0, !battle.double ? 1 : 2)
.reverse() .reverse()
.forEach(playerPokemon => { .forEach(playerPokemon => {
applyAbAttrs("SyncEncounterNatureAbAttr", playerPokemon, null, false, battle.enemyParty[e]); applyAbAttrs("SyncEncounterNatureAbAttr", { pokemon: playerPokemon, target: battle.enemyParty[e] });
}); });
} }
} }
@ -249,7 +249,7 @@ export class EncounterPhase extends BattlePhase {
if (e < (battle.double ? 2 : 1)) { if (e < (battle.double ? 2 : 1)) {
if (battle.battleType === BattleType.WILD) { if (battle.battleType === BattleType.WILD) {
for (const pokemon of globalScene.getField()) { for (const pokemon of globalScene.getField()) {
applyPreSummonAbAttrs("PreSummonAbAttr", pokemon, []); applyAbAttrs("PreSummonAbAttr", { pokemon });
} }
globalScene.field.add(enemyPokemon); globalScene.field.add(enemyPokemon);
battle.seenEnemyPartyMemberIds.add(enemyPokemon.id); battle.seenEnemyPartyMemberIds.add(enemyPokemon.id);

View File

@ -1,11 +1,7 @@
import type { BattlerIndex } from "#enums/battler-index"; import type { BattlerIndex } from "#enums/battler-index";
import { BattleType } from "#enums/battle-type"; import { BattleType } from "#enums/battle-type";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
applyPostFaintAbAttrs,
applyPostKnockOutAbAttrs,
applyPostVictoryAbAttrs,
} from "#app/data/abilities/apply-ab-attrs";
import { BattlerTagLapseType } from "#enums/battler-tag-lapse-type"; import { BattlerTagLapseType } from "#enums/battler-tag-lapse-type";
import { battleSpecDialogue } from "#app/data/dialogue"; import { battleSpecDialogue } from "#app/data/dialogue";
import { allMoves } from "#app/data/data-lists"; import { allMoves } from "#app/data/data-lists";
@ -117,29 +113,31 @@ export class FaintPhase extends PokemonPhase {
pokemon.resetTera(); pokemon.resetTera();
// TODO: this can be simplified by just checking whether lastAttack is defined
if (pokemon.turnData.attacksReceived?.length) { if (pokemon.turnData.attacksReceived?.length) {
const lastAttack = pokemon.turnData.attacksReceived[0]; const lastAttack = pokemon.turnData.attacksReceived[0];
applyPostFaintAbAttrs( applyAbAttrs("PostFaintAbAttr", {
"PostFaintAbAttr", pokemon: pokemon,
pokemon, // TODO: We should refactor lastAttack's sourceId to forbid null and just use undefined
globalScene.getPokemonById(lastAttack.sourceId)!, attacker: globalScene.getPokemonById(lastAttack.sourceId) ?? undefined,
new PokemonMove(lastAttack.move).getMove(), // TODO: improve the way that we provide the move that knocked out the pokemon...
lastAttack.result, move: new PokemonMove(lastAttack.move).getMove(),
); // TODO: is this bang correct? hitResult: lastAttack.result,
}); // TODO: is this bang correct?
} else { } else {
//If killed by indirect damage, apply post-faint abilities without providing a last move //If killed by indirect damage, apply post-faint abilities without providing a last move
applyPostFaintAbAttrs("PostFaintAbAttr", pokemon); applyAbAttrs("PostFaintAbAttr", { pokemon });
} }
const alivePlayField = globalScene.getField(true); const alivePlayField = globalScene.getField(true);
for (const p of alivePlayField) { for (const p of alivePlayField) {
applyPostKnockOutAbAttrs("PostKnockOutAbAttr", p, pokemon); applyAbAttrs("PostKnockOutAbAttr", { pokemon: p, victim: pokemon });
} }
if (pokemon.turnData.attacksReceived?.length) { if (pokemon.turnData.attacksReceived?.length) {
const defeatSource = this.source; const defeatSource = this.source;
if (defeatSource?.isOnField()) { if (defeatSource?.isOnField()) {
applyPostVictoryAbAttrs("PostVictoryAbAttr", defeatSource); applyAbAttrs("PostVictoryAbAttr", { pokemon: defeatSource });
const pvmove = allMoves[pokemon.turnData.attacksReceived[0].move]; const pvmove = allMoves[pokemon.turnData.attacksReceived[0].move];
const pvattrs = pvmove.getAttrs("PostVictoryStatStageChangeAttr"); const pvattrs = pvmove.getAttrs("PostVictoryStatStageChangeAttr");
if (pvattrs.length) { if (pvattrs.length) {

View File

@ -1,6 +1,6 @@
import { BattlerIndex } from "#enums/battler-index"; import { BattlerIndex } from "#enums/battler-index";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { applyAbAttrs, applyPostMoveUsedAbAttrs, applyPreAttackAbAttrs } from "#app/data/abilities/apply-ab-attrs"; import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
import type { DelayedAttackTag } from "#app/data/arena-tag"; import type { DelayedAttackTag } from "#app/data/arena-tag";
import { CommonAnim } from "#enums/move-anims-common"; import { CommonAnim } from "#enums/move-anims-common";
import { CenterOfAttentionTag } from "#app/data/battler-tags"; import { CenterOfAttentionTag } from "#app/data/battler-tags";
@ -228,14 +228,11 @@ export class MovePhase extends BattlePhase {
case StatusEffect.SLEEP: { case StatusEffect.SLEEP: {
applyMoveAttrs("BypassSleepAttr", this.pokemon, null, this.move.getMove()); applyMoveAttrs("BypassSleepAttr", this.pokemon, null, this.move.getMove());
const turnsRemaining = new NumberHolder(this.pokemon.status.sleepTurnsRemaining ?? 0); const turnsRemaining = new NumberHolder(this.pokemon.status.sleepTurnsRemaining ?? 0);
applyAbAttrs( applyAbAttrs("ReduceStatusEffectDurationAbAttr", {
"ReduceStatusEffectDurationAbAttr", pokemon: this.pokemon,
this.pokemon, statusEffect: this.pokemon.status.effect,
null, duration: turnsRemaining,
false, });
this.pokemon.status.effect,
turnsRemaining,
);
this.pokemon.status.sleepTurnsRemaining = turnsRemaining.value; this.pokemon.status.sleepTurnsRemaining = turnsRemaining.value;
healed = this.pokemon.status.sleepTurnsRemaining <= 0; healed = this.pokemon.status.sleepTurnsRemaining <= 0;
activated = !healed && !this.pokemon.getTag(BattlerTagType.BYPASS_SLEEP); activated = !healed && !this.pokemon.getTag(BattlerTagType.BYPASS_SLEEP);
@ -246,7 +243,10 @@ export class MovePhase extends BattlePhase {
!!this.move !!this.move
.getMove() .getMove()
.findAttr( .findAttr(
attr => attr.is("HealStatusEffectAttr") && attr.selfTarget && attr.isOfEffect(StatusEffect.FREEZE), attr =>
attr.is("HealStatusEffectAttr") &&
attr.selfTarget &&
(attr as unknown as HealStatusEffectAttr).isOfEffect(StatusEffect.FREEZE),
) || ) ||
(!this.pokemon.randBattleSeedInt(5) && Overrides.STATUS_ACTIVATION_OVERRIDE !== true) || (!this.pokemon.randBattleSeedInt(5) && Overrides.STATUS_ACTIVATION_OVERRIDE !== true) ||
Overrides.STATUS_ACTIVATION_OVERRIDE === false; Overrides.STATUS_ACTIVATION_OVERRIDE === false;
@ -396,7 +396,8 @@ export class MovePhase extends BattlePhase {
*/ */
if (success) { if (success) {
const move = this.move.getMove(); const move = this.move.getMove();
applyPreAttackAbAttrs("PokemonTypeChangeAbAttr", this.pokemon, null, move); // TODO: Investigate whether PokemonTypeChangeAbAttr can drop the "opponent" parameter
applyAbAttrs("PokemonTypeChangeAbAttr", { pokemon: this.pokemon, move, opponent: targets[0] });
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew(
"MoveEffectPhase", "MoveEffectPhase",
this.pokemon.getBattlerIndex(), this.pokemon.getBattlerIndex(),
@ -406,7 +407,11 @@ export class MovePhase extends BattlePhase {
); );
} else { } else {
if ([MoveId.ROAR, MoveId.WHIRLWIND, MoveId.TRICK_OR_TREAT, MoveId.FORESTS_CURSE].includes(this.move.moveId)) { if ([MoveId.ROAR, MoveId.WHIRLWIND, MoveId.TRICK_OR_TREAT, MoveId.FORESTS_CURSE].includes(this.move.moveId)) {
applyPreAttackAbAttrs("PokemonTypeChangeAbAttr", this.pokemon, null, this.move.getMove()); applyAbAttrs("PokemonTypeChangeAbAttr", {
pokemon: this.pokemon,
move: this.move.getMove(),
opponent: targets[0],
});
} }
this.pokemon.pushMoveHistory({ this.pokemon.pushMoveHistory({
@ -438,7 +443,7 @@ export class MovePhase extends BattlePhase {
if (this.move.getMove().hasFlag(MoveFlags.DANCE_MOVE) && !dancerModes.includes(this.useMode)) { if (this.move.getMove().hasFlag(MoveFlags.DANCE_MOVE) && !dancerModes.includes(this.useMode)) {
// TODO: Fix in dancer PR to move to MEP for hit checks // TODO: Fix in dancer PR to move to MEP for hit checks
globalScene.getField(true).forEach(pokemon => { globalScene.getField(true).forEach(pokemon => {
applyPostMoveUsedAbAttrs("PostMoveUsedAbAttr", pokemon, this.move, this.pokemon, this.targets); applyAbAttrs("PostMoveUsedAbAttr", { pokemon, move: this.move, source: this.pokemon, targets: this.targets });
}); });
} }
} }
@ -470,7 +475,11 @@ export class MovePhase extends BattlePhase {
} }
// Protean and Libero apply on the charging turn of charge moves // Protean and Libero apply on the charging turn of charge moves
applyPreAttackAbAttrs("PokemonTypeChangeAbAttr", this.pokemon, null, this.move.getMove()); applyAbAttrs("PokemonTypeChangeAbAttr", {
pokemon: this.pokemon,
move: this.move.getMove(),
opponent: targets[0],
});
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew(
"MoveChargePhase", "MoveChargePhase",
@ -523,7 +532,12 @@ export class MovePhase extends BattlePhase {
.getField(true) .getField(true)
.filter(p => p !== this.pokemon) .filter(p => p !== this.pokemon)
.forEach(p => .forEach(p =>
applyAbAttrs("RedirectMoveAbAttr", p, null, false, this.move.moveId, redirectTarget, this.pokemon), applyAbAttrs("RedirectMoveAbAttr", {
pokemon: p,
moveId: this.move.moveId,
targetIndex: redirectTarget,
sourcePokemon: this.pokemon,
}),
); );
/** `true` if an Ability is responsible for redirecting the move to another target; `false` otherwise */ /** `true` if an Ability is responsible for redirecting the move to another target; `false` otherwise */