Update callsites in moves.ts

This commit is contained in:
Sirz Benjie 2025-06-14 14:18:29 -05:00
parent 4c5c5ca737
commit 40e97f1633
No known key found for this signature in database
GPG Key ID: 38AC42D68CF5E138
4 changed files with 76 additions and 53 deletions

View File

@ -465,7 +465,9 @@ type PreDefendAbAttrCondition = (pokemon: Pokemon, attacker: Pokemon, move: Move
* Often extended by other interfaces to add more parameters. * Often extended by other interfaces to add more parameters.
* Used, e.g. by {@linkcode PreDefendAbAttr} and {@linkcode PostAttackAbAttr} * Used, e.g. by {@linkcode PreDefendAbAttr} and {@linkcode PostAttackAbAttr}
*/ */
export interface AugmentMoveInteractionAbAttrParams extends AbAttrParamsWithCancel { // TODO: Consider making this not require `cancelled`, as many abilities do not do anything with the parameter.
// Leaving it in bloats callsites.
export interface AugmentMoveInteractionAbAttrParams extends AbAttrBaseParams {
/** The move used by (or against, for defend attributes) */ /** The move used by (or against, for defend attributes) */
move: Move; move: Move;
/** The pokemon on the other side of the interaction*/ /** The pokemon on the other side of the interaction*/
@ -593,6 +595,8 @@ export class ReceivedTypeDamageMultiplierAbAttr extends ReceivedMoveDamageMultip
export interface TypeMultiplierAbAttrParams extends AugmentMoveInteractionAbAttrParams { export interface TypeMultiplierAbAttrParams extends AugmentMoveInteractionAbAttrParams {
/** Holds the type multiplier of an attack. In the case of an immunity, this value will be set to 0. */ /** Holds the type multiplier of an attack. In the case of an immunity, this value will be set to 0. */
typeMultiplier: NumberHolder; typeMultiplier: NumberHolder;
/** Its particular meaning depends on the ability attribute, though usually means that the "no effect" message should not be played */
cancelled: BooleanHolder;
} }
/** /**
@ -778,8 +782,13 @@ export class FullHpResistTypeAbAttr extends PreDefendAbAttr {
} }
} }
export interface FieldPriorityMoveImmunityAbAttrParams extends AugmentMoveInteractionAbAttrParams {
/** Holds whether the pokemon is immune to the move being used */
cancelled: BooleanHolder;
}
export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr { export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
override canApply({ move, opponent: attacker }: AugmentMoveInteractionAbAttrParams): boolean { override canApply({ move, opponent: attacker }: FieldPriorityMoveImmunityAbAttrParams): boolean {
return ( return (
!(move.moveTarget === MoveTarget.USER || move.moveTarget === MoveTarget.NEAR_ALLY) && !(move.moveTarget === MoveTarget.USER || move.moveTarget === MoveTarget.NEAR_ALLY) &&
move.getPriority(attacker) > 0 && move.getPriority(attacker) > 0 &&
@ -787,11 +796,17 @@ export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
); );
} }
override apply({ cancelled }: AugmentMoveInteractionAbAttrParams): void { override apply({ cancelled }: FieldPriorityMoveImmunityAbAttrParams): void {
cancelled.value = true; cancelled.value = true;
} }
} }
export interface MoveImmunityAbAttrParams extends AugmentMoveInteractionAbAttrParams {
/** Holds whether the standard "no effect" message (due to a type-based immunity) should be suppressed */
cancelled: BooleanHolder;
}
// TODO: Consider examining whether the this move immunity ability attribute
// can be merged with the MoveTypeMultiplierAbAttr in some way.
export class MoveImmunityAbAttr extends PreDefendAbAttr { export class MoveImmunityAbAttr extends PreDefendAbAttr {
private immuneCondition: PreDefendAbAttrCondition; private immuneCondition: PreDefendAbAttrCondition;
@ -801,15 +816,17 @@ export class MoveImmunityAbAttr extends PreDefendAbAttr {
this.immuneCondition = immuneCondition; this.immuneCondition = immuneCondition;
} }
override canApply({ pokemon, opponent: attacker, move }: AugmentMoveInteractionAbAttrParams): boolean { override canApply({ pokemon, opponent: attacker, move }: MoveImmunityAbAttrParams): boolean {
// TODO: Investigate whether this method should be checking against `cancelled`, specifically
// if not checking this results in multiple flyouts showing when multiple abilities block the move.
return this.immuneCondition(pokemon, attacker, move); return this.immuneCondition(pokemon, attacker, move);
} }
override apply({ cancelled }: AugmentMoveInteractionAbAttrParams): void { override apply({ cancelled }: MoveImmunityAbAttrParams): void {
cancelled.value = true; cancelled.value = true;
} }
override getTriggerMessage({ pokemon }: AugmentMoveInteractionAbAttrParams, _abilityName: string): string { override getTriggerMessage({ pokemon }: MoveImmunityAbAttrParams, _abilityName: string): string {
return i18next.t("abilityTriggers:moveImmunity", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }); return i18next.t("abilityTriggers:moveImmunity", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) });
} }
} }
@ -847,13 +864,13 @@ export class MoveImmunityStatStageChangeAbAttr extends MoveImmunityAbAttr {
this.stages = stages; this.stages = stages;
} }
override canApply(params: AugmentMoveInteractionAbAttrParams): boolean { override canApply(params: MoveImmunityAbAttrParams): boolean {
// TODO: Evaluate whether it makes sense to check against simulated here. // TODO: Evaluate whether it makes sense to check against simulated here.
// We likely want to check 'simulated' when the apply method enqueues the phase // We likely want to check 'simulated' when the apply method enqueues the phase
return !params.simulated && super.canApply(params); return !params.simulated && super.canApply(params);
} }
override apply(params: AugmentMoveInteractionAbAttrParams): void { override apply(params: MoveImmunityAbAttrParams): void {
super.apply(params); super.apply(params);
// TODO: We probably should not unshift the phase if this is simulated // TODO: We probably should not unshift the phase if this is simulated
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew(
@ -1479,8 +1496,14 @@ export class IgnoreMoveEffectsAbAttr extends PreDefendAbAttr {
} }
} }
export interface FieldPreventExplosiveMovesAbAttrParams extends AbAttrBaseParams {
/** Holds whether the explosive move should be prevented*/
cancelled: BooleanHolder;
}
export class FieldPreventExplosiveMovesAbAttr extends AbAttr { export class FieldPreventExplosiveMovesAbAttr extends AbAttr {
override apply({ cancelled }: AugmentMoveInteractionAbAttrParams): void { // TODO: investigate whether we need to check against `cancelled` in a `canApply` method
override apply({ cancelled }: FieldPreventExplosiveMovesAbAttrParams): void {
cancelled.value = true; cancelled.value = true;
} }
} }
@ -5327,8 +5350,6 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
pokemon: otherPokemon, pokemon: otherPokemon,
simulated, simulated,
cancelled, cancelled,
move,
opponent: pokemon,
}); });
} }
return !(!diedToDirectDamage || cancelled.value || attacker.hasAbilityWithAttr("BlockNonDirectDamageAbAttr")); return !(!diedToDirectDamage || cancelled.value || attacker.hasAbilityWithAttr("BlockNonDirectDamageAbAttr"));

View File

@ -88,6 +88,7 @@ import { isVirtual, MoveUseMode } from "#enums/move-use-mode";
import { ChargingMove, MoveAttrMap, MoveAttrString, MoveKindString, MoveClassMap } from "#app/@types/move-types"; import { ChargingMove, MoveAttrMap, MoveAttrString, MoveKindString, MoveClassMap } from "#app/@types/move-types";
import { applyMoveAttrs } from "./apply-attrs"; import { applyMoveAttrs } from "./apply-attrs";
import { frenzyMissFunc, getMoveTargets } from "./move-utils"; import { frenzyMissFunc, getMoveTargets } from "./move-utils";
import { AbAttrBaseParams, AbAttrParamsWithCancel, PreAttackModifyPowerAbAttrParams } from "../abilities/ability";
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
export type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean; export type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean;
@ -339,7 +340,7 @@ export default abstract class Move implements Localizable {
const bypassed = new BooleanHolder(false); const bypassed = new BooleanHolder(false);
// TODO: Allow this to be simulated // TODO: Allow this to be simulated
applyAbAttrs("InfiltratorAbAttr", user, null, false, bypassed); applyAbAttrs("InfiltratorAbAttr", {pokemon: user, bypassed});
return !bypassed.value return !bypassed.value
&& !this.hasFlag(MoveFlags.SOUND_BASED) && !this.hasFlag(MoveFlags.SOUND_BASED)
@ -637,7 +638,7 @@ export default abstract class Move implements Localizable {
case MoveFlags.IGNORE_ABILITIES: case MoveFlags.IGNORE_ABILITIES:
if (user.hasAbilityWithAttr("MoveAbilityBypassAbAttr")) { if (user.hasAbilityWithAttr("MoveAbilityBypassAbAttr")) {
const abilityEffectsIgnored = new BooleanHolder(false); const abilityEffectsIgnored = new BooleanHolder(false);
applyAbAttrs("MoveAbilityBypassAbAttr", user, abilityEffectsIgnored, false, this); applyAbAttrs("MoveAbilityBypassAbAttr", {pokemon: user, cancelled: abilityEffectsIgnored, move: this});
if (abilityEffectsIgnored.value) { if (abilityEffectsIgnored.value) {
return true; return true;
} }
@ -754,7 +755,7 @@ export default abstract class Move implements Localizable {
const moveAccuracy = new NumberHolder(this.accuracy); const moveAccuracy = new NumberHolder(this.accuracy);
applyMoveAttrs("VariableAccuracyAttr", user, target, this, moveAccuracy); applyMoveAttrs("VariableAccuracyAttr", user, target, this, moveAccuracy);
applyPreDefendAbAttrs("WonderSkinAbAttr", target, user, this, { value: false }, simulated, moveAccuracy); applyAbAttrs("WonderSkinAbAttr", {pokemon: target, opponent: user, move: this, simulated, accuracy: moveAccuracy});
if (moveAccuracy.value === -1) { if (moveAccuracy.value === -1) {
return moveAccuracy.value; return moveAccuracy.value;
@ -797,17 +798,25 @@ export default abstract class Move implements Localizable {
const typeChangeMovePowerMultiplier = new NumberHolder(1); const typeChangeMovePowerMultiplier = new NumberHolder(1);
const typeChangeHolder = new NumberHolder(this.type); const typeChangeHolder = new NumberHolder(this.type);
applyPreAttackAbAttrs("MoveTypeChangeAbAttr", source, target, this, true, typeChangeHolder, typeChangeMovePowerMultiplier); applyAbAttrs("MoveTypeChangeAbAttr", {pokemon: source, opponent: target, move: this, simulated: true, moveType: typeChangeHolder, power: typeChangeMovePowerMultiplier});
const sourceTeraType = source.getTeraType(); const sourceTeraType = source.getTeraType();
if (source.isTerastallized && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr("MultiHitAttr") && !globalScene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) { if (source.isTerastallized && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr("MultiHitAttr") && !globalScene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) {
power.value = 60; power.value = 60;
} }
applyPreAttackAbAttrs("VariableMovePowerAbAttr", source, target, this, simulated, power); const abAttrParams: PreAttackModifyPowerAbAttrParams = {
pokemon: source,
opponent: target,
simulated,
power,
move: this,
}
applyAbAttrs("VariableMovePowerAbAttr", abAttrParams);
const ally = source.getAlly(); const ally = source.getAlly();
if (!isNullOrUndefined(ally)) { if (!isNullOrUndefined(ally)) {
applyPreAttackAbAttrs("AllyMoveCategoryPowerBoostAbAttr", ally, target, this, simulated, power); applyAbAttrs("AllyMoveCategoryPowerBoostAbAttr", {...abAttrParams, pokemon: ally});
} }
const fieldAuras = new Set( const fieldAuras = new Set(
@ -819,11 +828,12 @@ export default abstract class Move implements Localizable {
.flat(), .flat(),
); );
for (const aura of fieldAuras) { for (const aura of fieldAuras) {
aura.applyPreAttack(source, null, simulated, target, this, [ power ]); // TODO: Refactor the fieldAura attribute so that its apply method is not directly called
aura.apply({pokemon: source, simulated, opponent: target, move: this, power});
} }
const alliedField: Pokemon[] = source.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField(); const alliedField: Pokemon[] = source.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
alliedField.forEach(p => applyPreAttackAbAttrs("UserFieldMoveTypePowerBoostAbAttr", p, target, this, simulated, power)); alliedField.forEach(p => applyAbAttrs("UserFieldMoveTypePowerBoostAbAttr", {pokemon: p, opponent: target, move: this, simulated, power}));
power.value *= typeChangeMovePowerMultiplier.value; power.value *= typeChangeMovePowerMultiplier.value;
@ -850,7 +860,7 @@ export default abstract class Move implements Localizable {
const priority = new NumberHolder(this.priority); const priority = new NumberHolder(this.priority);
applyMoveAttrs("IncrementMovePriorityAttr", user, null, this, priority); applyMoveAttrs("IncrementMovePriorityAttr", user, null, this, priority);
applyAbAttrs("ChangeMovePriorityAbAttr", user, null, simulated, this, priority); applyAbAttrs("ChangeMovePriorityAbAttr", {pokemon: user, simulated, move: this, priority});
return priority.value; return priority.value;
} }
@ -1302,7 +1312,7 @@ export class MoveEffectAttr extends MoveAttr {
getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean, showAbility?: Boolean): number { getMoveChance(user: Pokemon, target: Pokemon, move: Move, selfEffect?: Boolean, showAbility?: Boolean): number {
const moveChance = new NumberHolder(this.effectChanceOverride ?? move.chance); const moveChance = new NumberHolder(this.effectChanceOverride ?? move.chance);
applyAbAttrs("MoveEffectChanceMultiplierAbAttr", user, null, !showAbility, moveChance, move); applyAbAttrs("MoveEffectChanceMultiplierAbAttr", {pokemon: user, simulated: !showAbility, chance: moveChance, move});
if ((!move.hasAttr("FlinchAttr") || moveChance.value <= move.chance) && !move.hasAttr("SecretPowerAttr")) { if ((!move.hasAttr("FlinchAttr") || moveChance.value <= move.chance) && !move.hasAttr("SecretPowerAttr")) {
const userSide = user.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; const userSide = user.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
@ -1310,7 +1320,7 @@ export class MoveEffectAttr extends MoveAttr {
} }
if (!selfEffect) { if (!selfEffect) {
applyPreDefendAbAttrs("IgnoreMoveEffectsAbAttr", target, user, null, null, !showAbility, moveChance); applyAbAttrs("IgnoreMoveEffectsAbAttr", {pokemon: target, move, simulated: !showAbility, chance: moveChance});
} }
return moveChance.value; return moveChance.value;
} }
@ -1688,8 +1698,9 @@ export class RecoilAttr extends MoveEffectAttr {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
if (!this.unblockable) { if (!this.unblockable) {
applyAbAttrs("BlockRecoilDamageAttr", user, cancelled); const abAttrParams: AbAttrParamsWithCancel = {pokemon: user, cancelled};
applyAbAttrs("BlockNonDirectDamageAbAttr", user, cancelled); applyAbAttrs("BlockRecoilDamageAttr", abAttrParams);
applyAbAttrs("BlockNonDirectDamageAbAttr", abAttrParams);
} }
if (cancelled.value) { if (cancelled.value) {
@ -1822,7 +1833,7 @@ export class HalfSacrificialAttr extends MoveEffectAttr {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
// Check to see if the Pokemon has an ability that blocks non-direct damage // Check to see if the Pokemon has an ability that blocks non-direct damage
applyAbAttrs("BlockNonDirectDamageAbAttr", user, cancelled); applyAbAttrs("BlockNonDirectDamageAbAttr", {pokemon: user, cancelled});
if (!cancelled.value) { if (!cancelled.value) {
user.damageAndUpdate(toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT, ignoreSegments: true }); user.damageAndUpdate(toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT, ignoreSegments: true });
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", { pokemonName: getPokemonNameWithAffix(user) })); // Queue recoil message globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", { pokemonName: getPokemonNameWithAffix(user) })); // Queue recoil message
@ -2021,7 +2032,7 @@ export class FlameBurstAttr extends MoveEffectAttr {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
if (!isNullOrUndefined(targetAlly)) { if (!isNullOrUndefined(targetAlly)) {
applyAbAttrs("BlockNonDirectDamageAbAttr", targetAlly, cancelled); applyAbAttrs("BlockNonDirectDamageAbAttr", {pokemon: targetAlly, cancelled});
} }
if (cancelled.value || !targetAlly || targetAlly.switchOutStatus) { if (cancelled.value || !targetAlly || targetAlly.switchOutStatus) {
@ -2393,7 +2404,7 @@ export class MultiHitAttr extends MoveAttr {
{ {
const rand = user.randBattleSeedInt(20); const rand = user.randBattleSeedInt(20);
const hitValue = new NumberHolder(rand); const hitValue = new NumberHolder(rand);
applyAbAttrs("MaxMultiHitAbAttr", user, null, false, hitValue); applyAbAttrs("MaxMultiHitAbAttr", {pokemon: user, hits: hitValue});
if (hitValue.value >= 13) { if (hitValue.value >= 13) {
return 2; return 2;
} else if (hitValue.value >= 6) { } else if (hitValue.value >= 6) {
@ -2501,7 +2512,7 @@ export class StatusEffectAttr extends MoveEffectAttr {
} }
if (((!pokemon.status || this.overrideStatus) || (pokemon.status.effect === this.effect && moveChance < 0)) if (((!pokemon.status || this.overrideStatus) || (pokemon.status.effect === this.effect && moveChance < 0))
&& pokemon.trySetStatus(this.effect, true, user, this.turnsRemaining, null, this.overrideStatus, quiet)) { && pokemon.trySetStatus(this.effect, true, user, this.turnsRemaining, null, this.overrideStatus, quiet)) {
applyPostAttackAbAttrs("ConfusionOnStatusEffectAbAttr", user, target, move, null, false, this.effect); applyAbAttrs("ConfusionOnStatusEffectAbAttr", {pokemon: user, opponent: target, move, effect: this.effect});
return true; return true;
} }
} }
@ -2658,7 +2669,7 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
// Check for abilities that block item theft // Check for abilities that block item theft
// TODO: This should not trigger if the target would faint beforehand // TODO: This should not trigger if the target would faint beforehand
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
applyAbAttrs("BlockItemTheftAbAttr", target, cancelled); applyAbAttrs("BlockItemTheftAbAttr", {pokemon: target, cancelled});
if (cancelled.value) { if (cancelled.value) {
return false; return false;
@ -2775,8 +2786,8 @@ export class EatBerryAttr extends MoveEffectAttr {
protected eatBerry(consumer: Pokemon, berryOwner: Pokemon = consumer, updateHarvest = consumer === berryOwner) { protected eatBerry(consumer: Pokemon, berryOwner: Pokemon = consumer, updateHarvest = consumer === berryOwner) {
// consumer eats berry, owner triggers unburden and similar effects // consumer eats berry, owner triggers unburden and similar effects
getBerryEffectFunc(this.chosenBerry.berryType)(consumer); getBerryEffectFunc(this.chosenBerry.berryType)(consumer);
applyPostItemLostAbAttrs("PostItemLostAbAttr", berryOwner, false); applyAbAttrs("PostItemLostAbAttr", {pokemon: berryOwner});
applyAbAttrs("HealFromBerryUseAbAttr", consumer, new BooleanHolder(false)); applyAbAttrs("HealFromBerryUseAbAttr", {pokemon: consumer});
consumer.recordEatenBerry(this.chosenBerry.berryType, updateHarvest); consumer.recordEatenBerry(this.chosenBerry.berryType, updateHarvest);
} }
} }
@ -2801,7 +2812,7 @@ export class StealEatBerryAttr extends EatBerryAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
// check for abilities that block item theft // check for abilities that block item theft
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
applyAbAttrs("BlockItemTheftAbAttr", target, cancelled); applyAbAttrs("BlockItemTheftAbAttr", {pokemon: target, cancelled});
if (cancelled.value === true) { if (cancelled.value === true) {
return false; return false;
} }
@ -2815,7 +2826,7 @@ export class StealEatBerryAttr extends EatBerryAttr {
// pick a random berry and eat it // pick a random berry and eat it
this.chosenBerry = heldBerries[user.randBattleSeedInt(heldBerries.length)]; this.chosenBerry = heldBerries[user.randBattleSeedInt(heldBerries.length)];
applyPostItemLostAbAttrs("PostItemLostAbAttr", target, false); applyAbAttrs("PostItemLostAbAttr", {pokemon: target});
const message = i18next.t("battle:stealEatBerry", { pokemonName: user.name, targetName: target.name, berryName: this.chosenBerry.type.name }); const message = i18next.t("battle:stealEatBerry", { pokemonName: user.name, targetName: target.name, berryName: this.chosenBerry.type.name });
globalScene.phaseManager.queueMessage(message); globalScene.phaseManager.queueMessage(message);
this.reduceBerryModifier(target); this.reduceBerryModifier(target);
@ -3006,7 +3017,7 @@ export class OneHitKOAttr extends MoveAttr {
getCondition(): MoveConditionFunc { getCondition(): MoveConditionFunc {
return (user, target, move) => { return (user, target, move) => {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
applyAbAttrs("BlockOneHitKOAbAttr", target, cancelled); applyAbAttrs("BlockOneHitKOAbAttr", {pokemon: target, cancelled});
return !cancelled.value && user.level >= target.level; return !cancelled.value && user.level >= target.level;
}; };
} }
@ -5418,7 +5429,7 @@ export class NoEffectAttr extends MoveAttr {
const crashDamageFunc = (user: Pokemon, move: Move) => { const crashDamageFunc = (user: Pokemon, move: Move) => {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
applyAbAttrs("BlockNonDirectDamageAbAttr", user, cancelled); applyAbAttrs("BlockNonDirectDamageAbAttr", {pokemon: user, cancelled});
if (cancelled.value) { if (cancelled.value) {
return false; return false;
} }
@ -6417,9 +6428,9 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
} }
getFailedText(_user: Pokemon, target: Pokemon, _move: Move): string | undefined { getFailedText(_user: Pokemon, target: Pokemon, _move: Move): string | undefined {
const blockedByAbility = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
applyAbAttrs("ForceSwitchOutImmunityAbAttr", target, blockedByAbility); applyAbAttrs("ForceSwitchOutImmunityAbAttr", {pokemon: target, cancelled});
if (blockedByAbility.value) { if (cancelled.value) {
return i18next.t("moveTriggers:cannotBeSwitchedOut", { pokemonName: getPokemonNameWithAffix(target) }); return i18next.t("moveTriggers:cannotBeSwitchedOut", { pokemonName: getPokemonNameWithAffix(target) });
} }
} }
@ -6458,7 +6469,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
} }
const blockedByAbility = new BooleanHolder(false); const blockedByAbility = new BooleanHolder(false);
applyAbAttrs("ForceSwitchOutImmunityAbAttr", target, blockedByAbility); applyAbAttrs("ForceSwitchOutImmunityAbAttr", {pokemon: target, cancelled: blockedByAbility});
if (blockedByAbility.value) { if (blockedByAbility.value) {
return false; return false;
} }
@ -7967,7 +7978,7 @@ const failIfSingleBattle: MoveConditionFunc = (user, target, move) => globalScen
const failIfDampCondition: MoveConditionFunc = (user, target, move) => { const failIfDampCondition: MoveConditionFunc = (user, target, move) => {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
globalScene.getField(true).map(p=>applyAbAttrs("FieldPreventExplosiveMovesAbAttr", p, cancelled)); globalScene.getField(true).map(p=>applyAbAttrs("FieldPreventExplosiveMovesAbAttr", {pokemon: p, cancelled}));
// Queue a message if an ability prevented usage of the move // Queue a message if an ability prevented usage of the move
if (cancelled.value) { if (cancelled.value) {
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:cannotUseMove", { pokemonName: getPokemonNameWithAffix(user), moveName: move.name })); globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:cannotUseMove", { pokemonName: getPokemonNameWithAffix(user), moveName: move.name }));

View File

@ -2278,14 +2278,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
applyMoveAttrs("VariableMoveTypeAttr", this, null, move, moveTypeHolder); applyMoveAttrs("VariableMoveTypeAttr", this, null, move, moveTypeHolder);
const cancelled = new BooleanHolder(false);
const power = new NumberHolder(move.power); const power = new NumberHolder(move.power);
applyAbAttrs("MoveTypeChangeAbAttr", { applyAbAttrs("MoveTypeChangeAbAttr", {
pokemon: this, pokemon: this,
move, move,
simulated, simulated,
moveType: moveTypeHolder, moveType: moveTypeHolder,
cancelled,
power, power,
opponent: this, opponent: this,
}); });
@ -3747,7 +3745,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
opponent: this, opponent: this,
move, move,
simulated, simulated,
cancelled: new BooleanHolder(false),
multiplier: multiStrikeEnhancementMultiplier, multiplier: multiStrikeEnhancementMultiplier,
}); });
} }
@ -3855,8 +3852,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
move, move,
simulated, simulated,
damage, damage,
// cancelled isn't necessary for this ability attribute, but is required by the interface
cancelled: new BooleanHolder(false),
}); });
} }
@ -3872,7 +3867,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
pokemon: this, pokemon: this,
opponent: source, opponent: source,
move, move,
cancelled,
simulated, simulated,
damage, damage,
}; };

View File

@ -1,4 +1,4 @@
import { applyAbAttrs, applyPreLeaveFieldAbAttrs } from "#app/data/abilities/apply-ab-attrs"; import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import type { PlayerPokemon, EnemyPokemon } from "#app/field/pokemon"; import type { PlayerPokemon, EnemyPokemon } from "#app/field/pokemon";
@ -25,10 +25,10 @@ export class AttemptRunPhase extends PokemonPhase {
this.attemptRunAway(playerField, enemyField, escapeChance); this.attemptRunAway(playerField, enemyField, escapeChance);
applyAbAttrs("RunSuccessAbAttr", playerPokemon, null, false, escapeChance); applyAbAttrs("RunSuccessAbAttr", { pokemon: playerPokemon, chance: escapeChance });
if (playerPokemon.randBattleSeedInt(100) < escapeChance.value && !this.forceFailEscape) { if (playerPokemon.randBattleSeedInt(100) < escapeChance.value && !this.forceFailEscape) {
enemyField.forEach(enemyPokemon => applyPreLeaveFieldAbAttrs("PreLeaveFieldAbAttr", enemyPokemon)); enemyField.forEach(enemyPokemon => applyAbAttrs("PreLeaveFieldAbAttr", { pokemon: enemyPokemon }));
globalScene.playSound("se/flee"); globalScene.playSound("se/flee");
globalScene.phaseManager.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500); globalScene.phaseManager.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500);
@ -38,14 +38,11 @@ export class AttemptRunPhase extends PokemonPhase {
alpha: 0, alpha: 0,
duration: 250, duration: 250,
ease: "Sine.easeIn", ease: "Sine.easeIn",
onComplete: () => onComplete: () => enemyField.forEach(enemyPokemon => enemyPokemon.destroy()),
// biome-ignore lint/complexity/noForEach: TODO
enemyField.forEach(enemyPokemon => enemyPokemon.destroy()),
}); });
globalScene.clearEnemyHeldItemModifiers(); globalScene.clearEnemyHeldItemModifiers();
// biome-ignore lint/complexity/noForEach: TODO
enemyField.forEach(enemyPokemon => { enemyField.forEach(enemyPokemon => {
enemyPokemon.hideInfo().then(() => enemyPokemon.destroy()); enemyPokemon.hideInfo().then(() => enemyPokemon.destroy());
enemyPokemon.hp = 0; enemyPokemon.hp = 0;