mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-21 17:12:44 +02:00
Update callsites in pokemon.ts
This commit is contained in:
parent
55093ec0af
commit
b9781bd863
@ -1,7 +0,0 @@
|
|||||||
export type * from "#app/data/abilities/ability";
|
|
||||||
import type { AbAttrMap } from "./ability-types";
|
|
||||||
|
|
||||||
|
|
||||||
export type AbAttrParamMap = {
|
|
||||||
[K in keyof AbAttrMap]: Parameters<AbAttrMap[K]["apply"]>[0];
|
|
||||||
}
|
|
@ -1,17 +1,14 @@
|
|||||||
import type { AbAttr } from "#app/data/abilities/ability";
|
|
||||||
import type Move from "#app/data/moves/move";
|
import type Move from "#app/data/moves/move";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import type { BattleStat } from "#enums/stat";
|
import type { BattleStat } from "#enums/stat";
|
||||||
import type { AbAttrConstructorMap } from "#app/data/abilities/ability";
|
import type { AbAttrConstructorMap } from "#app/data/abilities/ability";
|
||||||
|
|
||||||
|
// intentionally re-export all types from abilities to have this be the centralized place to import ability types
|
||||||
|
export type * from "#app/data/abilities/ability";
|
||||||
|
|
||||||
// biome-ignore lint/correctness/noUnusedImports: Used in a tsdoc comment
|
// biome-ignore lint/correctness/noUnusedImports: Used in a tsdoc comment
|
||||||
import type { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
import type { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
||||||
|
|
||||||
// Intentionally re-export all types from the ability attributes module
|
|
||||||
export type * from "#app/data/abilities/ability";
|
|
||||||
|
|
||||||
export type AbAttrApplyFunc<TAttr extends AbAttr> = (attr: TAttr, passive: boolean, ...args: any[]) => void;
|
|
||||||
export type AbAttrSuccessFunc<TAttr extends AbAttr> = (attr: TAttr, passive: boolean, ...args: any[]) => boolean;
|
|
||||||
export type AbAttrCondition = (pokemon: Pokemon) => boolean;
|
export type AbAttrCondition = (pokemon: Pokemon) => boolean;
|
||||||
export type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean;
|
export type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean;
|
||||||
export type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean;
|
export type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean;
|
||||||
@ -33,11 +30,17 @@ export type AbAttrMap = {
|
|||||||
* Subset of ability attribute classes that may be passed to {@linkcode applyAbAttrs } method
|
* Subset of ability attribute classes that may be passed to {@linkcode applyAbAttrs } method
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* Our AbAttr classes violate Liskov Substitution Principal.
|
* Our AbAttr classes violate Liskov Substitution Principle.
|
||||||
*
|
*
|
||||||
* AbAttrs that are not in this have subclasses with apply methods requiring different parameters than
|
* AbAttrs that are not in this have subclasses with apply methods requiring different parameters than
|
||||||
* the base apply method.
|
* the base apply method.
|
||||||
*
|
*
|
||||||
* Such attributes may not be passed to the {@linkcode applyAbAttrs} method
|
* Such attributes may not be passed to the {@linkcode applyAbAttrs} method
|
||||||
*/
|
*/
|
||||||
export type CallableAbAttrString = Exclude<AbAttrString, "PreDefendAbAttr" | "PreAttackAbAttr">;
|
export type CallableAbAttrString =
|
||||||
|
| Exclude<AbAttrString, "PreDefendAbAttr" | "PreAttackAbAttr">
|
||||||
|
| "PreApplyBattlerTagAbAttr";
|
||||||
|
|
||||||
|
export type AbAttrParamMap = {
|
||||||
|
[K in keyof AbAttrMap]: Parameters<AbAttrMap[K]["apply"]>[0];
|
||||||
|
};
|
||||||
|
@ -22,3 +22,11 @@ export type Exact<T> = {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export type Closed<X> = X;
|
export type Closed<X> = X;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove `readonly` from all properties of the provided type
|
||||||
|
* @typeParam T - The type to make mutable
|
||||||
|
*/
|
||||||
|
export type Mutable<T> = {
|
||||||
|
-readonly [P in keyof T]: T[P];
|
||||||
|
};
|
||||||
|
@ -238,7 +238,7 @@ export interface AbAttrBaseParams {
|
|||||||
readonly simulated?: boolean;
|
readonly simulated?: boolean;
|
||||||
|
|
||||||
/** Whether the ability is the passive ability. Default false */
|
/** Whether the ability is the passive ability. Default false */
|
||||||
readonly passive?: boolean;
|
passive?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AbAttrParamsWithCancel extends AbAttrBaseParams {
|
export interface AbAttrParamsWithCancel extends AbAttrBaseParams {
|
||||||
@ -306,6 +306,7 @@ export abstract class AbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class BlockRecoilDamageAttr extends AbAttr {
|
export class BlockRecoilDamageAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
constructor() {
|
constructor() {
|
||||||
super(false);
|
super(false);
|
||||||
}
|
}
|
||||||
@ -314,7 +315,8 @@ export class BlockRecoilDamageAttr extends AbAttr {
|
|||||||
cancelled.value = true;
|
cancelled.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTriggerMessage({ pokemon }: AbAttrParamsWithCancel, abilityName: string) {
|
override getTriggerMessage({ pokemon }: AbAttrParamsWithCancel, abilityName: string) {
|
||||||
|
// TODO: remove this because this does not exist on cartridge
|
||||||
return i18next.t("abilityTriggers:blockRecoilDamage", {
|
return i18next.t("abilityTriggers:blockRecoilDamage", {
|
||||||
pokemonName: getPokemonNameWithAffix(pokemon),
|
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||||
abilityName: abilityName,
|
abilityName: abilityName,
|
||||||
@ -333,6 +335,7 @@ export interface DoubleBattleChanceAbAttrParams extends AbAttrBaseParams {
|
|||||||
* @see {@linkcode apply}
|
* @see {@linkcode apply}
|
||||||
*/
|
*/
|
||||||
export class DoubleBattleChanceAbAttr extends AbAttr {
|
export class DoubleBattleChanceAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
constructor() {
|
constructor() {
|
||||||
super(false);
|
super(false);
|
||||||
}
|
}
|
||||||
@ -1380,7 +1383,9 @@ export class PostDefendMoveDisableAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PostStatStageChangeAbAttr extends AbAttr {}
|
export class PostStatStageChangeAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PostStatStageChangeAbAttrParams extends AbAttrBaseParams {
|
export interface PostStatStageChangeAbAttrParams extends AbAttrBaseParams {
|
||||||
/** The stats that were changed */
|
/** The stats that were changed */
|
||||||
@ -1424,7 +1429,9 @@ export class PostStatStageChangeStatStageChangeAbAttr extends PostStatStageChang
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class PreAttackAbAttr extends AbAttr {}
|
export abstract class PreAttackAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ModifyMoveEffectChanceAbAttrParams extends AbAttrBaseParams {
|
export interface ModifyMoveEffectChanceAbAttrParams extends AbAttrBaseParams {
|
||||||
/** The move being used by the attacker */
|
/** The move being used by the attacker */
|
||||||
@ -1628,9 +1635,9 @@ export class PokemonTypeChangeAbAttr extends PreAttackAbAttr {
|
|||||||
*/
|
*/
|
||||||
export interface AddSecondStrikeAbAttrParams extends AugmentMoveInteractionAbAttrParams {
|
export interface AddSecondStrikeAbAttrParams extends AugmentMoveInteractionAbAttrParams {
|
||||||
/** Holder for the number of hits. May be modified by ability application */
|
/** Holder for the number of hits. May be modified by ability application */
|
||||||
hitCount: NumberHolder;
|
hitCount?: NumberHolder;
|
||||||
/** Holder for the damage multiplier _of the current hit_ */
|
/** Holder for the damage multiplier _of the current hit_ */
|
||||||
multiplier: NumberHolder;
|
multiplier?: NumberHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1660,11 +1667,11 @@ export class AddSecondStrikeAbAttr extends PreAttackAbAttr {
|
|||||||
* to the damage multiplier of this ability.
|
* to the damage multiplier of this ability.
|
||||||
*/
|
*/
|
||||||
override apply({ hitCount, multiplier, pokemon }: AddSecondStrikeAbAttrParams): void {
|
override apply({ hitCount, multiplier, pokemon }: AddSecondStrikeAbAttrParams): void {
|
||||||
if (hitCount.value) {
|
if (hitCount?.value) {
|
||||||
hitCount.value += 1;
|
hitCount.value += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multiplier.value && pokemon.turnData.hitsLeft === 1) {
|
if (multiplier?.value && pokemon.turnData.hitsLeft === 1) {
|
||||||
multiplier.value = this.damageMultiplier;
|
multiplier.value = this.damageMultiplier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1806,27 +1813,13 @@ export class FieldMovePowerBoostAbAttr extends AbAttr {
|
|||||||
this.powerMultiplier = powerMultiplier;
|
this.powerMultiplier = powerMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
canApplyPreAttack(
|
canApply(_params: PreAttackModifyPowerAbAttrParams): boolean {
|
||||||
_pokemon: Pokemon | null,
|
|
||||||
_passive: boolean | null,
|
|
||||||
_simulated: boolean,
|
|
||||||
_defender: Pokemon | null,
|
|
||||||
_move: Move,
|
|
||||||
_args: any[],
|
|
||||||
): boolean {
|
|
||||||
return true; // logic for this attr is handled in move.ts instead of normally
|
return true; // logic for this attr is handled in move.ts instead of normally
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPreAttack(
|
apply({ pokemon, opponent, move, power }: PreAttackModifyPowerAbAttrParams): void {
|
||||||
pokemon: Pokemon | null,
|
if (this.condition(pokemon, opponent, move)) {
|
||||||
_passive: boolean | null,
|
power.value *= this.powerMultiplier;
|
||||||
_simulated: boolean,
|
|
||||||
defender: Pokemon | null,
|
|
||||||
move: Move,
|
|
||||||
args: any[],
|
|
||||||
): void {
|
|
||||||
if (this.condition(pokemon, defender, move)) {
|
|
||||||
(args[0] as NumberHolder).value *= this.powerMultiplier;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1880,6 +1873,7 @@ export interface StatMultiplierAbAttrParams extends AbAttrBaseParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class StatMultiplierAbAttr extends AbAttr {
|
export class StatMultiplierAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
private stat: BattleStat;
|
private stat: BattleStat;
|
||||||
private multiplier: number;
|
private multiplier: number;
|
||||||
/** Function determining if the stat multiplier is able to be applied to the move.
|
/** Function determining if the stat multiplier is able to be applied to the move.
|
||||||
@ -1897,11 +1891,11 @@ export class StatMultiplierAbAttr extends AbAttr {
|
|||||||
this.condition = condition ?? null;
|
this.condition = condition ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
canApplyStatStage({ pokemon, move, stat }: StatMultiplierAbAttrParams): boolean {
|
override canApply({ pokemon, move, stat }: StatMultiplierAbAttrParams): boolean {
|
||||||
return stat === this.stat && (!this.condition || this.condition(pokemon, null, move));
|
return stat === this.stat && (!this.condition || this.condition(pokemon, null, move));
|
||||||
}
|
}
|
||||||
|
|
||||||
applyStatStage({ statVal }: StatMultiplierAbAttrParams): void {
|
override apply({ statVal }: StatMultiplierAbAttrParams): void {
|
||||||
statVal.value *= this.multiplier;
|
statVal.value *= this.multiplier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2380,7 +2374,7 @@ export class CopyFaintedAllyAbilityAbAttr extends PostKnockOutAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IgnoreOpponentStatStagesAbAttrParam extends AbAttrBaseParams {
|
export interface IgnoreOpponentStatStagesAbAttrParams extends AbAttrBaseParams {
|
||||||
/** The to check for ignorability */
|
/** The to check for ignorability */
|
||||||
stat: BattleStat;
|
stat: BattleStat;
|
||||||
/** Holds whether the stat is ignored by the ability */
|
/** Holds whether the stat is ignored by the ability */
|
||||||
@ -2402,14 +2396,14 @@ export class IgnoreOpponentStatStagesAbAttr extends AbAttr {
|
|||||||
/**
|
/**
|
||||||
* @returns Whether `stat` is one of the stats ignored by the ability
|
* @returns Whether `stat` is one of the stats ignored by the ability
|
||||||
*/
|
*/
|
||||||
override canApply({ stat }: IgnoreOpponentStatStagesAbAttrParam): boolean {
|
override canApply({ stat }: IgnoreOpponentStatStagesAbAttrParams): boolean {
|
||||||
return this.stats.includes(stat);
|
return this.stats.includes(stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the ignored holder to true.
|
* Sets the ignored holder to true.
|
||||||
*/
|
*/
|
||||||
override apply({ ignored }: IgnoreOpponentStatStagesAbAttrParam): void {
|
override apply({ ignored }: IgnoreOpponentStatStagesAbAttrParams): void {
|
||||||
ignored.value = true;
|
ignored.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3314,11 +3308,11 @@ export class PreSwitchOutFormChangeAbAttr extends PreSwitchOutAbAttr {
|
|||||||
* Base class for ability attributes that apply their effect just before the user leaves the field
|
* Base class for ability attributes that apply their effect just before the user leaves the field
|
||||||
*/
|
*/
|
||||||
export class PreLeaveFieldAbAttr extends AbAttr {
|
export class PreLeaveFieldAbAttr extends AbAttr {
|
||||||
canApplyPreLeaveField(_params: Closed<AbAttrBaseParams>): boolean {
|
canApply(_params: Closed<AbAttrBaseParams>): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPreLeaveField(_params: Closed<AbAttrBaseParams>): void {}
|
apply(_params: Closed<AbAttrBaseParams>): void {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3408,11 +3402,11 @@ export interface PreStatStageChangeAbAttrParams extends AbAttrBaseParams {
|
|||||||
* Base class for ability attributes that apply their effect before a stat stage change.
|
* Base class for ability attributes that apply their effect before a stat stage change.
|
||||||
*/
|
*/
|
||||||
export abstract class PreStatStageChangeAbAttr extends AbAttr {
|
export abstract class PreStatStageChangeAbAttr extends AbAttr {
|
||||||
canApplyPreStatStageChange(_params: Closed<PreStatStageChangeAbAttrParams>): boolean {
|
canApply(_params: Closed<PreStatStageChangeAbAttrParams>): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPreStatStageChange(_params: Closed<PreStatStageChangeAbAttrParams>): void {}
|
apply(_params: Closed<PreStatStageChangeAbAttrParams>): void {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3672,8 +3666,9 @@ export interface ConditionalUserFieldProtectStatAbAttrParams extends AbAttrBaseP
|
|||||||
stat: BattleStat;
|
stat: BattleStat;
|
||||||
/** Holds whether the stat stage change is prevented by the ability */
|
/** Holds whether the stat stage change is prevented by the ability */
|
||||||
cancelled: BooleanHolder;
|
cancelled: BooleanHolder;
|
||||||
|
// TODO: consider making this required and not inherit from PreStatStageChangeAbAttr
|
||||||
/** The target of the stat stage change */
|
/** The target of the stat stage change */
|
||||||
target: Pokemon;
|
target?: Pokemon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3724,21 +3719,20 @@ export interface PreApplyBattlerTagAbAttrParams extends AbAttrBaseParams {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for ability attributes that apply their effect before a BattlerTag {@linkcode BattlerTag} is applied.
|
* Base class for ability attributes that apply their effect before a BattlerTag {@linkcode BattlerTag} is applied.
|
||||||
|
* Subclasses violate Liskov Substitution Principle, so this class must not be provided to {@linkcode applyAbAttrs}
|
||||||
*/
|
*/
|
||||||
export abstract class PreApplyBattlerTagAbAttr extends AbAttr {
|
export abstract class PreApplyBattlerTagAbAttr extends AbAttr {
|
||||||
canApplyPreApplyBattlerTag(_params: Closed<PreApplyBattlerTagAbAttrParams>): boolean {
|
canApply(_params: PreApplyBattlerTagAbAttrParams): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPreApplyBattlerTag(_params: Closed<PreApplyBattlerTagAbAttrParams>): void {}
|
apply(_params: PreApplyBattlerTagAbAttrParams): void {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Intentionally not exported because this shouldn't be able to be passed to `applyAbAttrs`. It only exists so that
|
||||||
* Provides immunity to BattlerTags {@linkcode BattlerTag} to specified targets.
|
// PreApplyBattlerTagImmunityAbAttr and UserFieldPreApplyBattlerTagImmunityAbAttr can avoid code duplication
|
||||||
*
|
// while preserving type safety. (Since the UserField version require an additional parameter, target, in its apply methods)
|
||||||
* This does not check whether the tag is already applied; that check should happen in the caller.
|
abstract class BaseBattlerTagImmunityAbAttr<P extends PreApplyBattlerTagAbAttrParams> extends PreApplyBattlerTagAbAttr {
|
||||||
*/
|
|
||||||
export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
|
|
||||||
protected immuneTagTypes: BattlerTagType[];
|
protected immuneTagTypes: BattlerTagType[];
|
||||||
|
|
||||||
constructor(immuneTagTypes: BattlerTagType | BattlerTagType[]) {
|
constructor(immuneTagTypes: BattlerTagType | BattlerTagType[]) {
|
||||||
@ -3747,15 +3741,15 @@ export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
|
|||||||
this.immuneTagTypes = coerceArray(immuneTagTypes);
|
this.immuneTagTypes = coerceArray(immuneTagTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
override canApply({ cancelled, tag }: PreApplyBattlerTagAbAttrParams): boolean {
|
override canApply({ cancelled, tag }: P): boolean {
|
||||||
return !cancelled.value && this.immuneTagTypes.includes(tag.tagType);
|
return !cancelled.value && this.immuneTagTypes.includes(tag.tagType);
|
||||||
}
|
}
|
||||||
|
|
||||||
override apply({ cancelled }: PreApplyBattlerTagAbAttrParams): void {
|
override apply({ cancelled }: P): void {
|
||||||
cancelled.value = true;
|
cancelled.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
override getTriggerMessage({ pokemon, tag }: PreApplyBattlerTagAbAttrParams, abilityName: string): string {
|
override getTriggerMessage({ pokemon, tag }: P, abilityName: string): string {
|
||||||
return i18next.t("abilityTriggers:battlerTagImmunity", {
|
return i18next.t("abilityTriggers:battlerTagImmunity", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
abilityName,
|
abilityName,
|
||||||
@ -3764,18 +3758,31 @@ export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: The battler tag ability attributes are in dire need of improvement
|
||||||
|
// It is unclear why there is a `PreApplyBattlerTagImmunityAbAttr` class that isn't used,
|
||||||
|
// and then why there's a BattlerTagImmunityAbAttr class as well.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides immunity to BattlerTags {@linkcode BattlerTag} to specified targets.
|
||||||
|
*
|
||||||
|
* This does not check whether the tag is already applied; that check should happen in the caller.
|
||||||
|
*/
|
||||||
|
export class PreApplyBattlerTagImmunityAbAttr extends BaseBattlerTagImmunityAbAttr<PreApplyBattlerTagAbAttrParams> {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides immunity to BattlerTags {@linkcode BattlerTag} to the user.
|
* Provides immunity to BattlerTags {@linkcode BattlerTag} to the user.
|
||||||
*/
|
*/
|
||||||
export class BattlerTagImmunityAbAttr extends PreApplyBattlerTagImmunityAbAttr {}
|
export class BattlerTagImmunityAbAttr extends PreApplyBattlerTagImmunityAbAttr {}
|
||||||
|
|
||||||
|
export interface UserFieldBattlerTagImmunityAbAttrParams extends PreApplyBattlerTagAbAttrParams {
|
||||||
|
/** The pokemon that the battler tag is being applied to */
|
||||||
|
target: Pokemon;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Provides immunity to BattlerTags {@linkcode BattlerTag} to the user's field.
|
* Provides immunity to BattlerTags {@linkcode BattlerTag} to the user's field.
|
||||||
* @extends PreApplyBattlerTagImmunityAbAttr
|
|
||||||
*/
|
*/
|
||||||
export class UserFieldBattlerTagImmunityAbAttr extends PreApplyBattlerTagImmunityAbAttr {}
|
export class UserFieldBattlerTagImmunityAbAttr extends BaseBattlerTagImmunityAbAttr<UserFieldBattlerTagImmunityAbAttrParams> {}
|
||||||
|
|
||||||
// NOTE: We are inheriting from `PreApplyBattlerTagImmunityAbAttr` which has a different signature
|
|
||||||
export class ConditionalUserFieldBattlerTagImmunityAbAttr extends UserFieldBattlerTagImmunityAbAttr {
|
export class ConditionalUserFieldBattlerTagImmunityAbAttr extends UserFieldBattlerTagImmunityAbAttr {
|
||||||
private condition: (target: Pokemon) => boolean;
|
private condition: (target: Pokemon) => boolean;
|
||||||
|
|
||||||
@ -3783,12 +3790,14 @@ export class ConditionalUserFieldBattlerTagImmunityAbAttr extends UserFieldBattl
|
|||||||
* Determine whether the {@linkcode ConditionalUserFieldBattlerTagImmunityAbAttr} can be applied by passing the target pokemon to the condition.
|
* Determine whether the {@linkcode ConditionalUserFieldBattlerTagImmunityAbAttr} can be applied by passing the target pokemon to the condition.
|
||||||
* @returns Whether the ability can be used to cancel the battler tag
|
* @returns Whether the ability can be used to cancel the battler tag
|
||||||
*/
|
*/
|
||||||
override canApply(params: PreApplyBattlerTagAbAttrParams & { target: Pokemon }): boolean {
|
override canApply(params: UserFieldBattlerTagImmunityAbAttrParams): boolean {
|
||||||
// the `!!params` here is to ensure the target is not null or undefined. This is defensive programming
|
// the `!!params` here is to ensure the target is not null or undefined. This is defensive programming
|
||||||
// to guard against the case where
|
// to guard against the case where
|
||||||
return !!params.target && super.canApply(params) && this.condition(params.target ?? params.pokemon);
|
return !!params.target && super.canApply(params) && this.condition(params.target ?? params.pokemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override apply(_params: UserFieldBattlerTagImmunityAbAttrParams) {}
|
||||||
|
|
||||||
constructor(condition: (target: Pokemon) => boolean, immuneTagTypes: BattlerTagType | BattlerTagType[]) {
|
constructor(condition: (target: Pokemon) => boolean, immuneTagTypes: BattlerTagType | BattlerTagType[]) {
|
||||||
super(immuneTagTypes);
|
super(immuneTagTypes);
|
||||||
|
|
||||||
@ -3798,9 +3807,9 @@ export class ConditionalUserFieldBattlerTagImmunityAbAttr extends UserFieldBattl
|
|||||||
|
|
||||||
export interface BlockCritAbAttrParams extends AbAttrBaseParams {
|
export interface BlockCritAbAttrParams extends AbAttrBaseParams {
|
||||||
/**
|
/**
|
||||||
* Holds a boolean that will be set to false if the owner may not be crit
|
* Holds a boolean that will be set to true if the user's ability prevents the attack from being critical
|
||||||
*/
|
*/
|
||||||
readonly canCrit: BooleanHolder;
|
readonly blockCrit: BooleanHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BlockCritAbAttr extends AbAttr {
|
export class BlockCritAbAttr extends AbAttr {
|
||||||
@ -3863,7 +3872,7 @@ export interface ConditionalCritAbAttrParams extends AbAttrBaseParams {
|
|||||||
/** The move being used */
|
/** The move being used */
|
||||||
move: Move;
|
move: Move;
|
||||||
/** Holds whether the attack will critically hit */
|
/** Holds whether the attack will critically hit */
|
||||||
crit: BooleanHolder;
|
isCritical: BooleanHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3878,12 +3887,12 @@ export class ConditionalCritAbAttr extends AbAttr {
|
|||||||
this.condition = condition;
|
this.condition = condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
override canApply({ crit, pokemon, target, move }: ConditionalCritAbAttrParams): boolean {
|
override canApply({ isCritical, pokemon, target, move }: ConditionalCritAbAttrParams): boolean {
|
||||||
return !crit.value && this.condition(pokemon, target, move);
|
return !isCritical.value && this.condition(pokemon, target, move);
|
||||||
}
|
}
|
||||||
|
|
||||||
override apply({ crit }: ConditionalCritAbAttrParams): void {
|
override apply({ isCritical }: ConditionalCritAbAttrParams): void {
|
||||||
crit.value = true;
|
isCritical.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3904,7 +3913,7 @@ export class BlockStatusDamageAbAttr extends AbAttr {
|
|||||||
private effects: StatusEffect[];
|
private effects: StatusEffect[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {StatusEffect[]} effects The status effect(s) that will be blocked from damaging the ability pokemon
|
* @param effects - The status effect(s) that will be blocked from damaging the ability pokemon
|
||||||
*/
|
*/
|
||||||
constructor(...effects: StatusEffect[]) {
|
constructor(...effects: StatusEffect[]) {
|
||||||
super(false);
|
super(false);
|
||||||
@ -3916,8 +3925,6 @@ export class BlockStatusDamageAbAttr extends AbAttr {
|
|||||||
return !!pokemon.status?.effect && this.effects.includes(pokemon.status.effect);
|
return !!pokemon.status?.effect && this.effects.includes(pokemon.status.effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
override apply({ cancelled }: AbAttrParamsWithCancel): void {
|
override apply({ cancelled }: AbAttrParamsWithCancel): void {
|
||||||
cancelled.value = true;
|
cancelled.value = true;
|
||||||
}
|
}
|
||||||
@ -3967,7 +3974,9 @@ export class ChangeMovePriorityAbAttr extends AbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IgnoreContactAbAttr extends AbAttr {}
|
export class IgnoreContactAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared interface for attributes that respond to a weather.
|
* Shared interface for attributes that respond to a weather.
|
||||||
@ -4321,23 +4330,11 @@ export class PostWeatherLapseAbAttr extends AbAttr {
|
|||||||
this.weatherTypes = weatherTypes;
|
this.weatherTypes = weatherTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
canApplyPostWeatherLapse(
|
canApply(_params: Closed<PreWeatherEffectAbAttrParams>): boolean {
|
||||||
_pokemon: Pokemon,
|
|
||||||
_passive: boolean,
|
|
||||||
_simulated: boolean,
|
|
||||||
_weather: Weather | null,
|
|
||||||
_args: any[],
|
|
||||||
): boolean {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostWeatherLapse(
|
apply(_params: Closed<PreWeatherEffectAbAttrParams>): void {}
|
||||||
_pokemon: Pokemon,
|
|
||||||
_passive: boolean,
|
|
||||||
_simulated: boolean,
|
|
||||||
_weather: Weather | null,
|
|
||||||
_args: any[],
|
|
||||||
): void {}
|
|
||||||
|
|
||||||
getCondition(): AbAttrCondition {
|
getCondition(): AbAttrCondition {
|
||||||
return getWeatherCondition(...this.weatherTypes);
|
return getWeatherCondition(...this.weatherTypes);
|
||||||
@ -4353,23 +4350,11 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr {
|
|||||||
this.healFactor = healFactor;
|
this.healFactor = healFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
override canApplyPostWeatherLapse(
|
override canApply({ pokemon }: AbAttrBaseParams): boolean {
|
||||||
pokemon: Pokemon,
|
|
||||||
_passive: boolean,
|
|
||||||
_simulated: boolean,
|
|
||||||
_weather: Weather | null,
|
|
||||||
_args: any[],
|
|
||||||
): boolean {
|
|
||||||
return !pokemon.isFullHp();
|
return !pokemon.isFullHp();
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostWeatherLapse(
|
override apply({ pokemon, passive, simulated }: PreWeatherEffectAbAttrParams): void {
|
||||||
pokemon: Pokemon,
|
|
||||||
passive: boolean,
|
|
||||||
simulated: boolean,
|
|
||||||
_weather: Weather,
|
|
||||||
_args: any[],
|
|
||||||
): void {
|
|
||||||
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
globalScene.phaseManager.unshiftNew(
|
globalScene.phaseManager.unshiftNew(
|
||||||
@ -4395,23 +4380,11 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr {
|
|||||||
this.damageFactor = damageFactor;
|
this.damageFactor = damageFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
override canApplyPostWeatherLapse(
|
override canApply({ pokemon }: PreWeatherEffectAbAttrParams): boolean {
|
||||||
pokemon: Pokemon,
|
|
||||||
_passive: boolean,
|
|
||||||
_simulated: boolean,
|
|
||||||
_weather: Weather | null,
|
|
||||||
_args: any[],
|
|
||||||
): boolean {
|
|
||||||
return !pokemon.hasAbilityWithAttr("BlockNonDirectDamageAbAttr");
|
return !pokemon.hasAbilityWithAttr("BlockNonDirectDamageAbAttr");
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostWeatherLapse(
|
override apply({ simulated, pokemon, passive }: PreWeatherEffectAbAttrParams): void {
|
||||||
pokemon: Pokemon,
|
|
||||||
passive: boolean,
|
|
||||||
simulated: boolean,
|
|
||||||
_weather: Weather,
|
|
||||||
_args: any[],
|
|
||||||
): void {
|
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
||||||
globalScene.phaseManager.queueMessage(
|
globalScene.phaseManager.queueMessage(
|
||||||
@ -4430,8 +4403,6 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr {
|
|||||||
export interface PostTerrainChangeAbAttrParams extends AbAttrBaseParams {
|
export interface PostTerrainChangeAbAttrParams extends AbAttrBaseParams {
|
||||||
/** The terrain type that is being changed to */
|
/** The terrain type that is being changed to */
|
||||||
terrain: TerrainType;
|
terrain: TerrainType;
|
||||||
/** Holds whether the terrain change is prevented by the ability */
|
|
||||||
cancelled: BooleanHolder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PostTerrainChangeAbAttr extends AbAttr {
|
export class PostTerrainChangeAbAttr extends AbAttr {
|
||||||
@ -4858,7 +4829,9 @@ export class FetchBallAbAttr extends PostTurnAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PostBiomeChangeAbAttr extends AbAttr {}
|
export class PostBiomeChangeAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
|
}
|
||||||
|
|
||||||
export class PostBiomeChangeWeatherChangeAbAttr extends PostBiomeChangeAbAttr {
|
export class PostBiomeChangeWeatherChangeAbAttr extends PostBiomeChangeAbAttr {
|
||||||
private weatherType: WeatherType;
|
private weatherType: WeatherType;
|
||||||
@ -4914,11 +4887,11 @@ export interface PostMoveUsedAbAttrParams extends AbAttrBaseParams {
|
|||||||
* Triggers just after a move is used either by the opponent or the player
|
* Triggers just after a move is used either by the opponent or the player
|
||||||
*/
|
*/
|
||||||
export class PostMoveUsedAbAttr extends AbAttr {
|
export class PostMoveUsedAbAttr extends AbAttr {
|
||||||
canApplyPostMoveUsed(_params: Closed<PostMoveUsedAbAttrParams>): boolean {
|
canApply(_params: Closed<PostMoveUsedAbAttrParams>): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostMoveUsed(_params: Closed<PostMoveUsedAbAttrParams>): void {}
|
apply(_params: Closed<PostMoveUsedAbAttrParams>): void {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4926,7 +4899,7 @@ export class PostMoveUsedAbAttr extends AbAttr {
|
|||||||
* @extends PostMoveUsedAbAttr
|
* @extends PostMoveUsedAbAttr
|
||||||
*/
|
*/
|
||||||
export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
|
export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
|
||||||
override canApplyPostMoveUsed({ source, pokemon }: PostMoveUsedAbAttrParams): boolean {
|
override canApply({ source, pokemon }: PostMoveUsedAbAttrParams): boolean {
|
||||||
// List of tags that prevent the Dancer from replicating the move
|
// List of tags that prevent the Dancer from replicating the move
|
||||||
const forbiddenTags = [
|
const forbiddenTags = [
|
||||||
BattlerTagType.FLYING,
|
BattlerTagType.FLYING,
|
||||||
@ -4985,11 +4958,11 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
|
|||||||
* @extends AbAttr
|
* @extends AbAttr
|
||||||
*/
|
*/
|
||||||
export class PostItemLostAbAttr extends AbAttr {
|
export class PostItemLostAbAttr extends AbAttr {
|
||||||
canApplyPostItemLost(_pokemon: Pokemon, _simulated: boolean, _args: any[]): boolean {
|
canApply(_params: Closed<AbAttrBaseParams>): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostItemLost(_pokemon: Pokemon, _simulated: boolean, _args: any[]): void {}
|
apply(_params: Closed<AbAttrBaseParams>): void {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -5002,7 +4975,7 @@ export class PostItemLostApplyBattlerTagAbAttr extends PostItemLostAbAttr {
|
|||||||
this.tagType = tagType;
|
this.tagType = tagType;
|
||||||
}
|
}
|
||||||
|
|
||||||
override canApplyPostItemLost(pokemon: Pokemon, simulated: boolean, _args: any[]): boolean {
|
override canApply({ pokemon, simulated }: AbAttrBaseParams): boolean {
|
||||||
return !pokemon.getTag(this.tagType) && !simulated;
|
return !pokemon.getTag(this.tagType) && !simulated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5011,7 +4984,7 @@ export class PostItemLostApplyBattlerTagAbAttr extends PostItemLostAbAttr {
|
|||||||
* @param pokemon {@linkcode Pokemon} with this ability
|
* @param pokemon {@linkcode Pokemon} with this ability
|
||||||
* @param _args N/A
|
* @param _args N/A
|
||||||
*/
|
*/
|
||||||
override applyPostItemLost(pokemon: Pokemon, _simulated: boolean, _args: any[]): void {
|
override apply({ pokemon }: AbAttrBaseParams): void {
|
||||||
pokemon.addTag(this.tagType);
|
pokemon.addTag(this.tagType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5176,25 +5149,11 @@ export class CheckTrappedAbAttr extends AbAttr {
|
|||||||
this.arenaTrapCondition = condition;
|
this.arenaTrapCondition = condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
canApplyCheckTrapped(
|
override canApply(_params: Closed<CheckTrappedAbAttrParams>): boolean {
|
||||||
_pokemon: Pokemon,
|
|
||||||
_passive: boolean,
|
|
||||||
_simulated: boolean,
|
|
||||||
_trapped: BooleanHolder,
|
|
||||||
_otherPokemon: Pokemon,
|
|
||||||
_args: any[],
|
|
||||||
): boolean {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyCheckTrapped(
|
override apply(_params: Closed<CheckTrappedAbAttrParams>): void {}
|
||||||
_pokemon: Pokemon,
|
|
||||||
_passive: boolean,
|
|
||||||
_simulated: boolean,
|
|
||||||
_trapped: BooleanHolder,
|
|
||||||
_otherPokemon: Pokemon,
|
|
||||||
_args: any[],
|
|
||||||
): void {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CheckTrappedAbAttrParams extends AbAttrBaseParams {
|
export interface CheckTrappedAbAttrParams extends AbAttrBaseParams {
|
||||||
@ -5232,7 +5191,7 @@ export class ArenaTrapAbAttr extends CheckTrappedAbAttr {
|
|||||||
trapped.value = true;
|
trapped.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTriggerMessage({ pokemon }: CheckTrappedAbAttrParams, abilityName: string): string {
|
override getTriggerMessage({ pokemon }: CheckTrappedAbAttrParams, abilityName: string): string {
|
||||||
return i18next.t("abilityTriggers:arenaTrap", {
|
return i18next.t("abilityTriggers:arenaTrap", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
abilityName,
|
abilityName,
|
||||||
@ -5543,7 +5502,9 @@ export class FlinchStatStageChangeAbAttr extends FlinchEffectAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IncreasePpAbAttr extends AbAttr {}
|
export class IncreasePpAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
|
}
|
||||||
|
|
||||||
/** @sealed */
|
/** @sealed */
|
||||||
export class ForceSwitchOutImmunityAbAttr extends AbAttr {
|
export class ForceSwitchOutImmunityAbAttr extends AbAttr {
|
||||||
@ -5682,10 +5643,13 @@ export class InfiltratorAbAttr extends AbAttr {
|
|||||||
* moves as if the user had used {@linkcode MoveId.MAGIC_COAT | Magic Coat}.
|
* moves as if the user had used {@linkcode MoveId.MAGIC_COAT | Magic Coat}.
|
||||||
* @sealed
|
* @sealed
|
||||||
*/
|
*/
|
||||||
export class ReflectStatusMoveAbAttr extends AbAttr {}
|
export class ReflectStatusMoveAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
|
}
|
||||||
|
|
||||||
/** @sealed */
|
/** @sealed */
|
||||||
export class NoTransformAbilityAbAttr extends AbAttr {
|
export class NoTransformAbilityAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
constructor() {
|
constructor() {
|
||||||
super(false);
|
super(false);
|
||||||
}
|
}
|
||||||
@ -5693,6 +5657,7 @@ export class NoTransformAbilityAbAttr extends AbAttr {
|
|||||||
|
|
||||||
/** @sealed */
|
/** @sealed */
|
||||||
export class NoFusionAbilityAbAttr extends AbAttr {
|
export class NoFusionAbilityAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
constructor() {
|
constructor() {
|
||||||
super(false);
|
super(false);
|
||||||
}
|
}
|
||||||
@ -5917,6 +5882,7 @@ export class IllusionPreSummonAbAttr extends PreSummonAbAttr {
|
|||||||
|
|
||||||
/** @sealed */
|
/** @sealed */
|
||||||
export class IllusionBreakAbAttr extends AbAttr {
|
export class IllusionBreakAbAttr extends AbAttr {
|
||||||
|
private declare readonly _: never;
|
||||||
// TODO: Consider adding a `canApply` method that checks if the pokemon has an active illusion
|
// TODO: Consider adding a `canApply` method that checks if the pokemon has an active illusion
|
||||||
override apply({ pokemon }: AbAttrBaseParams): void {
|
override apply({ pokemon }: AbAttrBaseParams): void {
|
||||||
pokemon.breakIllusion();
|
pokemon.breakIllusion();
|
||||||
@ -6294,11 +6260,11 @@ export interface PostDamageAbAttrParams extends AbAttrBaseParams {
|
|||||||
* Triggers after the Pokemon takes any damage
|
* Triggers after the Pokemon takes any damage
|
||||||
*/
|
*/
|
||||||
export class PostDamageAbAttr extends AbAttr {
|
export class PostDamageAbAttr extends AbAttr {
|
||||||
public canApplyPostDamage(_params: PostDamageAbAttrParams): boolean {
|
override canApply(_params: PostDamageAbAttrParams): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public applyPostDamage(_params: PostDamageAbAttrParams): void {}
|
override apply(_params: PostDamageAbAttrParams): void {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import type { AbAttrParamMap } from "#app/@types/ab-attr-types";
|
import type { AbAttrParamMap } from "#app/@types/ability-types";
|
||||||
import type { AbAttr, AbAttrBaseParams, AbAttrMap, CallableAbAttrString } from "#app/@types/ability-types";
|
import type { AbAttr, AbAttrBaseParams, AbAttrString, CallableAbAttrString } from "#app/@types/ability-types";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
|
|
||||||
function applySingleAbAttrs<T extends CallableAbAttrString>(
|
function applySingleAbAttrs<T extends AbAttrString>(
|
||||||
attrType: T,
|
attrType: T,
|
||||||
params: AbAttrParamMap[T],
|
params: AbAttrParamMap[T],
|
||||||
gainedMidTurn = false,
|
gainedMidTurn = false,
|
||||||
@ -15,11 +15,10 @@ function applySingleAbAttrs<T extends CallableAbAttrString>(
|
|||||||
|
|
||||||
const attr = 1 as unknown as AbAttr;
|
const attr = 1 as unknown as AbAttr;
|
||||||
|
|
||||||
if (attr.is("BlockRedirectAbAttr")) {
|
if (attr.is("BypassSpeedChanceAbAttr")) {
|
||||||
attr
|
attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ability = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
|
const ability = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
|
||||||
if (
|
if (
|
||||||
gainedMidTurn &&
|
gainedMidTurn &&
|
||||||
@ -30,12 +29,15 @@ function applySingleAbAttrs<T extends CallableAbAttrString>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// typescript assert
|
// typescript assert
|
||||||
for (const attr of ability.getAttrs(attrType)) {
|
for (const attr of ability.getAttrs(attrType)) {
|
||||||
const condition = attr.getCondition();
|
const condition = attr.getCondition();
|
||||||
let abShown = false;
|
let abShown = false;
|
||||||
if ((condition && !condition(pokemon)) || !attr.canApply(params)) {
|
if (
|
||||||
|
(condition && !condition(pokemon)) ||
|
||||||
|
// @ts-ignore: typescript can't unify the type of params with the generic type that was passed
|
||||||
|
!attr.canApply(params)
|
||||||
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +47,7 @@ function applySingleAbAttrs<T extends CallableAbAttrString>(
|
|||||||
globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, true);
|
globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, true);
|
||||||
abShown = true;
|
abShown = true;
|
||||||
}
|
}
|
||||||
|
// @ts-expect-error - typescript can't unify the type of params with the generic type that was passed
|
||||||
const message = attr.getTriggerMessage(params, ability.name);
|
const message = attr.getTriggerMessage(params, ability.name);
|
||||||
if (message) {
|
if (message) {
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
@ -53,7 +56,8 @@ function applySingleAbAttrs<T extends CallableAbAttrString>(
|
|||||||
messages.push(message);
|
messages.push(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore: typescript can't unify the type of params with the generic type that was passed
|
||||||
|
attr.apply(params);
|
||||||
|
|
||||||
if (abShown) {
|
if (abShown) {
|
||||||
globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, false);
|
globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, false);
|
||||||
@ -69,31 +73,42 @@ function applySingleAbAttrs<T extends CallableAbAttrString>(
|
|||||||
|
|
||||||
function applyAbAttrsInternal<T extends CallableAbAttrString>(
|
function applyAbAttrsInternal<T extends CallableAbAttrString>(
|
||||||
attrType: T,
|
attrType: T,
|
||||||
params: Parameters<AbAttrMap[T]["apply"]>[0],
|
params: AbAttrParamMap[T],
|
||||||
messages: string[] = [],
|
messages: string[] = [],
|
||||||
gainedMidTurn = false,
|
gainedMidTurn = false,
|
||||||
) {
|
) {
|
||||||
const { pokemon } = params;
|
// If the pokemon is not defined, no ability attributes to be applied.
|
||||||
for (const passive of [false, true]) {
|
// TODO: Evaluate whether this check is even necessary anymore
|
||||||
if (pokemon) {
|
if (!params.pokemon) {
|
||||||
applySingleAbAttrs(attrType, { ...params, passive }, gainedMidTurn, messages);
|
return;
|
||||||
globalScene.phaseManager.clearPhaseQueueSplice();
|
|
||||||
}
|
}
|
||||||
|
if (params.passive !== undefined) {
|
||||||
|
applySingleAbAttrs(attrType, params, gainedMidTurn, messages);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const passive of [false, true]) {
|
||||||
|
params.passive = passive;
|
||||||
|
applySingleAbAttrs(attrType, params, gainedMidTurn, messages);
|
||||||
|
globalScene.phaseManager.clearPhaseQueueSplice();
|
||||||
|
// We need to restore passive to its original state in case it was undefined earlier
|
||||||
|
// this is necessary in case this method is called with an object that is reused.
|
||||||
|
params.passive = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param attrType - The type of the ability attribute to apply
|
* @param attrType - The type of the ability attribute to apply. (note: may not be any attribute that extends PostSummonAbAttr)
|
||||||
* @param params - The parameters to pass to the ability attribute's apply method
|
* @param params - The parameters to pass to the ability attribute's apply method
|
||||||
|
* @param messages - An optional array to which ability trigger messges will be added
|
||||||
*/
|
*/
|
||||||
export function applyAbAttrs<T extends CallableAbAttrString>(
|
export function applyAbAttrs<T extends CallableAbAttrString>(
|
||||||
attrType: T,
|
attrType: T,
|
||||||
params: Parameters<AbAttrMap[T]["apply"]>[0],
|
params: AbAttrParamMap[T],
|
||||||
|
messages?: string[],
|
||||||
): void {
|
): void {
|
||||||
applyAbAttrsInternal(attrType, params);
|
applyAbAttrsInternal(attrType, params, messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Improve the type signatures of the following methods / refactor the apply methods
|
// TODO: Improve the type signatures of the following methods / refactor the apply methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,17 +123,8 @@ export function applyOnGainAbAttrs(params: AbAttrBaseParams): void {
|
|||||||
/**
|
/**
|
||||||
* Applies ability attributes which activate when the ability is lost or suppressed (i.e. primal weather)
|
* Applies ability attributes which activate when the ability is lost or suppressed (i.e. primal weather)
|
||||||
*/
|
*/
|
||||||
export function applyOnLoseAbAttrs(params): void {
|
export function applyOnLoseAbAttrs(params: AbAttrBaseParams): void {
|
||||||
applySingleAbAttrs("PreLeaveFieldAbAttr");
|
applySingleAbAttrs("PreLeaveFieldAbAttr", params, true);
|
||||||
|
|
||||||
applySingleAbAttrs(
|
applySingleAbAttrs("IllusionBreakAbAttr", params, true);
|
||||||
pokemon,
|
|
||||||
passive,
|
|
||||||
"IllusionBreakAbAttr",
|
|
||||||
(attr, passive) => attr.apply(pokemon, passive, simulated, null, args),
|
|
||||||
(attr, passive) => attr.canApply(pokemon, passive, simulated, args),
|
|
||||||
args,
|
|
||||||
true,
|
|
||||||
simulated,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ export class MistTag extends ArenaTag {
|
|||||||
if (attacker) {
|
if (attacker) {
|
||||||
const bypassed = new BooleanHolder(false);
|
const bypassed = new BooleanHolder(false);
|
||||||
// TODO: Allow this to be simulated
|
// TODO: Allow this to be simulated
|
||||||
applyAbAttrs("InfiltratorAbAttr", attacker, null, false, bypassed);
|
applyAbAttrs("InfiltratorAbAttr", { pokemon: attacker, simulated: false, bypassed });
|
||||||
if (bypassed.value) {
|
if (bypassed.value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -758,7 +758,7 @@ class SpikesTag extends ArenaTrapTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cancelled = new BooleanHolder(false);
|
const cancelled = new BooleanHolder(false);
|
||||||
applyAbAttrs("BlockNonDirectDamageAbAttr", pokemon, cancelled);
|
applyAbAttrs("BlockNonDirectDamageAbAttr", { pokemon, cancelled });
|
||||||
if (simulated || cancelled.value) {
|
if (simulated || cancelled.value) {
|
||||||
return !cancelled.value;
|
return !cancelled.value;
|
||||||
}
|
}
|
||||||
@ -1438,7 +1438,10 @@ export class SuppressAbilitiesTag extends ArenaTag {
|
|||||||
const setter = globalScene
|
const setter = globalScene
|
||||||
.getField()
|
.getField()
|
||||||
.filter(p => p?.hasAbilityWithAttr("PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr", false))[0];
|
.filter(p => p?.hasAbilityWithAttr("PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr", false))[0];
|
||||||
applyOnGainAbAttrs(setter, setter.getAbility().hasAttr("PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr"));
|
applyOnGainAbAttrs({
|
||||||
|
pokemon: setter,
|
||||||
|
passive: setter.getAbility().hasAttr("PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr"),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1451,7 +1454,7 @@ export class SuppressAbilitiesTag extends ArenaTag {
|
|||||||
for (const pokemon of globalScene.getField(true)) {
|
for (const pokemon of globalScene.getField(true)) {
|
||||||
// There is only one pokemon with this attr on the field on removal, so its abilities are already active
|
// There is only one pokemon with this attr on the field on removal, so its abilities are already active
|
||||||
if (pokemon && !pokemon.hasAbilityWithAttr("PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr", false)) {
|
if (pokemon && !pokemon.hasAbilityWithAttr("PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr", false)) {
|
||||||
[true, false].forEach(passive => applyOnGainAbAttrs(pokemon, passive));
|
[true, false].forEach(passive => applyOnGainAbAttrs({ pokemon, passive }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2553,7 +2553,7 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr {
|
|||||||
apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
|
||||||
const statusToApply: StatusEffect | undefined = user.status?.effect ?? (user.hasAbility(AbilityId.COMATOSE) ? StatusEffect.SLEEP : undefined);
|
const statusToApply: StatusEffect | undefined = user.status?.effect ?? (user.hasAbility(AbilityId.COMATOSE) ? StatusEffect.SLEEP : undefined);
|
||||||
|
|
||||||
if (target.status) {
|
if (target.status || !statusToApply) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
const canSetStatus = target.canSetStatus(statusToApply, true, false, user);
|
const canSetStatus = target.canSetStatus(statusToApply, true, false, user);
|
||||||
@ -2569,7 +2569,8 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||||
return !target.status && target.canSetStatus(user.status?.effect, true, false, user) ? -10 : 0;
|
const statusToApply = user.status?.effect ?? (user.hasAbility(AbilityId.COMATOSE) ? StatusEffect.SLEEP : undefined);
|
||||||
|
return !target.status && statusToApply && target.canSetStatus(statusToApply, true, false, user) ? -10 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,8 +457,8 @@ export class Arena {
|
|||||||
pokemon.findAndRemoveTags(
|
pokemon.findAndRemoveTags(
|
||||||
t => "terrainTypes" in t && !(t.terrainTypes as TerrainType[]).find(t => t === terrain),
|
t => "terrainTypes" in t && !(t.terrainTypes as TerrainType[]).find(t => t === terrain),
|
||||||
);
|
);
|
||||||
applyPostTerrainChangeAbAttrs("PostTerrainChangeAbAttr", pokemon, terrain);
|
applyAbAttrs("PostTerrainChangeAbAttr", { pokemon, terrain });
|
||||||
applyAbAttrs("TerrainEventTypeChangeAbAttr", pokemon, null, false);
|
applyAbAttrs("TerrainEventTypeChangeAbAttr", { pokemon });
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -108,23 +108,8 @@ import { WeatherType } from "#enums/weather-type";
|
|||||||
import { NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag";
|
import { NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag";
|
||||||
import { ArenaTagSide } from "#enums/arena-tag-side";
|
import { ArenaTagSide } from "#enums/arena-tag-side";
|
||||||
import type { SuppressAbilitiesTag } from "#app/data/arena-tag";
|
import type { SuppressAbilitiesTag } from "#app/data/arena-tag";
|
||||||
import type { Ability } from "#app/data/abilities/ability";
|
import type { Ability, PreAttackModifyDamageAbAttrParams } from "#app/data/abilities/ability";
|
||||||
import {
|
import { applyAbAttrs, applyOnGainAbAttrs, applyOnLoseAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
||||||
applyAbAttrs,
|
|
||||||
applyStatMultiplierAbAttrs,
|
|
||||||
applyPreApplyBattlerTagAbAttrs,
|
|
||||||
applyPreAttackAbAttrs,
|
|
||||||
applyPreDefendAbAttrs,
|
|
||||||
applyPreSetStatusAbAttrs,
|
|
||||||
applyFieldStatMultiplierAbAttrs,
|
|
||||||
applyCheckTrappedAbAttrs,
|
|
||||||
applyPostDamageAbAttrs,
|
|
||||||
applyPostItemLostAbAttrs,
|
|
||||||
applyOnGainAbAttrs,
|
|
||||||
applyPreLeaveFieldAbAttrs,
|
|
||||||
applyOnLoseAbAttrs,
|
|
||||||
applyAllyStatMultiplierAbAttrs,
|
|
||||||
} from "#app/data/abilities/apply-ab-attrs";
|
|
||||||
import { allAbilities } from "#app/data/data-lists";
|
import { allAbilities } from "#app/data/data-lists";
|
||||||
import type PokemonData from "#app/system/pokemon-data";
|
import type PokemonData from "#app/system/pokemon-data";
|
||||||
import { BattlerIndex } from "#enums/battler-index";
|
import { BattlerIndex } from "#enums/battler-index";
|
||||||
@ -189,7 +174,7 @@ import { HitResult } from "#enums/hit-result";
|
|||||||
import { AiType } from "#enums/ai-type";
|
import { AiType } from "#enums/ai-type";
|
||||||
import type { MoveResult } from "#enums/move-result";
|
import type { MoveResult } from "#enums/move-result";
|
||||||
import { PokemonMove } from "#app/data/moves/pokemon-move";
|
import { PokemonMove } from "#app/data/moves/pokemon-move";
|
||||||
import type { AbAttrMap, AbAttrString } from "#app/@types/ability-types";
|
import type { AbAttrMap, AbAttrString, TypeMultiplierAbAttrParams } from "#app/@types/ability-types";
|
||||||
|
|
||||||
/** Base typeclass for damage parameter methods, used for DRY */
|
/** Base typeclass for damage parameter methods, used for DRY */
|
||||||
type damageParams = {
|
type damageParams = {
|
||||||
@ -1364,7 +1349,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
applyMoveAttrs("HighCritAttr", source, this, move, critStage);
|
applyMoveAttrs("HighCritAttr", source, this, move, critStage);
|
||||||
globalScene.applyModifiers(CritBoosterModifier, source.isPlayer(), source, critStage);
|
globalScene.applyModifiers(CritBoosterModifier, source.isPlayer(), source, critStage);
|
||||||
globalScene.applyModifiers(TempCritBoosterModifier, source.isPlayer(), critStage);
|
globalScene.applyModifiers(TempCritBoosterModifier, source.isPlayer(), critStage);
|
||||||
applyAbAttrs("BonusCritAbAttr", source, null, false, critStage);
|
applyAbAttrs("BonusCritAbAttr", { pokemon: source, critStage });
|
||||||
const critBoostTag = source.getTag(CritBoostTag);
|
const critBoostTag = source.getTag(CritBoostTag);
|
||||||
if (critBoostTag) {
|
if (critBoostTag) {
|
||||||
// Dragon cheer only gives +1 crit stage to non-dragon types
|
// Dragon cheer only gives +1 crit stage to non-dragon types
|
||||||
@ -1415,46 +1400,52 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
simulated = true,
|
simulated = true,
|
||||||
ignoreHeldItems = false,
|
ignoreHeldItems = false,
|
||||||
): number {
|
): number {
|
||||||
const statValue = new NumberHolder(this.getStat(stat, false));
|
const statVal = new NumberHolder(this.getStat(stat, false));
|
||||||
if (!ignoreHeldItems) {
|
if (!ignoreHeldItems) {
|
||||||
globalScene.applyModifiers(StatBoosterModifier, this.isPlayer(), this, stat, statValue);
|
globalScene.applyModifiers(StatBoosterModifier, this.isPlayer(), this, stat, statVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Ruin abilities here are never ignored, but they reveal themselves on summon anyway
|
// The Ruin abilities here are never ignored, but they reveal themselves on summon anyway
|
||||||
const fieldApplied = new BooleanHolder(false);
|
const fieldApplied = new BooleanHolder(false);
|
||||||
for (const pokemon of globalScene.getField(true)) {
|
for (const pokemon of globalScene.getField(true)) {
|
||||||
applyFieldStatMultiplierAbAttrs(
|
applyAbAttrs("FieldMultiplyStatAbAttr", {
|
||||||
"FieldMultiplyStatAbAttr",
|
|
||||||
pokemon,
|
pokemon,
|
||||||
stat,
|
stat,
|
||||||
statValue,
|
statVal,
|
||||||
this,
|
target: this,
|
||||||
fieldApplied,
|
hasApplied: fieldApplied,
|
||||||
simulated,
|
simulated,
|
||||||
);
|
});
|
||||||
if (fieldApplied.value) {
|
if (fieldApplied.value) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ignoreAbility) {
|
if (!ignoreAbility) {
|
||||||
applyStatMultiplierAbAttrs("StatMultiplierAbAttr", this, stat, statValue, simulated);
|
applyAbAttrs("StatMultiplierAbAttr", {
|
||||||
|
pokemon: this,
|
||||||
|
stat,
|
||||||
|
statVal,
|
||||||
|
simulated,
|
||||||
|
// TODO: maybe just don't call this if the move is none?
|
||||||
|
move: move ?? allMoves[MoveId.NONE],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const ally = this.getAlly();
|
const ally = this.getAlly();
|
||||||
if (!isNullOrUndefined(ally)) {
|
if (!isNullOrUndefined(ally)) {
|
||||||
applyAllyStatMultiplierAbAttrs(
|
applyAbAttrs("AllyStatMultiplierAbAttr", {
|
||||||
"AllyStatMultiplierAbAttr",
|
pokemon: ally,
|
||||||
ally,
|
|
||||||
stat,
|
stat,
|
||||||
statValue,
|
statVal,
|
||||||
simulated,
|
simulated,
|
||||||
this,
|
// TODO: maybe just don't call this if the move is none?
|
||||||
move?.hasFlag(MoveFlags.IGNORE_ABILITIES) || ignoreAllyAbility,
|
move: move ?? allMoves[MoveId.NONE],
|
||||||
);
|
ignoreAbility: move?.hasFlag(MoveFlags.IGNORE_ABILITIES) || ignoreAllyAbility,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret =
|
let ret =
|
||||||
statValue.value *
|
statVal.value *
|
||||||
this.getStatStageMultiplier(stat, opponent, move, ignoreOppAbility, isCritical, simulated, ignoreHeldItems);
|
this.getStatStageMultiplier(stat, opponent, move, ignoreOppAbility, isCritical, simulated, ignoreHeldItems);
|
||||||
|
|
||||||
switch (stat) {
|
switch (stat) {
|
||||||
@ -2045,20 +2036,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* @param ability New Ability
|
* @param ability New Ability
|
||||||
*/
|
*/
|
||||||
public setTempAbility(ability: Ability, passive = false): void {
|
public setTempAbility(ability: Ability, passive = false): void {
|
||||||
applyOnLoseAbAttrs(this, passive);
|
applyOnLoseAbAttrs({ pokemon: this, passive });
|
||||||
if (passive) {
|
if (passive) {
|
||||||
this.summonData.passiveAbility = ability.id;
|
this.summonData.passiveAbility = ability.id;
|
||||||
} else {
|
} else {
|
||||||
this.summonData.ability = ability.id;
|
this.summonData.ability = ability.id;
|
||||||
}
|
}
|
||||||
applyOnGainAbAttrs(this, passive);
|
applyOnGainAbAttrs({ pokemon: this, passive });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Suppresses an ability and calls its onlose attributes
|
* Suppresses an ability and calls its onlose attributes
|
||||||
*/
|
*/
|
||||||
public suppressAbility() {
|
public suppressAbility() {
|
||||||
[true, false].forEach(passive => applyOnLoseAbAttrs(this, passive));
|
[true, false].forEach(passive => applyOnLoseAbAttrs({ pokemon: this, passive }));
|
||||||
this.summonData.abilitySuppressed = true;
|
this.summonData.abilitySuppressed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2194,7 +2185,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const weight = new NumberHolder(this.species.weight - weightRemoved);
|
const weight = new NumberHolder(this.species.weight - weightRemoved);
|
||||||
|
|
||||||
// This will trigger the ability overlay so only call this function when necessary
|
// This will trigger the ability overlay so only call this function when necessary
|
||||||
applyAbAttrs("WeightMultiplierAbAttr", this, null, false, weight);
|
applyAbAttrs("WeightMultiplierAbAttr", { pokemon: this, weight });
|
||||||
return Math.max(minWeight, weight.value);
|
return Math.max(minWeight, weight.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2256,7 +2247,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const trappedByAbility = new BooleanHolder(false);
|
/** Holds whether the pokemon is trapped due to an ability */
|
||||||
|
const trapped = new BooleanHolder(false);
|
||||||
/**
|
/**
|
||||||
* Contains opposing Pokemon (Enemy/Player Pokemon) depending on perspective
|
* Contains opposing Pokemon (Enemy/Player Pokemon) depending on perspective
|
||||||
* Afterwards, it filters out Pokemon that have been switched out of the field so trapped abilities/moves do not trigger
|
* Afterwards, it filters out Pokemon that have been switched out of the field so trapped abilities/moves do not trigger
|
||||||
@ -2265,14 +2257,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const opposingField = opposingFieldUnfiltered.filter(enemyPkm => enemyPkm.switchOutStatus === false);
|
const opposingField = opposingFieldUnfiltered.filter(enemyPkm => enemyPkm.switchOutStatus === false);
|
||||||
|
|
||||||
for (const opponent of opposingField) {
|
for (const opponent of opposingField) {
|
||||||
applyCheckTrappedAbAttrs("CheckTrappedAbAttr", opponent, trappedByAbility, this, trappedAbMessages, simulated);
|
applyAbAttrs("CheckTrappedAbAttr", { pokemon: opponent, trapped, opponent: this, simulated }, trappedAbMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
const side = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
const side = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
||||||
return (
|
return (
|
||||||
trappedByAbility.value ||
|
trapped.value || !!this.getTag(TrappedTag) || !!globalScene.arena.getTagOnSide(ArenaTagType.FAIRY_LOCK, side)
|
||||||
!!this.getTag(TrappedTag) ||
|
|
||||||
!!globalScene.arena.getTagOnSide(ArenaTagType.FAIRY_LOCK, side)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2287,7 +2277,18 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const moveTypeHolder = new NumberHolder(move.type);
|
const moveTypeHolder = new NumberHolder(move.type);
|
||||||
|
|
||||||
applyMoveAttrs("VariableMoveTypeAttr", this, null, move, moveTypeHolder);
|
applyMoveAttrs("VariableMoveTypeAttr", this, null, move, moveTypeHolder);
|
||||||
applyPreAttackAbAttrs("MoveTypeChangeAbAttr", this, null, move, simulated, moveTypeHolder);
|
|
||||||
|
const cancelled = new BooleanHolder(false);
|
||||||
|
const power = new NumberHolder(move.power);
|
||||||
|
applyAbAttrs("MoveTypeChangeAbAttr", {
|
||||||
|
pokemon: this,
|
||||||
|
move,
|
||||||
|
simulated,
|
||||||
|
moveType: moveTypeHolder,
|
||||||
|
cancelled,
|
||||||
|
power,
|
||||||
|
opponent: this,
|
||||||
|
});
|
||||||
|
|
||||||
// If the user is terastallized and the move is tera blast, or tera starstorm that is stellar type,
|
// If the user is terastallized and the move is tera blast, or tera starstorm that is stellar type,
|
||||||
// then bypass the check for ion deluge and electrify
|
// then bypass the check for ion deluge and electrify
|
||||||
@ -2351,17 +2352,31 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cancelledHolder = cancelled ?? new BooleanHolder(false);
|
const cancelledHolder = cancelled ?? new BooleanHolder(false);
|
||||||
|
// TypeMultiplierAbAttrParams is shared amongst the type of AbAttrs we will be invoking
|
||||||
|
const commonAbAttrParams: TypeMultiplierAbAttrParams = {
|
||||||
|
pokemon: this,
|
||||||
|
opponent: source,
|
||||||
|
move,
|
||||||
|
cancelled: cancelledHolder,
|
||||||
|
simulated,
|
||||||
|
typeMultiplier,
|
||||||
|
};
|
||||||
if (!ignoreAbility) {
|
if (!ignoreAbility) {
|
||||||
applyPreDefendAbAttrs("TypeImmunityAbAttr", this, source, move, cancelledHolder, simulated, typeMultiplier);
|
applyAbAttrs("TypeImmunityAbAttr", commonAbAttrParams);
|
||||||
|
|
||||||
if (!cancelledHolder.value) {
|
if (!cancelledHolder.value) {
|
||||||
applyPreDefendAbAttrs("MoveImmunityAbAttr", this, source, move, cancelledHolder, simulated, typeMultiplier);
|
applyAbAttrs("MoveImmunityAbAttr", commonAbAttrParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cancelledHolder.value) {
|
if (!cancelledHolder.value) {
|
||||||
const defendingSidePlayField = this.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
|
const defendingSidePlayField = this.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
|
||||||
defendingSidePlayField.forEach(p =>
|
defendingSidePlayField.forEach(p =>
|
||||||
applyPreDefendAbAttrs("FieldPriorityMoveImmunityAbAttr", p, source, move, cancelledHolder),
|
applyAbAttrs("FieldPriorityMoveImmunityAbAttr", {
|
||||||
|
pokemon: p,
|
||||||
|
opponent: source,
|
||||||
|
move,
|
||||||
|
cancelled: cancelledHolder,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2376,7 +2391,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
// Apply Tera Shell's effect to attacks after all immunities are accounted for
|
// Apply Tera Shell's effect to attacks after all immunities are accounted for
|
||||||
if (!ignoreAbility && move.category !== MoveCategory.STATUS) {
|
if (!ignoreAbility && move.category !== MoveCategory.STATUS) {
|
||||||
applyPreDefendAbAttrs("FullHpResistTypeAbAttr", this, source, move, cancelledHolder, simulated, typeMultiplier);
|
applyAbAttrs("FullHpResistTypeAbAttr", commonAbAttrParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (move.category === MoveCategory.STATUS && move.hitsSubstitute(source, this)) {
|
if (move.category === MoveCategory.STATUS && move.hitsSubstitute(source, this)) {
|
||||||
@ -2420,16 +2435,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let multiplier = types
|
let multiplier = types
|
||||||
.map(defType => {
|
.map(defenderType => {
|
||||||
const multiplier = new NumberHolder(getTypeDamageMultiplier(moveType, defType));
|
const multiplier = new NumberHolder(getTypeDamageMultiplier(moveType, defenderType));
|
||||||
applyChallenges(ChallengeType.TYPE_EFFECTIVENESS, multiplier);
|
applyChallenges(ChallengeType.TYPE_EFFECTIVENESS, multiplier);
|
||||||
if (move) {
|
if (move) {
|
||||||
applyMoveAttrs("VariableMoveTypeChartAttr", null, this, move, multiplier, defType);
|
applyMoveAttrs("VariableMoveTypeChartAttr", null, this, move, multiplier, defenderType);
|
||||||
}
|
}
|
||||||
if (source) {
|
if (source) {
|
||||||
const ignoreImmunity = new BooleanHolder(false);
|
const ignoreImmunity = new BooleanHolder(false);
|
||||||
if (source.isActive(true) && source.hasAbilityWithAttr("IgnoreTypeImmunityAbAttr")) {
|
if (source.isActive(true) && source.hasAbilityWithAttr("IgnoreTypeImmunityAbAttr")) {
|
||||||
applyAbAttrs("IgnoreTypeImmunityAbAttr", source, ignoreImmunity, simulated, moveType, defType);
|
applyAbAttrs("IgnoreTypeImmunityAbAttr", {
|
||||||
|
pokemon: source,
|
||||||
|
cancelled: ignoreImmunity,
|
||||||
|
simulated,
|
||||||
|
moveType,
|
||||||
|
defenderType,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (ignoreImmunity.value) {
|
if (ignoreImmunity.value) {
|
||||||
if (multiplier.value === 0) {
|
if (multiplier.value === 0) {
|
||||||
@ -2438,7 +2459,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const exposedTags = this.findTags(tag => tag instanceof ExposedTag) as ExposedTag[];
|
const exposedTags = this.findTags(tag => tag instanceof ExposedTag) as ExposedTag[];
|
||||||
if (exposedTags.some(t => t.ignoreImmunity(defType, moveType))) {
|
if (exposedTags.some(t => t.ignoreImmunity(defenderType, moveType))) {
|
||||||
if (multiplier.value === 0) {
|
if (multiplier.value === 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -3358,7 +3379,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ignoreOppAbility) {
|
if (!ignoreOppAbility) {
|
||||||
applyAbAttrs("IgnoreOpponentStatStagesAbAttr", opponent, null, simulated, stat, ignoreStatStage);
|
applyAbAttrs("IgnoreOpponentStatStagesAbAttr", {
|
||||||
|
pokemon: opponent,
|
||||||
|
ignored: ignoreStatStage,
|
||||||
|
stat,
|
||||||
|
simulated,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (move) {
|
if (move) {
|
||||||
applyMoveAttrs("IgnoreOpponentStatStagesAttr", this, opponent, move, ignoreStatStage);
|
applyMoveAttrs("IgnoreOpponentStatStagesAttr", this, opponent, move, ignoreStatStage);
|
||||||
@ -3397,8 +3423,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const ignoreAccStatStage = new BooleanHolder(false);
|
const ignoreAccStatStage = new BooleanHolder(false);
|
||||||
const ignoreEvaStatStage = new BooleanHolder(false);
|
const ignoreEvaStatStage = new BooleanHolder(false);
|
||||||
|
|
||||||
applyAbAttrs("IgnoreOpponentStatStagesAbAttr", target, null, false, Stat.ACC, ignoreAccStatStage);
|
// TODO: consider refactoring this method to accept `simulated` and then pass simulated to these applyAbAttrs
|
||||||
applyAbAttrs("IgnoreOpponentStatStagesAbAttr", this, null, false, Stat.EVA, ignoreEvaStatStage);
|
applyAbAttrs("IgnoreOpponentStatStagesAbAttr", { pokemon: target, stat: Stat.ACC, ignored: ignoreAccStatStage });
|
||||||
|
applyAbAttrs("IgnoreOpponentStatStagesAbAttr", { pokemon: this, stat: Stat.EVA, ignored: ignoreEvaStatStage });
|
||||||
applyMoveAttrs("IgnoreOpponentStatStagesAttr", this, target, sourceMove, ignoreEvaStatStage);
|
applyMoveAttrs("IgnoreOpponentStatStagesAttr", this, target, sourceMove, ignoreEvaStatStage);
|
||||||
|
|
||||||
globalScene.applyModifiers(TempStatStageBoosterModifier, this.isPlayer(), Stat.ACC, userAccStage);
|
globalScene.applyModifiers(TempStatStageBoosterModifier, this.isPlayer(), Stat.ACC, userAccStage);
|
||||||
@ -3418,33 +3445,40 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
: 3 / (3 + Math.min(targetEvaStage.value - userAccStage.value, 6));
|
: 3 / (3 + Math.min(targetEvaStage.value - userAccStage.value, 6));
|
||||||
}
|
}
|
||||||
|
|
||||||
applyStatMultiplierAbAttrs("StatMultiplierAbAttr", this, Stat.ACC, accuracyMultiplier, false, sourceMove);
|
applyAbAttrs("StatMultiplierAbAttr", {
|
||||||
|
pokemon: this,
|
||||||
|
stat: Stat.ACC,
|
||||||
|
statVal: accuracyMultiplier,
|
||||||
|
move: sourceMove,
|
||||||
|
});
|
||||||
|
|
||||||
const evasionMultiplier = new NumberHolder(1);
|
const evasionMultiplier = new NumberHolder(1);
|
||||||
applyStatMultiplierAbAttrs("StatMultiplierAbAttr", target, Stat.EVA, evasionMultiplier);
|
applyAbAttrs("StatMultiplierAbAttr", {
|
||||||
|
pokemon: target,
|
||||||
|
stat: Stat.EVA,
|
||||||
|
statVal: evasionMultiplier,
|
||||||
|
move: sourceMove,
|
||||||
|
});
|
||||||
|
|
||||||
const ally = this.getAlly();
|
const ally = this.getAlly();
|
||||||
if (!isNullOrUndefined(ally)) {
|
if (!isNullOrUndefined(ally)) {
|
||||||
const ignore =
|
const ignore =
|
||||||
this.hasAbilityWithAttr("MoveAbilityBypassAbAttr") || sourceMove.hasFlag(MoveFlags.IGNORE_ABILITIES);
|
this.hasAbilityWithAttr("MoveAbilityBypassAbAttr") || sourceMove.hasFlag(MoveFlags.IGNORE_ABILITIES);
|
||||||
applyAllyStatMultiplierAbAttrs(
|
applyAbAttrs("AllyStatMultiplierAbAttr", {
|
||||||
"AllyStatMultiplierAbAttr",
|
pokemon: ally,
|
||||||
ally,
|
stat: Stat.ACC,
|
||||||
Stat.ACC,
|
statVal: accuracyMultiplier,
|
||||||
accuracyMultiplier,
|
ignoreAbility: ignore,
|
||||||
false,
|
move: sourceMove,
|
||||||
this,
|
});
|
||||||
ignore,
|
|
||||||
);
|
applyAbAttrs("AllyStatMultiplierAbAttr", {
|
||||||
applyAllyStatMultiplierAbAttrs(
|
pokemon: ally,
|
||||||
"AllyStatMultiplierAbAttr",
|
stat: Stat.EVA,
|
||||||
ally,
|
statVal: evasionMultiplier,
|
||||||
Stat.EVA,
|
ignoreAbility: ignore,
|
||||||
evasionMultiplier,
|
move: sourceMove,
|
||||||
false,
|
});
|
||||||
this,
|
|
||||||
ignore,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return accuracyMultiplier.value / evasionMultiplier.value;
|
return accuracyMultiplier.value / evasionMultiplier.value;
|
||||||
@ -3559,7 +3593,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
applyMoveAttrs("CombinedPledgeStabBoostAttr", source, this, move, stabMultiplier);
|
applyMoveAttrs("CombinedPledgeStabBoostAttr", source, this, move, stabMultiplier);
|
||||||
|
|
||||||
if (!ignoreSourceAbility) {
|
if (!ignoreSourceAbility) {
|
||||||
applyAbAttrs("StabBoostAbAttr", source, null, simulated, stabMultiplier);
|
applyAbAttrs("StabBoostAbAttr", { pokemon: source, simulated, multiplier: stabMultiplier });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source.isTerastallized && sourceTeraType === moveType && moveType !== PokemonType.STELLAR) {
|
if (source.isTerastallized && sourceTeraType === moveType && moveType !== PokemonType.STELLAR) {
|
||||||
@ -3706,16 +3740,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
null,
|
null,
|
||||||
multiStrikeEnhancementMultiplier,
|
multiStrikeEnhancementMultiplier,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!ignoreSourceAbility) {
|
if (!ignoreSourceAbility) {
|
||||||
applyPreAttackAbAttrs(
|
applyAbAttrs("AddSecondStrikeAbAttr", {
|
||||||
"AddSecondStrikeAbAttr",
|
pokemon: source,
|
||||||
source,
|
opponent: this,
|
||||||
this,
|
|
||||||
move,
|
move,
|
||||||
simulated,
|
simulated,
|
||||||
null,
|
cancelled: new BooleanHolder(false),
|
||||||
multiStrikeEnhancementMultiplier,
|
multiplier: multiStrikeEnhancementMultiplier,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Doubles damage if this Pokemon's last move was Glaive Rush */
|
/** Doubles damage if this Pokemon's last move was Glaive Rush */
|
||||||
@ -3726,7 +3760,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
/** The damage multiplier when the given move critically hits */
|
/** The damage multiplier when the given move critically hits */
|
||||||
const criticalMultiplier = new NumberHolder(isCritical ? 1.5 : 1);
|
const criticalMultiplier = new NumberHolder(isCritical ? 1.5 : 1);
|
||||||
applyAbAttrs("MultCritAbAttr", source, null, simulated, criticalMultiplier);
|
applyAbAttrs("MultCritAbAttr", { pokemon: source, simulated, critMult: criticalMultiplier });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A multiplier for random damage spread in the range [0.85, 1]
|
* A multiplier for random damage spread in the range [0.85, 1]
|
||||||
@ -3747,7 +3781,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
) {
|
) {
|
||||||
const burnDamageReductionCancelled = new BooleanHolder(false);
|
const burnDamageReductionCancelled = new BooleanHolder(false);
|
||||||
if (!ignoreSourceAbility) {
|
if (!ignoreSourceAbility) {
|
||||||
applyAbAttrs("BypassBurnDamageReductionAbAttr", source, burnDamageReductionCancelled, simulated);
|
applyAbAttrs("BypassBurnDamageReductionAbAttr", {
|
||||||
|
pokemon: source,
|
||||||
|
cancelled: burnDamageReductionCancelled,
|
||||||
|
simulated,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (!burnDamageReductionCancelled.value) {
|
if (!burnDamageReductionCancelled.value) {
|
||||||
burnMultiplier = 0.5;
|
burnMultiplier = 0.5;
|
||||||
@ -3811,7 +3849,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
/** Doubles damage if the attacker has Tinted Lens and is using a resisted move */
|
/** Doubles damage if the attacker has Tinted Lens and is using a resisted move */
|
||||||
if (!ignoreSourceAbility) {
|
if (!ignoreSourceAbility) {
|
||||||
applyPreAttackAbAttrs("DamageBoostAbAttr", source, this, move, simulated, damage);
|
applyAbAttrs("DamageBoostAbAttr", {
|
||||||
|
pokemon: source,
|
||||||
|
opponent: this,
|
||||||
|
move,
|
||||||
|
simulated,
|
||||||
|
damage,
|
||||||
|
// cancelled isn't necessary for this ability attribute, but is required by the interface
|
||||||
|
cancelled: new BooleanHolder(false),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Apply the enemy's Damage and Resistance tokens */
|
/** Apply the enemy's Damage and Resistance tokens */
|
||||||
@ -3822,14 +3868,26 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
globalScene.applyModifiers(EnemyDamageReducerModifier, false, damage);
|
globalScene.applyModifiers(EnemyDamageReducerModifier, false, damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const abAttrParams: PreAttackModifyDamageAbAttrParams = {
|
||||||
|
pokemon: this,
|
||||||
|
opponent: source,
|
||||||
|
move,
|
||||||
|
cancelled,
|
||||||
|
simulated,
|
||||||
|
damage,
|
||||||
|
};
|
||||||
/** Apply this Pokemon's post-calc defensive modifiers (e.g. Fur Coat) */
|
/** Apply this Pokemon's post-calc defensive modifiers (e.g. Fur Coat) */
|
||||||
if (!ignoreAbility) {
|
if (!ignoreAbility) {
|
||||||
applyPreDefendAbAttrs("ReceivedMoveDamageMultiplierAbAttr", this, source, move, cancelled, simulated, damage);
|
applyAbAttrs("ReceivedMoveDamageMultiplierAbAttr", abAttrParams);
|
||||||
|
|
||||||
const ally = this.getAlly();
|
const ally = this.getAlly();
|
||||||
/** Additionally apply friend guard damage reduction if ally has it. */
|
/** Additionally apply friend guard damage reduction if ally has it. */
|
||||||
if (globalScene.currentBattle.double && !isNullOrUndefined(ally) && ally.isActive(true)) {
|
if (globalScene.currentBattle.double && !isNullOrUndefined(ally) && ally.isActive(true)) {
|
||||||
applyPreDefendAbAttrs("AlliedFieldDamageReductionAbAttr", ally, source, move, cancelled, simulated, damage);
|
applyAbAttrs("AlliedFieldDamageReductionAbAttr", {
|
||||||
|
...abAttrParams,
|
||||||
|
// Same parameters as before, except we are applying the ally's ability
|
||||||
|
pokemon: ally,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3837,7 +3895,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
applyMoveAttrs("ModifiedDamageAttr", source, this, move, damage);
|
applyMoveAttrs("ModifiedDamageAttr", source, this, move, damage);
|
||||||
|
|
||||||
if (this.isFullHp() && !ignoreAbility) {
|
if (this.isFullHp() && !ignoreAbility) {
|
||||||
applyPreDefendAbAttrs("PreDefendFullHpEndureAbAttr", this, source, move, cancelled, false, damage);
|
applyAbAttrs("PreDefendFullHpEndureAbAttr", abAttrParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug message for when damage is applied (i.e. not simulated)
|
// debug message for when damage is applied (i.e. not simulated)
|
||||||
@ -3875,7 +3933,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
const alwaysCrit = new BooleanHolder(false);
|
const alwaysCrit = new BooleanHolder(false);
|
||||||
applyMoveAttrs("CritOnlyAttr", source, this, move, alwaysCrit);
|
applyMoveAttrs("CritOnlyAttr", source, this, move, alwaysCrit);
|
||||||
applyAbAttrs("ConditionalCritAbAttr", source, null, false, alwaysCrit, this, move);
|
applyAbAttrs("ConditionalCritAbAttr", { pokemon: source, isCritical: alwaysCrit, target: this, move });
|
||||||
const alwaysCritTag = !!source.getTag(BattlerTagType.ALWAYS_CRIT);
|
const alwaysCritTag = !!source.getTag(BattlerTagType.ALWAYS_CRIT);
|
||||||
const critChance = [24, 8, 2, 1][Phaser.Math.Clamp(this.getCritStage(source, move), 0, 3)];
|
const critChance = [24, 8, 2, 1][Phaser.Math.Clamp(this.getCritStage(source, move), 0, 3)];
|
||||||
|
|
||||||
@ -3886,7 +3944,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
// apply crit block effects from lucky chant & co., overriding previous effects
|
// apply crit block effects from lucky chant & co., overriding previous effects
|
||||||
const blockCrit = new BooleanHolder(false);
|
const blockCrit = new BooleanHolder(false);
|
||||||
applyAbAttrs("BlockCritAbAttr", this, null, false, blockCrit);
|
applyAbAttrs("BlockCritAbAttr", { pokemon: this, blockCrit });
|
||||||
const blockCritTag = globalScene.arena.getTagOnSide(
|
const blockCritTag = globalScene.arena.getTagOnSide(
|
||||||
NoCritTag,
|
NoCritTag,
|
||||||
this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY,
|
this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY,
|
||||||
@ -3998,7 +4056,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* Multi-hits are handled in move-effect-phase.ts for PostDamageAbAttr
|
* Multi-hits are handled in move-effect-phase.ts for PostDamageAbAttr
|
||||||
*/
|
*/
|
||||||
if (!source || source.turnData.hitCount <= 1) {
|
if (!source || source.turnData.hitCount <= 1) {
|
||||||
applyPostDamageAbAttrs("PostDamageAbAttr", this, damage, this.hasPassive(), false, [], source);
|
applyAbAttrs("PostDamageAbAttr", { pokemon: this, damage });
|
||||||
}
|
}
|
||||||
return damage;
|
return damage;
|
||||||
}
|
}
|
||||||
@ -4046,11 +4104,17 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const stubTag = new BattlerTag(tagType, 0, 0);
|
const stubTag = new BattlerTag(tagType, 0, 0);
|
||||||
|
|
||||||
const cancelled = new BooleanHolder(false);
|
const cancelled = new BooleanHolder(false);
|
||||||
applyAbAttrs("BattlerTagImmunityAbAttr", this, stubTag, cancelled, true, this);
|
applyAbAttrs("BattlerTagImmunityAbAttr", { pokemon: this, tag: stubTag, cancelled, simulated: true });
|
||||||
|
|
||||||
const userField = this.getAlliedField();
|
const userField = this.getAlliedField();
|
||||||
userField.forEach(pokemon =>
|
userField.forEach(pokemon =>
|
||||||
applyPreApplyBattlerTagAbAttrs("UserFieldBattlerTagImmunityAbAttr", pokemon, stubTag, cancelled, true, this),
|
applyAbAttrs("UserFieldBattlerTagImmunityAbAttr", {
|
||||||
|
pokemon,
|
||||||
|
tag: stubTag,
|
||||||
|
cancelled,
|
||||||
|
simulated: true,
|
||||||
|
target: this,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return !cancelled.value;
|
return !cancelled.value;
|
||||||
@ -4066,13 +4130,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const newTag = getBattlerTag(tagType, turnCount, sourceMove!, sourceId!); // TODO: are the bangs correct?
|
const newTag = getBattlerTag(tagType, turnCount, sourceMove!, sourceId!); // TODO: are the bangs correct?
|
||||||
|
|
||||||
const cancelled = new BooleanHolder(false);
|
const cancelled = new BooleanHolder(false);
|
||||||
applyPreApplyBattlerTagAbAttrs("BattlerTagImmunityAbAttr", this, newTag, cancelled);
|
applyAbAttrs("BattlerTagImmunityAbAttr", { pokemon: this, tag: newTag, cancelled });
|
||||||
if (cancelled.value) {
|
if (cancelled.value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const pokemon of this.getAlliedField()) {
|
for (const pokemon of this.getAlliedField()) {
|
||||||
applyPreApplyBattlerTagAbAttrs("UserFieldBattlerTagImmunityAbAttr", pokemon, newTag, cancelled, false, this);
|
applyAbAttrs("UserFieldBattlerTagImmunityAbAttr", { pokemon, tag: newTag, cancelled, target: this });
|
||||||
if (cancelled.value) {
|
if (cancelled.value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -4597,7 +4661,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* @param ignoreField Whether any field effects (weather, terrain, etc.) should be considered
|
* @param ignoreField Whether any field effects (weather, terrain, etc.) should be considered
|
||||||
*/
|
*/
|
||||||
canSetStatus(
|
canSetStatus(
|
||||||
effect: StatusEffect | undefined,
|
effect: StatusEffect,
|
||||||
quiet = false,
|
quiet = false,
|
||||||
overrideStatus = false,
|
overrideStatus = false,
|
||||||
sourcePokemon: Pokemon | null = null,
|
sourcePokemon: Pokemon | null = null,
|
||||||
@ -4628,8 +4692,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
// Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity
|
// Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity
|
||||||
const cancelImmunity = new BooleanHolder(false);
|
const cancelImmunity = new BooleanHolder(false);
|
||||||
|
// TODO: Determine if we need to pass `quiet` as the value for simulated in this call
|
||||||
if (sourcePokemon) {
|
if (sourcePokemon) {
|
||||||
applyAbAttrs("IgnoreTypeStatusEffectImmunityAbAttr", sourcePokemon, cancelImmunity, false, effect, defType);
|
applyAbAttrs("IgnoreTypeStatusEffectImmunityAbAttr", {
|
||||||
|
pokemon: sourcePokemon,
|
||||||
|
cancelled: cancelImmunity,
|
||||||
|
statusEffect: effect,
|
||||||
|
defenderType: defType,
|
||||||
|
});
|
||||||
if (cancelImmunity.value) {
|
if (cancelImmunity.value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -4678,21 +4748,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cancelled = new BooleanHolder(false);
|
const cancelled = new BooleanHolder(false);
|
||||||
applyPreSetStatusAbAttrs("StatusEffectImmunityAbAttr", this, effect, cancelled, quiet);
|
applyAbAttrs("StatusEffectImmunityAbAttr", { pokemon: this, effect, cancelled, simulated: quiet });
|
||||||
if (cancelled.value) {
|
if (cancelled.value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const pokemon of this.getAlliedField()) {
|
for (const pokemon of this.getAlliedField()) {
|
||||||
applyPreSetStatusAbAttrs(
|
applyAbAttrs("UserFieldStatusEffectImmunityAbAttr", {
|
||||||
"UserFieldStatusEffectImmunityAbAttr",
|
|
||||||
pokemon,
|
pokemon,
|
||||||
effect,
|
effect,
|
||||||
cancelled,
|
cancelled,
|
||||||
quiet,
|
simulated: quiet,
|
||||||
this,
|
target: this,
|
||||||
sourcePokemon,
|
source: sourcePokemon,
|
||||||
);
|
});
|
||||||
if (cancelled.value) {
|
if (cancelled.value) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4723,6 +4792,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
overrideStatus?: boolean,
|
overrideStatus?: boolean,
|
||||||
quiet = true,
|
quiet = true,
|
||||||
): boolean {
|
): boolean {
|
||||||
|
if (!effect) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!this.canSetStatus(effect, quiet, overrideStatus, sourcePokemon)) {
|
if (!this.canSetStatus(effect, quiet, overrideStatus, sourcePokemon)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -4781,7 +4853,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sleepTurnsRemaining = sleepTurnsRemaining!; // tell TS compiler it's defined
|
sleepTurnsRemaining = sleepTurnsRemaining!; // tell TS compiler it's defined
|
||||||
effect = effect!; // If `effect` is undefined then `trySetStatus()` will have already returned early via the `canSetStatus()` call
|
|
||||||
this.status = new Status(effect, 0, sleepTurnsRemaining?.value);
|
this.status = new Status(effect, 0, sleepTurnsRemaining?.value);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -4842,7 +4913,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
if (globalScene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, defendingSide)) {
|
if (globalScene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, defendingSide)) {
|
||||||
const bypassed = new BooleanHolder(false);
|
const bypassed = new BooleanHolder(false);
|
||||||
if (attacker) {
|
if (attacker) {
|
||||||
applyAbAttrs("InfiltratorAbAttr", attacker, null, false, bypassed);
|
applyAbAttrs("InfiltratorAbAttr", { pokemon: attacker, bypassed });
|
||||||
}
|
}
|
||||||
return !bypassed.value;
|
return !bypassed.value;
|
||||||
}
|
}
|
||||||
@ -5391,7 +5462,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.hideInfo();
|
this.hideInfo();
|
||||||
}
|
}
|
||||||
// Trigger abilities that activate upon leaving the field
|
// Trigger abilities that activate upon leaving the field
|
||||||
applyPreLeaveFieldAbAttrs("PreLeaveFieldAbAttr", this);
|
applyAbAttrs("PreLeaveFieldAbAttr", { pokemon: this });
|
||||||
this.setSwitchOutStatus(true);
|
this.setSwitchOutStatus(true);
|
||||||
globalScene.triggerPokemonFormChange(this, SpeciesFormChangeActiveTrigger, true);
|
globalScene.triggerPokemonFormChange(this, SpeciesFormChangeActiveTrigger, true);
|
||||||
globalScene.field.remove(this, destroy);
|
globalScene.field.remove(this, destroy);
|
||||||
@ -5451,7 +5522,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
globalScene.removeModifier(heldItem, this.isEnemy());
|
globalScene.removeModifier(heldItem, this.isEnemy());
|
||||||
}
|
}
|
||||||
if (forBattle) {
|
if (forBattle) {
|
||||||
applyPostItemLostAbAttrs("PostItemLostAbAttr", this, false);
|
applyAbAttrs("PostItemLostAbAttr", { pokemon: this });
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -2,8 +2,8 @@ import { globalScene } from "#app/global-scene";
|
|||||||
import { BattlerTagLapseType } from "#enums/battler-tag-lapse-type";
|
import { BattlerTagLapseType } from "#enums/battler-tag-lapse-type";
|
||||||
import { PokemonPhase } from "./pokemon-phase";
|
import { PokemonPhase } from "./pokemon-phase";
|
||||||
import type { BattlerIndex } from "#enums/battler-index";
|
import type { BattlerIndex } from "#enums/battler-index";
|
||||||
import { applyPostSummonAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
|
import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
|
||||||
|
|
||||||
export class MoveEndPhase extends PokemonPhase {
|
export class MoveEndPhase extends PokemonPhase {
|
||||||
public readonly phaseName = "MoveEndPhase";
|
public readonly phaseName = "MoveEndPhase";
|
||||||
@ -30,7 +30,7 @@ export class MoveEndPhase extends PokemonPhase {
|
|||||||
globalScene.arena.setIgnoreAbilities(false);
|
globalScene.arena.setIgnoreAbilities(false);
|
||||||
for (const target of this.targets) {
|
for (const target of this.targets) {
|
||||||
if (target) {
|
if (target) {
|
||||||
applyPostSummonAbAttrs("PostSummonRemoveEffectAbAttr", target);
|
applyAbAttrs("PostSummonRemoveEffectAbAttr", { pokemon: target });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +288,7 @@ describe("Abilities - Unburden", () => {
|
|||||||
expect(getHeldItemCount(purrloin)).toBe(1);
|
expect(getHeldItemCount(purrloin)).toBe(1);
|
||||||
expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialTreeckoSpeed);
|
expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialTreeckoSpeed);
|
||||||
expect(purrloin.getEffectiveStat(Stat.SPD)).toBe(initialPurrloinSpeed);
|
expect(purrloin.getEffectiveStat(Stat.SPD)).toBe(initialPurrloinSpeed);
|
||||||
expect(unburdenAttr.applyPostItemLost).not.toHaveBeenCalled();
|
expect(unburdenAttr.apply).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not speed up a Pokemon after it loses the ability Unburden", async () => {
|
it("should not speed up a Pokemon after it loses the ability Unburden", async () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user