Compare commits

...

9 Commits

Author SHA1 Message Date
Bertie690
056de7eec1
Merge 751d824af8 into 3b36ab17e4 2025-08-05 21:17:33 +00:00
Bertie690
751d824af8 Cleaned up Stockpile tests 2025-08-05 17:17:05 -04:00
Bertie690
89536fafda Added MoveHealBoostAbAttr + implemented Healing Pulse boost 2025-08-05 16:48:39 -04:00
Bertie690
95dbfe69a0 Added heal pulse tests and clarified rounding 2025-08-05 13:54:10 -04:00
Bertie690
90c9c71cd9 Cleaned up pokemonHealPhase + wrapped inside an object 2025-08-05 12:53:10 -04:00
Bertie690
e760ed9949 Squashed changes and such 2025-08-05 12:09:55 -04:00
Jimmybald1
3b36ab17e4
[Bug] Protect now tracks success chance properly (#5869)
* Protect rng now resets on new waves and fixed to look at all turns in the same wave.

* Added per-wave move history object to fix issues

@Jimmybald1 I added a commented out `console.log` in the protect code (L5797) for you to use for testing

* Added many tests

* Wave move history has to be looped in reverse

* Update src/data/moves/move.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Update src/data/moves/move.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* comments

* Fixed forceEnemyMove references after merge

* Removed console log

Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com>

* Fixed test message

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Apply Biome

* Fix merge issues

* Fix Crafty Shield test

* Remove protect chance reset on wave change

* Fix merge issue

---------

Co-authored-by: Jimmybald1 <147992650+IBBCalc@users.noreply.github.com>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com>
Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>
2025-08-05 07:35:14 +02:00
NightKev
375587213e [Misc] Replace Moves.MOVE_NAME with MoveId.MOVE_NAME in comments 2025-08-04 21:24:58 -07:00
Bertie690
8da02bad50
[Test] Replace game.scene.getXPokemon()! with game.field.getXPokemon()
https://github.com/pagefaultgames/pokerogue/pull/6178

* Replaced all instances of `game.scene.getXXXPokemon()!`
inside tests with `game.field.getXXXPokemon()`

* Fixed tests

* Fixed oblivious test

* Fix Grudge test
2025-08-04 21:19:57 -07:00
245 changed files with 2802 additions and 2557 deletions

View File

@ -748,16 +748,12 @@ export class TypeImmunityHealAbAttr extends TypeImmunityAbAttr {
const { pokemon, cancelled, simulated, passive } = params; const { pokemon, cancelled, simulated, passive } = params;
if (!pokemon.isFullHp() && !simulated) { if (!pokemon.isFullHp() && !simulated) {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew("PokemonHealPhase", pokemon.getBattlerIndex(), pokemon.getMaxHp() / 4, {
"PokemonHealPhase", message: i18next.t("abilityTriggers:typeImmunityHeal", {
pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 4),
i18next.t("abilityTriggers:typeImmunityHeal", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
abilityName, abilityName,
}), }),
true, });
);
cancelled.value = true; // Suppresses "No Effect" message cancelled.value = true; // Suppresses "No Effect" message
} }
} }
@ -1545,6 +1541,51 @@ export abstract class PreAttackAbAttr extends AbAttr {
private declare readonly _: never; private declare readonly _: never;
} }
export interface MoveHealBoostAbAttrParams extends AugmentMoveInteractionAbAttrParams {
/** The base amount of HP being healed, as a fraction of the recipient's maximum HP. */
healRatio: NumberHolder;
}
/**
* Ability attribute to boost the healing potency of the user's moves.
* Used by {@linkcode AbilityId.MEGA_LAUNCHER} to implement Heal Pulse boosting.
*/
export class MoveHealBoostAbAttr extends AbAttr {
/**
* The amount to boost the healing by, as a multiplier of the base amount.
*/
private healMulti: number;
/**
* A lambda function determining whether to boost the heal amount.
* The ability will not be applied if this evaluates to `false`.
*/
// TODO: Use a `MoveConditionFunc` maybe?
private boostCondition: (user: Pokemon, target: Pokemon, move: Move) => boolean;
constructor(
boostCondition: (user: Pokemon, target: Pokemon, move: Move) => boolean,
healMulti: number,
showAbility = false,
) {
super(showAbility);
if (healMulti === 1) {
throw new Error("Calling `MoveHealBoostAbAttr` with a multiplier of 1 is useless!");
}
this.healMulti = healMulti;
this.boostCondition = boostCondition;
}
override canApply({ pokemon: user, opponent: target, move }: MoveHealBoostAbAttrParams): boolean {
return this.boostCondition?.(user, target, move) ?? true;
}
override apply({ healRatio }: MoveHealBoostAbAttrParams): void {
healRatio.value *= this.healMulti;
}
}
export interface ModifyMoveEffectChanceAbAttrParams extends AbAttrBaseParams { export interface ModifyMoveEffectChanceAbAttrParams extends AbAttrBaseParams {
/** The move being used by the attacker */ /** The move being used by the attacker */
move: Move; move: Move;
@ -1686,7 +1727,7 @@ export class MoveTypeChangeAbAttr extends PreAttackAbAttr {
*/ */
override canApply({ pokemon, opponent: target, move }: MoveTypeChangeAbAttrParams): boolean { override canApply({ pokemon, opponent: target, move }: MoveTypeChangeAbAttrParams): boolean {
return ( return (
(!this.condition || this.condition(pokemon, target, move)) && (this.condition?.(pokemon, target, move) ?? true) &&
!noAbilityTypeOverrideMoves.has(move.id) && !noAbilityTypeOverrideMoves.has(move.id) &&
!( !(
pokemon.isTerastallized && pokemon.isTerastallized &&
@ -1768,7 +1809,7 @@ export interface AddSecondStrikeAbAttrParams extends Omit<AugmentMoveInteraction
/** /**
* Class for abilities that add additional strikes to single-target moves. * Class for abilities that add additional strikes to single-target moves.
* Used by {@linkcode Moves.PARENTAL_BOND | Parental Bond}. * Used by {@linkcode MoveId.PARENTAL_BOND | Parental Bond}.
*/ */
export class AddSecondStrikeAbAttr extends PreAttackAbAttr { export class AddSecondStrikeAbAttr extends PreAttackAbAttr {
/** /**
@ -2830,12 +2871,13 @@ export class PostSummonAllyHealAbAttr extends PostSummonAbAttr {
"PokemonHealPhase", "PokemonHealPhase",
target.getBattlerIndex(), target.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / this.healRatio), toDmgValue(pokemon.getMaxHp() / this.healRatio),
i18next.t("abilityTriggers:postSummonAllyHeal", { {
pokemonNameWithAffix: getPokemonNameWithAffix(target), message: i18next.t("abilityTriggers:postSummonAllyHeal", {
pokemonName: pokemon.name, pokemonNameWithAffix: getPokemonNameWithAffix(target),
}), pokemonName: pokemon.name,
true, }),
!this.showAnim, skipAnim: !this.showAnim,
},
); );
} }
} }
@ -4476,11 +4518,12 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr {
"PokemonHealPhase", "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / (16 / this.healFactor)), toDmgValue(pokemon.getMaxHp() / (16 / this.healFactor)),
i18next.t("abilityTriggers:postWeatherLapseHeal", { {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), message: i18next.t("abilityTriggers:postWeatherLapseHeal", {
abilityName, pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), abilityName,
true, }),
},
); );
} }
} }
@ -4595,8 +4638,12 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr {
"PokemonHealPhase", "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 8), toDmgValue(pokemon.getMaxHp() / 8),
i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }), {
true, message: i18next.t("abilityTriggers:poisonHeal", {
pokemonName: getPokemonNameWithAffix(pokemon),
abilityName,
}),
},
); );
} }
} }
@ -4843,11 +4890,12 @@ export class PostTurnHealAbAttr extends PostTurnAbAttr {
"PokemonHealPhase", "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16), toDmgValue(pokemon.getMaxHp() / 16),
i18next.t("abilityTriggers:postTurnHeal", { {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), message: i18next.t("abilityTriggers:postTurnHeal", {
abilityName, pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), abilityName,
true, }),
},
); );
} }
} }
@ -5224,11 +5272,12 @@ export class HealFromBerryUseAbAttr extends AbAttr {
"PokemonHealPhase", "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() * this.healPercent), toDmgValue(pokemon.getMaxHp() * this.healPercent),
i18next.t("abilityTriggers:healFromBerryUse", { {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), message: i18next.t("abilityTriggers:healFromBerryUse", {
abilityName, pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), abilityName,
true, }),
},
); );
} }
} }
@ -6554,6 +6603,7 @@ const AbilityAttrs = Object.freeze({
PostDefendMoveDisableAbAttr, PostDefendMoveDisableAbAttr,
PostStatStageChangeStatStageChangeAbAttr, PostStatStageChangeStatStageChangeAbAttr,
PreAttackAbAttr, PreAttackAbAttr,
MoveHealBoostAbAttr,
MoveEffectChanceMultiplierAbAttr, MoveEffectChanceMultiplierAbAttr,
IgnoreMoveEffectsAbAttr, IgnoreMoveEffectsAbAttr,
VariableMovePowerAbAttr, VariableMovePowerAbAttr,
@ -7329,7 +7379,9 @@ export function initAbilities() {
.attr(PostSummonUserFieldRemoveStatusEffectAbAttr, StatusEffect.SLEEP) .attr(PostSummonUserFieldRemoveStatusEffectAbAttr, StatusEffect.SLEEP)
.attr(UserFieldBattlerTagImmunityAbAttr, BattlerTagType.DROWSY) .attr(UserFieldBattlerTagImmunityAbAttr, BattlerTagType.DROWSY)
.ignorable() .ignorable()
.partial(), // Mold Breaker ally should not be affected by Sweet Veil // Mold Breaker ally should not be affected by Sweet Veil
// TODO: Review this
.partial(),
new Ability(AbilityId.STANCE_CHANGE, 6) new Ability(AbilityId.STANCE_CHANGE, 6)
.attr(NoFusionAbilityAbAttr) .attr(NoFusionAbilityAbAttr)
.uncopiable() .uncopiable()
@ -7338,7 +7390,8 @@ export function initAbilities() {
new Ability(AbilityId.GALE_WINGS, 6) new Ability(AbilityId.GALE_WINGS, 6)
.attr(ChangeMovePriorityAbAttr, (pokemon, move) => pokemon.isFullHp() && pokemon.getMoveType(move) === PokemonType.FLYING, 1), .attr(ChangeMovePriorityAbAttr, (pokemon, move) => pokemon.isFullHp() && pokemon.getMoveType(move) === PokemonType.FLYING, 1),
new Ability(AbilityId.MEGA_LAUNCHER, 6) new Ability(AbilityId.MEGA_LAUNCHER, 6)
.attr(MovePowerBoostAbAttr, (_user, _target, move) => move.hasFlag(MoveFlags.PULSE_MOVE), 1.5), .attr(MovePowerBoostAbAttr, (_user, _target, move) => move.hasFlag(MoveFlags.PULSE_MOVE), 1.5)
.attr(MoveHealBoostAbAttr, (_user, _target, move) => move.hasFlag(MoveFlags.PULSE_MOVE), 1.5),
new Ability(AbilityId.GRASS_PELT, 6) new Ability(AbilityId.GRASS_PELT, 6)
.conditionalAttr(getTerrainCondition(TerrainType.GRASSY), StatMultiplierAbAttr, Stat.DEF, 1.5) .conditionalAttr(getTerrainCondition(TerrainType.GRASSY), StatMultiplierAbAttr, Stat.DEF, 1.5)
.ignorable(), .ignorable(),

View File

@ -1076,18 +1076,16 @@ export class SeedTag extends SerializableBattlerTag {
); );
// Damage the target and restore our HP (or take damage in the case of liquid ooze) // Damage the target and restore our HP (or take damage in the case of liquid ooze)
// TODO: Liquid ooze should queue a damage anim phase directly
const damage = pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT }); const damage = pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT });
const reverseDrain = pokemon.hasAbilityWithAttr("ReverseDrainAbAttr", false); const reverseDrain = pokemon.hasAbilityWithAttr("ReverseDrainAbAttr", false);
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew("PokemonHealPhase", source.getBattlerIndex(), reverseDrain ? -damage : damage, {
"PokemonHealPhase", message: i18next.t(reverseDrain ? "battlerTags:seededLapseShed" : "battlerTags:seededLapse", {
source.getBattlerIndex(),
reverseDrain ? -damage : damage,
i18next.t(reverseDrain ? "battlerTags:seededLapseShed" : "battlerTags:seededLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), }),
false, showFullHpMessage: false,
true, skipAnim: true,
); });
return true; return true;
} }
@ -1382,10 +1380,11 @@ export class IngrainTag extends TrappedTag {
"PokemonHealPhase", "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16), toDmgValue(pokemon.getMaxHp() / 16),
i18next.t("battlerTags:ingrainLapse", { {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), message: i18next.t("battlerTags:ingrainLapse", {
}), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
true, }),
},
); );
} }
@ -1455,11 +1454,12 @@ export class AquaRingTag extends SerializableBattlerTag {
"PokemonHealPhase", "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16), toDmgValue(pokemon.getMaxHp() / 16),
i18next.t("battlerTags:aquaRingLapse", { {
moveName: this.getMoveName(), message: i18next.t("battlerTags:aquaRingLapse", {
pokemonName: getPokemonNameWithAffix(pokemon), moveName: this.getMoveName(),
}), pokemonName: getPokemonNameWithAffix(pokemon),
true, }),
},
); );
} }
@ -2055,7 +2055,7 @@ export class TruantTag extends AbilityBattlerTag {
const lastMove = pokemon.getLastXMoves()[0]; const lastMove = pokemon.getLastXMoves()[0];
if (!lastMove || lastMove.move === MoveId.NONE) { if (!lastMove || lastMove.move === MoveId.NONE) {
// Don't interrupt move if last move was `Moves.NONE` OR no prior move was found // Don't interrupt move if last move was `MoveId.NONE` OR no prior move was found
return true; return true;
} }
@ -2698,29 +2698,30 @@ export class StockpilingTag extends SerializableBattlerTag {
* For each stat, an internal counter is incremented (by 1) if the stat was successfully changed. * For each stat, an internal counter is incremented (by 1) if the stat was successfully changed.
*/ */
onAdd(pokemon: Pokemon): void { onAdd(pokemon: Pokemon): void {
if (this.stockpiledCount < 3) { if (this.stockpiledCount >= 3) {
this.stockpiledCount++; return;
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:stockpilingOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
stockpiledCount: this.stockpiledCount,
}),
);
// Attempt to increase DEF and SPDEF by one stage, keeping track of successful changes.
globalScene.phaseManager.unshiftNew(
"StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[Stat.SPDEF, Stat.DEF],
1,
true,
false,
true,
this.onStatStagesChanged,
);
} }
this.stockpiledCount++;
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:stockpilingOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
stockpiledCount: this.stockpiledCount,
}),
);
// Attempt to increase DEF and SPDEF by one stage, keeping track of successful changes.
globalScene.phaseManager.unshiftNew(
"StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[Stat.SPDEF, Stat.DEF],
1,
true,
false,
true,
this.onStatStagesChanged,
);
} }
onOverlap(pokemon: Pokemon): void { onOverlap(pokemon: Pokemon): void {

View File

@ -73,16 +73,12 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
{ {
const hpHealed = new NumberHolder(toDmgValue(consumer.getMaxHp() / 4)); const hpHealed = new NumberHolder(toDmgValue(consumer.getMaxHp() / 4));
applyAbAttrs("DoubleBerryEffectAbAttr", { pokemon: consumer, effectValue: hpHealed }); applyAbAttrs("DoubleBerryEffectAbAttr", { pokemon: consumer, effectValue: hpHealed });
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew("PokemonHealPhase", consumer.getBattlerIndex(), hpHealed.value, {
"PokemonHealPhase", message: i18next.t("battle:hpHealBerry", {
consumer.getBattlerIndex(),
hpHealed.value,
i18next.t("battle:hpHealBerry", {
pokemonNameWithAffix: getPokemonNameWithAffix(consumer), pokemonNameWithAffix: getPokemonNameWithAffix(consumer),
berryName: getBerryName(berryType), berryName: getBerryName(berryType),
}), }),
true, });
);
} }
break; break;
case BerryType.LUM: case BerryType.LUM:

View File

@ -256,7 +256,7 @@ export const noAbilityTypeOverrideMoves: ReadonlySet<MoveId> = new Set([
MoveId.HIDDEN_POWER, MoveId.HIDDEN_POWER,
]); ]);
/** Set of all moves that cannot be copied by {@linkcode Moves.SKETCH}. */ /** Set of all moves that cannot be copied by {@linkcode MoveId.SKETCH}. */
export const invalidSketchMoves: ReadonlySet<MoveId> = new Set([ export const invalidSketchMoves: ReadonlySet<MoveId> = new Set([
MoveId.NONE, MoveId.NONE,
MoveId.CHATTER, MoveId.CHATTER,
@ -270,7 +270,7 @@ export const invalidSketchMoves: ReadonlySet<MoveId> = new Set([
MoveId.BREAKNECK_BLITZ__SPECIAL, MoveId.BREAKNECK_BLITZ__SPECIAL,
]); ]);
/** Set of all moves that cannot be locked into by {@linkcode Moves.ENCORE}. */ /** Set of all moves that cannot be locked into by {@linkcode MoveId.ENCORE}. */
export const invalidEncoreMoves: ReadonlySet<MoveId> = new Set([ export const invalidEncoreMoves: ReadonlySet<MoveId> = new Set([
MoveId.MIMIC, MoveId.MIMIC,
MoveId.MIRROR_MOVE, MoveId.MIRROR_MOVE,

View File

@ -1940,25 +1940,51 @@ export class AddSubstituteAttr extends MoveEffectAttr {
} }
/** /**
* Heals the user or target by {@linkcode healRatio} depending on the value of {@linkcode selfTarget} * Attribute to implement healing moves, such as {@linkcode MoveId.RECOVER} or {@linkcode MoveId.SOFT_BOILED}.
* @extends MoveEffectAttr * Heals the user or target of the move by a fixed amount relative to their maximum HP.
* @see {@linkcode apply}
*/ */
export class HealAttr extends MoveEffectAttr { export class HealAttr extends MoveEffectAttr {
/** The percentage of {@linkcode Stat.HP} to heal */ /** The percentage of {@linkcode Stat.HP} to heal; default `1` */
private healRatio: number; protected healRatio = 1
/** Should an animation be shown? */ /** Whether to display a healing animation upon healing the target; default `false` */
private showAnim: boolean; private showAnim = false
constructor(healRatio?: number, showAnim?: boolean, selfTarget?: boolean) { /**
super(selfTarget === undefined || selfTarget); * Whether the move should fail if the target is at full HP.
* @defaultValue `true`
* @todo Remove post move failure rework - this solely exists to prevent Lunar Blessing and co. from failing
*/
private failOnFullHp = true;
this.healRatio = healRatio || 1; constructor(
this.showAnim = !!showAnim; healRatio = 1,
showAnim = false,
selfTarget = true,
failOnFullHp = true
) {
super(selfTarget);
this.healRatio = healRatio;
this.showAnim = showAnim;
this.failOnFullHp = failOnFullHp;
} }
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
this.addHealPhase(this.selfTarget ? user : target, this.healRatio); if (!super.apply(user, target, move, args)) {
return false;
}
// Apply any boosts to healing amounts (i.e. Heal Pulse + Mega Launcher).
const hp = new NumberHolder(this.healRatio)
applyAbAttrs("MoveHealBoostAbAttr", {
pokemon: user,
opponent: target,
move,
healRatio: hp
})
this.healRatio = hp.value;
this.addHealPhase(this.selfTarget ? user : target);
return true; return true;
} }
@ -1966,15 +1992,81 @@ export class HealAttr extends MoveEffectAttr {
* Creates a new {@linkcode PokemonHealPhase}. * Creates a new {@linkcode PokemonHealPhase}.
* This heals the target and shows the appropriate message. * This heals the target and shows the appropriate message.
*/ */
addHealPhase(target: Pokemon, healRatio: number) { protected addHealPhase(healedPokemon: Pokemon) {
globalScene.phaseManager.unshiftNew("PokemonHealPhase", target.getBattlerIndex(), globalScene.phaseManager.unshiftNew("PokemonHealPhase", healedPokemon.getBattlerIndex(),
toDmgValue(target.getMaxHp() * healRatio), i18next.t("moveTriggers:healHp", { pokemonName: getPokemonNameWithAffix(target) }), true, !this.showAnim); // Healing moves round half UP the hp healed
// (unlike most other sources which round down)
Math.round(healedPokemon.getMaxHp() * this.healRatio),
{
message: i18next.t("moveTriggers:healHp", { pokemonName: getPokemonNameWithAffix(healedPokemon) }),
showFullHpMessage: true,
skipAnim: !this.showAnim,
}
);
} }
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { override getTargetBenefitScore(user: Pokemon, target: Pokemon, _move: Move): number {
const score = ((1 - (this.selfTarget ? user : target).getHpRatio()) * 20) - this.healRatio * 10; const score = ((1 - (this.selfTarget ? user : target).getHpRatio()) * 20) - this.healRatio * 10;
return Math.round(score / (1 - this.healRatio / 2)); return Math.round(score / (1 - this.healRatio / 2));
} }
override getCondition(): MoveConditionFunc {
return (user, target) => !(this.failOnFullHp && (this.selfTarget ? user : target).isFullHp());
}
override getFailedText(user: Pokemon, target: Pokemon): string | undefined {
const healedPokemon = this.selfTarget ? user : target;
return i18next.t("battle:hpIsFull", {
pokemonName: getPokemonNameWithAffix(healedPokemon),
})
}
}
/**
* Attribute for moves with variable healing amounts.
* Heals the user/target by an amount depending on the return value of {@linkcode healFunc}.
*
* Used for:
* - {@linkcode MoveId.MOONLIGHT} and variants
* - {@linkcode MoveId.SHORE_UP}
* - {@linkcode MoveId.FLORAL_HEALING}
* - {@linkcode MoveId.SWALLOW}
*/
export class VariableHealAttr extends HealAttr {
constructor(
/** A function yielding the amount of HP to heal. */
private healFunc: (user: Pokemon, target: Pokemon, move: Move) => number,
showAnim = false,
selfTarget = true,
failOnFullHp = true,
) {
super(1, showAnim, selfTarget, selfTarget);
this.healFunc = healFunc;
}
apply(user: Pokemon, target: Pokemon, move: Move, _args: any[]): boolean {
this.healRatio = this.healFunc(user, target, move)
return super.apply(user, target, move, _args);
}
}
/**
* Heals the target only if it is an ally.
* Used for {@linkcode MoveId.POLLEN_PUFF}.
*/
export class HealOnAllyAttr extends HealAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (user.getAlly() === target) {
super.apply(user, target, move, args);
return true;
}
return false;
}
override getCondition(): MoveConditionFunc {
return (user, target, _move) => user.getAlly() !== target || super.getCondition()(user, target, _move)
}
} }
/** /**
@ -2101,17 +2193,19 @@ export class SacrificialFullRestoreAttr extends SacrificialAttr {
const pm = globalScene.phaseManager; const pm = globalScene.phaseManager;
pm.pushPhase( pm.pushPhase(
pm.create("PokemonHealPhase", pm.create(
"PokemonHealPhase",
user.getBattlerIndex(), user.getBattlerIndex(),
maxPartyMemberHp, maxPartyMemberHp,
i18next.t(this.moveMessage, { pokemonName: getPokemonNameWithAffix(user) }), {
true, message: i18next.t(this.moveMessage, { pokemonName: getPokemonNameWithAffix(user) }),
false, showFullHpMessage: false,
false, skipAnim: true,
true, healStatus: true,
false, fullRestorePP: this.restorePP,
this.restorePP), }
true); ),
true);
return true; return true;
} }
@ -2157,112 +2251,6 @@ export class IgnoreWeatherTypeDebuffAttr extends MoveAttr {
} }
} }
export abstract class WeatherHealAttr extends HealAttr {
constructor() {
super(0.5);
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
let healRatio = 0.5;
if (!globalScene.arena.weather?.isEffectSuppressed()) {
const weatherType = globalScene.arena.weather?.weatherType || WeatherType.NONE;
healRatio = this.getWeatherHealRatio(weatherType);
}
this.addHealPhase(user, healRatio);
return true;
}
abstract getWeatherHealRatio(weatherType: WeatherType): number;
}
export class PlantHealAttr extends WeatherHealAttr {
getWeatherHealRatio(weatherType: WeatherType): number {
switch (weatherType) {
case WeatherType.SUNNY:
case WeatherType.HARSH_SUN:
return 2 / 3;
case WeatherType.RAIN:
case WeatherType.SANDSTORM:
case WeatherType.HAIL:
case WeatherType.SNOW:
case WeatherType.FOG:
case WeatherType.HEAVY_RAIN:
return 0.25;
default:
return 0.5;
}
}
}
export class SandHealAttr extends WeatherHealAttr {
getWeatherHealRatio(weatherType: WeatherType): number {
switch (weatherType) {
case WeatherType.SANDSTORM:
return 2 / 3;
default:
return 0.5;
}
}
}
/**
* Heals the target or the user by either {@linkcode normalHealRatio} or {@linkcode boostedHealRatio}
* depending on the evaluation of {@linkcode condition}
* @extends HealAttr
* @see {@linkcode apply}
*/
export class BoostHealAttr extends HealAttr {
/** Healing received when {@linkcode condition} is false */
private normalHealRatio: number;
/** Healing received when {@linkcode condition} is true */
private boostedHealRatio: number;
/** The lambda expression to check against when boosting the healing value */
private condition?: MoveConditionFunc;
constructor(normalHealRatio: number = 0.5, boostedHealRatio: number = 2 / 3, showAnim?: boolean, selfTarget?: boolean, condition?: MoveConditionFunc) {
super(normalHealRatio, showAnim, selfTarget);
this.normalHealRatio = normalHealRatio;
this.boostedHealRatio = boostedHealRatio;
this.condition = condition;
}
/**
* @param user {@linkcode Pokemon} using the move
* @param target {@linkcode Pokemon} target of the move
* @param move {@linkcode Move} with this attribute
* @param args N/A
* @returns true if the move was successful
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const healRatio: number = (this.condition ? this.condition(user, target, move) : false) ? this.boostedHealRatio : this.normalHealRatio;
this.addHealPhase(target, healRatio);
return true;
}
}
/**
* Heals the target only if it is the ally
* @extends HealAttr
* @see {@linkcode apply}
*/
export class HealOnAllyAttr extends HealAttr {
/**
* @param user {@linkcode Pokemon} using the move
* @param target {@linkcode Pokemon} target of the move
* @param move {@linkcode Move} with this attribute
* @param args N/A
* @returns true if the function succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (user.getAlly() === target) {
super.apply(user, target, move, args);
return true;
}
return false;
}
}
/** /**
* Heals user as a side effect of a move that hits a target. * Heals user as a side effect of a move that hits a target.
* Healing is based on {@linkcode healRatio} * the amount of damage dealt or a stat of the target. * Healing is based on {@linkcode healRatio} * the amount of damage dealt or a stat of the target.
@ -2313,7 +2301,9 @@ export class HitHealAttr extends MoveEffectAttr {
message = ""; message = "";
} }
} }
globalScene.phaseManager.unshiftNew("PokemonHealPhase", user.getBattlerIndex(), healAmount, message, false, true); globalScene.phaseManager.unshiftNew("PokemonHealPhase", user.getBattlerIndex(), healAmount,
{message, showFullHpMessage: false, skipAnim: true}
);
return true; return true;
} }
@ -2587,7 +2577,7 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr {
} }
/** /**
* Applies the effect of {@linkcode Moves.PSYCHO_SHIFT} to its target. * Applies the effect of {@linkcode MoveId.PSYCHO_SHIFT} to its target.
* Psycho Shift takes the user's status effect and passes it onto the target. * Psycho Shift takes the user's status effect and passes it onto the target.
* The user is then healed after the move has been successfully executed. * The user is then healed after the move has been successfully executed.
* @param user - The {@linkcode Pokemon} using the move * @param user - The {@linkcode Pokemon} using the move
@ -2927,7 +2917,7 @@ export class HealStatusEffectAttr extends MoveEffectAttr {
/** /**
* Attribute to add the {@linkcode BattlerTagType.BYPASS_SLEEP | BYPASS_SLEEP Battler Tag} for 1 turn to the user before move use. * Attribute to add the {@linkcode BattlerTagType.BYPASS_SLEEP | BYPASS_SLEEP Battler Tag} for 1 turn to the user before move use.
* Used by {@linkcode Moves.SNORE} and {@linkcode Moves.SLEEP_TALK}. * Used by {@linkcode MoveId.SNORE} and {@linkcode MoveId.SLEEP_TALK}.
*/ */
// TODO: Should this use a battler tag? // TODO: Should this use a battler tag?
// TODO: Give this `userSleptOrComatoseCondition` by default // TODO: Give this `userSleptOrComatoseCondition` by default
@ -4346,7 +4336,8 @@ export class PunishmentPowerAttr extends VariablePowerAttr {
} }
export class PresentPowerAttr extends VariablePowerAttr { export class PresentPowerAttr extends VariablePowerAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: [NumberHolder]): boolean {
const power = args[0]
/** /**
* If this move is multi-hit, and this attribute is applied to any hit * If this move is multi-hit, and this attribute is applied to any hit
* other than the first, this move cannot result in a heal. * other than the first, this move cannot result in a heal.
@ -4355,17 +4346,21 @@ export class PresentPowerAttr extends VariablePowerAttr {
const powerSeed = randSeedInt(firstHit ? 100 : 80); const powerSeed = randSeedInt(firstHit ? 100 : 80);
if (powerSeed <= 40) { if (powerSeed <= 40) {
(args[0] as NumberHolder).value = 40; power.value = 40;
} else if (40 < powerSeed && powerSeed <= 70) { } else if (powerSeed <= 70) {
(args[0] as NumberHolder).value = 80; power.value = 80;
} else if (70 < powerSeed && powerSeed <= 80) { } else if (powerSeed <= 80) {
(args[0] as NumberHolder).value = 120; power.value = 120;
} else if (80 < powerSeed && powerSeed <= 100) { } else if (powerSeed <= 100) {
// If this move is multi-hit, disable all other hits // Disable all other hits and heal the target for 25% max HP
user.turnData.hitCount = 1; user.turnData.hitCount = 1;
user.turnData.hitsLeft = 1; user.turnData.hitsLeft = 1;
globalScene.phaseManager.unshiftNew("PokemonHealPhase", target.getBattlerIndex(), globalScene.phaseManager.unshiftNew(
toDmgValue(target.getMaxHp() / 4), i18next.t("moveTriggers:regainedHealth", { pokemonName: getPokemonNameWithAffix(target) }), true); "PokemonHealPhase",
target.getBattlerIndex(),
toDmgValue(target.getMaxHp() / 4),
{message: i18next.t("moveTriggers:regainedHealth", { pokemonName: getPokemonNameWithAffix(target) })}
)
} }
return true; return true;
@ -4406,36 +4401,6 @@ export class SpitUpPowerAttr extends VariablePowerAttr {
} }
} }
/**
* Attribute used to apply Swallow's healing, which scales with Stockpile stacks.
* Does NOT remove stockpiled stacks.
*/
export class SwallowHealAttr extends HealAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const stockpilingTag = user.getTag(StockpilingTag);
if (stockpilingTag && stockpilingTag.stockpiledCount > 0) {
const stockpiled = stockpilingTag.stockpiledCount;
let healRatio: number;
if (stockpiled === 1) {
healRatio = 0.25;
} else if (stockpiled === 2) {
healRatio = 0.50;
} else { // stockpiled >= 3
healRatio = 1.00;
}
if (healRatio) {
this.addHealPhase(user, healRatio);
return true;
}
}
return false;
}
}
const hasStockpileStacksCondition: MoveConditionFunc = (user) => { const hasStockpileStacksCondition: MoveConditionFunc = (user) => {
const hasStockpilingTag = user.getTag(StockpilingTag); const hasStockpilingTag = user.getTag(StockpilingTag);
return !!hasStockpilingTag && hasStockpilingTag.stockpiledCount > 0; return !!hasStockpilingTag && hasStockpilingTag.stockpiledCount > 0;
@ -5912,20 +5877,21 @@ export class ProtectAttr extends AddBattlerTagAttr {
getCondition(): MoveConditionFunc { getCondition(): MoveConditionFunc {
return ((user, target, move): boolean => { return ((user, target, move): boolean => {
let timesUsed = 0; let timesUsed = 0;
const moveHistory = user.getLastXMoves();
let turnMove: TurnMove | undefined;
while (moveHistory.length) { for (const turnMove of user.getLastXMoves(-1).slice()) {
turnMove = moveHistory.shift(); if (
if (!allMoves[turnMove?.move ?? MoveId.NONE].hasAttr("ProtectAttr") || turnMove?.result !== MoveResult.SUCCESS) { // Quick & Wide guard increment the Protect counter without using it for fail chance
!(allMoves[turnMove.move].hasAttr("ProtectAttr") ||
[MoveId.QUICK_GUARD, MoveId.WIDE_GUARD].includes(turnMove.move)) ||
turnMove.result !== MoveResult.SUCCESS
) {
break; break;
} }
timesUsed++;
timesUsed++
} }
if (timesUsed) {
return !user.randBattleSeedInt(Math.pow(3, timesUsed)); return timesUsed === 0 || user.randBattleSeedInt(Math.pow(3, timesUsed)) === 0;
}
return true;
}); });
} }
} }
@ -7139,7 +7105,7 @@ export class CopyMoveAttr extends CallMoveAttr {
/** /**
* Attribute used for moves that cause the target to repeat their last used move. * Attribute used for moves that cause the target to repeat their last used move.
* *
* Used by {@linkcode Moves.INSTRUCT | Instruct}. * Used by {@linkcode MoveId.INSTRUCT | Instruct}.
* @see [Instruct on Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Instruct_(move)) * @see [Instruct on Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Instruct_(move))
*/ */
export class RepeatMoveAttr extends MoveEffectAttr { export class RepeatMoveAttr extends MoveEffectAttr {
@ -7402,7 +7368,7 @@ const targetMoveCopiableCondition: MoveConditionFunc = (user, target, move) => {
/** /**
* Attribute to temporarily copy the last move in the target's moveset. * Attribute to temporarily copy the last move in the target's moveset.
* Used by {@linkcode Moves.MIMIC}. * Used by {@linkcode MoveId.MIMIC}.
*/ */
export class MovesetCopyMoveAttr extends OverrideMoveEffectAttr { export class MovesetCopyMoveAttr extends OverrideMoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
@ -7966,7 +7932,7 @@ export class VariableTargetAttr extends MoveAttr {
/** /**
* Attribute to cause the target to move immediately after the user. * Attribute to cause the target to move immediately after the user.
* *
* Used by {@linkcode Moves.AFTER_YOU}. * Used by {@linkcode MoveId.AFTER_YOU}.
*/ */
export class AfterYouAttr extends MoveEffectAttr { export class AfterYouAttr extends MoveEffectAttr {
/** /**
@ -8088,6 +8054,53 @@ const attackedByItemMessageFunc = (user: Pokemon, target: Pokemon, move: Move) =
return message; return message;
}; };
const sunnyHealRatioFunc = (): number => {
if (globalScene.arena.weather?.isEffectSuppressed()) {
return 1 / 2;
}
switch (globalScene.arena.getWeatherType()) {
case WeatherType.SUNNY:
case WeatherType.HARSH_SUN:
return 2 / 3;
case WeatherType.RAIN:
case WeatherType.SANDSTORM:
case WeatherType.HAIL:
case WeatherType.SNOW:
case WeatherType.HEAVY_RAIN:
case WeatherType.FOG:
return 1 / 4;
case WeatherType.STRONG_WINDS:
default:
return 1 / 2;
}
}
const shoreUpHealRatioFunc = (): number => {
if (globalScene.arena.weather?.isEffectSuppressed()) {
return 1 / 2;
}
return globalScene.arena.getWeatherType() === WeatherType.SANDSTORM ? 2 / 3 : 1 / 2;
}
const swallowHealFunc = (user: Pokemon): number => {
const tag = user.getTag(StockpilingTag);
if (!tag || tag.stockpiledCount <= 0) {
return 0;
}
switch (tag.stockpiledCount) {
case 1:
return 0.25
case 2:
return 0.5
case 3:
default: // in case we ever get more stacks
return 1;
}
}
export class MoveCondition { export class MoveCondition {
protected func: MoveConditionFunc; protected func: MoveConditionFunc;
@ -8299,15 +8312,12 @@ const MoveAttrs = Object.freeze({
SacrificialAttrOnHit, SacrificialAttrOnHit,
HalfSacrificialAttr, HalfSacrificialAttr,
AddSubstituteAttr, AddSubstituteAttr,
HealAttr,
PartyStatusCureAttr, PartyStatusCureAttr,
FlameBurstAttr, FlameBurstAttr,
SacrificialFullRestoreAttr, SacrificialFullRestoreAttr,
IgnoreWeatherTypeDebuffAttr, IgnoreWeatherTypeDebuffAttr,
WeatherHealAttr, HealAttr,
PlantHealAttr, VariableHealAttr,
SandHealAttr,
BoostHealAttr,
HealOnAllyAttr, HealOnAllyAttr,
HitHealAttr, HitHealAttr,
IncrementMovePriorityAttr, IncrementMovePriorityAttr,
@ -8371,7 +8381,6 @@ const MoveAttrs = Object.freeze({
PresentPowerAttr, PresentPowerAttr,
WaterShurikenPowerAttr, WaterShurikenPowerAttr,
SpitUpPowerAttr, SpitUpPowerAttr,
SwallowHealAttr,
MultiHitPowerIncrementAttr, MultiHitPowerIncrementAttr,
LastMoveDoublePowerAttr, LastMoveDoublePowerAttr,
CombinedPledgePowerAttr, CombinedPledgePowerAttr,
@ -9222,13 +9231,13 @@ export function initMoves() {
.attr(StatStageChangeAttr, [ Stat.ATK ], 1, true), .attr(StatStageChangeAttr, [ Stat.ATK ], 1, true),
new AttackMove(MoveId.VITAL_THROW, PokemonType.FIGHTING, MoveCategory.PHYSICAL, 70, -1, 10, -1, -1, 2), new AttackMove(MoveId.VITAL_THROW, PokemonType.FIGHTING, MoveCategory.PHYSICAL, 70, -1, 10, -1, -1, 2),
new SelfStatusMove(MoveId.MORNING_SUN, PokemonType.NORMAL, -1, 5, -1, 0, 2) new SelfStatusMove(MoveId.MORNING_SUN, PokemonType.NORMAL, -1, 5, -1, 0, 2)
.attr(PlantHealAttr) .attr(VariableHealAttr, sunnyHealRatioFunc)
.triageMove(), .triageMove(),
new SelfStatusMove(MoveId.SYNTHESIS, PokemonType.GRASS, -1, 5, -1, 0, 2) new SelfStatusMove(MoveId.SYNTHESIS, PokemonType.GRASS, -1, 5, -1, 0, 2)
.attr(PlantHealAttr) .attr(VariableHealAttr, sunnyHealRatioFunc)
.triageMove(), .triageMove(),
new SelfStatusMove(MoveId.MOONLIGHT, PokemonType.FAIRY, -1, 5, -1, 0, 2) new SelfStatusMove(MoveId.MOONLIGHT, PokemonType.FAIRY, -1, 5, -1, 0, 2)
.attr(PlantHealAttr) .attr(VariableHealAttr, sunnyHealRatioFunc)
.triageMove(), .triageMove(),
new AttackMove(MoveId.HIDDEN_POWER, PokemonType.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 2) new AttackMove(MoveId.HIDDEN_POWER, PokemonType.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 2)
.attr(HiddenPowerTypeAttr), .attr(HiddenPowerTypeAttr),
@ -9285,15 +9294,15 @@ export function initMoves() {
.partial(), // Does not lock the user, does not stop Pokemon from sleeping .partial(), // Does not lock the user, does not stop Pokemon from sleeping
// Likely can make use of FrenzyAttr and an ArenaTag (just without the FrenzyMissFunc) // Likely can make use of FrenzyAttr and an ArenaTag (just without the FrenzyMissFunc)
new SelfStatusMove(MoveId.STOCKPILE, PokemonType.NORMAL, -1, 20, -1, 0, 3) new SelfStatusMove(MoveId.STOCKPILE, PokemonType.NORMAL, -1, 20, -1, 0, 3)
.condition(user => (user.getTag(StockpilingTag)?.stockpiledCount ?? 0) < 3) .condition(user => (user.getTag(BattlerTagType.STOCKPILING)?.stockpiledCount ?? 0) < 3)
.attr(AddBattlerTagAttr, BattlerTagType.STOCKPILING, true), .attr(AddBattlerTagAttr, BattlerTagType.STOCKPILING, true),
new AttackMove(MoveId.SPIT_UP, PokemonType.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) new AttackMove(MoveId.SPIT_UP, PokemonType.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3)
.condition(hasStockpileStacksCondition)
.attr(SpitUpPowerAttr, 100) .attr(SpitUpPowerAttr, 100)
.condition(hasStockpileStacksCondition)
.attr(RemoveBattlerTagAttr, [ BattlerTagType.STOCKPILING ], true), .attr(RemoveBattlerTagAttr, [ BattlerTagType.STOCKPILING ], true),
new SelfStatusMove(MoveId.SWALLOW, PokemonType.NORMAL, -1, 10, -1, 0, 3) new SelfStatusMove(MoveId.SWALLOW, PokemonType.NORMAL, -1, 10, -1, 0, 3)
.attr(VariableHealAttr, swallowHealFunc, false, true, true)
.condition(hasStockpileStacksCondition) .condition(hasStockpileStacksCondition)
.attr(SwallowHealAttr)
.attr(RemoveBattlerTagAttr, [ BattlerTagType.STOCKPILING ], true) .attr(RemoveBattlerTagAttr, [ BattlerTagType.STOCKPILING ], true)
.triageMove(), .triageMove(),
new AttackMove(MoveId.HEAT_WAVE, PokemonType.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3) new AttackMove(MoveId.HEAT_WAVE, PokemonType.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3)
@ -10555,7 +10564,7 @@ export function initMoves() {
.unimplemented(), .unimplemented(),
/* End Unused */ /* End Unused */
new SelfStatusMove(MoveId.SHORE_UP, PokemonType.GROUND, -1, 5, -1, 0, 7) new SelfStatusMove(MoveId.SHORE_UP, PokemonType.GROUND, -1, 5, -1, 0, 7)
.attr(SandHealAttr) .attr(VariableHealAttr, shoreUpHealRatioFunc)
.triageMove(), .triageMove(),
new AttackMove(MoveId.FIRST_IMPRESSION, PokemonType.BUG, MoveCategory.PHYSICAL, 90, 100, 10, -1, 2, 7) new AttackMove(MoveId.FIRST_IMPRESSION, PokemonType.BUG, MoveCategory.PHYSICAL, 90, 100, 10, -1, 2, 7)
.condition(new FirstMoveCondition()), .condition(new FirstMoveCondition()),
@ -10575,7 +10584,7 @@ export function initMoves() {
.attr(StatStageChangeAttr, [ Stat.SPD ], -1, true) .attr(StatStageChangeAttr, [ Stat.SPD ], -1, true)
.punchingMove(), .punchingMove(),
new StatusMove(MoveId.FLORAL_HEALING, PokemonType.FAIRY, -1, 10, -1, 0, 7) new StatusMove(MoveId.FLORAL_HEALING, PokemonType.FAIRY, -1, 10, -1, 0, 7)
.attr(BoostHealAttr, 0.5, 2 / 3, true, false, (user, target, move) => globalScene.arena.terrain?.terrainType === TerrainType.GRASSY) .attr(VariableHealAttr, () => globalScene.arena.getTerrainType() === TerrainType.GRASSY ? 2 / 3 : 1 / 2, true, false)
.triageMove() .triageMove()
.reflectable(), .reflectable(),
new AttackMove(MoveId.HIGH_HORSEPOWER, PokemonType.GROUND, MoveCategory.PHYSICAL, 95, 95, 10, -1, 0, 7), new AttackMove(MoveId.HIGH_HORSEPOWER, PokemonType.GROUND, MoveCategory.PHYSICAL, 95, 95, 10, -1, 0, 7),
@ -11067,10 +11076,11 @@ export function initMoves() {
.attr(HealStatusEffectAttr, false, StatusEffect.FREEZE) .attr(HealStatusEffectAttr, false, StatusEffect.FREEZE)
.attr(StatusEffectAttr, StatusEffect.BURN), .attr(StatusEffectAttr, StatusEffect.BURN),
new StatusMove(MoveId.JUNGLE_HEALING, PokemonType.GRASS, -1, 10, -1, 0, 8) new StatusMove(MoveId.JUNGLE_HEALING, PokemonType.GRASS, -1, 10, -1, 0, 8)
.attr(HealAttr, 0.25, true, false) .attr(HealAttr, 0.25, true, false, false)
.attr(HealStatusEffectAttr, false, getNonVolatileStatusEffects()) .attr(HealStatusEffectAttr, false, getNonVolatileStatusEffects())
.target(MoveTarget.USER_AND_ALLIES) .target(MoveTarget.USER_AND_ALLIES)
.triageMove(), .triageMove()
.edgeCase(), // TODO: Review if jungle healing fails if HP cannot be restored and status cannot be cured
new AttackMove(MoveId.WICKED_BLOW, PokemonType.DARK, MoveCategory.PHYSICAL, 75, 100, 5, -1, 0, 8) new AttackMove(MoveId.WICKED_BLOW, PokemonType.DARK, MoveCategory.PHYSICAL, 75, 100, 5, -1, 0, 8)
.attr(CritOnlyAttr) .attr(CritOnlyAttr)
.punchingMove(), .punchingMove(),
@ -11172,10 +11182,11 @@ export function initMoves() {
.windMove() .windMove()
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new StatusMove(MoveId.LUNAR_BLESSING, PokemonType.PSYCHIC, -1, 5, -1, 0, 8) new StatusMove(MoveId.LUNAR_BLESSING, PokemonType.PSYCHIC, -1, 5, -1, 0, 8)
.attr(HealAttr, 0.25, true, false) .attr(HealAttr, 0.25, true, false, false)
.attr(HealStatusEffectAttr, false, getNonVolatileStatusEffects()) .attr(HealStatusEffectAttr, false, getNonVolatileStatusEffects())
.target(MoveTarget.USER_AND_ALLIES) .target(MoveTarget.USER_AND_ALLIES)
.triageMove(), .triageMove()
.edgeCase(), // TODO: Review if lunar blessing fails if HP cannot be restored and status cannot be cured
new SelfStatusMove(MoveId.TAKE_HEART, PokemonType.PSYCHIC, -1, 10, -1, 0, 8) new SelfStatusMove(MoveId.TAKE_HEART, PokemonType.PSYCHIC, -1, 10, -1, 0, 8)
.attr(StatStageChangeAttr, [ Stat.SPATK, Stat.SPDEF ], 1, true) .attr(StatStageChangeAttr, [ Stat.SPATK, Stat.SPDEF ], 1, true)
.attr(HealStatusEffectAttr, true, [ StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN, StatusEffect.SLEEP ]), .attr(HealStatusEffectAttr, true, [ StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN, StatusEffect.SLEEP ]),

View File

@ -253,7 +253,6 @@ export class PokemonTempSummonData {
* Only currently used for positioning the battle cursor. * Only currently used for positioning the battle cursor.
*/ */
turnCount = 1; turnCount = 1;
/** /**
* The number of turns this pokemon has spent in the active position since the start of the wave * The number of turns this pokemon has spent in the active position since the start of the wave
* without switching out. * without switching out.

View File

@ -155,13 +155,12 @@ export class WishTag extends PositionalTag implements WishArgs {
public override trigger(): void { public override trigger(): void {
// TODO: Rename this locales key - wish shows a message on REMOVAL, not addition // TODO: Rename this locales key - wish shows a message on REMOVAL, not addition
globalScene.phaseManager.queueMessage( // TODO: What messages does Wish show when healing a Pokemon at full HP?
i18next.t("arenaTag:wishTagOnAdd", { globalScene.phaseManager.unshiftNew("PokemonHealPhase", this.targetIndex, this.healHp, {
message: i18next.t("arenaTag:wishTagOnAdd", {
pokemonNameWithAffix: this.pokemonName, pokemonNameWithAffix: this.pokemonName,
}), }),
); });
globalScene.phaseManager.unshiftNew("PokemonHealPhase", this.targetIndex, this.healHp, null, true, false);
} }
public override shouldTrigger(): boolean { public override shouldTrigger(): boolean {

View File

@ -24,11 +24,11 @@ import { NoCritTag, WeakenMoveScreenTag } from "#data/arena-tag";
import { import {
AutotomizedTag, AutotomizedTag,
BattlerTag, BattlerTag,
type BattlerTagTypeMap,
CritBoostTag, CritBoostTag,
EncoreTag, EncoreTag,
ExposedTag, ExposedTag,
GroundedTag, GroundedTag,
type GrudgeTag,
getBattlerTag, getBattlerTag,
HighestStatBoostTag, HighestStatBoostTag,
MoveRestrictionBattlerTag, MoveRestrictionBattlerTag,
@ -725,7 +725,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
/** /**
* Load all assets needed for this Pokemon's use in battle * Load all assets needed for this Pokemon's use in battle
* @param ignoreOverride - Whether to ignore overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `true` * @param ignoreOverride - Whether to ignore overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `true`
* @param useIllusion - Whether to consider this pokemon's active illusion; default `false` * @param useIllusion - Whether to consider this pokemon's active illusion; default `false`
* @returns A promise that resolves once all the corresponding assets have been loaded. * @returns A promise that resolves once all the corresponding assets have been loaded.
*/ */
@ -1032,7 +1032,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
/** /**
* Return this Pokemon's {@linkcode PokemonSpeciesForm | SpeciesForm}. * Return this Pokemon's {@linkcode PokemonSpeciesForm | SpeciesForm}.
* @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false`
* and overrides `useIllusion`. * and overrides `useIllusion`.
* @param useIllusion - Whether to consider this Pokemon's illusion if present; default `false`. * @param useIllusion - Whether to consider this Pokemon's illusion if present; default `false`.
* @returns This Pokemon's {@linkcode PokemonSpeciesForm}. * @returns This Pokemon's {@linkcode PokemonSpeciesForm}.
@ -1088,7 +1088,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
/** /**
* Return the {@linkcode PokemonSpeciesForm | SpeciesForm} of this Pokemon's fusion counterpart. * Return the {@linkcode PokemonSpeciesForm | SpeciesForm} of this Pokemon's fusion counterpart.
* @param ignoreOverride - Whether to ignore species overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` * @param ignoreOverride - Whether to ignore species overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false`
* @param useIllusion - Whether to consider the species of this Pokemon's illusion; default `false` * @param useIllusion - Whether to consider the species of this Pokemon's illusion; default `false`
* @returns The {@linkcode PokemonSpeciesForm} of this Pokemon's fusion counterpart. * @returns The {@linkcode PokemonSpeciesForm} of this Pokemon's fusion counterpart.
*/ */
@ -1640,6 +1640,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
return this.getMaxHp() - this.hp; return this.getMaxHp() - this.hp;
} }
// TODO: Why does this default to `false`?
getHpRatio(precise = false): number { getHpRatio(precise = false): number {
return precise ? this.hp / this.getMaxHp() : Math.round((this.hp / this.getMaxHp()) * 100) / 100; return precise ? this.hp / this.getMaxHp() : Math.round((this.hp / this.getMaxHp()) * 100) / 100;
} }
@ -1659,7 +1660,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
/** /**
* Return this Pokemon's {@linkcode Gender}. * Return this Pokemon's {@linkcode Gender}.
* @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false`
* @param useIllusion - Whether to consider this pokemon's illusion if present; default `false` * @param useIllusion - Whether to consider this pokemon's illusion if present; default `false`
* @returns the {@linkcode Gender} of this {@linkcode Pokemon}. * @returns the {@linkcode Gender} of this {@linkcode Pokemon}.
*/ */
@ -1675,7 +1676,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
/** /**
* Return this Pokemon's fusion's {@linkcode Gender}. * Return this Pokemon's fusion's {@linkcode Gender}.
* @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false`
* @param useIllusion - Whether to consider this pokemon's illusion if present; default `false` * @param useIllusion - Whether to consider this pokemon's illusion if present; default `false`
* @returns The {@linkcode Gender} of this {@linkcode Pokemon}'s fusion. * @returns The {@linkcode Gender} of this {@linkcode Pokemon}'s fusion.
*/ */
@ -1817,7 +1818,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
/** /**
* Return all the {@linkcode PokemonMove}s that make up this Pokemon's moveset. * Return all the {@linkcode PokemonMove}s that make up this Pokemon's moveset.
* Takes into account player/enemy moveset overrides (which will also override PP count). * Takes into account player/enemy moveset overrides (which will also override PP count).
* @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false`
* @returns An array of {@linkcode PokemonMove}, as described above. * @returns An array of {@linkcode PokemonMove}, as described above.
*/ */
getMoveset(ignoreOverride = false): PokemonMove[] { getMoveset(ignoreOverride = false): PokemonMove[] {
@ -1883,7 +1884,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
* Evaluate and return this Pokemon's typing. * Evaluate and return this Pokemon's typing.
* @param includeTeraType - Whether to use this Pokemon's tera type if Terastallized; default `false` * @param includeTeraType - Whether to use this Pokemon's tera type if Terastallized; default `false`
* @param forDefend - Whether this Pokemon is currently receiving an attack; default `false` * @param forDefend - Whether this Pokemon is currently receiving an attack; default `false`
* @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false`
* @param useIllusion - Whether to consider this Pokemon's illusion if present; default `false` * @param useIllusion - Whether to consider this Pokemon's illusion if present; default `false`
* @returns An array of {@linkcode PokemonType}s corresponding to this Pokemon's typing (real or percieved). * @returns An array of {@linkcode PokemonType}s corresponding to this Pokemon's typing (real or percieved).
*/ */
@ -2006,7 +2007,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
* @param type - The {@linkcode PokemonType} to check * @param type - The {@linkcode PokemonType} to check
* @param includeTeraType - Whether to use this Pokemon's tera type if Terastallized; default `true` * @param includeTeraType - Whether to use this Pokemon's tera type if Terastallized; default `true`
* @param forDefend - Whether this Pokemon is currently receiving an attack; default `false` * @param forDefend - Whether this Pokemon is currently receiving an attack; default `false`
* @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false`
* @returns Whether this Pokemon is of the specified type. * @returns Whether this Pokemon is of the specified type.
*/ */
public isOfType(type: PokemonType, includeTeraType = true, forDefend = false, ignoreOverride = false): boolean { public isOfType(type: PokemonType, includeTeraType = true, forDefend = false, ignoreOverride = false): boolean {
@ -2019,7 +2020,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
* Should rarely be called directly in favor of {@linkcode hasAbility} or {@linkcode hasAbilityWithAttr}, * Should rarely be called directly in favor of {@linkcode hasAbility} or {@linkcode hasAbilityWithAttr},
* both of which check both ability slots and account for suppression. * both of which check both ability slots and account for suppression.
* @see {@linkcode hasAbility} and {@linkcode hasAbilityWithAttr} are the intended ways to check abilities in most cases * @see {@linkcode hasAbility} and {@linkcode hasAbilityWithAttr} are the intended ways to check abilities in most cases
* @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false`
* @returns The non-passive {@linkcode Ability} of this Pokemon. * @returns The non-passive {@linkcode Ability} of this Pokemon.
*/ */
public getAbility(ignoreOverride = false): Ability { public getAbility(ignoreOverride = false): Ability {
@ -2201,7 +2202,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
* Accounts for all the various effects which can disable or modify abilities. * Accounts for all the various effects which can disable or modify abilities.
* @param ability - The {@linkcode Abilities | Ability} to check for * @param ability - The {@linkcode Abilities | Ability} to check for
* @param canApply - Whether to check if the ability is currently active; default `true` * @param canApply - Whether to check if the ability is currently active; default `true`
* @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false`
* @returns Whether this {@linkcode Pokemon} has the given ability * @returns Whether this {@linkcode Pokemon} has the given ability
*/ */
public hasAbility(ability: AbilityId, canApply = true, ignoreOverride = false): boolean { public hasAbility(ability: AbilityId, canApply = true, ignoreOverride = false): boolean {
@ -2216,7 +2217,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
* Accounts for all the various effects which can disable or modify abilities. * Accounts for all the various effects which can disable or modify abilities.
* @param attrType - The {@linkcode AbAttr | attribute} to check for * @param attrType - The {@linkcode AbAttr | attribute} to check for
* @param canApply - Whether to check if the ability is currently active; default `true` * @param canApply - Whether to check if the ability is currently active; default `true`
* @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false`
* @returns Whether this Pokemon has an ability with the given {@linkcode AbAttr}. * @returns Whether this Pokemon has an ability with the given {@linkcode AbAttr}.
*/ */
public hasAbilityWithAttr(attrType: AbAttrString, canApply = true, ignoreOverride = false): boolean { public hasAbilityWithAttr(attrType: AbAttrString, canApply = true, ignoreOverride = false): boolean {
@ -4237,14 +4238,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
return false; return false;
} }
/**@overload */
getTag(tagType: BattlerTagType.GRUDGE): GrudgeTag | undefined;
/** @overload */ /** @overload */
getTag(tagType: BattlerTagType.SUBSTITUTE): SubstituteTag | undefined; getTag<T extends BattlerTagType>(tagType: T): BattlerTagTypeMap[T] | undefined;
/** @overload */
getTag(tagType: BattlerTagType): BattlerTag | undefined;
/** @overload */ /** @overload */
getTag<T extends BattlerTag>(tagType: Constructor<T>): T | undefined; getTag<T extends BattlerTag>(tagType: Constructor<T>): T | undefined;
@ -4466,7 +4461,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
* Return the most recently executed {@linkcode TurnMove} this {@linkcode Pokemon} has used that is: * Return the most recently executed {@linkcode TurnMove} this {@linkcode Pokemon} has used that is:
* - Not {@linkcode MoveId.NONE} * - Not {@linkcode MoveId.NONE}
* - Non-virtual ({@linkcode MoveUseMode | useMode} < {@linkcode MoveUseMode.INDIRECT}) * - Non-virtual ({@linkcode MoveUseMode | useMode} < {@linkcode MoveUseMode.INDIRECT})
* @param ignoreStruggle - Whether to additionally ignore {@linkcode Moves.STRUGGLE}; default `false` * @param ignoreStruggle - Whether to additionally ignore {@linkcode MoveId.STRUGGLE}; default `false`
* @param ignoreFollowUp - Whether to ignore moves with a use type of {@linkcode MoveUseMode.FOLLOW_UP} * @param ignoreFollowUp - Whether to ignore moves with a use type of {@linkcode MoveUseMode.FOLLOW_UP}
* (e.g. ones called by Copycat/Mirror Move); default `true`. * (e.g. ones called by Copycat/Mirror Move); default `true`.
* @returns The last move this Pokemon has used satisfying the aforementioned conditions, * @returns The last move this Pokemon has used satisfying the aforementioned conditions,
@ -5094,6 +5089,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
*/ */
resetWaveData(): void { resetWaveData(): void {
this.waveData = new PokemonWaveData(); this.waveData = new PokemonWaveData();
this.tempSummonData.waveTurnCount = 1;
} }
resetTera(): void { resetTera(): void {

View File

@ -1674,11 +1674,12 @@ export class TurnHealModifier extends PokemonHeldItemModifier {
"PokemonHealPhase", "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount, toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount,
i18next.t("modifier:turnHealApply", { {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), message: i18next.t("modifier:turnHealApply", {
typeName: this.type.name, pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), typeName: this.type.name,
true, }),
},
); );
return true; return true;
} }
@ -1766,16 +1767,16 @@ export class HitHealModifier extends PokemonHeldItemModifier {
*/ */
override apply(pokemon: Pokemon): boolean { override apply(pokemon: Pokemon): boolean {
if (pokemon.turnData.totalDamageDealt && !pokemon.isFullHp()) { if (pokemon.turnData.totalDamageDealt && !pokemon.isFullHp()) {
// TODO: this shouldn't be undefined AFAIK
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew(
"PokemonHealPhase", "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.turnData.totalDamageDealt / 8) * this.stackCount, toDmgValue((pokemon.turnData.totalDamageDealt * this.stackCount) / 8),
i18next.t("modifier:hitHealApply", { {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), message: i18next.t("modifier:hitHealApply", {
typeName: this.type.name, pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), typeName: this.type.name,
true, }),
},
); );
} }
@ -1934,20 +1935,22 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier {
*/ */
override apply(pokemon: Pokemon): boolean { override apply(pokemon: Pokemon): boolean {
// Restore the Pokemon to half HP // Restore the Pokemon to half HP
// TODO: This should not use a phase to revive pokemon
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew(
"PokemonHealPhase", "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 2), toDmgValue(pokemon.getMaxHp() / 2),
i18next.t("modifier:pokemonInstantReviveApply", { {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), message: i18next.t("modifier:pokemonInstantReviveApply", {
typeName: this.type.name, pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), typeName: this.type.name,
false, }),
false, revive: true,
true, },
); );
// Remove the Pokemon's FAINT status // Remove the Pokemon's FAINT status
// TODO: Remove call to `resetStatus` once StatusEffect.FAINT is canned
pokemon.resetStatus(true, false, true, false); pokemon.resetStatus(true, false, true, false);
// Reapply Commander on the Pokemon's side of the field, if applicable // Reapply Commander on the Pokemon's side of the field, if applicable
@ -3549,24 +3552,24 @@ export class EnemyTurnHealModifier extends EnemyPersistentModifier {
* @returns `true` if the {@linkcode Pokemon} was healed * @returns `true` if the {@linkcode Pokemon} was healed
*/ */
override apply(enemyPokemon: Pokemon): boolean { override apply(enemyPokemon: Pokemon): boolean {
if (!enemyPokemon.isFullHp()) { if (enemyPokemon.isFullHp()) {
globalScene.phaseManager.unshiftNew( return false;
"PokemonHealPhase",
enemyPokemon.getBattlerIndex(),
Math.max(Math.floor(enemyPokemon.getMaxHp() / (100 / this.healPercent)) * this.stackCount, 1),
i18next.t("modifier:enemyTurnHealApply", {
pokemonNameWithAffix: getPokemonNameWithAffix(enemyPokemon),
}),
true,
false,
false,
false,
true,
);
return true;
} }
return false; // Prevent healing to full from healing tokens
globalScene.phaseManager.unshiftNew(
"PokemonHealPhase",
enemyPokemon.getBattlerIndex(),
(enemyPokemon.getMaxHp() * this.stackCount * this.healPercent) / 100,
{
message: i18next.t("modifier:enemyTurnHealApply", {
pokemonNameWithAffix: getPokemonNameWithAffix(enemyPokemon),
}),
preventFullHeal: true,
},
);
return true;
} }
getMaxStackCount(): number { getMaxStackCount(): number {

View File

@ -58,12 +58,6 @@ export class BattleEndPhase extends BattlePhase {
globalScene.phaseManager.unshiftNew("GameOverPhase", true); globalScene.phaseManager.unshiftNew("GameOverPhase", true);
} }
for (const pokemon of globalScene.getField()) {
if (pokemon) {
pokemon.tempSummonData.waveTurnCount = 1;
}
}
for (const pokemon of globalScene.getPokemonAllowedInBattle()) { for (const pokemon of globalScene.getPokemonAllowedInBattle()) {
applyAbAttrs("PostBattleAbAttr", { pokemon, victory: this.isVictory }); applyAbAttrs("PostBattleAbAttr", { pokemon, victory: this.isVictory });
} }

View File

@ -649,7 +649,6 @@ export class MovePhase extends BattlePhase {
* Displays the move's usage text to the player as applicable for the move being used. * Displays the move's usage text to the player as applicable for the move being used.
*/ */
public showMoveText(): void { public showMoveText(): void {
// No text for Moves.NONE, recharging/2-turn moves or interrupted moves
if ( if (
this.move.moveId === MoveId.NONE || this.move.moveId === MoveId.NONE ||
this.pokemon.getTag(BattlerTagType.RECHARGING) || this.pokemon.getTag(BattlerTagType.RECHARGING) ||
@ -658,7 +657,6 @@ export class MovePhase extends BattlePhase {
return; return;
} }
// Play message for magic coat reflection
// TODO: This should be done by the move... // TODO: This should be done by the move...
globalScene.phaseManager.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t(isReflected(this.useMode) ? "battle:magicCoatActivated" : "battle:useMove", { i18next.t(isReflected(this.useMode) ? "battle:magicCoatActivated" : "battle:useMove", {

View File

@ -1,39 +1,81 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import type { HealBlockTag } from "#data/battler-tags";
import { getStatusEffectHealText } from "#data/status-effect"; import { getStatusEffectHealText } from "#data/status-effect";
import type { BattlerIndex } from "#enums/battler-index"; import type { BattlerIndex } from "#enums/battler-index";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { HitResult } from "#enums/hit-result"; import { HitResult } from "#enums/hit-result";
import { CommonAnim } from "#enums/move-anims-common"; import { CommonAnim } from "#enums/move-anims-common";
import { StatusEffect } from "#enums/status-effect";
import { HealingBoosterModifier } from "#modifiers/modifier"; import { HealingBoosterModifier } from "#modifiers/modifier";
import { CommonAnimPhase } from "#phases/common-anim-phase"; import { CommonAnimPhase } from "#phases/common-anim-phase";
import { HealAchv } from "#system/achv"; import { HealAchv } from "#system/achv";
import { NumberHolder } from "#utils/common"; import { NumberHolder, toDmgValue } from "#utils/common";
import i18next from "i18next"; import i18next from "i18next";
export class PokemonHealPhase extends CommonAnimPhase { export class PokemonHealPhase extends CommonAnimPhase {
public readonly phaseName = "PokemonHealPhase"; public readonly phaseName = "PokemonHealPhase";
/** The base amount of HP to heal. */
private hpHealed: number; private hpHealed: number;
private message: string | null; /**
* The message to display upon healing the target, or `undefined` to show no message.
* Will be overridden by the full HP message if {@linkcode showFullHpMessage} is set to `true`
*/
private message: string | undefined;
/**
* Whether to show a failure message upon healing a Pokemon already at full HP.
* @defaultValue `true`
*/
private showFullHpMessage: boolean; private showFullHpMessage: boolean;
/**
* Whether to skip showing the healing animation.
* @defaultValue `false`
*/
private skipAnim: boolean; private skipAnim: boolean;
/**
* Whether to revive the affected Pokemon in addition to healing.
* Revives will not be affected by any Healing Charms.
* @todo Remove post modifier rework as revives will not be using phases to heal stuff
* @defaultValue `false`
*/
private revive: boolean; private revive: boolean;
/**
* Whether to heal the affected Pokemon's status condition.
* @todo This should not be the healing phase's job
* @defaultValue `false`
*/
private healStatus: boolean; private healStatus: boolean;
/**
* Whether to prevent fully healing affected Pokemon, leaving them 1 HP below full.
* @defaultValue `false`
*/
private preventFullHeal: boolean; private preventFullHeal: boolean;
/**
* Whether to fully restore PP upon healing.
* @todo This should not be the healing phase's job
* @defaultValue `false`
*/
private fullRestorePP: boolean; private fullRestorePP: boolean;
constructor( constructor(
battlerIndex: BattlerIndex, battlerIndex: BattlerIndex,
hpHealed: number, hpHealed: number,
message: string | null, {
showFullHpMessage: boolean, message,
skipAnim = false, showFullHpMessage = true,
revive = false, skipAnim = false,
healStatus = false, revive = false,
preventFullHeal = false, healStatus = false,
fullRestorePP = false, preventFullHeal = false,
fullRestorePP = false,
}: {
message?: string;
showFullHpMessage?: boolean;
skipAnim?: boolean;
revive?: boolean;
healStatus?: boolean;
preventFullHeal?: boolean;
fullRestorePP?: boolean;
} = {},
) { ) {
super(battlerIndex, undefined, CommonAnim.HEALTH_UP); super(battlerIndex, undefined, CommonAnim.HEALTH_UP);
@ -47,89 +89,110 @@ export class PokemonHealPhase extends CommonAnimPhase {
this.fullRestorePP = fullRestorePP; this.fullRestorePP = fullRestorePP;
} }
start() { override start() {
if (!this.skipAnim && (this.revive || this.getPokemon().hp) && !this.getPokemon().isFullHp()) { // Only play animation if not skipped and target is at full HP
if (!this.skipAnim && !this.getPokemon().isFullHp()) {
super.start(); super.start();
} else {
this.end();
} }
this.heal();
super.end();
} }
end() { private heal() {
const pokemon = this.getPokemon(); const pokemon = this.getPokemon();
if (!pokemon.isOnField() || (!this.revive && !pokemon.isActive())) { // Prevent healing off-field pokemon unless via revives
return super.end(); // TODO: Revival effects shouldn't use this phase
if (!this.revive && !pokemon.isActive(true)) {
super.end();
return;
} }
const hasMessage = !!this.message; // Check for heal block, ending the phase early if healing was prevented
const healOrDamage = !pokemon.isFullHp() || this.hpHealed < 0; const healBlock = pokemon.getTag(BattlerTagType.HEAL_BLOCK);
const healBlock = pokemon.getTag(BattlerTagType.HEAL_BLOCK) as HealBlockTag;
let lastStatusEffect = StatusEffect.NONE;
if (healBlock && this.hpHealed > 0) { if (healBlock && this.hpHealed > 0) {
globalScene.phaseManager.queueMessage(healBlock.onActivation(pokemon)); globalScene.phaseManager.queueMessage(healBlock.onActivation(pokemon));
this.message = null; super.end();
return super.end(); return;
} }
if (healOrDamage) {
const hpRestoreMultiplier = new NumberHolder(1); this.doHealPokemon();
if (!this.revive) {
globalScene.applyModifiers(HealingBoosterModifier, this.player, hpRestoreMultiplier); // Cure status as applicable
} // TODO: This should not be the job of the healing phase
const healAmount = new NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value)); if (this.healStatus && pokemon.status) {
if (healAmount.value < 0) { this.message = getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon));
pokemon.damageAndUpdate(healAmount.value * -1, { result: HitResult.INDIRECT });
healAmount.value = 0;
}
// Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock)
if (this.preventFullHeal && pokemon.hp + healAmount.value >= pokemon.getMaxHp()) {
healAmount.value = pokemon.getMaxHp() - pokemon.hp - 1;
}
healAmount.value = pokemon.heal(healAmount.value);
if (healAmount.value) {
globalScene.damageNumberHandler.add(pokemon, healAmount.value, HitResult.HEAL);
}
if (pokemon.isPlayer()) {
globalScene.validateAchvs(HealAchv, healAmount);
if (healAmount.value > globalScene.gameData.gameStats.highestHeal) {
globalScene.gameData.gameStats.highestHeal = healAmount.value;
}
}
if (this.healStatus && !this.revive && pokemon.status) {
lastStatusEffect = pokemon.status.effect;
pokemon.resetStatus();
}
if (this.fullRestorePP) {
for (const move of this.getPokemon().getMoveset()) {
if (move) {
move.ppUsed = 0;
}
}
}
pokemon.updateInfo().then(() => super.end());
} else if (this.healStatus && !this.revive && pokemon.status) {
lastStatusEffect = pokemon.status.effect;
pokemon.resetStatus(); pokemon.resetStatus();
pokemon.updateInfo().then(() => super.end()); }
} else if (this.showFullHpMessage) {
this.message = i18next.t("battle:hpIsFull", { // Restore PP.
pokemonName: getPokemonNameWithAffix(pokemon), // TODO: This should not be the job of the healing phase
if (this.fullRestorePP) {
pokemon.getMoveset().forEach(m => {
m.ppUsed = 0;
}); });
} }
// Show message, update info boxes and then wrap up.
if (this.message) { if (this.message) {
globalScene.phaseManager.queueMessage(this.message); globalScene.phaseManager.queueMessage(this.message);
} }
pokemon.updateInfo().then(() => super.end());
}
if (this.healStatus && lastStatusEffect && !hasMessage) { /**
globalScene.phaseManager.queueMessage( * Heal the Pokemon affected by this Phase.
getStatusEffectHealText(lastStatusEffect, getPokemonNameWithAffix(pokemon)), */
); private doHealPokemon(): void {
const pokemon = this.getPokemon()!;
// If we would heal the user past full HP, don't.
if (this.hpHealed > 0 && pokemon.isFullHp()) {
if (this.showFullHpMessage) {
this.message = i18next.t("battle:hpIsFull", {
pokemonName: getPokemonNameWithAffix(pokemon),
});
}
return;
} }
if (!healOrDamage && !lastStatusEffect) { const healAmount = this.getHealAmount();
super.end();
if (healAmount < 0) {
// If Liquid Ooze is active, damage the user for the healing amount, then return.
// TODO: Consider refactoring liquid ooze to not use a heal phase to do damage
pokemon.damageAndUpdate(-healAmount, { result: HitResult.INDIRECT });
return;
}
// Heal the pokemon, then show damage numbers and validate achievements.
pokemon.heal(healAmount);
globalScene.damageNumberHandler.add(pokemon, healAmount, HitResult.HEAL);
if (pokemon.isPlayer()) {
globalScene.validateAchvs(HealAchv, healAmount);
globalScene.gameData.gameStats.highestHeal = Math.max(globalScene.gameData.gameStats.highestHeal, healAmount);
} }
} }
/**
* Calculate the amount of HP to be healed during this Phase.
* @returns The updated healing amount post-modifications, capped at the Pokemon's maximum HP.
* @remarks
* The effect of Healing Charms are rounded down for parity with the closest mainline counterpart
* (i.e. Big Root).
*/
private getHealAmount(): number {
if (this.revive) {
return toDmgValue(this.hpHealed);
}
// Apply the effect of healing charms for non-revival items before rounding down and capping at max HP
// (or 1 below max for healing tokens).
// Liquid Ooze damage (being negative) remains uncapped as normal.
const healMulti = new NumberHolder(1);
globalScene.applyModifiers(HealingBoosterModifier, this.player, healMulti);
return toDmgValue(Math.min(this.hpHealed * healMulti.value, this.getPokemon().getMaxHp() - +this.preventFullHeal));
}
} }

View File

@ -154,16 +154,11 @@ export class QuietFormChangePhase extends BattlePhase {
this.pokemon.findAndRemoveTags(t => t.tagType === BattlerTagType.AUTOTOMIZED); this.pokemon.findAndRemoveTags(t => t.tagType === BattlerTagType.AUTOTOMIZED);
if (globalScene?.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon.isEnemy()) { if (globalScene?.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon.isEnemy()) {
globalScene.playBgm(); globalScene.playBgm();
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew("PokemonHealPhase", this.pokemon.getBattlerIndex(), this.pokemon.getMaxHp(), {
"PokemonHealPhase", showFullHpMessage: false,
this.pokemon.getBattlerIndex(), healStatus: true,
this.pokemon.getMaxHp(), fullRestorePP: true,
null, });
false,
false,
false,
true,
);
this.pokemon.findAndRemoveTags(() => true); this.pokemon.findAndRemoveTags(() => true);
this.pokemon.bossSegments = 5; this.pokemon.bossSegments = 5;
this.pokemon.bossSegmentIndex = 4; this.pokemon.bossSegmentIndex = 4;

View File

@ -35,15 +35,11 @@ export class TurnEndPhase extends FieldPhase {
globalScene.applyModifiers(TurnHealModifier, pokemon.isPlayer(), pokemon); globalScene.applyModifiers(TurnHealModifier, pokemon.isPlayer(), pokemon);
if (globalScene.arena.terrain?.terrainType === TerrainType.GRASSY && pokemon.isGrounded()) { if (globalScene.arena.terrain?.terrainType === TerrainType.GRASSY && pokemon.isGrounded()) {
globalScene.phaseManager.unshiftNew( globalScene.phaseManager.unshiftNew("PokemonHealPhase", pokemon.getBattlerIndex(), pokemon.getMaxHp() / 16, {
"PokemonHealPhase", message: i18next.t("battle:turnEndHpRestore", {
pokemon.getBattlerIndex(),
Math.max(pokemon.getMaxHp() >> 4, 1),
i18next.t("battle:turnEndHpRestore", {
pokemonName: getPokemonNameWithAffix(pokemon), pokemonName: getPokemonNameWithAffix(pokemon),
}), }),
true, });
);
} }
if (!pokemon.isPlayer()) { if (!pokemon.isPlayer()) {

View File

@ -38,7 +38,7 @@ describe("Abilities - Analytic", () => {
it("should increase damage if the user moves last", async () => { it("should increase damage if the user moves last", async () => {
await game.classicMode.startBattle([SpeciesId.ARCEUS]); await game.classicMode.startBattle([SpeciesId.ARCEUS]);
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.TACKLE); game.move.select(MoveId.TACKLE);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);

View File

@ -36,7 +36,7 @@ describe("Ability - Anger Point", () => {
it("should set the user's attack stage to +6 when hit by a critical hit", async () => { it("should set the user's attack stage to +6 when hit by a critical hit", async () => {
game.override.enemyAbility(AbilityId.ANGER_POINT).moveset(MoveId.FALSE_SWIPE); game.override.enemyAbility(AbilityId.ANGER_POINT).moveset(MoveId.FALSE_SWIPE);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
// minimize the enemy's attack stage to ensure it is always set to +6 // minimize the enemy's attack stage to ensure it is always set to +6
enemy.setStatStage(Stat.ATK, -6); enemy.setStatStage(Stat.ATK, -6);
@ -53,7 +53,7 @@ describe("Ability - Anger Point", () => {
.enemyAbility(AbilityId.ANGER_POINT) .enemyAbility(AbilityId.ANGER_POINT)
.ability(AbilityId.SKILL_LINK); .ability(AbilityId.SKILL_LINK);
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "getCriticalHitResult").mockReturnValueOnce(true); vi.spyOn(enemy, "getCriticalHitResult").mockReturnValueOnce(true);
const angerPointSpy = vi.spyOn(PostReceiveCritStatStageChangeAbAttr.prototype, "apply"); const angerPointSpy = vi.spyOn(PostReceiveCritStatStageChangeAbAttr.prototype, "apply");
game.move.select(MoveId.BULLET_SEED); game.move.select(MoveId.BULLET_SEED);
@ -68,7 +68,7 @@ describe("Ability - Anger Point", () => {
.enemyHasPassiveAbility(true) .enemyHasPassiveAbility(true)
.moveset(MoveId.FALSE_SWIPE); .moveset(MoveId.FALSE_SWIPE);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "getCriticalHitResult").mockReturnValueOnce(true); vi.spyOn(enemy, "getCriticalHitResult").mockReturnValueOnce(true);
enemy.setStatStage(Stat.ATK, 6); enemy.setStatStage(Stat.ATK, 6);
game.move.select(MoveId.FALSE_SWIPE); game.move.select(MoveId.FALSE_SWIPE);

View File

@ -36,7 +36,7 @@ describe("Abilities - Beast Boost", () => {
it("should prefer highest stat to boost its corresponding stat stage by 1 when winning a battle", async () => { it("should prefer highest stat to boost its corresponding stat stage by 1 when winning a battle", async () => {
await game.classicMode.startBattle([SpeciesId.SLOWBRO]); await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
// Set the pokemon's highest stat to DEF, so it should be picked by Beast Boost // Set the pokemon's highest stat to DEF, so it should be picked by Beast Boost
vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([10000, 100, 1000, 200, 100, 100]); vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([10000, 100, 1000, 200, 100, 100]);
console.log(playerPokemon.stats); console.log(playerPokemon.stats);
@ -54,7 +54,7 @@ describe("Abilities - Beast Boost", () => {
await game.classicMode.startBattle([SpeciesId.SLOWBRO]); await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
// If the opponent uses Guard Split, the pokemon's second highest stat (SPATK) should be chosen // If the opponent uses Guard Split, the pokemon's second highest stat (SPATK) should be chosen
vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([10000, 100, 201, 200, 100, 100]); vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([10000, 100, 201, 200, 100, 100]);
@ -72,7 +72,7 @@ describe("Abilities - Beast Boost", () => {
// Order preference follows the order of EFFECTIVE_STAT // Order preference follows the order of EFFECTIVE_STAT
await game.classicMode.startBattle([SpeciesId.SLOWBRO]); await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
// Set up tie between SPATK, SPDEF, and SPD, where SPATK should win // Set up tie between SPATK, SPDEF, and SPD, where SPATK should win
vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([10000, 1, 1, 100, 100, 100]); vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([10000, 1, 1, 100, 100, 100]);

View File

@ -36,7 +36,7 @@ describe("Abilities - Competitive", () => {
it("lower atk and def by 1 via tickle, then increase spatk by 4 via competitive", async () => { it("lower atk and def by 1 via tickle, then increase spatk by 4 via competitive", async () => {
await game.classicMode.startBattle([SpeciesId.FLYGON]); await game.classicMode.startBattle([SpeciesId.FLYGON]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to(TurnInitPhase); await game.phaseInterceptor.to(TurnInitPhase);
@ -49,7 +49,7 @@ describe("Abilities - Competitive", () => {
game.override.enemyMoveset(MoveId.SPLASH); game.override.enemyMoveset(MoveId.SPLASH);
await game.classicMode.startBattle([SpeciesId.FLYGON]); await game.classicMode.startBattle([SpeciesId.FLYGON]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.CLOSE_COMBAT); game.move.select(MoveId.CLOSE_COMBAT);
await game.phaseInterceptor.to(TurnInitPhase); await game.phaseInterceptor.to(TurnInitPhase);
@ -62,7 +62,7 @@ describe("Abilities - Competitive", () => {
game.override.startingHeldItems([{ name: "WHITE_HERB" }]); game.override.startingHeldItems([{ name: "WHITE_HERB" }]);
await game.classicMode.startBattle([SpeciesId.FLYGON]); await game.classicMode.startBattle([SpeciesId.FLYGON]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to(TurnInitPhase); await game.phaseInterceptor.to(TurnInitPhase);

View File

@ -33,7 +33,7 @@ describe("Abilities - Contrary", () => {
it("should invert stat changes when applied", async () => { it("should invert stat changes when applied", async () => {
await game.classicMode.startBattle([SpeciesId.SLOWBRO]); await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
}); });
@ -43,7 +43,7 @@ describe("Abilities - Contrary", () => {
game.override.enemyPassiveAbility(AbilityId.CLEAR_BODY).moveset([MoveId.TAIL_WHIP]); game.override.enemyPassiveAbility(AbilityId.CLEAR_BODY).moveset([MoveId.TAIL_WHIP]);
await game.classicMode.startBattle([SpeciesId.SLOWBRO]); await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
@ -57,7 +57,7 @@ describe("Abilities - Contrary", () => {
game.override.enemyPassiveAbility(AbilityId.CLEAR_BODY).enemyMoveset(MoveId.HOWL).moveset([MoveId.SPLASH]); game.override.enemyPassiveAbility(AbilityId.CLEAR_BODY).enemyMoveset(MoveId.HOWL).moveset([MoveId.SPLASH]);
await game.classicMode.startBattle([SpeciesId.SLOWBRO]); await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);

View File

@ -43,7 +43,7 @@ describe("Abilities - Cud Chew", () => {
it("stores inside summonData at end of turn", async () => { it("stores inside summonData at end of turn", async () => {
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
farigiraf.hp = 1; // needed to allow sitrus procs farigiraf.hp = 1; // needed to allow sitrus procs
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -71,7 +71,7 @@ describe("Abilities - Cud Chew", () => {
game.override.enemyMoveset([MoveId.SPLASH, MoveId.HEAL_PULSE]); game.override.enemyMoveset([MoveId.SPLASH, MoveId.HEAL_PULSE]);
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
// Dip below half to eat berry // Dip below half to eat berry
farigiraf.hp = farigiraf.getMaxHp() / 2 - 1; farigiraf.hp = farigiraf.getMaxHp() / 2 - 1;
@ -120,7 +120,7 @@ describe("Abilities - Cud Chew", () => {
.enemyMoveset(MoveId.TEATIME); .enemyMoveset(MoveId.TEATIME);
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
farigiraf.hp = 1; // needed to allow berry procs farigiraf.hp = 1; // needed to allow berry procs
game.move.select(MoveId.STUFF_CHEEKS); game.move.select(MoveId.STUFF_CHEEKS);
@ -148,7 +148,7 @@ describe("Abilities - Cud Chew", () => {
it("should reset both arrays on switch", async () => { it("should reset both arrays on switch", async () => {
await game.classicMode.startBattle([SpeciesId.FARIGIRAF, SpeciesId.GIRAFARIG]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF, SpeciesId.GIRAFARIG]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
farigiraf.hp = 1; farigiraf.hp = 1;
// eat berry turn 1, switch out turn 2 // eat berry turn 1, switch out turn 2
@ -177,7 +177,7 @@ describe("Abilities - Cud Chew", () => {
game.override.enemyAbility(AbilityId.NEUTRALIZING_GAS); game.override.enemyAbility(AbilityId.NEUTRALIZING_GAS);
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
farigiraf.hp = 1; farigiraf.hp = 1;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -199,7 +199,7 @@ describe("Abilities - Cud Chew", () => {
const apply = vi.spyOn(CudChewConsumeBerryAbAttr.prototype, "apply"); const apply = vi.spyOn(CudChewConsumeBerryAbAttr.prototype, "apply");
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
farigiraf.hp = 1; farigiraf.hp = 1;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -225,7 +225,7 @@ describe("Abilities - Cud Chew", () => {
game.override.enemyAbility(AbilityId.UNNERVE); game.override.enemyAbility(AbilityId.UNNERVE);
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
farigiraf.hp = 1; farigiraf.hp = 1;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -243,7 +243,7 @@ describe("Abilities - Cud Chew", () => {
game.override.enemyMoveset(MoveId.INCINERATE); game.override.enemyMoveset(MoveId.INCINERATE);
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
farigiraf.hp = farigiraf.getMaxHp() / 4; farigiraf.hp = farigiraf.getMaxHp() / 4;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -262,7 +262,7 @@ describe("Abilities - Cud Chew", () => {
.startingHeldItems([]); .startingHeldItems([]);
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
game.move.select(MoveId.BUG_BITE); game.move.select(MoveId.BUG_BITE);
await game.toNextTurn(); await game.toNextTurn();
@ -278,7 +278,7 @@ describe("Abilities - Cud Chew", () => {
game.override.passiveAbility(AbilityId.RIPEN); game.override.passiveAbility(AbilityId.RIPEN);
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
farigiraf.hp = 1; farigiraf.hp = 1;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -294,7 +294,7 @@ describe("Abilities - Cud Chew", () => {
game.override.enemyLevel(1); game.override.enemyLevel(1);
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
const farigiraf = game.scene.getPlayerPokemon()!; const farigiraf = game.field.getPlayerPokemon();
farigiraf.hp = 1; farigiraf.hp = 1;
game.move.select(MoveId.HYPER_VOICE); game.move.select(MoveId.HYPER_VOICE);
@ -307,7 +307,7 @@ describe("Abilities - Cud Chew", () => {
// reload and the berry should still be there // reload and the berry should still be there
await game.reload.reloadSession(); await game.reload.reloadSession();
const farigirafReloaded = game.scene.getPlayerPokemon()!; const farigirafReloaded = game.field.getPlayerPokemon();
expect(farigirafReloaded.summonData.berriesEatenLast).toEqual([BerryType.SITRUS]); expect(farigirafReloaded.summonData.berriesEatenLast).toEqual([BerryType.SITRUS]);
const wave1Hp = farigirafReloaded.hp; const wave1Hp = farigirafReloaded.hp;

View File

@ -125,7 +125,7 @@ describe("Abilities - Dancer", () => {
game.override.battleStyle("double").moveset(MoveId.SPLASH).enemyMoveset([MoveId.SWORDS_DANCE, MoveId.FAKE_OUT]); game.override.battleStyle("double").moveset(MoveId.SPLASH).enemyMoveset([MoveId.SWORDS_DANCE, MoveId.FAKE_OUT]);
await game.classicMode.startBattle([SpeciesId.ORICORIO]); await game.classicMode.startBattle([SpeciesId.ORICORIO]);
const oricorio = game.scene.getPlayerPokemon()!; const oricorio = game.field.getPlayerPokemon();
expect(oricorio).toBeDefined(); expect(oricorio).toBeDefined();
// get faked out and copy swords dance // get faked out and copy swords dance

View File

@ -36,7 +36,7 @@ describe("Abilities - Defiant", () => {
it("lower atk and def by 1 via tickle, then increase atk by 4 via defiant", async () => { it("lower atk and def by 1 via tickle, then increase atk by 4 via defiant", async () => {
await game.classicMode.startBattle([SpeciesId.FLYGON]); await game.classicMode.startBattle([SpeciesId.FLYGON]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to(TurnInitPhase); await game.phaseInterceptor.to(TurnInitPhase);
@ -48,7 +48,7 @@ describe("Abilities - Defiant", () => {
game.override.enemyMoveset(MoveId.SPLASH); game.override.enemyMoveset(MoveId.SPLASH);
await game.classicMode.startBattle([SpeciesId.FLYGON]); await game.classicMode.startBattle([SpeciesId.FLYGON]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.CLOSE_COMBAT); game.move.select(MoveId.CLOSE_COMBAT);
await game.phaseInterceptor.to(TurnInitPhase); await game.phaseInterceptor.to(TurnInitPhase);
@ -61,7 +61,7 @@ describe("Abilities - Defiant", () => {
game.override.startingHeldItems([{ name: "WHITE_HERB" }]); game.override.startingHeldItems([{ name: "WHITE_HERB" }]);
await game.classicMode.startBattle([SpeciesId.FLYGON]); await game.classicMode.startBattle([SpeciesId.FLYGON]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to(TurnInitPhase); await game.phaseInterceptor.to(TurnInitPhase);

View File

@ -145,7 +145,7 @@ describe("Abilities - Desolate Land", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.HARSH_SUN); expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.HARSH_SUN);
vi.spyOn(game.scene.getPlayerPokemon()!, "randBattleSeedInt").mockReturnValue(0); vi.spyOn(game.field.getPlayerPokemon(), "randBattleSeedInt").mockReturnValue(0);
vi.spyOn(globalScene, "randBattleSeedInt").mockReturnValue(0); vi.spyOn(globalScene, "randBattleSeedInt").mockReturnValue(0);
const commandPhase = game.scene.phaseManager.getCurrentPhase() as CommandPhase; const commandPhase = game.scene.phaseManager.getCurrentPhase() as CommandPhase;

View File

@ -37,7 +37,7 @@ describe("Abilities - Disguise", () => {
it("takes no damage from attacking move and transforms to Busted form, takes 1/8 max HP damage from the disguise breaking", async () => { it("takes no damage from attacking move and transforms to Busted form, takes 1/8 max HP damage from the disguise breaking", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const mimikyu = game.scene.getEnemyPokemon()!; const mimikyu = game.field.getEnemyPokemon();
const maxHp = mimikyu.getMaxHp(); const maxHp = mimikyu.getMaxHp();
const disguiseDamage = toDmgValue(maxHp / 8); const disguiseDamage = toDmgValue(maxHp / 8);
@ -54,7 +54,7 @@ describe("Abilities - Disguise", () => {
it("doesn't break disguise when attacked with ineffective move", async () => { it("doesn't break disguise when attacked with ineffective move", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const mimikyu = game.scene.getEnemyPokemon()!; const mimikyu = game.field.getEnemyPokemon();
expect(mimikyu.formIndex).toBe(disguisedForm); expect(mimikyu.formIndex).toBe(disguisedForm);
@ -69,7 +69,7 @@ describe("Abilities - Disguise", () => {
game.override.moveset([MoveId.SURGING_STRIKES]).enemyLevel(5); game.override.moveset([MoveId.SURGING_STRIKES]).enemyLevel(5);
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const mimikyu = game.scene.getEnemyPokemon()!; const mimikyu = game.field.getEnemyPokemon();
const maxHp = mimikyu.getMaxHp(); const maxHp = mimikyu.getMaxHp();
const disguiseDamage = toDmgValue(maxHp / 8); const disguiseDamage = toDmgValue(maxHp / 8);
@ -91,7 +91,7 @@ describe("Abilities - Disguise", () => {
it("takes effects from status moves and damage from status effects", async () => { it("takes effects from status moves and damage from status effects", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const mimikyu = game.scene.getEnemyPokemon()!; const mimikyu = game.field.getEnemyPokemon();
expect(mimikyu.hp).toBe(mimikyu.getMaxHp()); expect(mimikyu.hp).toBe(mimikyu.getMaxHp());
game.move.select(MoveId.TOXIC_THREAD); game.move.select(MoveId.TOXIC_THREAD);
@ -109,7 +109,7 @@ describe("Abilities - Disguise", () => {
await game.classicMode.startBattle([SpeciesId.MIMIKYU, SpeciesId.FURRET]); await game.classicMode.startBattle([SpeciesId.MIMIKYU, SpeciesId.FURRET]);
const mimikyu = game.scene.getPlayerPokemon()!; const mimikyu = game.field.getPlayerPokemon();
const maxHp = mimikyu.getMaxHp(); const maxHp = mimikyu.getMaxHp();
const disguiseDamage = toDmgValue(maxHp / 8); const disguiseDamage = toDmgValue(maxHp / 8);
@ -154,7 +154,7 @@ describe("Abilities - Disguise", () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const mimikyu = game.scene.getPlayerPokemon()!; const mimikyu = game.field.getPlayerPokemon();
expect(mimikyu.formIndex).toBe(bustedForm); expect(mimikyu.formIndex).toBe(bustedForm);
@ -175,7 +175,7 @@ describe("Abilities - Disguise", () => {
await game.classicMode.startBattle([SpeciesId.MIMIKYU, SpeciesId.FURRET]); await game.classicMode.startBattle([SpeciesId.MIMIKYU, SpeciesId.FURRET]);
const mimikyu1 = game.scene.getPlayerPokemon()!; const mimikyu1 = game.field.getPlayerPokemon();
expect(mimikyu1.formIndex).toBe(bustedForm); expect(mimikyu1.formIndex).toBe(bustedForm);
@ -190,7 +190,7 @@ describe("Abilities - Disguise", () => {
game.override.enemyMoveset([MoveId.ENDURE]); game.override.enemyMoveset([MoveId.ENDURE]);
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const mimikyu = game.scene.getEnemyPokemon()!; const mimikyu = game.field.getEnemyPokemon();
mimikyu.hp = 1; mimikyu.hp = 1;
game.move.select(MoveId.SHADOW_SNEAK); game.move.select(MoveId.SHADOW_SNEAK);
@ -205,7 +205,7 @@ describe("Abilities - Disguise", () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const mimikyu = game.scene.getEnemyPokemon()!; const mimikyu = game.field.getEnemyPokemon();
const maxHp = mimikyu.getMaxHp(); const maxHp = mimikyu.getMaxHp();
const disguiseDamage = toDmgValue(maxHp / 8); const disguiseDamage = toDmgValue(maxHp / 8);
@ -225,6 +225,6 @@ describe("Abilities - Disguise", () => {
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getEnemyPokemon()!.formIndex).toBe(disguisedForm); expect(game.field.getEnemyPokemon().formIndex).toBe(disguisedForm);
}); });
}); });

View File

@ -35,7 +35,7 @@ describe("Abilities - Dry Skin", () => {
it("during sunlight, lose 1/8 of maximum health at the end of each turn", async () => { it("during sunlight, lose 1/8 of maximum health at the end of each turn", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
// first turn // first turn
game.move.select(MoveId.SUNNY_DAY); game.move.select(MoveId.SUNNY_DAY);
@ -52,7 +52,7 @@ describe("Abilities - Dry Skin", () => {
it("during rain, gain 1/8 of maximum health at the end of each turn", async () => { it("during rain, gain 1/8 of maximum health at the end of each turn", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
enemy.hp = 1; enemy.hp = 1;
@ -72,7 +72,7 @@ describe("Abilities - Dry Skin", () => {
game.override.moveset([MoveId.FLAMETHROWER]); game.override.moveset([MoveId.FLAMETHROWER]);
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
const initialHP = 1000; const initialHP = 1000;
enemy.hp = initialHP; enemy.hp = initialHP;
@ -95,7 +95,7 @@ describe("Abilities - Dry Skin", () => {
it("opposing water attacks heal 1/4 of maximum health and deal no damage", async () => { it("opposing water attacks heal 1/4 of maximum health and deal no damage", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
enemy.hp = 1; enemy.hp = 1;
@ -109,7 +109,7 @@ describe("Abilities - Dry Skin", () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
enemy.hp = 1; enemy.hp = 1;
@ -123,7 +123,7 @@ describe("Abilities - Dry Skin", () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
enemy.hp = 1; enemy.hp = 1;
@ -145,7 +145,7 @@ describe("Abilities - Dry Skin", () => {
it("opposing water moves still heal regardless of accuracy check", async () => { it("opposing water moves still heal regardless of accuracy check", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.WATER_GUN); game.move.select(MoveId.WATER_GUN);
enemy.hp = enemy.hp - 1; enemy.hp = enemy.hp - 1;

View File

@ -37,7 +37,7 @@ describe("Abilities - Early Bird", () => {
it("reduces Rest's sleep time to 1 turn", async () => { it("reduces Rest's sleep time to 1 turn", async () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
game.move.select(MoveId.BELLY_DRUM); game.move.select(MoveId.BELLY_DRUM);
await game.toNextTurn(); await game.toNextTurn();
@ -62,7 +62,7 @@ describe("Abilities - Early Bird", () => {
it("reduces 3-turn sleep to 1 turn", async () => { it("reduces 3-turn sleep to 1 turn", async () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
player.status = new Status(StatusEffect.SLEEP, 0, 4); player.status = new Status(StatusEffect.SLEEP, 0, 4);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -81,7 +81,7 @@ describe("Abilities - Early Bird", () => {
it("reduces 1-turn sleep to 0 turns", async () => { it("reduces 1-turn sleep to 0 turns", async () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
player.status = new Status(StatusEffect.SLEEP, 0, 2); player.status = new Status(StatusEffect.SLEEP, 0, 2);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);

View File

@ -39,7 +39,7 @@ describe("Abilities - Flash Fire", () => {
game.override.enemyMoveset([MoveId.EMBER]).moveset(MoveId.SPLASH); game.override.enemyMoveset([MoveId.EMBER]).moveset(MoveId.SPLASH);
await game.classicMode.startBattle([SpeciesId.BLISSEY]); await game.classicMode.startBattle([SpeciesId.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!; const blissey = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -50,7 +50,7 @@ describe("Abilities - Flash Fire", () => {
game.override.enemyMoveset([MoveId.EMBER]).moveset([MoveId.PROTECT]); game.override.enemyMoveset([MoveId.EMBER]).moveset([MoveId.PROTECT]);
await game.classicMode.startBattle([SpeciesId.BLISSEY]); await game.classicMode.startBattle([SpeciesId.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!; const blissey = game.field.getPlayerPokemon();
game.move.select(MoveId.PROTECT); game.move.select(MoveId.PROTECT);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -61,7 +61,7 @@ describe("Abilities - Flash Fire", () => {
game.override.enemyMoveset([MoveId.WILL_O_WISP]).moveset(MoveId.SPLASH); game.override.enemyMoveset([MoveId.WILL_O_WISP]).moveset(MoveId.SPLASH);
await game.classicMode.startBattle([SpeciesId.BLISSEY]); await game.classicMode.startBattle([SpeciesId.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!; const blissey = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.move.forceHit(); await game.move.forceHit();
@ -76,7 +76,7 @@ describe("Abilities - Flash Fire", () => {
game.override.enemyMoveset([MoveId.EMBER]).moveset(MoveId.SPLASH).statusEffect(StatusEffect.FREEZE); game.override.enemyMoveset([MoveId.EMBER]).moveset(MoveId.SPLASH).statusEffect(StatusEffect.FREEZE);
await game.classicMode.startBattle([SpeciesId.BLISSEY]); await game.classicMode.startBattle([SpeciesId.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!; const blissey = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -95,8 +95,8 @@ describe("Abilities - Flash Fire", () => {
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const chansey = game.scene.getPlayerPokemon()!; const chansey = game.field.getPlayerPokemon();
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(SpeciesId.CHANSEY); expect(game.field.getPlayerPokemon().species.speciesId).toBe(SpeciesId.CHANSEY);
expect(chansey!.getTag(BattlerTagType.FIRE_BOOST)).toBeUndefined(); expect(chansey!.getTag(BattlerTagType.FIRE_BOOST)).toBeUndefined();
}); });
@ -107,7 +107,7 @@ describe("Abilities - Flash Fire", () => {
.enemyAbility(AbilityId.FLASH_FIRE) .enemyAbility(AbilityId.FLASH_FIRE)
.ability(AbilityId.NONE); .ability(AbilityId.NONE);
await game.classicMode.startBattle([SpeciesId.BLISSEY]); await game.classicMode.startBattle([SpeciesId.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!; const blissey = game.field.getPlayerPokemon();
const initialHP = 1000; const initialHP = 1000;
blissey.hp = initialHP; blissey.hp = initialHP;
@ -137,7 +137,7 @@ describe("Abilities - Flash Fire", () => {
.enemySpecies(SpeciesId.BLISSEY); .enemySpecies(SpeciesId.BLISSEY);
await game.classicMode.startBattle([SpeciesId.RATTATA]); await game.classicMode.startBattle([SpeciesId.RATTATA]);
const blissey = game.scene.getEnemyPokemon()!; const blissey = game.field.getEnemyPokemon();
const initialHP = 1000; const initialHP = 1000;
blissey.hp = initialHP; blissey.hp = initialHP;

View File

@ -27,7 +27,7 @@ describe("Abilities - Flower Gift", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
expect(game.scene.getPlayerPokemon()?.formIndex).toBe(OVERCAST_FORM); expect(game.field.getPlayerPokemon().formIndex).toBe(OVERCAST_FORM);
}; };
/** /**
@ -169,7 +169,7 @@ describe("Abilities - Flower Gift", () => {
game.override.weather(WeatherType.HARSH_SUN); game.override.weather(WeatherType.HARSH_SUN);
await game.classicMode.startBattle([SpeciesId.CHERRIM]); await game.classicMode.startBattle([SpeciesId.CHERRIM]);
const cherrim = game.scene.getPlayerPokemon()!; const cherrim = game.field.getPlayerPokemon();
expect(cherrim.formIndex).toBe(SUNSHINE_FORM); expect(cherrim.formIndex).toBe(SUNSHINE_FORM);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -188,7 +188,7 @@ describe("Abilities - Flower Gift", () => {
await game.classicMode.startBattle([SpeciesId.CHERRIM, SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.CHERRIM, SpeciesId.MAGIKARP]);
const cherrim = game.scene.getPlayerPokemon()!; const cherrim = game.field.getPlayerPokemon();
expect(cherrim.formIndex).toBe(SUNSHINE_FORM); expect(cherrim.formIndex).toBe(SUNSHINE_FORM);
@ -215,7 +215,7 @@ describe("Abilities - Flower Gift", () => {
game.override.weather(WeatherType.SUNNY); game.override.weather(WeatherType.SUNNY);
await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.MAGIKARP]);
const cherrim = game.scene.getPlayerPokemon()!; const cherrim = game.field.getPlayerPokemon();
expect(cherrim.formIndex).toBe(SUNSHINE_FORM); expect(cherrim.formIndex).toBe(SUNSHINE_FORM);

View File

@ -46,7 +46,7 @@ describe("Abilities - Flower Veil", () => {
.moveset([MoveId.REST, MoveId.SPLASH]) .moveset([MoveId.REST, MoveId.SPLASH])
.startingHeldItems([{ name: "FLAME_ORB" }]); .startingHeldItems([{ name: "FLAME_ORB" }]);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const user = game.scene.getPlayerPokemon()!; const user = game.field.getPlayerPokemon();
game.move.select(MoveId.REST); game.move.select(MoveId.REST);
await game.move.selectEnemyMove(MoveId.TACKLE); await game.move.selectEnemyMove(MoveId.TACKLE);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
@ -74,7 +74,7 @@ describe("Abilities - Flower Veil", () => {
await game.move.selectEnemyMove(MoveId.YAWN, BattlerIndex.PLAYER_2); await game.move.selectEnemyMove(MoveId.YAWN, BattlerIndex.PLAYER_2);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
const user = game.scene.getPlayerPokemon()!; const user = game.field.getPlayerPokemon();
expect(user.getTag(BattlerTagType.DROWSY)).toBeFalsy(); expect(user.getTag(BattlerTagType.DROWSY)).toBeFalsy();
expect(ally.getTag(BattlerTagType.DROWSY)).toBeFalsy(); expect(ally.getTag(BattlerTagType.DROWSY)).toBeFalsy();
}); });
@ -87,7 +87,7 @@ describe("Abilities - Flower Veil", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.move.selectEnemyMove(MoveId.THUNDER_WAVE); await game.move.selectEnemyMove(MoveId.THUNDER_WAVE);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!.status).toBeUndefined(); expect(game.field.getPlayerPokemon().status).toBeUndefined();
}); });
it("should not prevent status conditions for a non-grass user and its non-grass allies", async () => { it("should not prevent status conditions for a non-grass user and its non-grass allies", async () => {
@ -155,7 +155,7 @@ describe("Abilities - Flower Veil", () => {
it("should prevent the drops while retaining the boosts from spicy extract", async () => { it("should prevent the drops while retaining the boosts from spicy extract", async () => {
game.override.enemyMoveset([MoveId.SPICY_EXTRACT]).moveset([MoveId.SPLASH]); game.override.enemyMoveset([MoveId.SPICY_EXTRACT]).moveset([MoveId.SPLASH]);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const user = game.scene.getPlayerPokemon()!; const user = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(user.getStatStage(Stat.ATK)).toBe(2); expect(user.getStatStage(Stat.ATK)).toBe(2);

View File

@ -32,7 +32,7 @@ describe("Abilities - Forecast", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
expect(game.scene.getPlayerPokemon()?.formIndex).toBe(NORMAL_FORM); expect(game.field.getPlayerPokemon().formIndex).toBe(NORMAL_FORM);
}; };
beforeAll(() => { beforeAll(() => {
@ -186,14 +186,14 @@ describe("Abilities - Forecast", () => {
game.move.select(MoveId.RAIN_DANCE); game.move.select(MoveId.RAIN_DANCE);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()?.formIndex).toBe(RAINY_FORM); expect(game.field.getPlayerPokemon().formIndex).toBe(RAINY_FORM);
expect(game.scene.getEnemyPokemon()?.formIndex).not.toBe(RAINY_FORM); expect(game.field.getEnemyPokemon().formIndex).not.toBe(RAINY_FORM);
}); });
it("reverts to Normal Form when Forecast is suppressed, changes form to match the weather when it regains it", async () => { it("reverts to Normal Form when Forecast is suppressed, changes form to match the weather when it regains it", async () => {
game.override.enemyMoveset([MoveId.GASTRO_ACID]).weather(WeatherType.RAIN); game.override.enemyMoveset([MoveId.GASTRO_ACID]).weather(WeatherType.RAIN);
await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.PIKACHU]);
const castform = game.scene.getPlayerPokemon()!; const castform = game.field.getPlayerPokemon();
expect(castform.formIndex).toBe(RAINY_FORM); expect(castform.formIndex).toBe(RAINY_FORM);
@ -233,7 +233,7 @@ describe("Abilities - Forecast", () => {
game.doSwitchPokemon(1); game.doSwitchPokemon(1);
await game.phaseInterceptor.to(PostSummonPhase); await game.phaseInterceptor.to(PostSummonPhase);
const castform = game.scene.getPlayerPokemon()!; const castform = game.field.getPlayerPokemon();
// Damage phase should come first // Damage phase should come first
await game.phaseInterceptor.to(DamageAnimPhase); await game.phaseInterceptor.to(DamageAnimPhase);
@ -248,7 +248,7 @@ describe("Abilities - Forecast", () => {
game.override.weather(WeatherType.RAIN); game.override.weather(WeatherType.RAIN);
await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.MAGIKARP]);
const castform = game.scene.getPlayerPokemon()!; const castform = game.field.getPlayerPokemon();
expect(castform.formIndex).toBe(RAINY_FORM); expect(castform.formIndex).toBe(RAINY_FORM);
@ -263,14 +263,14 @@ describe("Abilities - Forecast", () => {
it("should trigger player's form change when summoned at the same time as an enemy with a weather changing ability", async () => { it("should trigger player's form change when summoned at the same time as an enemy with a weather changing ability", async () => {
game.override.enemyAbility(AbilityId.DROUGHT); game.override.enemyAbility(AbilityId.DROUGHT);
await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.MAGIKARP]);
const castform = game.scene.getPlayerPokemon()!; const castform = game.field.getPlayerPokemon();
expect(castform.formIndex).toBe(SUNNY_FORM); expect(castform.formIndex).toBe(SUNNY_FORM);
}); });
it("should trigger enemy's form change when summoned at the same time as a player with a weather changing ability", async () => { it("should trigger enemy's form change when summoned at the same time as a player with a weather changing ability", async () => {
game.override.ability(AbilityId.DROUGHT).enemySpecies(SpeciesId.CASTFORM).enemyAbility(AbilityId.FORECAST); game.override.ability(AbilityId.DROUGHT).enemySpecies(SpeciesId.CASTFORM).enemyAbility(AbilityId.FORECAST);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const castform = game.scene.getEnemyPokemon()!; const castform = game.field.getEnemyPokemon();
expect(castform.formIndex).toBe(SUNNY_FORM); expect(castform.formIndex).toBe(SUNNY_FORM);
}); });
}); });

View File

@ -43,7 +43,7 @@ describe("Abilities - Good As Gold", () => {
game.override.enemyMoveset([MoveId.GROWL]); game.override.enemyMoveset([MoveId.GROWL]);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);

View File

@ -40,7 +40,7 @@ describe("Abilities - Gorilla Tactics", () => {
it("boosts the Pokémon's Attack by 50%, but limits the Pokémon to using only one move", async () => { it("boosts the Pokémon's Attack by 50%, but limits the Pokémon to using only one move", async () => {
await game.classicMode.startBattle([SpeciesId.GALAR_DARMANITAN]); await game.classicMode.startBattle([SpeciesId.GALAR_DARMANITAN]);
const darmanitan = game.scene.getPlayerPokemon()!; const darmanitan = game.field.getPlayerPokemon();
const initialAtkStat = darmanitan.getStat(Stat.ATK); const initialAtkStat = darmanitan.getStat(Stat.ATK);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -86,7 +86,7 @@ describe("Abilities - Gorilla Tactics", () => {
vi.spyOn(RandomMoveAttr.prototype, "getMoveOverride").mockReturnValue(MoveId.TACKLE); vi.spyOn(RandomMoveAttr.prototype, "getMoveOverride").mockReturnValue(MoveId.TACKLE);
await game.classicMode.startBattle([SpeciesId.GALAR_DARMANITAN]); await game.classicMode.startBattle([SpeciesId.GALAR_DARMANITAN]);
const darmanitan = game.scene.getPlayerPokemon()!; const darmanitan = game.field.getPlayerPokemon();
game.move.select(MoveId.METRONOME); game.move.select(MoveId.METRONOME);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");

View File

@ -52,7 +52,7 @@ describe("Abilities - Gulp Missile", () => {
it("changes to Gulping Form if HP is over half when Surf or Dive is used", async () => { it("changes to Gulping Form if HP is over half when Surf or Dive is used", async () => {
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
game.move.select(MoveId.DIVE); game.move.select(MoveId.DIVE);
await game.toNextTurn(); await game.toNextTurn();
@ -66,7 +66,7 @@ describe("Abilities - Gulp Missile", () => {
it("changes to Gorging Form if HP is under half when Surf or Dive is used", async () => { it("changes to Gorging Form if HP is under half when Surf or Dive is used", async () => {
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.49); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.49);
expect(cramorant.getHpRatio()).toBe(0.49); expect(cramorant.getHpRatio()).toBe(0.49);
@ -80,7 +80,7 @@ describe("Abilities - Gulp Missile", () => {
it("changes to base form when switched out after Surf or Dive is used", async () => { it("changes to base form when switched out after Surf or Dive is used", async () => {
await game.classicMode.startBattle([SpeciesId.CRAMORANT, SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.CRAMORANT, SpeciesId.MAGIKARP]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
game.move.select(MoveId.SURF); game.move.select(MoveId.SURF);
await game.toNextTurn(); await game.toNextTurn();
@ -95,7 +95,7 @@ describe("Abilities - Gulp Missile", () => {
it("changes form during Dive's charge turn", async () => { it("changes form during Dive's charge turn", async () => {
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
game.move.select(MoveId.DIVE); game.move.select(MoveId.DIVE);
await game.phaseInterceptor.to("MoveEndPhase"); await game.phaseInterceptor.to("MoveEndPhase");
@ -108,7 +108,7 @@ describe("Abilities - Gulp Missile", () => {
game.override.enemyMoveset(MoveId.TACKLE); game.override.enemyMoveset(MoveId.TACKLE);
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "damageAndUpdate"); vi.spyOn(enemy, "damageAndUpdate");
game.move.select(MoveId.SURF); game.move.select(MoveId.SURF);
@ -121,7 +121,7 @@ describe("Abilities - Gulp Missile", () => {
game.override.enemyMoveset(MoveId.TAIL_WHIP); game.override.enemyMoveset(MoveId.TAIL_WHIP);
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55);
game.move.select(MoveId.SURF); game.move.select(MoveId.SURF);
@ -140,8 +140,8 @@ describe("Abilities - Gulp Missile", () => {
game.override.enemyMoveset(MoveId.TACKLE); game.override.enemyMoveset(MoveId.TACKLE);
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "damageAndUpdate"); vi.spyOn(enemy, "damageAndUpdate");
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55);
@ -164,8 +164,8 @@ describe("Abilities - Gulp Missile", () => {
game.override.enemyMoveset(MoveId.TACKLE); game.override.enemyMoveset(MoveId.TACKLE);
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "damageAndUpdate"); vi.spyOn(enemy, "damageAndUpdate");
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.45); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.45);
@ -188,7 +188,7 @@ describe("Abilities - Gulp Missile", () => {
game.override.enemyMoveset(MoveId.SURF); game.override.enemyMoveset(MoveId.SURF);
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
game.move.select(MoveId.DIVE); game.move.select(MoveId.DIVE);
await game.phaseInterceptor.to("BerryPhase", false); await game.phaseInterceptor.to("BerryPhase", false);
@ -201,8 +201,8 @@ describe("Abilities - Gulp Missile", () => {
game.override.enemyMoveset(MoveId.TACKLE).enemyAbility(AbilityId.MAGIC_GUARD); game.override.enemyMoveset(MoveId.TACKLE).enemyAbility(AbilityId.MAGIC_GUARD);
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55);
@ -225,7 +225,7 @@ describe("Abilities - Gulp Missile", () => {
game.override.enemyMoveset(MoveId.THUNDERBOLT); game.override.enemyMoveset(MoveId.THUNDERBOLT);
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
game.move.select(MoveId.SURF); game.move.select(MoveId.SURF);
await game.phaseInterceptor.to("FaintPhase"); await game.phaseInterceptor.to("FaintPhase");
@ -233,7 +233,7 @@ describe("Abilities - Gulp Missile", () => {
expect(cramorant.hp).toBe(0); expect(cramorant.hp).toBe(0);
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeUndefined(); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeUndefined();
expect(cramorant.formIndex).toBe(NORMAL_FORM); expect(cramorant.formIndex).toBe(NORMAL_FORM);
expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.DEF)).toBe(-1); expect(game.field.getEnemyPokemon().getStatStage(Stat.DEF)).toBe(-1);
}); });
it("doesn't trigger if user is behind a substitute", async () => { it("doesn't trigger if user is behind a substitute", async () => {
@ -244,21 +244,21 @@ describe("Abilities - Gulp Missile", () => {
await game.move.selectEnemyMove(MoveId.SPLASH); await game.move.selectEnemyMove(MoveId.SPLASH);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!.formIndex).toBe(GULPING_FORM); expect(game.field.getPlayerPokemon().formIndex).toBe(GULPING_FORM);
game.move.select(MoveId.SUBSTITUTE); game.move.select(MoveId.SUBSTITUTE);
await game.move.selectEnemyMove(MoveId.POWER_TRIP); await game.move.selectEnemyMove(MoveId.POWER_TRIP);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!.formIndex).toBe(GULPING_FORM); expect(game.field.getPlayerPokemon().formIndex).toBe(GULPING_FORM);
}); });
it("cannot be suppressed", async () => { it("cannot be suppressed", async () => {
game.override.enemyMoveset(MoveId.GASTRO_ACID); game.override.enemyMoveset(MoveId.GASTRO_ACID);
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55);
game.move.select(MoveId.SURF); game.move.select(MoveId.SURF);
@ -278,7 +278,7 @@ describe("Abilities - Gulp Missile", () => {
game.override.enemyMoveset(MoveId.SKILL_SWAP); game.override.enemyMoveset(MoveId.SKILL_SWAP);
await game.classicMode.startBattle([SpeciesId.CRAMORANT]); await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!; const cramorant = game.field.getPlayerPokemon();
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55);
game.move.select(MoveId.SURF); game.move.select(MoveId.SURF);
@ -301,6 +301,6 @@ describe("Abilities - Gulp Missile", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("TurnStartPhase"); await game.phaseInterceptor.to("TurnStartPhase");
expect(game.scene.getEnemyPokemon()?.hasAbility(AbilityId.GULP_MISSILE)).toBe(false); expect(game.field.getEnemyPokemon().hasAbility(AbilityId.GULP_MISSILE)).toBe(false);
}); });
}); });

View File

@ -19,7 +19,7 @@ describe("Abilities - Harvest", () => {
let game: GameManager; let game: GameManager;
const getPlayerBerries = () => const getPlayerBerries = () =>
game.scene.getModifiers(BerryModifier, true).filter(b => b.pokemonId === game.scene.getPlayerPokemon()?.id); game.scene.getModifiers(BerryModifier, true).filter(b => b.pokemonId === game.field.getPlayerPokemon().id);
/** Check whether the player's Modifiers contains the specified berries and nothing else. */ /** Check whether the player's Modifiers contains the specified berries and nothing else. */
function expectBerriesContaining(...berries: ModifierOverride[]): void { function expectBerriesContaining(...berries: ModifierOverride[]): void {
@ -64,11 +64,11 @@ describe("Abilities - Harvest", () => {
await game.move.selectEnemyMove(MoveId.NUZZLE); await game.move.selectEnemyMove(MoveId.NUZZLE);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(getPlayerBerries()).toHaveLength(0); expect(getPlayerBerries()).toHaveLength(0);
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toHaveLength(1); expect(game.field.getPlayerPokemon().battleData.berriesEaten).toHaveLength(1);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expectBerriesContaining({ name: "BERRY", type: BerryType.LUM, count: 1 }); expectBerriesContaining({ name: "BERRY", type: BerryType.LUM, count: 1 });
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); expect(game.field.getPlayerPokemon().battleData.berriesEaten).toEqual([]);
}); });
it("tracks berries eaten while disabled/not present", async () => { it("tracks berries eaten while disabled/not present", async () => {
@ -82,7 +82,7 @@ describe("Abilities - Harvest", () => {
.enemyAbility(AbilityId.NEUTRALIZING_GAS); .enemyAbility(AbilityId.NEUTRALIZING_GAS);
await game.classicMode.startBattle([SpeciesId.MILOTIC]); await game.classicMode.startBattle([SpeciesId.MILOTIC]);
const milotic = game.scene.getPlayerPokemon()!; const milotic = game.field.getPlayerPokemon();
expect(milotic).toBeDefined(); expect(milotic).toBeDefined();
// Chug a few berries without harvest (should get tracked) // Chug a few berries without harvest (should get tracked)
@ -122,7 +122,7 @@ describe("Abilities - Harvest", () => {
.ability(AbilityId.BALL_FETCH); // don't actually need harvest for this test .ability(AbilityId.BALL_FETCH); // don't actually need harvest for this test
await game.classicMode.startBattle([SpeciesId.REGIELEKI]); await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
const regieleki = game.scene.getPlayerPokemon()!; const regieleki = game.field.getPlayerPokemon();
regieleki.hp = 1; regieleki.hp = 1;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -150,7 +150,7 @@ describe("Abilities - Harvest", () => {
.enemyAbility(AbilityId.COMPOUND_EYES); .enemyAbility(AbilityId.COMPOUND_EYES);
await game.classicMode.startBattle([SpeciesId.REGIELEKI]); await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
const regieleki = game.scene.getPlayerPokemon()!; const regieleki = game.field.getPlayerPokemon();
regieleki.hp = regieleki.getMaxHp() / 4 + 1; regieleki.hp = regieleki.getMaxHp() / 4 + 1;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -161,7 +161,7 @@ describe("Abilities - Harvest", () => {
// ate 1 berry and recovered it // ate 1 berry and recovered it
expect(regieleki.battleData.berriesEaten).toEqual([]); expect(regieleki.battleData.berriesEaten).toEqual([]);
expect(getPlayerBerries()).toEqual([expect.objectContaining({ berryType: BerryType.PETAYA, stackCount: 1 })]); expect(getPlayerBerries()).toEqual([expect.objectContaining({ berryType: BerryType.PETAYA, stackCount: 1 })]);
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1); expect(game.field.getPlayerPokemon().getStatStage(Stat.SPATK)).toBe(1);
// heal up so harvest doesn't proc and kill enemy // heal up so harvest doesn't proc and kill enemy
game.move.select(MoveId.EARTHQUAKE); game.move.select(MoveId.EARTHQUAKE);
@ -170,13 +170,13 @@ describe("Abilities - Harvest", () => {
await game.toNextWave(); await game.toNextWave();
expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA }); expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA });
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1); expect(game.field.getPlayerPokemon().getStatStage(Stat.SPATK)).toBe(1);
await game.reload.reloadSession(); await game.reload.reloadSession();
expect(regieleki.battleData.berriesEaten).toEqual([]); expect(regieleki.battleData.berriesEaten).toEqual([]);
expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA }); expectBerriesContaining({ name: "BERRY", count: 1, type: BerryType.PETAYA });
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.SPATK)).toBe(1); expect(game.field.getPlayerPokemon().getStatStage(Stat.SPATK)).toBe(1);
}); });
it("cannot restore capped berries", async () => { it("cannot restore capped berries", async () => {
@ -187,7 +187,7 @@ describe("Abilities - Harvest", () => {
game.override.startingHeldItems(initBerries); game.override.startingHeldItems(initBerries);
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const feebas = game.scene.getPlayerPokemon()!; const feebas = game.field.getPlayerPokemon();
feebas.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF]; feebas.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF];
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -215,7 +215,7 @@ describe("Abilities - Harvest", () => {
game.override.startingHeldItems(initBerries); game.override.startingHeldItems(initBerries);
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
player.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF]; player.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF];
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -234,7 +234,7 @@ describe("Abilities - Harvest", () => {
await game.move.selectEnemyMove(MoveId.INCINERATE); await game.move.selectEnemyMove(MoveId.INCINERATE);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); expect(game.field.getPlayerPokemon().battleData.berriesEaten).toEqual([]);
}); });
it("cannot restore knocked off berries", async () => { it("cannot restore knocked off berries", async () => {
@ -245,7 +245,7 @@ describe("Abilities - Harvest", () => {
await game.move.selectEnemyMove(MoveId.KNOCK_OFF); await game.move.selectEnemyMove(MoveId.KNOCK_OFF);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); expect(game.field.getPlayerPokemon().battleData.berriesEaten).toEqual([]);
}); });
it("can restore berries eaten by Teatime", async () => { it("can restore berries eaten by Teatime", async () => {
@ -257,7 +257,7 @@ describe("Abilities - Harvest", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); expect(game.field.getPlayerPokemon().battleData.berriesEaten).toEqual([]);
expectBerriesContaining(...initBerries); expectBerriesContaining(...initBerries);
}); });
@ -271,8 +271,8 @@ describe("Abilities - Harvest", () => {
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
// pluck triggers harvest for neither side // pluck triggers harvest for neither side
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); expect(game.field.getPlayerPokemon().battleData.berriesEaten).toEqual([]);
expect(game.scene.getEnemyPokemon()?.battleData.berriesEaten).toEqual([]); expect(game.field.getEnemyPokemon().battleData.berriesEaten).toEqual([]);
expect(getPlayerBerries()).toEqual([]); expect(getPlayerBerries()).toEqual([]);
}); });
@ -293,7 +293,7 @@ describe("Abilities - Harvest", () => {
await game.phaseInterceptor.to("TurnEndPhase", false); await game.phaseInterceptor.to("TurnEndPhase", false);
// won't trigger harvest since we didn't lose the berry (it just doesn't ever add it to the array) // won't trigger harvest since we didn't lose the berry (it just doesn't ever add it to the array)
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); expect(game.field.getPlayerPokemon().battleData.berriesEaten).toEqual([]);
expectBerriesContaining(...initBerries); expectBerriesContaining(...initBerries);
}); });
@ -303,7 +303,7 @@ describe("Abilities - Harvest", () => {
await game.classicMode.startBattle([SpeciesId.MEOWSCARADA]); await game.classicMode.startBattle([SpeciesId.MEOWSCARADA]);
// pre damage // pre damage
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
player.hp = 1; player.hp = 1;
// steal a sitrus and immediately consume it // steal a sitrus and immediately consume it
@ -326,7 +326,7 @@ describe("Abilities - Harvest", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toBe([]); expect(game.field.getPlayerPokemon().battleData.berriesEaten).toBe([]);
expect(getPlayerBerries()).toEqual([]); expect(getPlayerBerries()).toEqual([]);
}); });
@ -339,7 +339,7 @@ describe("Abilities - Harvest", () => {
game.move.select(MoveId.NATURAL_GIFT); game.move.select(MoveId.NATURAL_GIFT);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toHaveLength(0); expect(game.field.getPlayerPokemon().battleData.berriesEaten).toHaveLength(0);
expectBerriesContaining(...initBerries); expectBerriesContaining(...initBerries);
}); });
}); });

View File

@ -46,7 +46,7 @@ describe("Abilities - Healer", () => {
game.override.moveset([MoveId.SPLASH, MoveId.LUNAR_DANCE]); game.override.moveset([MoveId.SPLASH, MoveId.LUNAR_DANCE]);
await game.classicMode.startBattle([SpeciesId.MAGIKARP, SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP, SpeciesId.MAGIKARP]);
const user = game.scene.getPlayerPokemon()!; const user = game.field.getPlayerPokemon();
// Only want one magikarp to have the ability // Only want one magikarp to have the ability
vi.spyOn(user, "getAbility").mockReturnValue(allAbilities[AbilityId.HEALER]); vi.spyOn(user, "getAbility").mockReturnValue(allAbilities[AbilityId.HEALER]);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);

View File

@ -40,7 +40,7 @@ describe("Abilities - Heatproof", () => {
it("reduces Fire type damage by half", async () => { it("reduces Fire type damage by half", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
const initialHP = 1000; const initialHP = 1000;
enemy.hp = initialHP; enemy.hp = initialHP;
@ -63,7 +63,7 @@ describe("Abilities - Heatproof", () => {
game.override.enemyStatusEffect(StatusEffect.BURN).enemySpecies(SpeciesId.ABRA); game.override.enemyStatusEffect(StatusEffect.BURN).enemySpecies(SpeciesId.ABRA);
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.toNextTurn(); await game.toNextTurn();

View File

@ -62,7 +62,7 @@ describe("Abilities - Honey Gather", () => {
game.scene.money = 1000; game.scene.money = 1000;
// something weird is going on with the test framework, so this is required to prevent a crash // something weird is going on with the test framework, so this is required to prevent a crash
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "scene", "get").mockReturnValue(game.scene); vi.spyOn(enemy, "scene", "get").mockReturnValue(game.scene);
// Expects next wave so run must succeed // Expects next wave so run must succeed
vi.spyOn(Overrides, "RUN_SUCCESS_OVERRIDE", "get").mockReturnValue(true); vi.spyOn(Overrides, "RUN_SUCCESS_OVERRIDE", "get").mockReturnValue(true);

View File

@ -35,7 +35,7 @@ describe("Abilities - Hustle", () => {
it("increases the user's Attack stat by 50%", async () => { it("increases the user's Attack stat by 50%", async () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.field.getPlayerPokemon();
const atk = pikachu.stats[Stat.ATK]; const atk = pikachu.stats[Stat.ATK];
vi.spyOn(pikachu, "getEffectiveStat"); vi.spyOn(pikachu, "getEffectiveStat");
@ -49,7 +49,7 @@ describe("Abilities - Hustle", () => {
it("lowers the accuracy of the user's physical moves by 20%", async () => { it("lowers the accuracy of the user's physical moves by 20%", async () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.field.getPlayerPokemon();
vi.spyOn(pikachu, "getAccuracyMultiplier"); vi.spyOn(pikachu, "getAccuracyMultiplier");
@ -61,7 +61,7 @@ describe("Abilities - Hustle", () => {
it("does not affect non-physical moves", async () => { it("does not affect non-physical moves", async () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.field.getPlayerPokemon();
const spatk = pikachu.stats[Stat.SPATK]; const spatk = pikachu.stats[Stat.SPATK];
vi.spyOn(pikachu, "getEffectiveStat"); vi.spyOn(pikachu, "getEffectiveStat");
@ -78,8 +78,8 @@ describe("Abilities - Hustle", () => {
game.override.startingLevel(100).enemyLevel(30); game.override.startingLevel(100).enemyLevel(30);
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
vi.spyOn(pikachu, "getAccuracyMultiplier"); vi.spyOn(pikachu, "getAccuracyMultiplier");
vi.spyOn(allMoves[MoveId.FISSURE], "calculateBattleAccuracy"); vi.spyOn(allMoves[MoveId.FISSURE], "calculateBattleAccuracy");

View File

@ -36,7 +36,7 @@ describe("Abilities - Hyper Cutter", () => {
it("only prevents ATK drops", async () => { it("only prevents ATK drops", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.OCTOLOCK); game.move.select(MoveId.OCTOLOCK);
await game.toNextTurn(); await game.toNextTurn();

View File

@ -44,7 +44,7 @@ describe("Abilities - Ice Face", () => {
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
const eiscue = game.scene.getEnemyPokemon()!; const eiscue = game.field.getEnemyPokemon();
expect(eiscue.isFullHp()).toBe(true); expect(eiscue.isFullHp()).toBe(true);
expect(eiscue.formIndex).toBe(noiceForm); expect(eiscue.formIndex).toBe(noiceForm);
@ -57,7 +57,7 @@ describe("Abilities - Ice Face", () => {
game.move.select(MoveId.SURGING_STRIKES); game.move.select(MoveId.SURGING_STRIKES);
const eiscue = game.scene.getEnemyPokemon()!; const eiscue = game.field.getEnemyPokemon();
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined(); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined();
// First hit // First hit
@ -85,7 +85,7 @@ describe("Abilities - Ice Face", () => {
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
const eiscue = game.scene.getEnemyPokemon()!; const eiscue = game.field.getEnemyPokemon();
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined);
expect(eiscue.formIndex).toBe(icefaceForm); expect(eiscue.formIndex).toBe(icefaceForm);
@ -99,7 +99,7 @@ describe("Abilities - Ice Face", () => {
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
const eiscue = game.scene.getEnemyPokemon()!; const eiscue = game.field.getEnemyPokemon();
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined);
expect(eiscue.formIndex).toBe(icefaceForm); expect(eiscue.formIndex).toBe(icefaceForm);
@ -114,7 +114,7 @@ describe("Abilities - Ice Face", () => {
await game.phaseInterceptor.to(MoveEndPhase); await game.phaseInterceptor.to(MoveEndPhase);
const eiscue = game.scene.getEnemyPokemon()!; const eiscue = game.field.getEnemyPokemon();
expect(eiscue.isFullHp()).toBe(true); expect(eiscue.isFullHp()).toBe(true);
expect(eiscue.formIndex).toBe(noiceForm); expect(eiscue.formIndex).toBe(noiceForm);
@ -134,7 +134,7 @@ describe("Abilities - Ice Face", () => {
game.move.select(MoveId.SNOWSCAPE); game.move.select(MoveId.SNOWSCAPE);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
let eiscue = game.scene.getPlayerPokemon()!; let eiscue = game.field.getPlayerPokemon();
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined();
expect(eiscue.formIndex).toBe(noiceForm); expect(eiscue.formIndex).toBe(noiceForm);
@ -146,7 +146,7 @@ describe("Abilities - Ice Face", () => {
game.doSwitchPokemon(1); game.doSwitchPokemon(1);
await game.phaseInterceptor.to(QuietFormChangePhase); await game.phaseInterceptor.to(QuietFormChangePhase);
eiscue = game.scene.getPlayerPokemon()!; eiscue = game.field.getPlayerPokemon();
expect(eiscue.formIndex).toBe(icefaceForm); expect(eiscue.formIndex).toBe(icefaceForm);
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined);
@ -158,7 +158,7 @@ describe("Abilities - Ice Face", () => {
await game.classicMode.startBattle([SpeciesId.EISCUE]); await game.classicMode.startBattle([SpeciesId.EISCUE]);
game.move.select(MoveId.HAIL); game.move.select(MoveId.HAIL);
const eiscue = game.scene.getPlayerPokemon()!; const eiscue = game.field.getPlayerPokemon();
await game.phaseInterceptor.to(QuietFormChangePhase); await game.phaseInterceptor.to(QuietFormChangePhase);
@ -179,7 +179,7 @@ describe("Abilities - Ice Face", () => {
game.move.select(MoveId.ICE_BEAM); game.move.select(MoveId.ICE_BEAM);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
let eiscue = game.scene.getPlayerPokemon()!; let eiscue = game.field.getPlayerPokemon();
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined();
expect(eiscue.formIndex).toBe(noiceForm); expect(eiscue.formIndex).toBe(noiceForm);
@ -206,7 +206,7 @@ describe("Abilities - Ice Face", () => {
await game.classicMode.startBattle([SpeciesId.EISCUE]); await game.classicMode.startBattle([SpeciesId.EISCUE]);
const eiscue = game.scene.getPlayerPokemon()!; const eiscue = game.field.getPlayerPokemon();
expect(eiscue.formIndex).toBe(noiceForm); expect(eiscue.formIndex).toBe(noiceForm);
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined();
@ -229,7 +229,7 @@ describe("Abilities - Ice Face", () => {
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getEnemyPokemon()!.formIndex).toBe(icefaceForm); expect(game.field.getEnemyPokemon().formIndex).toBe(icefaceForm);
}); });
it("cannot be suppressed", async () => { it("cannot be suppressed", async () => {
@ -241,7 +241,7 @@ describe("Abilities - Ice Face", () => {
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const eiscue = game.scene.getEnemyPokemon()!; const eiscue = game.field.getEnemyPokemon();
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined);
expect(eiscue.formIndex).toBe(icefaceForm); expect(eiscue.formIndex).toBe(icefaceForm);
@ -257,7 +257,7 @@ describe("Abilities - Ice Face", () => {
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
const eiscue = game.scene.getEnemyPokemon()!; const eiscue = game.field.getEnemyPokemon();
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined(); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined();
expect(eiscue.formIndex).toBe(icefaceForm); expect(eiscue.formIndex).toBe(icefaceForm);
@ -269,10 +269,10 @@ describe("Abilities - Ice Face", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const eiscue = game.scene.getEnemyPokemon()!; const eiscue = game.field.getEnemyPokemon();
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined(); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined();
expect(eiscue.formIndex).toBe(icefaceForm); expect(eiscue.formIndex).toBe(icefaceForm);
expect(game.scene.getPlayerPokemon()!.hasAbility(AbilityId.TRACE)).toBe(true); expect(game.field.getPlayerPokemon().hasAbility(AbilityId.TRACE)).toBe(true);
}); });
}); });

View File

@ -33,7 +33,7 @@ describe("Abilities - Illuminate", () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
expect(player.getStatStage(Stat.ACC)).toBe(0); expect(player.getStatStage(Stat.ACC)).toBe(0);

View File

@ -35,8 +35,8 @@ describe("Abilities - Illusion", () => {
it("creates illusion at the start", async () => { it("creates illusion at the start", async () => {
await game.classicMode.startBattle([SpeciesId.ZOROARK, SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.ZOROARK, SpeciesId.FEEBAS]);
const zoroark = game.scene.getPlayerPokemon()!; const zoroark = game.field.getPlayerPokemon();
const zorua = game.scene.getEnemyPokemon()!; const zorua = game.field.getEnemyPokemon();
expect(!!zoroark.summonData.illusion).equals(true); expect(!!zoroark.summonData.illusion).equals(true);
expect(!!zorua.summonData.illusion).equals(true); expect(!!zorua.summonData.illusion).equals(true);
@ -48,7 +48,7 @@ describe("Abilities - Illusion", () => {
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
const zorua = game.scene.getEnemyPokemon()!; const zorua = game.field.getEnemyPokemon();
expect(!!zorua.summonData.illusion).equals(false); expect(!!zorua.summonData.illusion).equals(false);
expect(zorua.name).equals("Zorua"); expect(zorua.name).equals("Zorua");
@ -60,7 +60,7 @@ describe("Abilities - Illusion", () => {
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
const zorua = game.scene.getEnemyPokemon()!; const zorua = game.field.getEnemyPokemon();
expect(!!zorua.summonData.illusion).equals(false); expect(!!zorua.summonData.illusion).equals(false);
}); });
@ -69,7 +69,7 @@ describe("Abilities - Illusion", () => {
game.override.enemyAbility(AbilityId.NEUTRALIZING_GAS); game.override.enemyAbility(AbilityId.NEUTRALIZING_GAS);
await game.classicMode.startBattle([SpeciesId.KOFFING]); await game.classicMode.startBattle([SpeciesId.KOFFING]);
const zorua = game.scene.getEnemyPokemon()!; const zorua = game.field.getEnemyPokemon();
expect(!!zorua.summonData.illusion).equals(false); expect(!!zorua.summonData.illusion).equals(false);
}); });
@ -85,15 +85,15 @@ describe("Abilities - Illusion", () => {
game.doSwitchPokemon(1); game.doSwitchPokemon(1);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!.summonData.illusion).toBeFalsy(); expect(game.field.getPlayerPokemon().summonData.illusion).toBeFalsy();
}); });
it("causes enemy AI to consider the illusion's type instead of the actual type when considering move effectiveness", async () => { it("causes enemy AI to consider the illusion's type instead of the actual type when considering move effectiveness", async () => {
game.override.enemyMoveset([MoveId.FLAMETHROWER, MoveId.PSYCHIC, MoveId.TACKLE]); game.override.enemyMoveset([MoveId.FLAMETHROWER, MoveId.PSYCHIC, MoveId.TACKLE]);
await game.classicMode.startBattle([SpeciesId.ZOROARK, SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.ZOROARK, SpeciesId.FEEBAS]);
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
const zoroark = game.scene.getPlayerPokemon()!; const zoroark = game.field.getPlayerPokemon();
const flameThrower = enemy.getMoveset()[0]!.getMove(); const flameThrower = enemy.getMoveset()[0]!.getMove();
const psychic = enemy.getMoveset()[1]!.getMove(); const psychic = enemy.getMoveset()[1]!.getMove();
@ -125,7 +125,7 @@ describe("Abilities - Illusion", () => {
await game.move.forceEnemyMove(MoveId.WILL_O_WISP); await game.move.forceEnemyMove(MoveId.WILL_O_WISP);
await game.toEndOfTurn(); await game.toEndOfTurn();
const zoroark = game.scene.getPlayerPokemon()!; const zoroark = game.field.getPlayerPokemon();
expect(!!zoroark.summonData.illusion).equals(true); expect(!!zoroark.summonData.illusion).equals(true);
}); });
@ -143,7 +143,7 @@ describe("Abilities - Illusion", () => {
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
const zoroark = game.scene.getPlayerPokemon()!; const zoroark = game.field.getPlayerPokemon();
expect(zoroark.summonData.illusion?.name).equals("Axew"); expect(zoroark.summonData.illusion?.name).equals("Axew");
expect(zoroark.getNameToRender(true)).equals("axew nickname"); expect(zoroark.getNameToRender(true)).equals("axew nickname");
@ -155,7 +155,7 @@ describe("Abilities - Illusion", () => {
it("breaks when suppressed", async () => { it("breaks when suppressed", async () => {
game.override.moveset(MoveId.GASTRO_ACID); game.override.moveset(MoveId.GASTRO_ACID);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const zorua = game.scene.getEnemyPokemon()!; const zorua = game.field.getEnemyPokemon();
expect(!!zorua.summonData?.illusion).toBe(true); expect(!!zorua.summonData?.illusion).toBe(true);

View File

@ -58,8 +58,8 @@ describe("Abilities - Infiltrator", () => {
])("should bypass the target's $effectName", async ({ tagType, move }) => { ])("should bypass the target's $effectName", async ({ tagType, move }) => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
const preScreenDmg = enemy.getAttackDamage({ source: player, move: allMoves[move] }).damage; const preScreenDmg = enemy.getAttackDamage({ source: player, move: allMoves[move] }).damage;
@ -74,8 +74,8 @@ describe("Abilities - Infiltrator", () => {
it("should bypass the target's Safeguard", async () => { it("should bypass the target's Safeguard", async () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.scene.arena.addTag(ArenaTagType.SAFEGUARD, 1, MoveId.NONE, enemy.id, ArenaTagSide.ENEMY, true); game.scene.arena.addTag(ArenaTagType.SAFEGUARD, 1, MoveId.NONE, enemy.id, ArenaTagSide.ENEMY, true);
@ -90,8 +90,8 @@ describe("Abilities - Infiltrator", () => {
it.todo("should bypass the target's Mist", async () => { it.todo("should bypass the target's Mist", async () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.scene.arena.addTag(ArenaTagType.MIST, 1, MoveId.NONE, enemy.id, ArenaTagSide.ENEMY, true); game.scene.arena.addTag(ArenaTagType.MIST, 1, MoveId.NONE, enemy.id, ArenaTagSide.ENEMY, true);
@ -105,8 +105,8 @@ describe("Abilities - Infiltrator", () => {
it("should bypass the target's Substitute", async () => { it("should bypass the target's Substitute", async () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
enemy.addTag(BattlerTagType.SUBSTITUTE, 1, MoveId.NONE, enemy.id); enemy.addTag(BattlerTagType.SUBSTITUTE, 1, MoveId.NONE, enemy.id);

View File

@ -32,8 +32,8 @@ describe("Abilities - Intrepid Sword", () => {
it("should raise ATK stat stage by 1 on entry", async () => { it("should raise ATK stat stage by 1 on entry", async () => {
await game.classicMode.runToSummon([SpeciesId.ZACIAN]); await game.classicMode.runToSummon([SpeciesId.ZACIAN]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
await game.phaseInterceptor.to(CommandPhase, false); await game.phaseInterceptor.to(CommandPhase, false);

View File

@ -42,7 +42,7 @@ describe("Abilities - Magic Bounce", () => {
game.move.use(MoveId.GROWL); game.move.use(MoveId.GROWL);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.getStatStage(Stat.ATK)).toBe(-1); expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(-1);
}); });
it("should not bounce moves while the target is in the semi-invulnerable state", async () => { it("should not bounce moves while the target is in the semi-invulnerable state", async () => {
@ -53,7 +53,7 @@ describe("Abilities - Magic Bounce", () => {
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.getStatStage(Stat.ATK)).toBe(0); expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(0);
}); });
it("should individually bounce back multi-target moves", async () => { it("should individually bounce back multi-target moves", async () => {
@ -70,12 +70,12 @@ describe("Abilities - Magic Bounce", () => {
it("should still bounce back a move that would otherwise fail", async () => { it("should still bounce back a move that would otherwise fail", async () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
game.scene.getEnemyPokemon()?.setStatStage(Stat.ATK, -6); game.field.getEnemyPokemon().setStatStage(Stat.ATK, -6);
game.move.use(MoveId.GROWL); game.move.use(MoveId.GROWL);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.getStatStage(Stat.ATK)).toBe(-1); expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(-1);
}); });
it("should not bounce back a move that was just bounced", async () => { it("should not bounce back a move that was just bounced", async () => {
@ -85,7 +85,7 @@ describe("Abilities - Magic Bounce", () => {
game.move.select(MoveId.GROWL); game.move.select(MoveId.GROWL);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.getStatStage(Stat.ATK)).toBe(-1); expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(-1);
}); });
it("should receive the stat change after reflecting a move back to a mirror armor user", async () => { it("should receive the stat change after reflecting a move back to a mirror armor user", async () => {
@ -95,7 +95,7 @@ describe("Abilities - Magic Bounce", () => {
game.move.select(MoveId.GROWL); game.move.select(MoveId.GROWL);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.ATK)).toBe(-1); expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-1);
}); });
it("should not bounce back a move from a mold breaker user", async () => { it("should not bounce back a move from a mold breaker user", async () => {
@ -105,7 +105,7 @@ describe("Abilities - Magic Bounce", () => {
game.move.use(MoveId.GROWL); game.move.use(MoveId.GROWL);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.ATK)).toBe(-1); expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-1);
}); });
it("should bounce back a spread status move against both pokemon", async () => { it("should bounce back a spread status move against both pokemon", async () => {
@ -156,7 +156,7 @@ describe("Abilities - Magic Bounce", () => {
game.move.select(MoveId.CURSE); game.move.select(MoveId.CURSE);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()!.getTag(BattlerTagType.CURSED)).toBeDefined(); expect(game.field.getEnemyPokemon().getTag(BattlerTagType.CURSED)).toBeDefined();
}); });
// TODO: enable when Magic Bounce is fixed to properly reset the hit count // TODO: enable when Magic Bounce is fixed to properly reset the hit count
@ -164,8 +164,8 @@ describe("Abilities - Magic Bounce", () => {
game.override.moveset([MoveId.SPLASH, MoveId.GROWL, MoveId.ENCORE]).enemyMoveset([MoveId.TACKLE, MoveId.GROWL]); game.override.moveset([MoveId.SPLASH, MoveId.GROWL, MoveId.ENCORE]).enemyMoveset([MoveId.TACKLE, MoveId.GROWL]);
// game.override.ability(AbilityId.MOLD_BREAKER); // game.override.ability(AbilityId.MOLD_BREAKER);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
// Give the player MOLD_BREAKER for this turn to bypass Magic Bounce. // Give the player MOLD_BREAKER for this turn to bypass Magic Bounce.
const playerAbilitySpy = game.field.mockAbility(playerPokemon, AbilityId.MOLD_BREAKER); const playerAbilitySpy = game.field.mockAbility(playerPokemon, AbilityId.MOLD_BREAKER);
@ -194,8 +194,8 @@ describe("Abilities - Magic Bounce", () => {
.enemyAbility(AbilityId.MAGIC_BOUNCE); .enemyAbility(AbilityId.MAGIC_BOUNCE);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
// turn 1 // turn 1
game.move.select(MoveId.GROWL); game.move.select(MoveId.GROWL);
@ -237,7 +237,7 @@ describe("Abilities - Magic Bounce", () => {
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const stomping_tantrum = allMoves[MoveId.STOMPING_TANTRUM]; const stomping_tantrum = allMoves[MoveId.STOMPING_TANTRUM];
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(stomping_tantrum, "calculateBattlePower"); vi.spyOn(stomping_tantrum, "calculateBattlePower");
// Spore gets reflected back onto us // Spore gets reflected back onto us
@ -260,35 +260,35 @@ describe("Abilities - Magic Bounce", () => {
// Turn 1 - thunder wave immunity test // Turn 1 - thunder wave immunity test
game.move.select(MoveId.THUNDER_WAVE); game.move.select(MoveId.THUNDER_WAVE);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.status).toBeUndefined(); expect(game.field.getPlayerPokemon().status).toBeUndefined();
// Turn 2 - soundproof immunity test // Turn 2 - soundproof immunity test
game.move.select(MoveId.GROWL); game.move.select(MoveId.GROWL);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.getStatStage(Stat.ATK)).toBe(0); expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(0);
}); });
it("should bounce back a move before the accuracy check", async () => { it("should bounce back a move before the accuracy check", async () => {
game.override.moveset([MoveId.SPORE]); game.override.moveset([MoveId.SPORE]);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const attacker = game.scene.getPlayerPokemon()!; const attacker = game.field.getPlayerPokemon();
vi.spyOn(attacker, "getAccuracyMultiplier").mockReturnValue(0.0); vi.spyOn(attacker, "getAccuracyMultiplier").mockReturnValue(0.0);
game.move.select(MoveId.SPORE); game.move.select(MoveId.SPORE);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.SLEEP); expect(game.field.getPlayerPokemon().status?.effect).toBe(StatusEffect.SLEEP);
}); });
it("should take the accuracy of the magic bounce user into account", async () => { it("should take the accuracy of the magic bounce user into account", async () => {
game.override.moveset([MoveId.SPORE]); game.override.moveset([MoveId.SPORE]);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const opponent = game.scene.getEnemyPokemon()!; const opponent = game.field.getEnemyPokemon();
vi.spyOn(opponent, "getAccuracyMultiplier").mockReturnValue(0); vi.spyOn(opponent, "getAccuracyMultiplier").mockReturnValue(0);
game.move.select(MoveId.SPORE); game.move.select(MoveId.SPORE);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.status).toBeUndefined(); expect(game.field.getPlayerPokemon().status).toBeUndefined();
}); });
it("should always apply the leftmost available target's magic bounce when bouncing moves like sticky webs in doubles", async () => { it("should always apply the leftmost available target's magic bounce when bouncing moves like sticky webs in doubles", async () => {
@ -332,14 +332,14 @@ describe("Abilities - Magic Bounce", () => {
await game.move.selectEnemyMove(MoveId.FLY); await game.move.selectEnemyMove(MoveId.FLY);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.TOXIC); expect(game.field.getEnemyPokemon().status?.effect).toBe(StatusEffect.TOXIC);
expect(game.scene.getPlayerPokemon()!.status).toBeUndefined(); expect(game.field.getPlayerPokemon().status).toBeUndefined();
game.override.ability(AbilityId.NO_GUARD); game.override.ability(AbilityId.NO_GUARD);
game.move.select(MoveId.CHARM); game.move.select(MoveId.CHARM);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.ATK)).toBe(-2); expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-2);
expect(game.scene.getPlayerPokemon()!.getStatStage(Stat.ATK)).toBe(0); expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(0);
}); });
}); });

View File

@ -47,44 +47,44 @@ describe("Abilities - Mimicry", () => {
}); });
it("Pokemon should revert back to its original, root type once terrain ends", async () => { it("Pokemon should revert back to its original, root type once terrain ends", async () => {
game.override game.override.enemyAbility(AbilityId.MIMICRY);
.moveset([MoveId.SPLASH, MoveId.TRANSFORM])
.enemyAbility(AbilityId.MIMICRY)
.enemyMoveset([MoveId.SPLASH, MoveId.PSYCHIC_TERRAIN]);
await game.classicMode.startBattle([SpeciesId.REGIELEKI]); await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
const playerPokemon = game.scene.getPlayerPokemon(); const playerPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.TRANSFORM);
await game.move.selectEnemyMove(MoveId.PSYCHIC_TERRAIN); game.move.use(MoveId.SKILL_SWAP);
await game.move.forceEnemyMove(MoveId.PSYCHIC_TERRAIN);
await game.toNextTurn(); await game.toNextTurn();
expect(playerPokemon?.getTypes().includes(PokemonType.PSYCHIC)).toBe(true);
expect(playerPokemon.getTypes()).toEqual([PokemonType.PSYCHIC]);
if (game.scene.arena.terrain) { if (game.scene.arena.terrain) {
game.scene.arena.terrain.turnsLeft = 1; game.scene.arena.terrain.turnsLeft = 1;
} }
game.move.select(MoveId.SPLASH); game.move.use(MoveId.SPLASH);
await game.move.selectEnemyMove(MoveId.SPLASH); await game.move.forceEnemyMove(MoveId.SPLASH);
await game.toNextTurn(); await game.toNextTurn();
expect(playerPokemon?.getTypes().includes(PokemonType.ELECTRIC)).toBe(true);
expect(playerPokemon.getTypes()).toEqual([PokemonType.ELECTRIC]);
}); });
it("If the Pokemon is under the effect of a type-adding move and an equivalent terrain activates, the move's effect disappears", async () => { it("If the Pokemon is under the effect of a type-adding move and an equivalent terrain activates, the move's effect disappears", async () => {
game.override.enemyMoveset([MoveId.FORESTS_CURSE, MoveId.GRASSY_TERRAIN]); game.override.enemyMoveset([MoveId.FORESTS_CURSE, MoveId.GRASSY_TERRAIN]);
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const playerPokemon = game.scene.getPlayerPokemon(); const playerPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.move.selectEnemyMove(MoveId.FORESTS_CURSE); await game.move.selectEnemyMove(MoveId.FORESTS_CURSE);
await game.toNextTurn(); await game.toNextTurn();
expect(playerPokemon?.summonData.addedType).toBe(PokemonType.GRASS); expect(playerPokemon.summonData.addedType).toBe(PokemonType.GRASS);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.move.selectEnemyMove(MoveId.GRASSY_TERRAIN); await game.move.selectEnemyMove(MoveId.GRASSY_TERRAIN);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(playerPokemon?.summonData.addedType).toBeNull(); expect(playerPokemon.summonData.addedType).toBeNull();
expect(playerPokemon?.getTypes().includes(PokemonType.GRASS)).toBe(true); expect(playerPokemon.getTypes()).toEqual([PokemonType.GRASS]);
}); });
}); });

View File

@ -40,8 +40,8 @@ describe("Ability - Mirror Armor", () => {
game.override.ability(AbilityId.MIRROR_ARMOR).enemyAbility(AbilityId.INTIMIDATE); game.override.ability(AbilityId.MIRROR_ARMOR).enemyAbility(AbilityId.INTIMIDATE);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const userPokemon = game.scene.getPlayerPokemon()!; const userPokemon = game.field.getPlayerPokemon();
// Enemy has intimidate, enemy should lose -1 atk // Enemy has intimidate, enemy should lose -1 atk
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -56,8 +56,8 @@ describe("Ability - Mirror Armor", () => {
game.override.enemyAbility(AbilityId.MIRROR_ARMOR).ability(AbilityId.INTIMIDATE); game.override.enemyAbility(AbilityId.MIRROR_ARMOR).ability(AbilityId.INTIMIDATE);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const userPokemon = game.scene.getPlayerPokemon()!; const userPokemon = game.field.getPlayerPokemon();
// Enemy has intimidate, enemy should lose -1 atk // Enemy has intimidate, enemy should lose -1 atk
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -112,8 +112,8 @@ describe("Ability - Mirror Armor", () => {
game.override.ability(AbilityId.MIRROR_ARMOR).enemyAbility(AbilityId.INTIMIDATE); game.override.ability(AbilityId.MIRROR_ARMOR).enemyAbility(AbilityId.INTIMIDATE);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const userPokemon = game.scene.getPlayerPokemon()!; const userPokemon = game.field.getPlayerPokemon();
// Enemy has intimidate and uses tickle, enemy receives -2 atk and -1 defense // Enemy has intimidate and uses tickle, enemy receives -2 atk and -1 defense
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -153,8 +153,8 @@ describe("Ability - Mirror Armor", () => {
game.override.enemyAbility(AbilityId.MIRROR_ARMOR).ability(AbilityId.INTIMIDATE); game.override.enemyAbility(AbilityId.MIRROR_ARMOR).ability(AbilityId.INTIMIDATE);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const userPokemon = game.scene.getPlayerPokemon()!; const userPokemon = game.field.getPlayerPokemon();
// Enemy has intimidate and uses tickle, enemy receives -2 atk and -1 defense // Enemy has intimidate and uses tickle, enemy receives -2 atk and -1 defense
game.move.select(MoveId.TICKLE); game.move.select(MoveId.TICKLE);
@ -171,8 +171,8 @@ describe("Ability - Mirror Armor", () => {
game.override.enemyAbility(AbilityId.WHITE_SMOKE).ability(AbilityId.MIRROR_ARMOR); game.override.enemyAbility(AbilityId.WHITE_SMOKE).ability(AbilityId.MIRROR_ARMOR);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const userPokemon = game.scene.getPlayerPokemon()!; const userPokemon = game.field.getPlayerPokemon();
// Enemy has intimidate and uses tickle, enemy has white smoke, no one loses stats // Enemy has intimidate and uses tickle, enemy has white smoke, no one loses stats
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -189,8 +189,8 @@ describe("Ability - Mirror Armor", () => {
game.override.ability(AbilityId.WHITE_SMOKE).enemyAbility(AbilityId.MIRROR_ARMOR); game.override.ability(AbilityId.WHITE_SMOKE).enemyAbility(AbilityId.MIRROR_ARMOR);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const userPokemon = game.scene.getPlayerPokemon()!; const userPokemon = game.field.getPlayerPokemon();
// Enemy has intimidate and uses tickle, enemy has white smoke, no one loses stats // Enemy has intimidate and uses tickle, enemy has white smoke, no one loses stats
game.move.select(MoveId.TICKLE); game.move.select(MoveId.TICKLE);
@ -207,8 +207,8 @@ describe("Ability - Mirror Armor", () => {
game.override.ability(AbilityId.MIRROR_ARMOR); game.override.ability(AbilityId.MIRROR_ARMOR);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const userPokemon = game.scene.getPlayerPokemon()!; const userPokemon = game.field.getPlayerPokemon();
// Enemy uses octolock, player loses stats at end of turn // Enemy uses octolock, player loses stats at end of turn
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -225,8 +225,8 @@ describe("Ability - Mirror Armor", () => {
game.override.enemyAbility(AbilityId.MIRROR_ARMOR); game.override.enemyAbility(AbilityId.MIRROR_ARMOR);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const userPokemon = game.scene.getPlayerPokemon()!; const userPokemon = game.field.getPlayerPokemon();
// Player uses octolock, enemy loses stats at end of turn // Player uses octolock, enemy loses stats at end of turn
game.move.select(MoveId.OCTOLOCK); game.move.select(MoveId.OCTOLOCK);
@ -243,8 +243,8 @@ describe("Ability - Mirror Armor", () => {
game.override.enemyAbility(AbilityId.MIRROR_ARMOR).ability(AbilityId.MIRROR_ARMOR).ability(AbilityId.INTIMIDATE); game.override.enemyAbility(AbilityId.MIRROR_ARMOR).ability(AbilityId.MIRROR_ARMOR).ability(AbilityId.INTIMIDATE);
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const userPokemon = game.scene.getPlayerPokemon()!; const userPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.move.selectEnemyMove(MoveId.SPLASH, BattlerIndex.PLAYER); await game.move.selectEnemyMove(MoveId.SPLASH, BattlerIndex.PLAYER);
@ -258,8 +258,8 @@ describe("Ability - Mirror Armor", () => {
game.override.ability(AbilityId.MIRROR_ARMOR); game.override.ability(AbilityId.MIRROR_ARMOR);
await game.classicMode.startBattle([SpeciesId.BULBASAUR, SpeciesId.CHARMANDER, SpeciesId.SQUIRTLE]); await game.classicMode.startBattle([SpeciesId.BULBASAUR, SpeciesId.CHARMANDER, SpeciesId.SQUIRTLE]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const userPokemon = game.scene.getPlayerPokemon()!; const userPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.move.selectEnemyMove(MoveId.STICKY_WEB, BattlerIndex.PLAYER); await game.move.selectEnemyMove(MoveId.STICKY_WEB, BattlerIndex.PLAYER);

View File

@ -35,7 +35,7 @@ describe("Abilities - Moody", () => {
it("should increase one stat stage by 2 and decrease a different stat stage by 1", async () => { it("should increase one stat stage by 2 and decrease a different stat stage by 1", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.toNextTurn(); await game.toNextTurn();
@ -52,7 +52,7 @@ describe("Abilities - Moody", () => {
it("should only increase one stat stage by 2 if all stat stages are at -6", async () => { it("should only increase one stat stage by 2 if all stat stages are at -6", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
// Set all stat stages to -6 // Set all stat stages to -6
vi.spyOn(playerPokemon.summonData, "statStages", "get").mockReturnValue(new Array(BATTLE_STATS.length).fill(-6)); vi.spyOn(playerPokemon.summonData, "statStages", "get").mockReturnValue(new Array(BATTLE_STATS.length).fill(-6));
@ -70,7 +70,7 @@ describe("Abilities - Moody", () => {
it("should only decrease one stat stage by 1 stage if all stat stages are at 6", async () => { it("should only decrease one stat stage by 1 stage if all stat stages are at 6", async () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
// Set all stat stages to 6 // Set all stat stages to 6
vi.spyOn(playerPokemon.summonData, "statStages", "get").mockReturnValue(new Array(BATTLE_STATS.length).fill(6)); vi.spyOn(playerPokemon.summonData, "statStages", "get").mockReturnValue(new Array(BATTLE_STATS.length).fill(6));

View File

@ -41,7 +41,7 @@ describe("Abilities - Moxie", () => {
const moveToUse = MoveId.AERIAL_ACE; const moveToUse = MoveId.AERIAL_ACE;
await game.classicMode.startBattle([SpeciesId.MIGHTYENA, SpeciesId.MIGHTYENA]); await game.classicMode.startBattle([SpeciesId.MIGHTYENA, SpeciesId.MIGHTYENA]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
expect(playerPokemon.getStatStage(Stat.ATK)).toBe(0); expect(playerPokemon.getStatStage(Stat.ATK)).toBe(0);

View File

@ -37,7 +37,7 @@ describe("Abilities - Mummy", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(AbilityId.MUMMY); expect(game.field.getEnemyPokemon().getAbility().id).toBe(AbilityId.MUMMY);
}); });
it("should not change the enemy's ability hit by a non-contact move", async () => { it("should not change the enemy's ability hit by a non-contact move", async () => {
@ -47,6 +47,6 @@ describe("Abilities - Mummy", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(AbilityId.BALL_FETCH); expect(game.field.getEnemyPokemon().getAbility().id).toBe(AbilityId.BALL_FETCH);
}); });
}); });

View File

@ -42,12 +42,12 @@ describe("Abilities - Mycelium Might", () => {
* https://www.smogon.com/forums/threads/scarlet-violet-battle-mechanics-research.3709545/page-24 * https://www.smogon.com/forums/threads/scarlet-violet-battle-mechanics-research.3709545/page-24
*/ */
it("will move last in its priority bracket and ignore protective abilities", async () => { it("should move last in its priority bracket and ignore protective abilities", async () => {
await game.classicMode.startBattle([SpeciesId.REGIELEKI]); await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
const enemyPokemon = game.scene.getEnemyPokemon(); const enemyPokemon = game.field.getEnemyPokemon();
const playerIndex = game.scene.getPlayerPokemon()?.getBattlerIndex(); const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
const enemyIndex = enemyPokemon?.getBattlerIndex(); const enemyIndex = enemyPokemon.getBattlerIndex();
game.move.select(MoveId.BABY_DOLL_EYES); game.move.select(MoveId.BABY_DOLL_EYES);
@ -62,16 +62,16 @@ describe("Abilities - Mycelium Might", () => {
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
// Despite the opponent's ability (Clear Body), its ATK stat stage is still reduced. // Despite the opponent's ability (Clear Body), its ATK stat stage is still reduced.
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(-1); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(-1);
}); });
it("will still go first if a status move that is in a higher priority bracket than the opponent's move is used", async () => { it("should still go first if a status move that is in a higher priority bracket than the opponent's move is used", async () => {
game.override.enemyMoveset(MoveId.TACKLE); game.override.enemyMoveset(MoveId.TACKLE);
await game.classicMode.startBattle([SpeciesId.REGIELEKI]); await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
const enemyPokemon = game.scene.getEnemyPokemon(); const enemyPokemon = game.field.getEnemyPokemon();
const playerIndex = game.scene.getPlayerPokemon()?.getBattlerIndex(); const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
const enemyIndex = enemyPokemon?.getBattlerIndex(); const enemyIndex = enemyPokemon.getBattlerIndex();
game.move.select(MoveId.BABY_DOLL_EYES); game.move.select(MoveId.BABY_DOLL_EYES);
@ -85,14 +85,14 @@ describe("Abilities - Mycelium Might", () => {
expect(commandOrder).toEqual([playerIndex, enemyIndex]); expect(commandOrder).toEqual([playerIndex, enemyIndex]);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
// Despite the opponent's ability (Clear Body), its ATK stat stage is still reduced. // Despite the opponent's ability (Clear Body), its ATK stat stage is still reduced.
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(-1); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(-1);
}); });
it("will not affect non-status moves", async () => { it("should not affect non-status moves", async () => {
await game.classicMode.startBattle([SpeciesId.REGIELEKI]); await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); const enemyIndex = game.field.getEnemyPokemon().getBattlerIndex();
game.move.select(MoveId.QUICK_ATTACK); game.move.select(MoveId.QUICK_ATTACK);

View File

@ -46,7 +46,7 @@ describe("Abilities - Neutralizing Gas", () => {
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
// Intimidate is suppressed, so the attack stat should not be lowered // Intimidate is suppressed, so the attack stat should not be lowered
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.ATK)).toBe(0); expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(0);
}); });
it("should allow the user's passive to activate", async () => { it("should allow the user's passive to activate", async () => {
@ -56,7 +56,7 @@ describe("Abilities - Neutralizing Gas", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.ATK)).toBe(1); expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(1);
}); });
it.todo("should activate before other abilities", async () => { it.todo("should activate before other abilities", async () => {
@ -68,7 +68,7 @@ describe("Abilities - Neutralizing Gas", () => {
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
// Intimidate is suppressed even when the user's speed is lower // Intimidate is suppressed even when the user's speed is lower
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.ATK)).toBe(0); expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(0);
}); });
it("should activate other abilities when removed", async () => { it("should activate other abilities when removed", async () => {
@ -79,15 +79,15 @@ describe("Abilities - Neutralizing Gas", () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const enemyPokemon = game.scene.getEnemyPokemon(); const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(0); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(0);
expect(enemyPokemon?.getStatStage(Stat.DEF)).toBe(0); expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(0);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
// Enemy removes user's ability, so both abilities are activated // Enemy removes user's ability, so both abilities are activated
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(1); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
expect(enemyPokemon?.getStatStage(Stat.DEF)).toBe(1); expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(1);
}); });
it("should not activate the user's other ability when removed", async () => { it("should not activate the user's other ability when removed", async () => {
@ -95,13 +95,13 @@ describe("Abilities - Neutralizing Gas", () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
// Neutralising gas user's passive is still active // Neutralising gas user's passive is still active
const enemyPokemon = game.scene.getEnemyPokemon(); const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(-1); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(-1);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
// Intimidate did not reactivate after neutralizing gas was removed // Intimidate did not reactivate after neutralizing gas was removed
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(-1); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(-1);
}); });
it("should only deactivate when all setters are off the field", async () => { it("should only deactivate when all setters are off the field", async () => {
@ -164,7 +164,7 @@ describe("Abilities - Neutralizing Gas", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined(); expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined();
vi.spyOn(game.scene.getPlayerPokemon()!, "randBattleSeedInt").mockReturnValue(0); vi.spyOn(game.field.getPlayerPokemon(), "randBattleSeedInt").mockReturnValue(0);
vi.spyOn(globalScene, "randBattleSeedInt").mockReturnValue(0); vi.spyOn(globalScene, "randBattleSeedInt").mockReturnValue(0);
const commandPhase = game.scene.phaseManager.getCurrentPhase() as CommandPhase; const commandPhase = game.scene.phaseManager.getCurrentPhase() as CommandPhase;
@ -178,7 +178,7 @@ describe("Abilities - Neutralizing Gas", () => {
game.override.battleStyle("single").ability(AbilityId.NEUTRALIZING_GAS).enemyAbility(AbilityId.DELTA_STREAM); game.override.battleStyle("single").ability(AbilityId.NEUTRALIZING_GAS).enemyAbility(AbilityId.DELTA_STREAM);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
const weatherChangeAttr = enemy.getAbilityAttrs("PostSummonWeatherChangeAbAttr", false)[0]; const weatherChangeAttr = enemy.getAbilityAttrs("PostSummonWeatherChangeAbAttr", false)[0];
const weatherChangeSpy = vi.spyOn(weatherChangeAttr, "apply"); const weatherChangeSpy = vi.spyOn(weatherChangeAttr, "apply");
@ -186,7 +186,7 @@ describe("Abilities - Neutralizing Gas", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.killPokemon(enemy); await game.killPokemon(enemy);
await game.killPokemon(game.scene.getPlayerPokemon()!); await game.killPokemon(game.field.getPlayerPokemon());
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined(); expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
expect(weatherChangeSpy).not.toHaveBeenCalled(); expect(weatherChangeSpy).not.toHaveBeenCalled();

View File

@ -58,10 +58,10 @@ describe.each([
it(`should change Normal-type attacks to ${tyName} type and boost their power`, async () => { it(`should change Normal-type attacks to ${tyName} type and boost their power`, async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const typeSpy = vi.spyOn(playerPokemon, "getMoveType"); const typeSpy = vi.spyOn(playerPokemon, "getMoveType");
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const enemySpy = vi.spyOn(enemyPokemon, "getMoveEffectiveness"); const enemySpy = vi.spyOn(enemyPokemon, "getMoveEffectiveness");
const powerSpy = vi.spyOn(allMoves[MoveId.TACKLE], "calculateBattlePower"); const powerSpy = vi.spyOn(allMoves[MoveId.TACKLE], "calculateBattlePower");
@ -103,10 +103,10 @@ describe.each([
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const tySpy = vi.spyOn(playerPokemon, "getMoveType"); const tySpy = vi.spyOn(playerPokemon, "getMoveType");
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const enemyEffectivenessSpy = vi.spyOn(enemyPokemon, "getMoveEffectiveness"); const enemyEffectivenessSpy = vi.spyOn(enemyPokemon, "getMoveEffectiveness");
enemyPokemon.hp = Math.floor(enemyPokemon.getMaxHp() * 0.8); enemyPokemon.hp = Math.floor(enemyPokemon.getMaxHp() * 0.8);
@ -137,7 +137,7 @@ describe.each([
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const tySpy = vi.spyOn(playerPokemon, "getMoveType"); const tySpy = vi.spyOn(playerPokemon, "getMoveType");
game.move.select(move); game.move.select(move);
@ -149,10 +149,10 @@ describe.each([
it("should affect all hits of a Normal-type multi-hit move", async () => { it("should affect all hits of a Normal-type multi-hit move", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const tySpy = vi.spyOn(playerPokemon, "getMoveType"); const tySpy = vi.spyOn(playerPokemon, "getMoveType");
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.FURY_SWIPES); game.move.select(MoveId.FURY_SWIPES);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
@ -183,7 +183,7 @@ describe.each([
expect(boost, "power boost should be defined").toBeDefined(); expect(boost, "power boost should be defined").toBeDefined();
const powerSpy = vi.spyOn(testMoveInstance, "calculateBattlePower"); const powerSpy = vi.spyOn(testMoveInstance, "calculateBattlePower");
const typeSpy = vi.spyOn(game.scene.getPlayerPokemon()!, "getMoveType"); const typeSpy = vi.spyOn(game.field.getPlayerPokemon(), "getMoveType");
game.move.select(MoveId.TACKLE); game.move.select(MoveId.TACKLE);
await game.phaseInterceptor.to("BerryPhase", false); await game.phaseInterceptor.to("BerryPhase", false);
expect(typeSpy, "type was not changed").toHaveLastReturnedWith(ty); expect(typeSpy, "type was not changed").toHaveLastReturnedWith(ty);

View File

@ -39,14 +39,14 @@ describe("Abilities - Oblivious", () => {
.moveset(MoveId.SKILL_SWAP) .moveset(MoveId.SKILL_SWAP)
.enemyMoveset(MoveId.SPLASH); .enemyMoveset(MoveId.SPLASH);
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const enemy = game.scene.getEnemyPokemon(); const enemy = game.field.getEnemyPokemon();
enemy?.addTag(BattlerTagType.TAUNT); enemy.addTag(BattlerTagType.TAUNT);
expect(enemy?.getTag(BattlerTagType.TAUNT)).toBeTruthy(); expect(enemy.getTag(BattlerTagType.TAUNT)).toBeDefined();
game.move.select(MoveId.SKILL_SWAP); game.move.select(MoveId.SKILL_SWAP);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(enemy?.getTag(BattlerTagType.TAUNT)).toBeFalsy(); expect(enemy.getTag(BattlerTagType.TAUNT)).toBeUndefined();
}); });
it("should remove infatuation when gained", async () => { it("should remove infatuation when gained", async () => {
@ -56,14 +56,15 @@ describe("Abilities - Oblivious", () => {
.moveset(MoveId.SKILL_SWAP) .moveset(MoveId.SKILL_SWAP)
.enemyMoveset(MoveId.SPLASH); .enemyMoveset(MoveId.SPLASH);
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const enemy = game.scene.getEnemyPokemon();
vi.spyOn(enemy!, "isOppositeGender").mockReturnValue(true); const enemy = game.field.getEnemyPokemon();
enemy?.addTag(BattlerTagType.INFATUATED, 5, MoveId.JUDGMENT, game.scene.getPlayerPokemon()?.id); // sourceID needs to be defined vi.spyOn(enemy, "isOppositeGender").mockReturnValue(true);
expect(enemy?.getTag(BattlerTagType.INFATUATED)).toBeTruthy(); enemy.addTag(BattlerTagType.INFATUATED, 5, MoveId.JUDGMENT, game.field.getPlayerPokemon().id); // sourceID needs to be defined
expect(enemy.getTag(BattlerTagType.INFATUATED)).toBeTruthy();
game.move.select(MoveId.SKILL_SWAP); game.move.select(MoveId.SKILL_SWAP);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(enemy?.getTag(BattlerTagType.INFATUATED)).toBeFalsy(); expect(enemy.getTag(BattlerTagType.INFATUATED)).toBeFalsy();
}); });
}); });

View File

@ -42,8 +42,8 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
let enemyStartingHp = enemyPokemon.hp; let enemyStartingHp = enemyPokemon.hp;
@ -66,7 +66,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.POWER_UP_PUNCH); game.move.select(MoveId.POWER_UP_PUNCH);
@ -81,7 +81,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.BABY_DOLL_EYES); game.move.select(MoveId.BABY_DOLL_EYES);
@ -95,7 +95,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.DOUBLE_HIT); game.move.select(MoveId.DOUBLE_HIT);
await game.move.forceHit(); await game.move.forceHit();
@ -110,7 +110,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.SELF_DESTRUCT); game.move.select(MoveId.SELF_DESTRUCT);
@ -124,7 +124,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.ROLLOUT); game.move.select(MoveId.ROLLOUT);
await game.move.forceHit(); await game.move.forceHit();
@ -139,7 +139,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.DRAGON_RAGE); game.move.select(MoveId.DRAGON_RAGE);
await game.phaseInterceptor.to("BerryPhase", false); await game.phaseInterceptor.to("BerryPhase", false);
@ -152,8 +152,8 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.SHUCKLE]); await game.classicMode.startBattle([SpeciesId.SHUCKLE]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.COUNTER); game.move.select(MoveId.COUNTER);
await game.phaseInterceptor.to("DamageAnimPhase"); await game.phaseInterceptor.to("DamageAnimPhase");
@ -185,7 +185,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.EARTHQUAKE); game.move.select(MoveId.EARTHQUAKE);
await game.phaseInterceptor.to("DamageAnimPhase", false); await game.phaseInterceptor.to("DamageAnimPhase", false);
@ -199,7 +199,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.MIND_BLOWN); game.move.select(MoveId.MIND_BLOWN);
@ -218,8 +218,8 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.CHARIZARD]); await game.classicMode.startBattle([SpeciesId.CHARIZARD]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.BURN_UP); game.move.select(MoveId.BURN_UP);
@ -239,7 +239,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.HYPER_BEAM); game.move.select(MoveId.HYPER_BEAM);
await game.move.forceHit(); await game.move.forceHit();
@ -259,8 +259,8 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.ANCHOR_SHOT); game.move.select(MoveId.ANCHOR_SHOT);
await game.move.forceHit(); await game.move.forceHit();
@ -283,8 +283,8 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.SMACK_DOWN); game.move.select(MoveId.SMACK_DOWN);
await game.move.forceHit(); await game.move.forceHit();
@ -304,7 +304,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP, SpeciesId.BLASTOISE]); await game.classicMode.startBattle([SpeciesId.MAGIKARP, SpeciesId.BLASTOISE]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.U_TURN); game.move.select(MoveId.U_TURN);
await game.move.forceHit(); await game.move.forceHit();
@ -321,8 +321,8 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.WAKE_UP_SLAP); game.move.select(MoveId.WAKE_UP_SLAP);
await game.move.forceHit(); await game.move.forceHit();
@ -342,7 +342,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.TACKLE); game.move.select(MoveId.TACKLE);
@ -356,7 +356,7 @@ describe("Abilities - Parental Bond", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.WATER_GUN); game.move.select(MoveId.WATER_GUN);
@ -369,7 +369,7 @@ describe("Abilities - Parental Bond", () => {
game.override.enemyLevel(1000).moveset(MoveId.FUTURE_SIGHT); game.override.enemyLevel(1000).moveset(MoveId.FUTURE_SIGHT);
await game.classicMode.startBattle([SpeciesId.BULBASAUR, SpeciesId.CHARMANDER, SpeciesId.SQUIRTLE]); await game.classicMode.startBattle([SpeciesId.BULBASAUR, SpeciesId.CHARMANDER, SpeciesId.SQUIRTLE]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
vi.spyOn(enemyPokemon, "damageAndUpdate"); vi.spyOn(enemyPokemon, "damageAndUpdate");
game.move.select(MoveId.FUTURE_SIGHT); game.move.select(MoveId.FUTURE_SIGHT);

View File

@ -34,55 +34,55 @@ describe("Abilities - Perish Song", () => {
it("should trigger when hit with damaging move", async () => { it("should trigger when hit with damaging move", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const cursola = game.scene.getPlayerPokemon(); const cursola = game.field.getPlayerPokemon();
const magikarp = game.scene.getEnemyPokemon(); const magikarp = game.field.getEnemyPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.toNextTurn(); await game.toNextTurn();
expect(cursola?.summonData.tags[0].turnCount).toBe(3); expect(cursola.summonData.tags[0].turnCount).toBe(3);
expect(magikarp?.summonData.tags[0].turnCount).toBe(3); expect(magikarp.summonData.tags[0].turnCount).toBe(3);
}); });
it("should trigger even when fainting", async () => { it("should trigger even when fainting", async () => {
game.override.enemyLevel(100).startingLevel(1); game.override.enemyLevel(100).startingLevel(1);
await game.classicMode.startBattle([SpeciesId.CURSOLA, SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.CURSOLA, SpeciesId.FEEBAS]);
const magikarp = game.scene.getEnemyPokemon(); const magikarp = game.field.getEnemyPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
await game.toNextTurn(); await game.toNextTurn();
expect(magikarp?.summonData.tags[0].turnCount).toBe(3); expect(magikarp.summonData.tags[0].turnCount).toBe(3);
}); });
it("should not activate if attacker already has perish song", async () => { it("should not activate if attacker already has perish song", async () => {
game.override.enemyMoveset([MoveId.PERISH_SONG, MoveId.AQUA_JET, MoveId.SPLASH]); game.override.enemyMoveset([MoveId.PERISH_SONG, MoveId.AQUA_JET, MoveId.SPLASH]);
await game.classicMode.startBattle([SpeciesId.FEEBAS, SpeciesId.CURSOLA]); await game.classicMode.startBattle([SpeciesId.FEEBAS, SpeciesId.CURSOLA]);
const feebas = game.scene.getPlayerPokemon(); const feebas = game.field.getPlayerPokemon();
const magikarp = game.scene.getEnemyPokemon(); const magikarp = game.field.getEnemyPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.move.selectEnemyMove(MoveId.PERISH_SONG); await game.move.selectEnemyMove(MoveId.PERISH_SONG);
await game.toNextTurn(); await game.toNextTurn();
expect(feebas?.summonData.tags[0].turnCount).toBe(3); expect(feebas.summonData.tags[0].turnCount).toBe(3);
expect(magikarp?.summonData.tags[0].turnCount).toBe(3); expect(magikarp.summonData.tags[0].turnCount).toBe(3);
game.doSwitchPokemon(1); game.doSwitchPokemon(1);
await game.move.selectEnemyMove(MoveId.SPLASH); await game.move.selectEnemyMove(MoveId.SPLASH);
await game.toNextTurn(); await game.toNextTurn();
const cursola = game.scene.getPlayerPokemon(); const cursola = game.field.getPlayerPokemon();
expect(cursola?.summonData.tags.length).toBe(0); expect(cursola.summonData.tags.length).toBe(0);
expect(magikarp?.summonData.tags[0].turnCount).toBe(2); expect(magikarp.summonData.tags[0].turnCount).toBe(2);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.move.selectEnemyMove(MoveId.AQUA_JET); await game.move.selectEnemyMove(MoveId.AQUA_JET);
await game.toNextTurn(); await game.toNextTurn();
expect(cursola?.summonData.tags.length).toBe(0); expect(cursola.summonData.tags.length).toBe(0);
expect(magikarp?.summonData.tags[0].turnCount).toBe(1); expect(magikarp.summonData.tags[0].turnCount).toBe(1);
}); });
it("should activate if cursola already has perish song, but not reset its counter", async () => { it("should activate if cursola already has perish song, but not reset its counter", async () => {
@ -91,22 +91,22 @@ describe("Abilities - Perish Song", () => {
.moveset([MoveId.WHIRLWIND, MoveId.SPLASH]) .moveset([MoveId.WHIRLWIND, MoveId.SPLASH])
.startingWave(5); .startingWave(5);
await game.classicMode.startBattle([SpeciesId.CURSOLA]); await game.classicMode.startBattle([SpeciesId.CURSOLA]);
const cursola = game.scene.getPlayerPokemon(); const cursola = game.field.getPlayerPokemon();
game.move.select(MoveId.WHIRLWIND); game.move.select(MoveId.WHIRLWIND);
await game.move.selectEnemyMove(MoveId.PERISH_SONG); await game.move.selectEnemyMove(MoveId.PERISH_SONG);
await game.toNextTurn(); await game.toNextTurn();
const magikarp = game.scene.getEnemyPokemon(); const magikarp = game.field.getEnemyPokemon();
expect(cursola?.summonData.tags[0].turnCount).toBe(3); expect(cursola.summonData.tags[0].turnCount).toBe(3);
expect(magikarp?.summonData.tags.length).toBe(0); expect(magikarp.summonData.tags.length).toBe(0);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.move.selectEnemyMove(MoveId.AQUA_JET); await game.move.selectEnemyMove(MoveId.AQUA_JET);
await game.toNextTurn(); await game.toNextTurn();
expect(cursola?.summonData.tags[0].turnCount).toBe(2); expect(cursola.summonData.tags[0].turnCount).toBe(2);
expect(magikarp?.summonData.tags.length).toBe(1); expect(magikarp.summonData.tags.length).toBe(1);
expect(magikarp?.summonData.tags[0].turnCount).toBe(3); expect(magikarp.summonData.tags[0].turnCount).toBe(3);
}); });
}); });

View File

@ -42,10 +42,10 @@ describe("Abilities - Protosynthesis", () => {
.startingLevel(100) .startingLevel(100)
.enemyLevel(100); .enemyLevel(100);
await game.classicMode.startBattle([SpeciesId.MEW]); await game.classicMode.startBattle([SpeciesId.MEW]);
const mew = game.scene.getPlayerPokemon()!; const mew = game.field.getPlayerPokemon();
// Nature of starting mon is randomized. We need to fix it to a neutral nature for the automated test. // Nature of starting mon is randomized. We need to fix it to a neutral nature for the automated test.
mew.setNature(Nature.HARDY); mew.setNature(Nature.HARDY);
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
const def_before_boost = mew.getEffectiveStat( const def_before_boost = mew.getEffectiveStat(
Stat.DEF, Stat.DEF,
undefined, undefined,

View File

@ -43,8 +43,8 @@ describe("Abilities - Quick Draw", () => {
test("makes pokemon going first in its priority bracket", async () => { test("makes pokemon going first in its priority bracket", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const pokemon = game.scene.getPlayerPokemon()!; const pokemon = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
pokemon.hp = 1; pokemon.hp = 1;
enemy.hp = 1; enemy.hp = 1;
@ -65,8 +65,8 @@ describe("Abilities - Quick Draw", () => {
async () => { async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const pokemon = game.scene.getPlayerPokemon()!; const pokemon = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
pokemon.hp = 1; pokemon.hp = 1;
enemy.hp = 1; enemy.hp = 1;
@ -85,8 +85,8 @@ describe("Abilities - Quick Draw", () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const pokemon = game.scene.getPlayerPokemon()!; const pokemon = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
pokemon.hp = 1; pokemon.hp = 1;
enemy.hp = 1; enemy.hp = 1;

View File

@ -45,7 +45,7 @@ describe("Abilities - Sap Sipper", () => {
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const initialEnemyHp = enemyPokemon.hp; const initialEnemyHp = enemyPokemon.hp;
game.move.select(moveToUse); game.move.select(moveToUse);
@ -63,7 +63,7 @@ describe("Abilities - Sap Sipper", () => {
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(moveToUse); game.move.select(moveToUse);
@ -86,7 +86,7 @@ describe("Abilities - Sap Sipper", () => {
expect(game.scene.arena.terrain).toBeDefined(); expect(game.scene.arena.terrain).toBeDefined();
expect(game.scene.arena.terrain!.terrainType).toBe(TerrainType.GRASSY); expect(game.scene.arena.terrain!.terrainType).toBe(TerrainType.GRASSY);
expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.ATK)).toBe(0); expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(0);
}); });
it("activate once against multi-hit grass attacks", async () => { it("activate once against multi-hit grass attacks", async () => {
@ -96,7 +96,7 @@ describe("Abilities - Sap Sipper", () => {
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const initialEnemyHp = enemyPokemon.hp; const initialEnemyHp = enemyPokemon.hp;
game.move.select(moveToUse); game.move.select(moveToUse);
@ -114,7 +114,7 @@ describe("Abilities - Sap Sipper", () => {
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
game.move.select(moveToUse); game.move.select(moveToUse);
@ -140,7 +140,7 @@ describe("Abilities - Sap Sipper", () => {
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const initialEnemyHp = enemyPokemon.hp; const initialEnemyHp = enemyPokemon.hp;
game.move.select(moveToUse); game.move.select(moveToUse);
@ -156,7 +156,7 @@ describe("Abilities - Sap Sipper", () => {
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.LEAF_BLADE); game.move.select(MoveId.LEAF_BLADE);
await game.phaseInterceptor.to("MoveEffectPhase"); await game.phaseInterceptor.to("MoveEffectPhase");

View File

@ -38,8 +38,8 @@ describe("Abilities - Shield Dust", () => {
it("Shield Dust", async () => { it("Shield Dust", async () => {
await game.classicMode.startBattle([SpeciesId.PIDGEOT]); await game.classicMode.startBattle([SpeciesId.PIDGEOT]);
game.scene.getEnemyPokemon()!.stats[Stat.SPDEF] = 10000; game.field.getEnemyPokemon().stats[Stat.SPDEF] = 10000;
expect(game.scene.getPlayerPokemon()!.formIndex).toBe(0); expect(game.field.getPlayerPokemon().formIndex).toBe(0);
game.move.select(MoveId.AIR_SLASH); game.move.select(MoveId.AIR_SLASH);

View File

@ -66,7 +66,7 @@ describe("Abilities - SHIELDS DOWN", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.status).toBe(undefined); expect(game.field.getPlayerPokemon().status).toBe(undefined);
}); });
test("should still ignore non-volatile status moves used by a pokemon with mold breaker", async () => { test("should still ignore non-volatile status moves used by a pokemon with mold breaker", async () => {
@ -78,7 +78,7 @@ describe("Abilities - SHIELDS DOWN", () => {
await game.move.selectEnemyMove(MoveId.SPORE); await game.move.selectEnemyMove(MoveId.SPORE);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.status).toBe(undefined); expect(game.field.getPlayerPokemon().status).toBe(undefined);
}); });
test("should ignore non-volatile secondary status effects", async () => { test("should ignore non-volatile secondary status effects", async () => {
@ -89,7 +89,7 @@ describe("Abilities - SHIELDS DOWN", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.status).toBe(undefined); expect(game.field.getPlayerPokemon().status).toBe(undefined);
}); });
test("should ignore status moves even through mold breaker", async () => { test("should ignore status moves even through mold breaker", async () => {
@ -101,7 +101,7 @@ describe("Abilities - SHIELDS DOWN", () => {
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.status).toBe(undefined); expect(game.field.getPlayerPokemon().status).toBe(undefined);
}); });
// toxic spikes currently does not poison flying types when gravity is in effect // toxic spikes currently does not poison flying types when gravity is in effect
@ -122,9 +122,9 @@ describe("Abilities - SHIELDS DOWN", () => {
await game.move.selectEnemyMove(MoveId.SPLASH); await game.move.selectEnemyMove(MoveId.SPLASH);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(SpeciesId.MINIOR); expect(game.field.getPlayerPokemon().species.speciesId).toBe(SpeciesId.MINIOR);
expect(game.scene.getPlayerPokemon()!.species.formIndex).toBe(0); expect(game.field.getPlayerPokemon().species.formIndex).toBe(0);
expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.POISON); expect(game.field.getPlayerPokemon().status?.effect).toBe(StatusEffect.POISON);
}); });
test("should ignore yawn", async () => { test("should ignore yawn", async () => {
@ -136,7 +136,7 @@ describe("Abilities - SHIELDS DOWN", () => {
await game.move.selectEnemyMove(MoveId.YAWN); await game.move.selectEnemyMove(MoveId.YAWN);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.findTag(tag => tag.tagType === BattlerTagType.DROWSY)).toBe(undefined); expect(game.field.getPlayerPokemon().findTag(tag => tag.tagType === BattlerTagType.DROWSY)).toBe(undefined);
}); });
test("should not ignore volatile status effects", async () => { test("should not ignore volatile status effects", async () => {
@ -149,7 +149,7 @@ describe("Abilities - SHIELDS DOWN", () => {
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getPlayerPokemon()!.findTag(tag => tag.tagType === BattlerTagType.CONFUSED)).not.toBe(undefined); expect(game.field.getPlayerPokemon().findTag(tag => tag.tagType === BattlerTagType.CONFUSED)).not.toBe(undefined);
}); });
// the `NoTransformAbilityAbAttr` attribute is not checked anywhere, so this test cannot pass. // the `NoTransformAbilityAbAttr` attribute is not checked anywhere, so this test cannot pass.
@ -162,7 +162,7 @@ describe("Abilities - SHIELDS DOWN", () => {
await game.move.selectEnemyMove(MoveId.SPLASH); await game.move.selectEnemyMove(MoveId.SPLASH);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.SLEEP); expect(game.field.getEnemyPokemon().status?.effect).toBe(StatusEffect.SLEEP);
}); });
test("should not prevent minior from receiving the fainted status effect in trainer battles", async () => { test("should not prevent minior from receiving the fainted status effect in trainer battles", async () => {
@ -173,7 +173,7 @@ describe("Abilities - SHIELDS DOWN", () => {
.startingWave(5) .startingWave(5)
.enemySpecies(SpeciesId.MINIOR); .enemySpecies(SpeciesId.MINIOR);
await game.classicMode.startBattle([SpeciesId.REGIELEKI]); await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
const minior = game.scene.getEnemyPokemon()!; const minior = game.field.getEnemyPokemon();
game.move.select(MoveId.THUNDERBOLT); game.move.select(MoveId.THUNDERBOLT);
await game.toNextTurn(); await game.toNextTurn();

View File

@ -33,7 +33,7 @@ describe("Abilities - Simple", () => {
it("should double stat changes when applied", async () => { it("should double stat changes when applied", async () => {
await game.classicMode.startBattle([SpeciesId.SLOWBRO]); await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(-2); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(-2);
}); });

View File

@ -40,7 +40,7 @@ describe("Abilities - Speed Boost", () => {
it("should increase speed by 1 stage at end of turn", async () => { it("should increase speed by 1 stage at end of turn", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.toNextTurn(); await game.toNextTurn();
@ -53,7 +53,7 @@ describe("Abilities - Speed Boost", () => {
game.move.select(MoveId.U_TURN); game.move.select(MoveId.U_TURN);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
await game.toNextTurn(); await game.toNextTurn();
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -69,13 +69,13 @@ describe("Abilities - Speed Boost", () => {
game.move.select(MoveId.U_TURN); game.move.select(MoveId.U_TURN);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!).toBe(ninjask); expect(game.field.getPlayerPokemon()).toBe(ninjask);
expect(ninjask.getStatStage(Stat.SPD)).toBe(0); expect(ninjask.getStatStage(Stat.SPD)).toBe(0);
game.move.select(MoveId.U_TURN); game.move.select(MoveId.U_TURN);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!).toBe(shuckle); expect(game.field.getPlayerPokemon()).toBe(shuckle);
expect(shuckle.getStatStage(Stat.SPD)).toBe(0); expect(shuckle.getStatStage(Stat.SPD)).toBe(0);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -88,7 +88,7 @@ describe("Abilities - Speed Boost", () => {
game.doSwitchPokemon(1); game.doSwitchPokemon(1);
await game.toNextTurn(); await game.toNextTurn();
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -109,7 +109,7 @@ describe("Abilities - Speed Boost", () => {
await game.phaseInterceptor.to(AttemptRunPhase); await game.phaseInterceptor.to(AttemptRunPhase);
await game.toNextTurn(); await game.toNextTurn();
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);

View File

@ -40,8 +40,8 @@ describe("Abilities - Stall", () => {
it("Pokemon with Stall should move last in its priority bracket regardless of speed", async () => { it("Pokemon with Stall should move last in its priority bracket regardless of speed", async () => {
await game.classicMode.startBattle([SpeciesId.SHUCKLE]); await game.classicMode.startBattle([SpeciesId.SHUCKLE]);
const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); const enemyIndex = game.field.getEnemyPokemon().getBattlerIndex();
game.move.select(MoveId.QUICK_ATTACK); game.move.select(MoveId.QUICK_ATTACK);
@ -58,8 +58,8 @@ describe("Abilities - Stall", () => {
it("Pokemon with Stall will go first if a move that is in a higher priority bracket than the opponent's move is used", async () => { it("Pokemon with Stall will go first if a move that is in a higher priority bracket than the opponent's move is used", async () => {
await game.classicMode.startBattle([SpeciesId.SHUCKLE]); await game.classicMode.startBattle([SpeciesId.SHUCKLE]);
const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); const enemyIndex = game.field.getEnemyPokemon().getBattlerIndex();
game.move.select(MoveId.TACKLE); game.move.select(MoveId.TACKLE);
@ -77,8 +77,8 @@ describe("Abilities - Stall", () => {
game.override.ability(AbilityId.STALL); game.override.ability(AbilityId.STALL);
await game.classicMode.startBattle([SpeciesId.SHUCKLE]); await game.classicMode.startBattle([SpeciesId.SHUCKLE]);
const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex(); const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex(); const enemyIndex = game.field.getEnemyPokemon().getBattlerIndex();
game.move.select(MoveId.TACKLE); game.move.select(MoveId.TACKLE);

View File

@ -39,7 +39,7 @@ describe("Abilities - Steely Spirit", () => {
it("increases Steel-type moves' power used by the user and its allies by 50%", async () => { it("increases Steel-type moves' power used by the user and its allies by 50%", async () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU, SpeciesId.SHUCKLE]); await game.classicMode.startBattle([SpeciesId.PIKACHU, SpeciesId.SHUCKLE]);
const boostSource = game.scene.getPlayerField()[1]; const boostSource = game.scene.getPlayerField()[1];
const enemyToCheck = game.scene.getEnemyPokemon()!; const enemyToCheck = game.field.getEnemyPokemon();
vi.spyOn(boostSource, "getAbility").mockReturnValue(allAbilities[AbilityId.STEELY_SPIRIT]); vi.spyOn(boostSource, "getAbility").mockReturnValue(allAbilities[AbilityId.STEELY_SPIRIT]);
@ -54,7 +54,7 @@ describe("Abilities - Steely Spirit", () => {
it("stacks if multiple users with this ability are on the field.", async () => { it("stacks if multiple users with this ability are on the field.", async () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU, SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU, SpeciesId.PIKACHU]);
const enemyToCheck = game.scene.getEnemyPokemon()!; const enemyToCheck = game.field.getEnemyPokemon();
game.scene.getPlayerField().forEach(p => { game.scene.getPlayerField().forEach(p => {
vi.spyOn(p, "getAbility").mockReturnValue(allAbilities[AbilityId.STEELY_SPIRIT]); vi.spyOn(p, "getAbility").mockReturnValue(allAbilities[AbilityId.STEELY_SPIRIT]);
@ -74,7 +74,7 @@ describe("Abilities - Steely Spirit", () => {
it("does not take effect when suppressed", async () => { it("does not take effect when suppressed", async () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU, SpeciesId.SHUCKLE]); await game.classicMode.startBattle([SpeciesId.PIKACHU, SpeciesId.SHUCKLE]);
const boostSource = game.scene.getPlayerField()[1]; const boostSource = game.scene.getPlayerField()[1];
const enemyToCheck = game.scene.getEnemyPokemon()!; const enemyToCheck = game.field.getEnemyPokemon();
vi.spyOn(boostSource, "getAbility").mockReturnValue(allAbilities[AbilityId.STEELY_SPIRIT]); vi.spyOn(boostSource, "getAbility").mockReturnValue(allAbilities[AbilityId.STEELY_SPIRIT]);
expect(boostSource.hasAbility(AbilityId.STEELY_SPIRIT)).toBe(true); expect(boostSource.hasAbility(AbilityId.STEELY_SPIRIT)).toBe(true);

View File

@ -32,7 +32,7 @@ describe("Abilities - Super Luck", () => {
it("should increase the user's crit stage by 1", async () => { it("should increase the user's crit stage by 1", async () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
const critSpy = vi.spyOn(enemy, "getCritStage"); // crit stage is called on enemy const critSpy = vi.spyOn(enemy, "getCritStage"); // crit stage is called on enemy
game.move.select(MoveId.TACKLE); game.move.select(MoveId.TACKLE);

View File

@ -38,7 +38,7 @@ describe("Abilities - Synchronize", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.status).toBeUndefined(); expect(game.field.getPlayerPokemon().status).toBeUndefined();
expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase"); expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase");
}); });
@ -48,8 +48,8 @@ describe("Abilities - Synchronize", () => {
game.move.select(MoveId.THUNDER_WAVE); game.move.select(MoveId.THUNDER_WAVE);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS); expect(game.field.getPlayerPokemon().status?.effect).toBe(StatusEffect.PARALYSIS);
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS); expect(game.field.getEnemyPokemon().status?.effect).toBe(StatusEffect.PARALYSIS);
expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase"); expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase");
}); });
@ -60,8 +60,8 @@ describe("Abilities - Synchronize", () => {
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.status?.effect).toBeUndefined(); expect(game.field.getPlayerPokemon().status?.effect).toBeUndefined();
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.SLEEP); expect(game.field.getEnemyPokemon().status?.effect).toBe(StatusEffect.SLEEP);
expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase"); expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase");
}); });
@ -76,8 +76,8 @@ describe("Abilities - Synchronize", () => {
game.doSwitchPokemon(1); game.doSwitchPokemon(1);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.POISON); expect(game.field.getPlayerPokemon().status?.effect).toBe(StatusEffect.POISON);
expect(game.scene.getEnemyPokemon()!.status?.effect).toBeUndefined(); expect(game.field.getEnemyPokemon().status?.effect).toBeUndefined();
expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase"); expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase");
}); });
@ -87,8 +87,8 @@ describe("Abilities - Synchronize", () => {
game.move.select(MoveId.THUNDER_WAVE); game.move.select(MoveId.THUNDER_WAVE);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()!.status?.effect).toBeUndefined(); expect(game.field.getPlayerPokemon().status?.effect).toBeUndefined();
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS); expect(game.field.getEnemyPokemon().status?.effect).toBe(StatusEffect.PARALYSIS);
expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase"); expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase");
}); });
}); });

View File

@ -36,7 +36,7 @@ describe("Abilities - Tera Shell", () => {
it("should change the effectiveness of non-resisted attacks when the source is at full HP", async () => { it("should change the effectiveness of non-resisted attacks when the source is at full HP", async () => {
await game.classicMode.startBattle([SpeciesId.SNORLAX]); await game.classicMode.startBattle([SpeciesId.SNORLAX]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
vi.spyOn(playerPokemon, "getMoveEffectiveness"); vi.spyOn(playerPokemon, "getMoveEffectiveness");
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -57,7 +57,7 @@ describe("Abilities - Tera Shell", () => {
await game.classicMode.startBattle([SpeciesId.SNORLAX]); await game.classicMode.startBattle([SpeciesId.SNORLAX]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
vi.spyOn(playerPokemon, "getMoveEffectiveness"); vi.spyOn(playerPokemon, "getMoveEffectiveness");
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -71,7 +71,7 @@ describe("Abilities - Tera Shell", () => {
await game.classicMode.startBattle([SpeciesId.AGGRON]); await game.classicMode.startBattle([SpeciesId.AGGRON]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
vi.spyOn(playerPokemon, "getMoveEffectiveness"); vi.spyOn(playerPokemon, "getMoveEffectiveness");
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -85,7 +85,7 @@ describe("Abilities - Tera Shell", () => {
await game.classicMode.startBattle([SpeciesId.CHARIZARD]); await game.classicMode.startBattle([SpeciesId.CHARIZARD]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const spy = vi.spyOn(playerPokemon, "getMoveEffectiveness"); const spy = vi.spyOn(playerPokemon, "getMoveEffectiveness");
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -100,7 +100,7 @@ describe("Abilities - Tera Shell", () => {
await game.classicMode.startBattle([SpeciesId.SNORLAX]); await game.classicMode.startBattle([SpeciesId.SNORLAX]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const spy = vi.spyOn(playerPokemon, "getMoveEffectiveness"); const spy = vi.spyOn(playerPokemon, "getMoveEffectiveness");
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);

View File

@ -38,7 +38,7 @@ describe("Abilities - Trace", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(AbilityId.BALL_FETCH); expect(game.field.getPlayerPokemon().getAbility().id).toBe(AbilityId.BALL_FETCH);
}); });
it("should activate a copied post-summon ability", async () => { it("should activate a copied post-summon ability", async () => {
@ -48,6 +48,6 @@ describe("Abilities - Trace", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1); expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-1);
}); });
}); });

View File

@ -64,7 +64,7 @@ describe("Abilities - Unburden", () => {
game.override.enemyMoveset(MoveId.FALSE_SWIPE); game.override.enemyMoveset(MoveId.FALSE_SWIPE);
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const playerHeldItems = getHeldItemCount(playerPokemon); const playerHeldItems = getHeldItemCount(playerPokemon);
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
@ -80,7 +80,7 @@ describe("Abilities - Unburden", () => {
game.override.enemyMoveset(MoveId.FALSE_SWIPE).startingModifier([{ name: "BERRY_POUCH", count: 5850 }]); game.override.enemyMoveset(MoveId.FALSE_SWIPE).startingModifier([{ name: "BERRY_POUCH", count: 5850 }]);
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const playerHeldItems = getHeldItemCount(playerPokemon); const playerHeldItems = getHeldItemCount(playerPokemon);
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
@ -95,9 +95,9 @@ describe("Abilities - Unburden", () => {
it("should activate for the target, and not the stealer, when a berry is stolen", async () => { it("should activate for the target, and not the stealer, when a berry is stolen", async () => {
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const enemyHeldItemCt = getHeldItemCount(enemyPokemon); const enemyHeldItemCt = getHeldItemCount(enemyPokemon);
const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD);
@ -113,7 +113,7 @@ describe("Abilities - Unburden", () => {
it("should activate when an item is knocked off", async () => { it("should activate when an item is knocked off", async () => {
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const enemyHeldItemCt = getHeldItemCount(enemyPokemon); const enemyHeldItemCt = getHeldItemCount(enemyPokemon);
const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD);
@ -129,7 +129,7 @@ describe("Abilities - Unburden", () => {
game.override.ability(AbilityId.MAGICIAN).startingHeldItems([]); // Remove player's full stacks of held items so it can steal opponent's held items game.override.ability(AbilityId.MAGICIAN).startingHeldItems([]); // Remove player's full stacks of held items so it can steal opponent's held items
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const enemyHeldItemCt = getHeldItemCount(enemyPokemon); const enemyHeldItemCt = getHeldItemCount(enemyPokemon);
const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD);
@ -145,7 +145,7 @@ describe("Abilities - Unburden", () => {
game.override.enemyAbility(AbilityId.PICKPOCKET).enemyHeldItems([]); // Remove opponent's full stacks of held items so it can steal player's held items game.override.enemyAbility(AbilityId.PICKPOCKET).enemyHeldItems([]); // Remove opponent's full stacks of held items so it can steal player's held items
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const playerHeldItems = getHeldItemCount(playerPokemon); const playerHeldItems = getHeldItemCount(playerPokemon);
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
@ -161,7 +161,7 @@ describe("Abilities - Unburden", () => {
game.override.moveset(MoveId.THIEF).startingHeldItems([]); // Remove player's full stacks of held items so it can steal opponent's held items game.override.moveset(MoveId.THIEF).startingHeldItems([]); // Remove player's full stacks of held items so it can steal opponent's held items
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const enemyHeldItemCt = getHeldItemCount(enemyPokemon); const enemyHeldItemCt = getHeldItemCount(enemyPokemon);
const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD);
@ -177,11 +177,11 @@ describe("Abilities - Unburden", () => {
game.override.startingHeldItems([{ name: "GRIP_CLAW", count: 1 }]); game.override.startingHeldItems([{ name: "GRIP_CLAW", count: 1 }]);
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const gripClaw = playerPokemon.getHeldItems()[0] as ContactHeldItemTransferChanceModifier; const gripClaw = playerPokemon.getHeldItems()[0] as ContactHeldItemTransferChanceModifier;
vi.spyOn(gripClaw, "chance", "get").mockReturnValue(100); vi.spyOn(gripClaw, "chance", "get").mockReturnValue(100);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const enemyHeldItemCt = getHeldItemCount(enemyPokemon); const enemyHeldItemCt = getHeldItemCount(enemyPokemon);
const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD); const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD);
@ -197,7 +197,7 @@ describe("Abilities - Unburden", () => {
game.override.enemyAbility(AbilityId.NEUTRALIZING_GAS).enemyMoveset(MoveId.FALSE_SWIPE); game.override.enemyAbility(AbilityId.NEUTRALIZING_GAS).enemyMoveset(MoveId.FALSE_SWIPE);
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const playerHeldItems = getHeldItemCount(playerPokemon); const playerHeldItems = getHeldItemCount(playerPokemon);
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
@ -214,7 +214,7 @@ describe("Abilities - Unburden", () => {
game.override.moveset(MoveId.STUFF_CHEEKS); game.override.moveset(MoveId.STUFF_CHEEKS);
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const playerHeldItemCt = getHeldItemCount(playerPokemon); const playerHeldItemCt = getHeldItemCount(playerPokemon);
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
@ -292,7 +292,7 @@ describe("Abilities - Unburden", () => {
game.override.enemyMoveset([MoveId.FALSE_SWIPE, MoveId.WORRY_SEED]); game.override.enemyMoveset([MoveId.FALSE_SWIPE, MoveId.WORRY_SEED]);
await game.classicMode.startBattle([SpeciesId.PURRLOIN]); await game.classicMode.startBattle([SpeciesId.PURRLOIN]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const playerHeldItems = getHeldItemCount(playerPokemon); const playerHeldItems = getHeldItemCount(playerPokemon);
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
@ -317,7 +317,7 @@ describe("Abilities - Unburden", () => {
game.override.startingHeldItems([{ name: "REVIVER_SEED" }]).enemyMoveset([MoveId.WING_ATTACK]); game.override.startingHeldItems([{ name: "REVIVER_SEED" }]).enemyMoveset([MoveId.WING_ATTACK]);
await game.classicMode.startBattle([SpeciesId.TREECKO]); await game.classicMode.startBattle([SpeciesId.TREECKO]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const playerHeldItems = getHeldItemCount(playerPokemon); const playerHeldItems = getHeldItemCount(playerPokemon);
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD); const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
@ -334,7 +334,7 @@ describe("Abilities - Unburden", () => {
game.override.enemyMoveset([MoveId.SPLASH, MoveId.THIEF]); game.override.enemyMoveset([MoveId.SPLASH, MoveId.THIEF]);
await game.classicMode.startBattle([SpeciesId.TREECKO, SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.TREECKO, SpeciesId.FEEBAS]);
const treecko = game.scene.getPlayerPokemon()!; const treecko = game.field.getPlayerPokemon();
const treeckoInitialHeldItems = getHeldItemCount(treecko); const treeckoInitialHeldItems = getHeldItemCount(treecko);
const initialSpeed = treecko.getStat(Stat.SPD); const initialSpeed = treecko.getStat(Stat.SPD);
@ -348,7 +348,7 @@ describe("Abilities - Unburden", () => {
await game.move.selectEnemyMove(MoveId.SPLASH); await game.move.selectEnemyMove(MoveId.SPLASH);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!).toBe(treecko); expect(game.field.getPlayerPokemon()).toBe(treecko);
expect(getHeldItemCount(treecko)).toBeLessThan(treeckoInitialHeldItems); expect(getHeldItemCount(treecko)).toBeLessThan(treeckoInitialHeldItems);
expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialSpeed); expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialSpeed);
}); });

View File

@ -55,7 +55,7 @@ describe("Abilities - Unseen Fist", () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
enemyPokemon.addTag(BattlerTagType.SUBSTITUTE, 0, MoveId.NONE, enemyPokemon.id); enemyPokemon.addTag(BattlerTagType.SUBSTITUTE, 0, MoveId.NONE, enemyPokemon.id);
game.move.select(MoveId.TACKLE); game.move.select(MoveId.TACKLE);
@ -77,10 +77,10 @@ async function testUnseenFistHitResult(
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const leadPokemon = game.scene.getPlayerPokemon()!; const leadPokemon = game.field.getPlayerPokemon();
expect(leadPokemon).not.toBe(undefined); expect(leadPokemon).not.toBe(undefined);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon).not.toBe(undefined); expect(enemyPokemon).not.toBe(undefined);
const enemyStartingHp = enemyPokemon.hp; const enemyStartingHp = enemyPokemon.hp;

View File

@ -42,7 +42,7 @@ describe("Abilities - Volt Absorb", () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
game.move.select(moveToUse); game.move.select(moveToUse);
@ -62,7 +62,7 @@ describe("Abilities - Volt Absorb", () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.THUNDERBOLT); game.move.select(MoveId.THUNDERBOLT);
enemyPokemon.hp = enemyPokemon.hp - 1; enemyPokemon.hp = enemyPokemon.hp - 1;
@ -83,7 +83,7 @@ describe("Abilities - Volt Absorb", () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
game.move.select(MoveId.THUNDERBOLT); game.move.select(MoveId.THUNDERBOLT);
enemyPokemon.hp = enemyPokemon.hp - 1; enemyPokemon.hp = enemyPokemon.hp - 1;

View File

@ -38,8 +38,8 @@ describe("Abilities - Wandering Spirit", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(AbilityId.BALL_FETCH); expect(game.field.getPlayerPokemon().getAbility().id).toBe(AbilityId.BALL_FETCH);
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(AbilityId.WANDERING_SPIRIT); expect(game.field.getEnemyPokemon().getAbility().id).toBe(AbilityId.WANDERING_SPIRIT);
}); });
it("should not exchange abilities when hit with a non-contact move", async () => { it("should not exchange abilities when hit with a non-contact move", async () => {
@ -49,8 +49,8 @@ describe("Abilities - Wandering Spirit", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(AbilityId.WANDERING_SPIRIT); expect(game.field.getPlayerPokemon().getAbility().id).toBe(AbilityId.WANDERING_SPIRIT);
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(AbilityId.BALL_FETCH); expect(game.field.getEnemyPokemon().getAbility().id).toBe(AbilityId.BALL_FETCH);
}); });
it("should activate post-summon abilities", async () => { it("should activate post-summon abilities", async () => {
@ -60,6 +60,6 @@ describe("Abilities - Wandering Spirit", () => {
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1); expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-1);
}); });
}); });

View File

@ -70,7 +70,7 @@ describe("Abilities - Wimp Out", () => {
game.override.passiveAbility(AbilityId.REGENERATOR).startingLevel(5).enemyLevel(100); game.override.passiveAbility(AbilityId.REGENERATOR).startingLevel(5).enemyLevel(100);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
const wimpod = game.scene.getPlayerPokemon()!; const wimpod = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -84,7 +84,7 @@ describe("Abilities - Wimp Out", () => {
game.override.enemyAbility(AbilityId.WIMP_OUT); game.override.enemyAbility(AbilityId.WIMP_OUT);
await game.classicMode.startBattle([SpeciesId.GOLISOPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.GOLISOPOD, SpeciesId.TYRUNT]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
enemyPokemon.hp *= 0.52; enemyPokemon.hp *= 0.52;
game.move.select(MoveId.FALSE_SWIPE); game.move.select(MoveId.FALSE_SWIPE);
@ -97,7 +97,7 @@ describe("Abilities - Wimp Out", () => {
it("Does not trigger when HP already below half", async () => { it("Does not trigger when HP already below half", async () => {
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
const wimpod = game.scene.getPlayerPokemon()!; const wimpod = game.field.getPlayerPokemon();
wimpod.hp = 5; wimpod.hp = 5;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -117,7 +117,7 @@ describe("Abilities - Wimp Out", () => {
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase");
expect(game.scene.getPlayerPokemon()!.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); expect(game.field.getPlayerPokemon().getTag(BattlerTagType.TRAPPED)).toBeUndefined();
expect(game.scene.getPlayerParty()[1].getTag(BattlerTagType.TRAPPED)).toBeUndefined(); expect(game.scene.getPlayerParty()[1].getTag(BattlerTagType.TRAPPED)).toBeUndefined();
confirmSwitch(); confirmSwitch();
}); });
@ -130,7 +130,7 @@ describe("Abilities - Wimp Out", () => {
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const hasFled = enemyPokemon.switchOutStatus; const hasFled = enemyPokemon.switchOutStatus;
expect(hasFled).toBe(false); expect(hasFled).toBe(false);
confirmSwitch(); confirmSwitch();
@ -139,17 +139,17 @@ describe("Abilities - Wimp Out", () => {
it("If this Ability does not activate due to being hit by U-turn or Volt Switch, the user of that move will be switched out.", async () => { it("If this Ability does not activate due to being hit by U-turn or Volt Switch, the user of that move will be switched out.", async () => {
game.override.startingLevel(190).startingWave(8).enemyMoveset([MoveId.U_TURN]); game.override.startingLevel(190).startingWave(8).enemyMoveset([MoveId.U_TURN]);
await game.classicMode.startBattle([SpeciesId.GOLISOPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.GOLISOPOD, SpeciesId.TYRUNT]);
const RIVAL_NINJASK1 = game.scene.getEnemyPokemon()?.id; const RIVAL_NINJASK1 = game.field.getEnemyPokemon().id;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("BerryPhase", false); await game.phaseInterceptor.to("BerryPhase", false);
expect(game.scene.getEnemyPokemon()?.id !== RIVAL_NINJASK1); expect(game.field.getEnemyPokemon().id !== RIVAL_NINJASK1);
}); });
it("Dragon Tail and Circle Throw switch out Pokémon before the Ability activates.", async () => { it("Dragon Tail and Circle Throw switch out Pokémon before the Ability activates.", async () => {
game.override.startingLevel(69).enemyMoveset([MoveId.DRAGON_TAIL]); game.override.startingLevel(69).enemyMoveset([MoveId.DRAGON_TAIL]);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
const wimpod = game.scene.getPlayerPokemon()!; const wimpod = game.field.getPlayerPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -159,7 +159,7 @@ describe("Abilities - Wimp Out", () => {
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(game.scene.getPlayerPokemon()!.species.speciesId).not.toBe(SpeciesId.WIMPOD); expect(game.field.getPlayerPokemon().species.speciesId).not.toBe(SpeciesId.WIMPOD);
}); });
it("triggers when recoil damage is taken", async () => { it("triggers when recoil damage is taken", async () => {
@ -177,7 +177,7 @@ describe("Abilities - Wimp Out", () => {
game.override.moveset([MoveId.SUBSTITUTE]).enemyMoveset([MoveId.SPLASH]); game.override.moveset([MoveId.SUBSTITUTE]).enemyMoveset([MoveId.SPLASH]);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
const wimpod = game.scene.getPlayerPokemon()!; const wimpod = game.field.getPlayerPokemon();
wimpod.hp *= 0.52; wimpod.hp *= 0.52;
game.move.select(MoveId.SUBSTITUTE); game.move.select(MoveId.SUBSTITUTE);
@ -208,7 +208,7 @@ describe("Abilities - Wimp Out", () => {
.startingHeldItems([{ name: "SHELL_BELL", count: 4 }]); .startingHeldItems([{ name: "SHELL_BELL", count: 4 }]);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
const wimpod = game.scene.getPlayerPokemon()!; const wimpod = game.field.getPlayerPokemon();
wimpod.damageAndUpdate(toDmgValue(wimpod.getMaxHp() * 0.4)); wimpod.damageAndUpdate(toDmgValue(wimpod.getMaxHp() * 0.4));
@ -219,7 +219,7 @@ describe("Abilities - Wimp Out", () => {
expect(game.scene.getPlayerParty()[1]).toBe(wimpod); expect(game.scene.getPlayerParty()[1]).toBe(wimpod);
expect(wimpod.hp).toBeGreaterThan(toDmgValue(wimpod.getMaxHp() / 2)); expect(wimpod.hp).toBeGreaterThan(toDmgValue(wimpod.getMaxHp() / 2));
expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase");
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(SpeciesId.TYRUNT); expect(game.field.getPlayerPokemon().species.speciesId).toBe(SpeciesId.TYRUNT);
}, },
); );
@ -227,7 +227,7 @@ describe("Abilities - Wimp Out", () => {
game.override.weather(WeatherType.HAIL).enemyMoveset([MoveId.SPLASH]); game.override.weather(WeatherType.HAIL).enemyMoveset([MoveId.SPLASH]);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.51; game.field.getPlayerPokemon().hp *= 0.51;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -240,7 +240,7 @@ describe("Abilities - Wimp Out", () => {
game.override.enemyAbility(AbilityId.SHEER_FORCE).enemyMoveset(MoveId.SLUDGE_BOMB).startingLevel(95); game.override.enemyAbility(AbilityId.SHEER_FORCE).enemyMoveset(MoveId.SLUDGE_BOMB).startingLevel(95);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.51; game.field.getPlayerPokemon().hp *= 0.51;
game.move.select(MoveId.ENDURE); game.move.select(MoveId.ENDURE);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
@ -252,7 +252,7 @@ describe("Abilities - Wimp Out", () => {
game.override.statusEffect(StatusEffect.POISON).enemyMoveset([MoveId.SPLASH]); game.override.statusEffect(StatusEffect.POISON).enemyMoveset([MoveId.SPLASH]);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.51; game.field.getPlayerPokemon().hp *= 0.51;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -265,7 +265,7 @@ describe("Abilities - Wimp Out", () => {
game.override.statusEffect(StatusEffect.SLEEP).enemyAbility(AbilityId.BAD_DREAMS); game.override.statusEffect(StatusEffect.SLEEP).enemyAbility(AbilityId.BAD_DREAMS);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.52; game.field.getPlayerPokemon().hp *= 0.52;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -277,7 +277,7 @@ describe("Abilities - Wimp Out", () => {
it("Wimp Out will activate due to leech seed", async () => { it("Wimp Out will activate due to leech seed", async () => {
game.override.enemyMoveset([MoveId.LEECH_SEED]); game.override.enemyMoveset([MoveId.LEECH_SEED]);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.52; game.field.getPlayerPokemon().hp *= 0.52;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -289,7 +289,7 @@ describe("Abilities - Wimp Out", () => {
it("Wimp Out will activate due to curse damage", async () => { it("Wimp Out will activate due to curse damage", async () => {
game.override.enemySpecies(SpeciesId.DUSKNOIR).enemyMoveset([MoveId.CURSE]); game.override.enemySpecies(SpeciesId.DUSKNOIR).enemyMoveset([MoveId.CURSE]);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.52; game.field.getPlayerPokemon().hp *= 0.52;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -301,7 +301,7 @@ describe("Abilities - Wimp Out", () => {
it("Wimp Out will activate due to salt cure damage", async () => { it("Wimp Out will activate due to salt cure damage", async () => {
game.override.enemySpecies(SpeciesId.NACLI).enemyMoveset([MoveId.SALT_CURE]).enemyLevel(1); game.override.enemySpecies(SpeciesId.NACLI).enemyMoveset([MoveId.SALT_CURE]).enemyLevel(1);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.7; game.field.getPlayerPokemon().hp *= 0.7;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -313,7 +313,7 @@ describe("Abilities - Wimp Out", () => {
it("Wimp Out will activate due to damaging trap damage", async () => { it("Wimp Out will activate due to damaging trap damage", async () => {
game.override.enemySpecies(SpeciesId.MAGIKARP).enemyMoveset([MoveId.WHIRLPOOL]).enemyLevel(1); game.override.enemySpecies(SpeciesId.MAGIKARP).enemyMoveset([MoveId.WHIRLPOOL]).enemyLevel(1);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.55; game.field.getPlayerPokemon().hp *= 0.55;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -331,14 +331,14 @@ describe("Abilities - Wimp Out", () => {
.weather(WeatherType.HAIL) .weather(WeatherType.HAIL)
.statusEffect(StatusEffect.POISON); .statusEffect(StatusEffect.POISON);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.51; game.field.getPlayerPokemon().hp *= 0.51;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(game.scene.getPlayerParty()[0].getHpRatio()).toEqual(0.51); expect(game.scene.getPlayerParty()[0].getHpRatio()).toEqual(0.51);
expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase");
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(SpeciesId.WIMPOD); expect(game.field.getPlayerPokemon().species.speciesId).toBe(SpeciesId.WIMPOD);
}); });
it("Wimp Out activating should not cancel a double battle", async () => { it("Wimp Out activating should not cancel a double battle", async () => {
@ -369,7 +369,7 @@ describe("Abilities - Wimp Out", () => {
.enemyMoveset([MoveId.SPLASH]) .enemyMoveset([MoveId.SPLASH])
.enemyLevel(1); .enemyLevel(1);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.51; game.field.getPlayerPokemon().hp *= 0.51;
game.move.select(MoveId.THUNDER_PUNCH); game.move.select(MoveId.THUNDER_PUNCH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -391,7 +391,7 @@ describe("Abilities - Wimp Out", () => {
it("Wimp Out will activate due to Nightmare", async () => { it("Wimp Out will activate due to Nightmare", async () => {
game.override.enemyMoveset([MoveId.NIGHTMARE]).statusEffect(StatusEffect.SLEEP); game.override.enemyMoveset([MoveId.NIGHTMARE]).statusEffect(StatusEffect.SLEEP);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.65; game.field.getPlayerPokemon().hp *= 0.65;
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
@ -417,13 +417,13 @@ describe("Abilities - Wimp Out", () => {
game.override.enemyMoveset(MoveId.BULLET_SEED).enemyAbility(AbilityId.SKILL_LINK); game.override.enemyMoveset(MoveId.BULLET_SEED).enemyAbility(AbilityId.SKILL_LINK);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.51; game.field.getPlayerPokemon().hp *= 0.51;
game.move.select(MoveId.ENDURE); game.move.select(MoveId.ENDURE);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon.turnData.hitsLeft).toBe(0); expect(enemyPokemon.turnData.hitsLeft).toBe(0);
expect(enemyPokemon.turnData.hitCount).toBe(5); expect(enemyPokemon.turnData.hitCount).toBe(5);
confirmSwitch(); confirmSwitch();
@ -433,13 +433,13 @@ describe("Abilities - Wimp Out", () => {
game.override.enemyMoveset(MoveId.TACKLE).enemyHeldItems([{ name: "MULTI_LENS", count: 1 }]); game.override.enemyMoveset(MoveId.TACKLE).enemyHeldItems([{ name: "MULTI_LENS", count: 1 }]);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.51; game.field.getPlayerPokemon().hp *= 0.51;
game.move.select(MoveId.ENDURE); game.move.select(MoveId.ENDURE);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon.turnData.hitsLeft).toBe(0); expect(enemyPokemon.turnData.hitsLeft).toBe(0);
expect(enemyPokemon.turnData.hitCount).toBe(2); expect(enemyPokemon.turnData.hitCount).toBe(2);
confirmSwitch(); confirmSwitch();
@ -448,13 +448,13 @@ describe("Abilities - Wimp Out", () => {
game.override.enemyMoveset(MoveId.TACKLE).enemyAbility(AbilityId.PARENTAL_BOND); game.override.enemyMoveset(MoveId.TACKLE).enemyAbility(AbilityId.PARENTAL_BOND);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
game.scene.getPlayerPokemon()!.hp *= 0.51; game.field.getPlayerPokemon().hp *= 0.51;
game.move.select(MoveId.ENDURE); game.move.select(MoveId.ENDURE);
game.doSelectPartyPokemon(1); game.doSelectPartyPokemon(1);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon.turnData.hitsLeft).toBe(0); expect(enemyPokemon.turnData.hitsLeft).toBe(0);
expect(enemyPokemon.turnData.hitCount).toBe(2); expect(enemyPokemon.turnData.hitCount).toBe(2);
confirmSwitch(); confirmSwitch();
@ -466,7 +466,7 @@ describe("Abilities - Wimp Out", () => {
async () => { async () => {
game.override.moveset([MoveId.SWORDS_DANCE]).enemyMoveset([MoveId.SWAGGER]); game.override.moveset([MoveId.SWORDS_DANCE]).enemyMoveset([MoveId.SWAGGER]);
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]); await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
playerPokemon.hp *= 0.51; playerPokemon.hp *= 0.51;
playerPokemon.setStatStage(Stat.ATK, 6); playerPokemon.setStatStage(Stat.ATK, 6);
playerPokemon.addTag(BattlerTagType.CONFUSED); playerPokemon.addTag(BattlerTagType.CONFUSED);
@ -486,7 +486,7 @@ describe("Abilities - Wimp Out", () => {
game.override.enemyAbility(AbilityId.WIMP_OUT).startingLevel(5850).startingWave(10); game.override.enemyAbility(AbilityId.WIMP_OUT).startingLevel(5850).startingWave(10);
await game.classicMode.startBattle([SpeciesId.GOLISOPOD]); await game.classicMode.startBattle([SpeciesId.GOLISOPOD]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
// Use 2 turns of False Swipe due to opponent's health bar shield // Use 2 turns of False Swipe due to opponent's health bar shield
game.move.select(MoveId.FALSE_SWIPE); game.move.select(MoveId.FALSE_SWIPE);

View File

@ -33,7 +33,7 @@ describe("Abilities - Wind Power", () => {
it("becomes charged when hit by wind moves", async () => { it("becomes charged when hit by wind moves", async () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const shiftry = game.scene.getEnemyPokemon()!; const shiftry = game.field.getEnemyPokemon();
expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
@ -47,7 +47,7 @@ describe("Abilities - Wind Power", () => {
game.override.ability(AbilityId.WIND_POWER).enemySpecies(SpeciesId.MAGIKARP); game.override.ability(AbilityId.WIND_POWER).enemySpecies(SpeciesId.MAGIKARP);
await game.classicMode.startBattle([SpeciesId.SHIFTRY]); await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
const shiftry = game.scene.getPlayerPokemon()!; const shiftry = game.field.getPlayerPokemon();
expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
@ -61,8 +61,8 @@ describe("Abilities - Wind Power", () => {
game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_POWER); game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_POWER);
await game.classicMode.startBattle([SpeciesId.SHIFTRY]); await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
const magikarp = game.scene.getEnemyPokemon()!; const magikarp = game.field.getEnemyPokemon();
const shiftry = game.scene.getPlayerPokemon()!; const shiftry = game.field.getPlayerPokemon();
expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
expect(magikarp.getTag(BattlerTagType.CHARGED)).toBeUndefined(); expect(magikarp.getTag(BattlerTagType.CHARGED)).toBeUndefined();
@ -79,7 +79,7 @@ describe("Abilities - Wind Power", () => {
game.override.enemySpecies(SpeciesId.MAGIKARP); game.override.enemySpecies(SpeciesId.MAGIKARP);
await game.classicMode.startBattle([SpeciesId.SHIFTRY]); await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
const shiftry = game.scene.getPlayerPokemon()!; const shiftry = game.field.getPlayerPokemon();
expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();

View File

@ -32,7 +32,7 @@ describe("Abilities - Wind Rider", () => {
it("takes no damage from wind moves and its ATK stat stage is raised by 1 when hit by one", async () => { it("takes no damage from wind moves and its ATK stat stage is raised by 1 when hit by one", async () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const shiftry = game.scene.getEnemyPokemon()!; const shiftry = game.field.getEnemyPokemon();
expect(shiftry.getStatStage(Stat.ATK)).toBe(0); expect(shiftry.getStatStage(Stat.ATK)).toBe(0);
@ -48,7 +48,7 @@ describe("Abilities - Wind Rider", () => {
game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_RIDER); game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_RIDER);
await game.classicMode.startBattle([SpeciesId.SHIFTRY]); await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
const shiftry = game.scene.getPlayerPokemon()!; const shiftry = game.field.getPlayerPokemon();
expect(shiftry.getStatStage(Stat.ATK)).toBe(0); expect(shiftry.getStatStage(Stat.ATK)).toBe(0);
@ -63,8 +63,8 @@ describe("Abilities - Wind Rider", () => {
game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_RIDER); game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_RIDER);
await game.classicMode.startBattle([SpeciesId.SHIFTRY]); await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
const magikarp = game.scene.getEnemyPokemon()!; const magikarp = game.field.getEnemyPokemon();
const shiftry = game.scene.getPlayerPokemon()!; const shiftry = game.field.getPlayerPokemon();
expect(shiftry.getStatStage(Stat.ATK)).toBe(0); expect(shiftry.getStatStage(Stat.ATK)).toBe(0);
expect(magikarp.getStatStage(Stat.ATK)).toBe(0); expect(magikarp.getStatStage(Stat.ATK)).toBe(0);
@ -81,8 +81,8 @@ describe("Abilities - Wind Rider", () => {
game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_RIDER); game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_RIDER);
await game.classicMode.startBattle([SpeciesId.SHIFTRY]); await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
const magikarp = game.scene.getEnemyPokemon()!; const magikarp = game.field.getEnemyPokemon();
const shiftry = game.scene.getPlayerPokemon()!; const shiftry = game.field.getPlayerPokemon();
expect(shiftry.getStatStage(Stat.ATK)).toBe(0); expect(shiftry.getStatStage(Stat.ATK)).toBe(0);
expect(magikarp.getStatStage(Stat.ATK)).toBe(0); expect(magikarp.getStatStage(Stat.ATK)).toBe(0);
@ -99,7 +99,7 @@ describe("Abilities - Wind Rider", () => {
game.override.enemySpecies(SpeciesId.MAGIKARP); game.override.enemySpecies(SpeciesId.MAGIKARP);
await game.classicMode.startBattle([SpeciesId.SHIFTRY]); await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
const shiftry = game.scene.getPlayerPokemon()!; const shiftry = game.field.getPlayerPokemon();
expect(shiftry.getStatStage(Stat.ATK)).toBe(0); expect(shiftry.getStatStage(Stat.ATK)).toBe(0);
expect(shiftry.isFullHp()).toBe(true); expect(shiftry.isFullHp()).toBe(true);

View File

@ -38,7 +38,7 @@ describe("Abilities - ZEN MODE", () => {
it("shouldn't change form when taking damage if not dropping below 50% HP", async () => { it("shouldn't change form when taking damage if not dropping below 50% HP", async () => {
await game.classicMode.startBattle([SpeciesId.DARMANITAN]); await game.classicMode.startBattle([SpeciesId.DARMANITAN]);
const darmanitan = game.scene.getPlayerPokemon()!; const darmanitan = game.field.getPlayerPokemon();
expect(darmanitan.formIndex).toBe(baseForm); expect(darmanitan.formIndex).toBe(baseForm);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -52,7 +52,7 @@ describe("Abilities - ZEN MODE", () => {
it("should change form when falling below 50% HP", async () => { it("should change form when falling below 50% HP", async () => {
await game.classicMode.startBattle([SpeciesId.DARMANITAN]); await game.classicMode.startBattle([SpeciesId.DARMANITAN]);
const darmanitan = game.scene.getPlayerPokemon()!; const darmanitan = game.field.getPlayerPokemon();
darmanitan.hp = darmanitan.getMaxHp() / 2 + 1; darmanitan.hp = darmanitan.getMaxHp() / 2 + 1;
expect(darmanitan.formIndex).toBe(baseForm); expect(darmanitan.formIndex).toBe(baseForm);
@ -65,7 +65,7 @@ describe("Abilities - ZEN MODE", () => {
it("should stay zen mode when fainted", async () => { it("should stay zen mode when fainted", async () => {
await game.classicMode.startBattle([SpeciesId.DARMANITAN, SpeciesId.CHARIZARD]); await game.classicMode.startBattle([SpeciesId.DARMANITAN, SpeciesId.CHARIZARD]);
const darmanitan = game.scene.getPlayerPokemon()!; const darmanitan = game.field.getPlayerPokemon();
darmanitan.hp = darmanitan.getMaxHp() / 2 + 1; darmanitan.hp = darmanitan.getMaxHp() / 2 + 1;
expect(darmanitan.formIndex).toBe(baseForm); expect(darmanitan.formIndex).toBe(baseForm);

View File

@ -62,7 +62,7 @@ describe("Abilities - ZERO TO HERO", () => {
it("should swap to Hero form when switching out during a battle", async () => { it("should swap to Hero form when switching out during a battle", async () => {
await game.classicMode.startBattle([SpeciesId.PALAFIN, SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.PALAFIN, SpeciesId.FEEBAS]);
const palafin = game.scene.getPlayerPokemon()!; const palafin = game.field.getPlayerPokemon();
expect(palafin.formIndex).toBe(baseForm); expect(palafin.formIndex).toBe(baseForm);
game.doSwitchPokemon(1); game.doSwitchPokemon(1);
@ -73,7 +73,7 @@ describe("Abilities - ZERO TO HERO", () => {
it("should not swap to Hero form if switching due to faint", async () => { it("should not swap to Hero form if switching due to faint", async () => {
await game.classicMode.startBattle([SpeciesId.PALAFIN, SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.PALAFIN, SpeciesId.FEEBAS]);
const palafin = game.scene.getPlayerPokemon()!; const palafin = game.field.getPlayerPokemon();
expect(palafin.formIndex).toBe(baseForm); expect(palafin.formIndex).toBe(baseForm);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -90,7 +90,7 @@ describe("Abilities - ZERO TO HERO", () => {
await game.classicMode.startBattle([SpeciesId.PALAFIN, SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.PALAFIN, SpeciesId.FEEBAS]);
const palafin = game.scene.getPlayerPokemon()!; const palafin = game.field.getPlayerPokemon();
expect(palafin.formIndex).toBe(heroForm); expect(palafin.formIndex).toBe(heroForm);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);

View File

@ -84,7 +84,7 @@ describe("Arena - Gravity", () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const pidgeot = game.scene.getEnemyPokemon()!; const pidgeot = game.field.getEnemyPokemon();
vi.spyOn(pidgeot, "getAttackTypeEffectiveness"); vi.spyOn(pidgeot, "getAttackTypeEffectiveness");
// Try earthquake on 1st turn (fails!); // Try earthquake on 1st turn (fails!);
@ -113,7 +113,7 @@ describe("Arena - Gravity", () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const pidgeot = game.scene.getEnemyPokemon()!; const pidgeot = game.field.getEnemyPokemon();
vi.spyOn(pidgeot, "getAttackTypeEffectiveness"); vi.spyOn(pidgeot, "getAttackTypeEffectiveness");
// Setup Gravity on 1st turn // Setup Gravity on 1st turn
@ -136,8 +136,8 @@ describe("Arena - Gravity", () => {
await game.classicMode.startBattle([SpeciesId.CHARIZARD]); await game.classicMode.startBattle([SpeciesId.CHARIZARD]);
const charizard = game.scene.getPlayerPokemon()!; const charizard = game.field.getPlayerPokemon();
const snorlax = game.scene.getEnemyPokemon()!; const snorlax = game.field.getEnemyPokemon();
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);

View File

@ -42,7 +42,7 @@ describe("Arena - Psychic Terrain", () => {
game.move.select(MoveId.DARK_VOID); game.move.select(MoveId.DARK_VOID);
await game.toEndOfTurn(); await game.toEndOfTurn();
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.SLEEP); expect(game.field.getEnemyPokemon().status?.effect).toBe(StatusEffect.SLEEP);
}); });
it("Rain Dance with Prankster is not blocked", async () => { it("Rain Dance with Prankster is not blocked", async () => {

View File

@ -52,8 +52,8 @@ describe("Weather - Hail", () => {
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp()); expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp());
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp() - Math.max(Math.floor(enemyPokemon.getMaxHp() / 16), 1)); expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp() - Math.max(Math.floor(enemyPokemon.getMaxHp() / 16), 1));
@ -66,8 +66,8 @@ describe("Weather - Hail", () => {
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp()); expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp());
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp() - Math.max(Math.floor(enemyPokemon.getMaxHp() / 16), 1)); expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp() - Math.max(Math.floor(enemyPokemon.getMaxHp() / 16), 1));

View File

@ -51,8 +51,8 @@ describe("Weather - Sandstorm", () => {
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp()); expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp());
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp() - Math.max(Math.floor(enemyPokemon.getMaxHp() / 16), 1)); expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp() - Math.max(Math.floor(enemyPokemon.getMaxHp() / 16), 1));
@ -80,11 +80,11 @@ describe("Weather - Sandstorm", () => {
it("increases Rock type Pokemon Sp.Def by 50%", async () => { it("increases Rock type Pokemon Sp.Def by 50%", async () => {
await game.classicMode.startBattle([SpeciesId.ROCKRUFF]); await game.classicMode.startBattle([SpeciesId.ROCKRUFF]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const playerSpdef = playerPokemon.getStat(Stat.SPDEF); const playerSpdef = playerPokemon.getStat(Stat.SPDEF);
expect(playerPokemon.getEffectiveStat(Stat.SPDEF)).toBe(Math.floor(playerSpdef * 1.5)); expect(playerPokemon.getEffectiveStat(Stat.SPDEF)).toBe(Math.floor(playerSpdef * 1.5));
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const enemySpdef = enemyPokemon.getStat(Stat.SPDEF); const enemySpdef = enemyPokemon.getStat(Stat.SPDEF);
expect(enemyPokemon.getEffectiveStat(Stat.SPDEF)).toBe(enemySpdef); expect(enemyPokemon.getEffectiveStat(Stat.SPDEF)).toBe(enemySpdef);
}); });

View File

@ -36,8 +36,8 @@ describe("Weather - Strong Winds", () => {
game.override.enemySpecies(SpeciesId.RAYQUAZA); game.override.enemySpecies(SpeciesId.RAYQUAZA);
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.THUNDERBOLT); game.move.select(MoveId.THUNDERBOLT);
@ -47,8 +47,8 @@ describe("Weather - Strong Winds", () => {
it("electric type move is neutral for flying type pokemon", async () => { it("electric type move is neutral for flying type pokemon", async () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.THUNDERBOLT); game.move.select(MoveId.THUNDERBOLT);
@ -58,8 +58,8 @@ describe("Weather - Strong Winds", () => {
it("ice type move is neutral for flying type pokemon", async () => { it("ice type move is neutral for flying type pokemon", async () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.ICE_BEAM); game.move.select(MoveId.ICE_BEAM);
@ -69,8 +69,8 @@ describe("Weather - Strong Winds", () => {
it("rock type move is neutral for flying type pokemon", async () => { it("rock type move is neutral for flying type pokemon", async () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!; const pikachu = game.field.getPlayerPokemon();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.ROCK_SLIDE); game.move.select(MoveId.ROCK_SLIDE);
@ -83,7 +83,7 @@ describe("Weather - Strong Winds", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
enemy.hp = 1; enemy.hp = 1;
game.move.use(MoveId.SPLASH); game.move.use(MoveId.SPLASH);

View File

@ -37,10 +37,10 @@ describe("Test Ability Swapping", () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.scene.getPlayerPokemon()?.setTempAbility(allAbilities[AbilityId.INTIMIDATE]); game.field.getPlayerPokemon().setTempAbility(allAbilities[AbilityId.INTIMIDATE]);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1); expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-1);
}); });
it("should remove primal weather when the setter's ability is removed", async () => { it("should remove primal weather when the setter's ability is removed", async () => {
@ -48,7 +48,7 @@ describe("Test Ability Swapping", () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.scene.getPlayerPokemon()?.setTempAbility(allAbilities[AbilityId.BALL_FETCH]); game.field.getPlayerPokemon().setTempAbility(allAbilities[AbilityId.BALL_FETCH]);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.arena.weather?.weatherType).toBeUndefined(); expect(game.scene.arena.weather?.weatherType).toBeUndefined();
@ -59,10 +59,10 @@ describe("Test Ability Swapping", () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
game.scene.getPlayerPokemon()?.setTempAbility(allAbilities[AbilityId.BALL_FETCH]); game.field.getPlayerPokemon().setTempAbility(allAbilities[AbilityId.BALL_FETCH]);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.ATK)).toBe(1); // would be 2 if passive activated again expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(1); // would be 2 if passive activated again
}); });
// Pickup and Honey Gather are special cases as they're the only abilities to be Unsuppressable but not Unswappable // Pickup and Honey Gather are special cases as they're the only abilities to be Unsuppressable but not Unswappable
@ -73,6 +73,6 @@ describe("Test Ability Swapping", () => {
game.move.select(MoveId.ROLE_PLAY); game.move.select(MoveId.ROLE_PLAY);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1); expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-1);
}); });
}); });

View File

@ -35,8 +35,8 @@ describe("Battle order", () => {
it("opponent faster than player 50 vs 150", async () => { it("opponent faster than player 50 vs 150", async () => {
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 50]); // set playerPokemon's speed to 50 vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 50]); // set playerPokemon's speed to 50
vi.spyOn(enemyPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 150]); // set enemyPokemon's speed to 150 vi.spyOn(enemyPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 150]); // set enemyPokemon's speed to 150
@ -54,8 +54,8 @@ describe("Battle order", () => {
it("Player faster than opponent 150 vs 50", async () => { it("Player faster than opponent 150 vs 50", async () => {
await game.classicMode.startBattle([SpeciesId.BULBASAUR]); await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 150]); // set playerPokemon's speed to 150 vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 150]); // set playerPokemon's speed to 150
vi.spyOn(enemyPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 50]); // set enemyPokemon's speed to 50 vi.spyOn(enemyPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 50]); // set enemyPokemon's speed to 50

View File

@ -293,7 +293,7 @@ describe("Phase - Battle Phase", () => {
.startingHeldItems([{ name: "TEMP_STAT_STAGE_BOOSTER", type: Stat.ACC }]); .startingHeldItems([{ name: "TEMP_STAT_STAGE_BOOSTER", type: Stat.ACC }]);
await game.classicMode.startBattle(); await game.classicMode.startBattle();
game.scene.getPlayerPokemon()!.hp = 1; game.field.getPlayerPokemon().hp = 1;
game.move.select(moveToUse); game.move.select(moveToUse);
await game.phaseInterceptor.to(BattleEndPhase); await game.phaseInterceptor.to(BattleEndPhase);

View File

@ -38,10 +38,10 @@ describe("Battle Mechanics - Damage Calculation", () => {
it("Tackle deals expected base damage", async () => { it("Tackle deals expected base damage", async () => {
await game.classicMode.startBattle([SpeciesId.CHARIZARD]); await game.classicMode.startBattle([SpeciesId.CHARIZARD]);
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
vi.spyOn(playerPokemon, "getEffectiveStat").mockReturnValue(80); vi.spyOn(playerPokemon, "getEffectiveStat").mockReturnValue(80);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
vi.spyOn(enemyPokemon, "getEffectiveStat").mockReturnValue(90); vi.spyOn(enemyPokemon, "getEffectiveStat").mockReturnValue(90);
// expected base damage = [(2*level/5 + 2) * power * playerATK / enemyDEF / 50] + 2 // expected base damage = [(2*level/5 + 2) * power * playerATK / enemyDEF / 50] + 2
@ -56,7 +56,7 @@ describe("Battle Mechanics - Damage Calculation", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const aggron = game.scene.getEnemyPokemon()!; const aggron = game.field.getEnemyPokemon();
game.move.select(MoveId.TACKLE); game.move.select(MoveId.TACKLE);
@ -75,7 +75,7 @@ describe("Battle Mechanics - Damage Calculation", () => {
dmg_redux_modifier.stackCount = 1000; dmg_redux_modifier.stackCount = 1000;
await game.scene.addEnemyModifier(modifierTypes.ENEMY_DAMAGE_REDUCTION().newModifier() as EnemyPersistentModifier); await game.scene.addEnemyModifier(modifierTypes.ENEMY_DAMAGE_REDUCTION().newModifier() as EnemyPersistentModifier);
const aggron = game.scene.getEnemyPokemon()!; const aggron = game.field.getEnemyPokemon();
game.move.select(MoveId.TACKLE); game.move.select(MoveId.TACKLE);
@ -89,8 +89,8 @@ describe("Battle Mechanics - Damage Calculation", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const magikarp = game.scene.getPlayerPokemon()!; const magikarp = game.field.getPlayerPokemon();
const dragonite = game.scene.getEnemyPokemon()!; const dragonite = game.field.getEnemyPokemon();
expect(dragonite.getAttackDamage({ source: magikarp, move: allMoves[MoveId.DRAGON_RAGE] }).damage).toBe(40); expect(dragonite.getAttackDamage({ source: magikarp, move: allMoves[MoveId.DRAGON_RAGE] }).damage).toBe(40);
}); });
@ -100,8 +100,8 @@ describe("Battle Mechanics - Damage Calculation", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const magikarp = game.scene.getPlayerPokemon()!; const magikarp = game.field.getPlayerPokemon();
const aggron = game.scene.getEnemyPokemon()!; const aggron = game.field.getEnemyPokemon();
expect(aggron.getAttackDamage({ source: magikarp, move: allMoves[MoveId.FISSURE] }).damage).toBe(aggron.hp); expect(aggron.getAttackDamage({ source: magikarp, move: allMoves[MoveId.FISSURE] }).damage).toBe(aggron.hp);
}); });
@ -111,7 +111,7 @@ describe("Battle Mechanics - Damage Calculation", () => {
await game.classicMode.startBattle([SpeciesId.SHEDINJA]); await game.classicMode.startBattle([SpeciesId.SHEDINJA]);
const shedinja = game.scene.getPlayerPokemon()!; const shedinja = game.field.getPlayerPokemon();
game.move.select(MoveId.JUMP_KICK); game.move.select(MoveId.JUMP_KICK);
@ -126,7 +126,7 @@ describe("Battle Mechanics - Damage Calculation", () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const charizard = game.scene.getEnemyPokemon()!; const charizard = game.field.getEnemyPokemon();
if (charizard.getMaxHp() % 2 === 1) { if (charizard.getMaxHp() % 2 === 1) {
expect(charizard.hp).toBeGreaterThan(charizard.getMaxHp() / 2); expect(charizard.hp).toBeGreaterThan(charizard.getMaxHp() / 2);

View File

@ -43,7 +43,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "getMoveEffectiveness"); vi.spyOn(enemy, "getMoveEffectiveness");
game.move.select(MoveId.THUNDERBOLT); game.move.select(MoveId.THUNDERBOLT);
@ -58,7 +58,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "getMoveEffectiveness"); vi.spyOn(enemy, "getMoveEffectiveness");
game.move.select(MoveId.THUNDERBOLT); game.move.select(MoveId.THUNDERBOLT);
@ -73,7 +73,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "getMoveEffectiveness"); vi.spyOn(enemy, "getMoveEffectiveness");
game.move.select(MoveId.THUNDERBOLT); game.move.select(MoveId.THUNDERBOLT);
@ -89,7 +89,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const charizard = game.scene.getEnemyPokemon()!; const charizard = game.field.getEnemyPokemon();
const maxHp = charizard.getMaxHp(); const maxHp = charizard.getMaxHp();
const damage_prediction = Math.max(Math.round(charizard.getMaxHp() / 32), 1); const damage_prediction = Math.max(Math.round(charizard.getMaxHp() / 32), 1);
@ -111,7 +111,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "getMoveEffectiveness"); vi.spyOn(enemy, "getMoveEffectiveness");
game.move.select(MoveId.FREEZE_DRY); game.move.select(MoveId.FREEZE_DRY);
@ -126,7 +126,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
enemy.hp = enemy.getMaxHp() - 1; enemy.hp = enemy.getMaxHp() - 1;
game.move.select(MoveId.WATER_GUN); game.move.select(MoveId.WATER_GUN);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
@ -140,7 +140,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.WILL_O_WISP); game.move.select(MoveId.WILL_O_WISP);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
@ -155,7 +155,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.NUZZLE); game.move.select(MoveId.NUZZLE);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
@ -169,7 +169,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
game.move.select(MoveId.THUNDER_WAVE); game.move.select(MoveId.THUNDER_WAVE);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
@ -184,7 +184,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
expect(game.scene.getEnemyPokemon()?.waveData.abilitiesApplied).toContain(AbilityId.ANTICIPATION); expect(game.field.getEnemyPokemon().waveData.abilitiesApplied).toContain(AbilityId.ANTICIPATION);
}); });
it("Conversion 2 should change the type to the resistive type - Conversion 2 against Dragonite", async () => { it("Conversion 2 should change the type to the resistive type - Conversion 2 against Dragonite", async () => {
@ -192,7 +192,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
game.move.select(MoveId.CONVERSION_2); game.move.select(MoveId.CONVERSION_2);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
@ -207,7 +207,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "getMoveEffectiveness"); vi.spyOn(enemy, "getMoveEffectiveness");
game.move.select(MoveId.FLYING_PRESS); game.move.select(MoveId.FLYING_PRESS);
@ -222,7 +222,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "getMoveEffectiveness"); vi.spyOn(enemy, "getMoveEffectiveness");
game.move.select(MoveId.TACKLE); game.move.select(MoveId.TACKLE);
@ -237,7 +237,7 @@ describe("Inverse Battle", () => {
await game.challengeMode.startBattle(); await game.challengeMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.field.getEnemyPokemon();
vi.spyOn(enemy, "getMoveEffectiveness"); vi.spyOn(enemy, "getMoveEffectiveness");
game.move.select(MoveId.FORESIGHT); game.move.select(MoveId.FORESIGHT);

View File

@ -80,7 +80,7 @@ describe("Boss Pokemon / Shields", () => {
await game.classicMode.startBattle([SpeciesId.MEWTWO]); await game.classicMode.startBattle([SpeciesId.MEWTWO]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
const segmentHp = enemyPokemon.getMaxHp() / enemyPokemon.bossSegments; const segmentHp = enemyPokemon.getMaxHp() / enemyPokemon.bossSegments;
expect(enemyPokemon.isBoss()).toBe(true); expect(enemyPokemon.isBoss()).toBe(true);
expect(enemyPokemon.bossSegments).toBe(3); expect(enemyPokemon.bossSegments).toBe(3);
@ -191,7 +191,7 @@ describe("Boss Pokemon / Shields", () => {
await game.classicMode.startBattle([SpeciesId.MEWTWO]); await game.classicMode.startBattle([SpeciesId.MEWTWO]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
expect(enemyPokemon.isBoss()).toBe(true); expect(enemyPokemon.isBoss()).toBe(true);
expect(enemyPokemon.bossSegments).toBe(2); expect(enemyPokemon.bossSegments).toBe(2);
expect(getTotalStatStageBoosts(enemyPokemon)).toBe(0); expect(getTotalStatStageBoosts(enemyPokemon)).toBe(0);

View File

@ -331,8 +331,8 @@ describe("Status Effects", () => {
await game.move.forceStatusActivation(true); await game.move.forceStatusActivation(true);
await game.toNextTurn(); await game.toNextTurn();
expect(game.scene.getEnemyPokemon()!.isFullHp()).toBe(true); expect(game.field.getEnemyPokemon().isFullHp()).toBe(true);
expect(game.scene.getPlayerPokemon()!.getLastXMoves(1)[0].result).toBe(MoveResult.FAIL); expect(game.field.getPlayerPokemon().getLastXMoves(1)[0].result).toBe(MoveResult.FAIL);
}); });
}); });
@ -365,7 +365,7 @@ describe("Status Effects", () => {
it("should last the appropriate number of turns", async () => { it("should last the appropriate number of turns", async () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]); await game.classicMode.startBattle([SpeciesId.FEEBAS]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
player.status = new Status(StatusEffect.SLEEP, 0, 4); player.status = new Status(StatusEffect.SLEEP, 0, 4);
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -422,7 +422,7 @@ describe("Status Effects", () => {
it("should not inflict a 0 HP mon with a status", async () => { it("should not inflict a 0 HP mon with a status", async () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS, SpeciesId.MILOTIC]); await game.classicMode.startBattle([SpeciesId.FEEBAS, SpeciesId.MILOTIC]);
const player = game.scene.getPlayerPokemon()!; const player = game.field.getPlayerPokemon();
player.hp = 0; player.hp = 0;
expect(player.trySetStatus(StatusEffect.BURN)).toBe(false); expect(player.trySetStatus(StatusEffect.BURN)).toBe(false);

View File

@ -34,10 +34,10 @@ describe("Endless Boss", () => {
expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Minor); expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Minor);
expect(game.scene.arena.biomeType).toBe(BiomeId.END); expect(game.scene.arena.biomeType).toBe(BiomeId.END);
const eternatus = game.scene.getEnemyPokemon(); const eternatus = game.field.getEnemyPokemon();
expect(eternatus?.species.speciesId).toBe(SpeciesId.ETERNATUS); expect(eternatus.species.speciesId).toBe(SpeciesId.ETERNATUS);
expect(eternatus?.hasPassive()).toBe(false); expect(eternatus.hasPassive()).toBe(false);
expect(eternatus?.formIndex).toBe(0); expect(eternatus.formIndex).toBe(0);
}); });
it(`should spawn a major boss every ${EndlessBossWave.Major} waves in END biome in Endless`, async () => { it(`should spawn a major boss every ${EndlessBossWave.Major} waves in END biome in Endless`, async () => {
@ -46,10 +46,10 @@ describe("Endless Boss", () => {
expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Major); expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Major);
expect(game.scene.arena.biomeType).toBe(BiomeId.END); expect(game.scene.arena.biomeType).toBe(BiomeId.END);
const eternatus = game.scene.getEnemyPokemon(); const eternatus = game.field.getEnemyPokemon();
expect(eternatus?.species.speciesId).toBe(SpeciesId.ETERNATUS); expect(eternatus.species.speciesId).toBe(SpeciesId.ETERNATUS);
expect(eternatus?.hasPassive()).toBe(false); expect(eternatus.hasPassive()).toBe(false);
expect(eternatus?.formIndex).toBe(1); expect(eternatus.formIndex).toBe(1);
}); });
it(`should spawn a minor boss every ${EndlessBossWave.Minor} waves in END biome in Spliced Endless`, async () => { it(`should spawn a minor boss every ${EndlessBossWave.Minor} waves in END biome in Spliced Endless`, async () => {
@ -58,10 +58,10 @@ describe("Endless Boss", () => {
expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Minor); expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Minor);
expect(game.scene.arena.biomeType).toBe(BiomeId.END); expect(game.scene.arena.biomeType).toBe(BiomeId.END);
const eternatus = game.scene.getEnemyPokemon(); const eternatus = game.field.getEnemyPokemon();
expect(eternatus?.species.speciesId).toBe(SpeciesId.ETERNATUS); expect(eternatus.species.speciesId).toBe(SpeciesId.ETERNATUS);
expect(eternatus?.hasPassive()).toBe(false); expect(eternatus.hasPassive()).toBe(false);
expect(eternatus?.formIndex).toBe(0); expect(eternatus.formIndex).toBe(0);
}); });
it(`should spawn a major boss every ${EndlessBossWave.Major} waves in END biome in Spliced Endless`, async () => { it(`should spawn a major boss every ${EndlessBossWave.Major} waves in END biome in Spliced Endless`, async () => {
@ -70,10 +70,10 @@ describe("Endless Boss", () => {
expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Major); expect(game.scene.currentBattle.waveIndex).toBe(EndlessBossWave.Major);
expect(game.scene.arena.biomeType).toBe(BiomeId.END); expect(game.scene.arena.biomeType).toBe(BiomeId.END);
const eternatus = game.scene.getEnemyPokemon(); const eternatus = game.field.getEnemyPokemon();
expect(eternatus?.species.speciesId).toBe(SpeciesId.ETERNATUS); expect(eternatus.species.speciesId).toBe(SpeciesId.ETERNATUS);
expect(eternatus?.hasPassive()).toBe(false); expect(eternatus.hasPassive()).toBe(false);
expect(eternatus?.formIndex).toBe(1); expect(eternatus.formIndex).toBe(1);
}); });
it(`should NOT spawn major or minor boss outside wave ${EndlessBossWave.Minor}s in END biome`, async () => { it(`should NOT spawn major or minor boss outside wave ${EndlessBossWave.Minor}s in END biome`, async () => {
@ -81,6 +81,6 @@ describe("Endless Boss", () => {
await game.runToFinalBossEncounter([SpeciesId.BIDOOF], GameModes.ENDLESS); await game.runToFinalBossEncounter([SpeciesId.BIDOOF], GameModes.ENDLESS);
expect(game.scene.currentBattle.waveIndex).not.toBe(EndlessBossWave.Minor); expect(game.scene.currentBattle.waveIndex).not.toBe(EndlessBossWave.Minor);
expect(game.scene.getEnemyPokemon()!.species.speciesId).not.toBe(SpeciesId.ETERNATUS); expect(game.field.getEnemyPokemon().species.speciesId).not.toBe(SpeciesId.ETERNATUS);
}); });
}); });

View File

@ -61,7 +61,7 @@ describe("Enemy Commands - Move Selection", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
enemyPokemon.aiType = AiType.SMART_RANDOM; enemyPokemon.aiType = AiType.SMART_RANDOM;
const moveChoices: MoveChoiceSet = {}; const moveChoices: MoveChoiceSet = {};
@ -85,7 +85,7 @@ describe("Enemy Commands - Move Selection", () => {
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
enemyPokemon.aiType = AiType.SMART_RANDOM; enemyPokemon.aiType = AiType.SMART_RANDOM;
const moveChoices: MoveChoiceSet = {}; const moveChoices: MoveChoiceSet = {};

View File

@ -64,7 +64,7 @@ describe("Evolution", () => {
it("should handle illegal abilityIndex values", async () => { it("should handle illegal abilityIndex values", async () => {
await game.classicMode.runToSummon([SpeciesId.SQUIRTLE]); await game.classicMode.runToSummon([SpeciesId.SQUIRTLE]);
const squirtle = game.scene.getPlayerPokemon()!; const squirtle = game.field.getPlayerPokemon();
squirtle.abilityIndex = 5; squirtle.abilityIndex = 5;
await squirtle.evolve(pokemonEvolutions[SpeciesId.SQUIRTLE][0], squirtle.getSpeciesForm()); await squirtle.evolve(pokemonEvolutions[SpeciesId.SQUIRTLE][0], squirtle.getSpeciesForm());
@ -74,7 +74,7 @@ describe("Evolution", () => {
it("should handle nincada's unique evolution", async () => { it("should handle nincada's unique evolution", async () => {
await game.classicMode.runToSummon([SpeciesId.NINCADA]); await game.classicMode.runToSummon([SpeciesId.NINCADA]);
const nincada = game.scene.getPlayerPokemon()!; const nincada = game.field.getPlayerPokemon();
nincada.abilityIndex = 2; nincada.abilityIndex = 2;
nincada.metBiome = -1; nincada.metBiome = -1;
nincada.gender = 1; nincada.gender = 1;
@ -107,12 +107,12 @@ describe("Evolution", () => {
await game.classicMode.startBattle([SpeciesId.TOTODILE]); await game.classicMode.startBattle([SpeciesId.TOTODILE]);
const totodile = game.scene.getPlayerPokemon()!; const totodile = game.field.getPlayerPokemon();
const hpBefore = totodile.hp; const hpBefore = totodile.hp;
expect(totodile.hp).toBe(totodile.getMaxHp()); expect(totodile.hp).toBe(totodile.getMaxHp());
const golem = game.scene.getEnemyPokemon()!; const golem = game.field.getEnemyPokemon();
golem.hp = 1; golem.hp = 1;
expect(golem.hp).toBe(1); expect(golem.hp).toBe(1);
@ -135,14 +135,14 @@ describe("Evolution", () => {
await game.classicMode.startBattle([SpeciesId.CYNDAQUIL]); await game.classicMode.startBattle([SpeciesId.CYNDAQUIL]);
const cyndaquil = game.scene.getPlayerPokemon()!; const cyndaquil = game.field.getPlayerPokemon();
cyndaquil.hp = Math.floor(cyndaquil.getMaxHp() / 2); cyndaquil.hp = Math.floor(cyndaquil.getMaxHp() / 2);
const hpBefore = cyndaquil.hp; const hpBefore = cyndaquil.hp;
const maxHpBefore = cyndaquil.getMaxHp(); const maxHpBefore = cyndaquil.getMaxHp();
expect(cyndaquil.hp).toBe(Math.floor(cyndaquil.getMaxHp() / 2)); expect(cyndaquil.hp).toBe(Math.floor(cyndaquil.getMaxHp() / 2));
const golem = game.scene.getEnemyPokemon()!; const golem = game.field.getEnemyPokemon();
golem.hp = 1; golem.hp = 1;
expect(golem.hp).toBe(1); expect(golem.hp).toBe(1);
@ -167,7 +167,7 @@ describe("Evolution", () => {
* 1, 2 or 3, it's a 4 family maushold * 1, 2 or 3, it's a 4 family maushold
*/ */
await game.classicMode.startBattle([SpeciesId.TANDEMAUS]); // starts us off with a tandemaus await game.classicMode.startBattle([SpeciesId.TANDEMAUS]); // starts us off with a tandemaus
const playerPokemon = game.scene.getPlayerPokemon()!; const playerPokemon = game.field.getPlayerPokemon();
playerPokemon.level = 25; // tandemaus evolves at level 25 playerPokemon.level = 25; // tandemaus evolves at level 25
vi.spyOn(Utils, "randSeedInt").mockReturnValue(0); // setting the random generator to be 0 to force a three family maushold vi.spyOn(Utils, "randSeedInt").mockReturnValue(0); // setting the random generator to be 0 to force a three family maushold
const threeForm = playerPokemon.getEvolution()!; const threeForm = playerPokemon.getEvolution()!;

View File

@ -28,7 +28,7 @@ describe("Spec - Pokemon", () => {
it("should not crash when trying to set status of undefined", async () => { it("should not crash when trying to set status of undefined", async () => {
await game.classicMode.runToSummon([SpeciesId.ABRA]); await game.classicMode.runToSummon([SpeciesId.ABRA]);
const pkm = game.scene.getPlayerPokemon()!; const pkm = game.field.getPlayerPokemon();
expect(pkm).toBeDefined(); expect(pkm).toBeDefined();
expect(pkm.trySetStatus(undefined)).toBe(false); expect(pkm.trySetStatus(undefined)).toBe(false);
@ -50,7 +50,7 @@ describe("Spec - Pokemon", () => {
}); });
it("should append a new pokemon by default", async () => { it("should append a new pokemon by default", async () => {
const zubat = scene.getEnemyPokemon()!; const zubat = game.field.getEnemyPokemon();
zubat.addToParty(PokeballType.LUXURY_BALL); zubat.addToParty(PokeballType.LUXURY_BALL);
const party = scene.getPlayerParty(); const party = scene.getPlayerParty();
@ -62,7 +62,7 @@ describe("Spec - Pokemon", () => {
it("should put a new pokemon into the passed slotIndex", async () => { it("should put a new pokemon into the passed slotIndex", async () => {
const slotIndex = 1; const slotIndex = 1;
const zubat = scene.getEnemyPokemon()!; const zubat = game.field.getEnemyPokemon();
zubat.addToParty(PokeballType.LUXURY_BALL, slotIndex); zubat.addToParty(PokeballType.LUXURY_BALL, slotIndex);
const party = scene.getPlayerParty(); const party = scene.getPlayerParty();
@ -78,7 +78,7 @@ describe("Spec - Pokemon", () => {
await game.classicMode.startBattle([SpeciesId.ROTOM]); await game.classicMode.startBattle([SpeciesId.ROTOM]);
const fanRotom = game.scene.getPlayerPokemon()!; const fanRotom = game.field.getPlayerPokemon();
expect(fanRotom.compatibleTms).not.toContain(MoveId.BLIZZARD); expect(fanRotom.compatibleTms).not.toContain(MoveId.BLIZZARD);
expect(fanRotom.compatibleTms).toContain(MoveId.AIR_SLASH); expect(fanRotom.compatibleTms).toContain(MoveId.AIR_SLASH);

View File

@ -41,7 +41,7 @@ describe("Final Boss", () => {
expect(game.scene.currentBattle.waveIndex).toBe(FinalWave.Classic); expect(game.scene.currentBattle.waveIndex).toBe(FinalWave.Classic);
expect(game.scene.arena.biomeType).toBe(BiomeId.END); expect(game.scene.arena.biomeType).toBe(BiomeId.END);
expect(game.scene.getEnemyPokemon()!.species.speciesId).toBe(SpeciesId.ETERNATUS); expect(game.field.getEnemyPokemon().species.speciesId).toBe(SpeciesId.ETERNATUS);
}); });
it("should NOT spawn Eternatus before wave 200 in END biome", async () => { it("should NOT spawn Eternatus before wave 200 in END biome", async () => {
@ -50,7 +50,7 @@ describe("Final Boss", () => {
expect(game.scene.currentBattle.waveIndex).not.toBe(FinalWave.Classic); expect(game.scene.currentBattle.waveIndex).not.toBe(FinalWave.Classic);
expect(game.scene.arena.biomeType).toBe(BiomeId.END); expect(game.scene.arena.biomeType).toBe(BiomeId.END);
expect(game.scene.getEnemyPokemon()!.species.speciesId).not.toBe(SpeciesId.ETERNATUS); expect(game.field.getEnemyPokemon().species.speciesId).not.toBe(SpeciesId.ETERNATUS);
}); });
it("should NOT spawn Eternatus outside of END biome", async () => { it("should NOT spawn Eternatus outside of END biome", async () => {
@ -59,13 +59,13 @@ describe("Final Boss", () => {
expect(game.scene.currentBattle.waveIndex).toBe(FinalWave.Classic); expect(game.scene.currentBattle.waveIndex).toBe(FinalWave.Classic);
expect(game.scene.arena.biomeType).not.toBe(BiomeId.END); expect(game.scene.arena.biomeType).not.toBe(BiomeId.END);
expect(game.scene.getEnemyPokemon()!.species.speciesId).not.toBe(SpeciesId.ETERNATUS); expect(game.field.getEnemyPokemon().species.speciesId).not.toBe(SpeciesId.ETERNATUS);
}); });
it("should initially spawn in regular form without passive & 4 boss segments", async () => { it("should initially spawn in regular form without passive & 4 boss segments", async () => {
await game.runToFinalBossEncounter([SpeciesId.BIDOOF], GameModes.CLASSIC); await game.runToFinalBossEncounter([SpeciesId.BIDOOF], GameModes.CLASSIC);
const eternatus = game.scene.getEnemyPokemon()!; const eternatus = game.field.getEnemyPokemon();
expect(eternatus.formIndex).toBe(0); expect(eternatus.formIndex).toBe(0);
expect(eternatus.bossSegments).toBe(4); expect(eternatus.bossSegments).toBe(4);
expect(eternatus.bossSegmentIndex).toBe(3); expect(eternatus.bossSegmentIndex).toBe(3);
@ -77,7 +77,7 @@ describe("Final Boss", () => {
await game.runToFinalBossEncounter([SpeciesId.KYUREM], GameModes.CLASSIC); await game.runToFinalBossEncounter([SpeciesId.KYUREM], GameModes.CLASSIC);
// phase 1 // phase 1
const eternatus = game.scene.getEnemyPokemon()!; const eternatus = game.field.getEnemyPokemon();
const phase1Hp = eternatus.getMaxHp(); const phase1Hp = eternatus.getMaxHp();
game.move.use(MoveId.DRAGON_PULSE); game.move.use(MoveId.DRAGON_PULSE);
@ -100,7 +100,7 @@ describe("Final Boss", () => {
await game.runToFinalBossEncounter([SpeciesId.SALAZZLE], GameModes.CLASSIC); await game.runToFinalBossEncounter([SpeciesId.SALAZZLE], GameModes.CLASSIC);
// Eternatus phase 1 // Eternatus phase 1
const eternatus = game.scene.getEnemyPokemon()!; const eternatus = game.field.getEnemyPokemon();
const phase1Hp = eternatus.getMaxHp(); const phase1Hp = eternatus.getMaxHp();
game.move.use(MoveId.WILL_O_WISP); game.move.use(MoveId.WILL_O_WISP);

View File

@ -24,7 +24,7 @@ describe("Internals", () => {
it("should provide Eevee with 3 defined abilities", async () => { it("should provide Eevee with 3 defined abilities", async () => {
await game.classicMode.runToSummon([SpeciesId.EEVEE]); await game.classicMode.runToSummon([SpeciesId.EEVEE]);
const eevee = game.scene.getPlayerPokemon()!; const eevee = game.field.getPlayerPokemon();
expect(eevee.getSpeciesForm().getAbilityCount()).toBe(3); expect(eevee.getSpeciesForm().getAbilityCount()).toBe(3);
@ -35,7 +35,7 @@ describe("Internals", () => {
it("should set Eeeve abilityIndex between 0-2", async () => { it("should set Eeeve abilityIndex between 0-2", async () => {
await game.classicMode.runToSummon([SpeciesId.EEVEE]); await game.classicMode.runToSummon([SpeciesId.EEVEE]);
const eevee = game.scene.getPlayerPokemon()!; const eevee = game.field.getPlayerPokemon();
expect(eevee.abilityIndex).toBeGreaterThanOrEqual(0); expect(eevee.abilityIndex).toBeGreaterThanOrEqual(0);
expect(eevee.abilityIndex).toBeLessThanOrEqual(2); expect(eevee.abilityIndex).toBeLessThanOrEqual(2);

View File

@ -42,7 +42,7 @@ describe("Items - Dire Hit", () => {
it("should raise CRIT stage by 1", async () => { it("should raise CRIT stage by 1", async () => {
await game.classicMode.startBattle([SpeciesId.GASTLY]); await game.classicMode.startBattle([SpeciesId.GASTLY]);
const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyPokemon = game.field.getEnemyPokemon();
vi.spyOn(enemyPokemon, "getCritStage"); vi.spyOn(enemyPokemon, "getCritStage");

View File

@ -28,7 +28,7 @@ describe("Items - Eviolite", () => {
it("should provide 50% boost to DEF and SPDEF for unevolved, unfused pokemon", async () => { it("should provide 50% boost to DEF and SPDEF for unevolved, unfused pokemon", async () => {
await game.classicMode.startBattle([SpeciesId.PICHU]); await game.classicMode.startBattle([SpeciesId.PICHU]);
const partyMember = game.scene.getPlayerPokemon()!; const partyMember = game.field.getPlayerPokemon();
vi.spyOn(partyMember, "getEffectiveStat").mockImplementation((stat, _opponent?, _move?, _isCritical?) => { vi.spyOn(partyMember, "getEffectiveStat").mockImplementation((stat, _opponent?, _move?, _isCritical?) => {
const statValue = new NumberHolder(partyMember.getStat(stat, false)); const statValue = new NumberHolder(partyMember.getStat(stat, false));
@ -49,7 +49,7 @@ describe("Items - Eviolite", () => {
it("should not provide a boost for fully evolved, unfused pokemon", async () => { it("should not provide a boost for fully evolved, unfused pokemon", async () => {
await game.classicMode.startBattle([SpeciesId.RAICHU]); await game.classicMode.startBattle([SpeciesId.RAICHU]);
const partyMember = game.scene.getPlayerPokemon()!; const partyMember = game.field.getPlayerPokemon();
vi.spyOn(partyMember, "getEffectiveStat").mockImplementation((stat, _opponent?, _move?, _isCritical?) => { vi.spyOn(partyMember, "getEffectiveStat").mockImplementation((stat, _opponent?, _move?, _isCritical?) => {
const statValue = new NumberHolder(partyMember.getStat(stat, false)); const statValue = new NumberHolder(partyMember.getStat(stat, false));
@ -199,7 +199,7 @@ describe("Items - Eviolite", () => {
await game.classicMode.startBattle([randItem(gMaxablePokemon)]); await game.classicMode.startBattle([randItem(gMaxablePokemon)]);
const partyMember = game.scene.getPlayerPokemon()!; const partyMember = game.field.getPlayerPokemon();
vi.spyOn(partyMember, "getEffectiveStat").mockImplementation((stat, _opponent?, _move?, _isCritical?) => { vi.spyOn(partyMember, "getEffectiveStat").mockImplementation((stat, _opponent?, _move?, _isCritical?) => {
const statValue = new NumberHolder(partyMember.getStat(stat, false)); const statValue = new NumberHolder(partyMember.getStat(stat, false));

View File

@ -29,7 +29,7 @@ describe("EXP Modifier Items", () => {
game.override.startingHeldItems([{ name: "LUCKY_EGG", count: 3 }, { name: "GOLDEN_EGG" }]); game.override.startingHeldItems([{ name: "LUCKY_EGG", count: 3 }, { name: "GOLDEN_EGG" }]);
await game.classicMode.startBattle(); await game.classicMode.startBattle();
const partyMember = game.scene.getPlayerPokemon()!; const partyMember = game.field.getPlayerPokemon();
partyMember.exp = 100; partyMember.exp = 100;
const expHolder = new NumberHolder(partyMember.exp); const expHolder = new NumberHolder(partyMember.exp);
game.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, expHolder); game.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, expHolder);

View File

@ -34,7 +34,7 @@ describe("Items - Leek", () => {
it("should raise CRIT stage by 2 when held by FARFETCHD", async () => { it("should raise CRIT stage by 2 when held by FARFETCHD", async () => {
await game.classicMode.startBattle([SpeciesId.FARFETCHD]); await game.classicMode.startBattle([SpeciesId.FARFETCHD]);
const enemyMember = game.scene.getEnemyPokemon()!; const enemyMember = game.field.getEnemyPokemon();
vi.spyOn(enemyMember, "getCritStage"); vi.spyOn(enemyMember, "getCritStage");
@ -48,7 +48,7 @@ describe("Items - Leek", () => {
it("should raise CRIT stage by 2 when held by GALAR_FARFETCHD", async () => { it("should raise CRIT stage by 2 when held by GALAR_FARFETCHD", async () => {
await game.classicMode.startBattle([SpeciesId.GALAR_FARFETCHD]); await game.classicMode.startBattle([SpeciesId.GALAR_FARFETCHD]);
const enemyMember = game.scene.getEnemyPokemon()!; const enemyMember = game.field.getEnemyPokemon();
vi.spyOn(enemyMember, "getCritStage"); vi.spyOn(enemyMember, "getCritStage");
@ -62,7 +62,7 @@ describe("Items - Leek", () => {
it("should raise CRIT stage by 2 when held by SIRFETCHD", async () => { it("should raise CRIT stage by 2 when held by SIRFETCHD", async () => {
await game.classicMode.startBattle([SpeciesId.SIRFETCHD]); await game.classicMode.startBattle([SpeciesId.SIRFETCHD]);
const enemyMember = game.scene.getEnemyPokemon()!; const enemyMember = game.field.getEnemyPokemon();
vi.spyOn(enemyMember, "getCritStage"); vi.spyOn(enemyMember, "getCritStage");
@ -90,7 +90,7 @@ describe("Items - Leek", () => {
partyMember.fusionGender = ally.gender; partyMember.fusionGender = ally.gender;
partyMember.fusionLuck = ally.luck; partyMember.fusionLuck = ally.luck;
const enemyMember = game.scene.getEnemyPokemon()!; const enemyMember = game.field.getEnemyPokemon();
vi.spyOn(enemyMember, "getCritStage"); vi.spyOn(enemyMember, "getCritStage");
@ -118,7 +118,7 @@ describe("Items - Leek", () => {
partyMember.fusionGender = ally.gender; partyMember.fusionGender = ally.gender;
partyMember.fusionLuck = ally.luck; partyMember.fusionLuck = ally.luck;
const enemyMember = game.scene.getEnemyPokemon()!; const enemyMember = game.field.getEnemyPokemon();
vi.spyOn(enemyMember, "getCritStage"); vi.spyOn(enemyMember, "getCritStage");
@ -132,7 +132,7 @@ describe("Items - Leek", () => {
it("should not raise CRIT stage when held by a Pokemon outside of FARFETCHD line", async () => { it("should not raise CRIT stage when held by a Pokemon outside of FARFETCHD line", async () => {
await game.classicMode.startBattle([SpeciesId.PIKACHU]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const enemyMember = game.scene.getEnemyPokemon()!; const enemyMember = game.field.getEnemyPokemon();
vi.spyOn(enemyMember, "getCritStage"); vi.spyOn(enemyMember, "getCritStage");

Some files were not shown because too many files have changed in this diff Show More