mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-07 07:59:26 +02:00
Compare commits
68 Commits
e49b10c9e4
...
af4f660f78
Author | SHA1 | Date | |
---|---|---|---|
|
af4f660f78 | ||
|
7264f56fa1 | ||
|
3b36ab17e4 | ||
|
375587213e | ||
|
8da02bad50 | ||
|
c34134159d | ||
|
99e1163752 | ||
|
a82768f040 | ||
|
8b1b1cd38a | ||
|
d6c77e0afa | ||
|
9ee0bfb84b | ||
|
c36394b781 | ||
|
a1c718322f | ||
|
2df1eaff10 | ||
|
b3eea02779 | ||
|
b55872ef32 | ||
|
ff6ec7f945 | ||
|
af77e2ef7f | ||
|
6edf75ca42 | ||
|
bda0f39df0 | ||
|
1bfdd8f24b | ||
|
19c0fba6f4 | ||
|
259a9b328d | ||
|
1f9eaf49c6 | ||
|
e1c999566e | ||
|
1cb1797f3b | ||
|
e385c73188 | ||
|
4fd44e8029 | ||
|
d614588783 | ||
|
adeedb84d5 | ||
|
eb1696e93e | ||
|
7d0ee7a9ed | ||
|
d82c105d55 | ||
|
e7b5f5fe99 | ||
|
fefa8e408f | ||
|
903d1a33dd | ||
|
7f2766f832 | ||
|
c6c3cd9f3c | ||
|
0c3ae62d1e | ||
|
779c95ba93 | ||
|
0402b07122 | ||
|
ba39af1bbe | ||
|
d20a47d082 | ||
|
9301e6db87 | ||
|
c24f630caf | ||
|
14f5849502 | ||
|
374474720b | ||
|
2eae68785d | ||
|
c919ea78cb | ||
|
e40b1bd452 | ||
|
a179fdeac6 | ||
|
455f3b6be1 | ||
|
059b9b2a95 | ||
|
b9a4e631db | ||
|
3e2d050d70 | ||
|
8a10cc2037 | ||
|
c76739f629 | ||
|
6f676e4438 | ||
|
3bd10f09e9 | ||
|
8a915d2dc8 | ||
|
d456b3849a | ||
|
82920fb059 | ||
|
4d93958627 | ||
|
47c45bc63e | ||
|
db927e8adb | ||
|
9bfb1bba88 | ||
|
96e4bb5e0e | ||
|
45bbaf2b25 |
@ -1238,7 +1238,7 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
|
||||
// TODO: Probably want to check against simulated here
|
||||
const effect =
|
||||
this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randBattleSeedInt(this.effects.length)];
|
||||
attacker.trySetStatus(effect, true, pokemon);
|
||||
attacker.trySetStatus(effect, pokemon);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1768,7 +1768,7 @@ export interface AddSecondStrikeAbAttrParams extends Omit<AugmentMoveInteraction
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
/**
|
||||
@ -2230,7 +2230,7 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
|
||||
apply({ pokemon, opponent }: PostMoveInteractionAbAttrParams): void {
|
||||
const effect =
|
||||
this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randBattleSeedInt(this.effects.length)];
|
||||
opponent.trySetStatus(effect, true, pokemon);
|
||||
opponent.trySetStatus(effect, pokemon);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2385,7 +2385,7 @@ export class SynchronizeStatusAbAttr extends PostSetStatusAbAttr {
|
||||
*/
|
||||
override apply({ simulated, effect, sourcePokemon, pokemon }: PostSetStatusAbAttrParams): void {
|
||||
if (!simulated && sourcePokemon) {
|
||||
sourcePokemon.trySetStatus(effect, true, pokemon);
|
||||
sourcePokemon.trySetStatus(effect, pokemon);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3661,7 +3661,8 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
|
||||
protected immuneEffects: StatusEffect[];
|
||||
|
||||
/**
|
||||
* @param immuneEffects - The status effects to which the Pokémon is immune.
|
||||
* @param immuneEffects - An array of {@linkcode StatusEffect}s to prevent application.
|
||||
* If none are provided, will block **all** status effects regardless of type.
|
||||
*/
|
||||
constructor(...immuneEffects: StatusEffect[]) {
|
||||
super();
|
||||
@ -3670,7 +3671,7 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
|
||||
}
|
||||
|
||||
override canApply({ effect }: PreSetStatusAbAttrParams): boolean {
|
||||
return (effect !== StatusEffect.FAINT && this.immuneEffects.length < 1) || this.immuneEffects.includes(effect);
|
||||
return (this.immuneEffects.length === 0 && effect !== StatusEffect.FAINT) || this.immuneEffects.includes(effect);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3722,6 +3723,11 @@ export interface UserFieldStatusEffectImmunityAbAttrParams extends AbAttrBasePar
|
||||
*/
|
||||
export class UserFieldStatusEffectImmunityAbAttr extends AbAttr {
|
||||
protected immuneEffects: StatusEffect[];
|
||||
|
||||
/**
|
||||
* @param immuneEffects - An array of {@linkcode StatusEffect}s to prevent application.
|
||||
* If none are provided, will block **all** status effects regardless of type.
|
||||
*/
|
||||
constructor(...immuneEffects: StatusEffect[]) {
|
||||
super();
|
||||
|
||||
@ -3730,7 +3736,7 @@ export class UserFieldStatusEffectImmunityAbAttr extends AbAttr {
|
||||
|
||||
override canApply({ effect, cancelled }: UserFieldStatusEffectImmunityAbAttrParams): boolean {
|
||||
return (
|
||||
(!cancelled.value && effect !== StatusEffect.FAINT && this.immuneEffects.length < 1) ||
|
||||
(!cancelled.value && this.immuneEffects.length === 0 && effect !== StatusEffect.FAINT) ||
|
||||
this.immuneEffects.includes(effect)
|
||||
);
|
||||
}
|
||||
@ -3756,6 +3762,10 @@ export class ConditionalUserFieldStatusEffectImmunityAbAttr extends UserFieldSta
|
||||
*/
|
||||
private condition: (target: Pokemon, source: Pokemon | null) => boolean;
|
||||
|
||||
/**
|
||||
* @param immuneEffects - An array of {@linkcode StatusEffect}s to prevent application.
|
||||
* If none are provided, will block **all** status effects regardless of type.
|
||||
*/
|
||||
constructor(condition: (target: Pokemon, source: Pokemon | null) => boolean, ...immuneEffects: StatusEffect[]) {
|
||||
super(...immuneEffects);
|
||||
|
||||
@ -7481,8 +7491,7 @@ export function initAbilities() {
|
||||
.unsuppressable()
|
||||
.bypassFaint(),
|
||||
new Ability(AbilityId.CORROSION, 7)
|
||||
.attr(IgnoreTypeStatusEffectImmunityAbAttr, [ StatusEffect.POISON, StatusEffect.TOXIC ], [ PokemonType.STEEL, PokemonType.POISON ])
|
||||
.edgeCase(), // Should poison itself with toxic orb.
|
||||
.attr(IgnoreTypeStatusEffectImmunityAbAttr, [ StatusEffect.POISON, StatusEffect.TOXIC ], [ PokemonType.STEEL, PokemonType.POISON ]),
|
||||
new Ability(AbilityId.COMATOSE, 7)
|
||||
.attr(StatusEffectImmunityAbAttr, ...getNonVolatileStatusEffects())
|
||||
.attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY)
|
||||
|
@ -890,32 +890,31 @@ class ToxicSpikesTag extends ArenaTrapTag {
|
||||
}
|
||||
|
||||
override activateTrap(pokemon: Pokemon, simulated: boolean): boolean {
|
||||
if (pokemon.isGrounded()) {
|
||||
if (simulated) {
|
||||
return true;
|
||||
}
|
||||
if (pokemon.isOfType(PokemonType.POISON)) {
|
||||
this.#neutralized = true;
|
||||
if (globalScene.arena.removeTag(this.tagType)) {
|
||||
globalScene.phaseManager.queueMessage(
|
||||
i18next.t("arenaTag:toxicSpikesActivateTrapPoison", {
|
||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||
moveName: this.getMoveName(),
|
||||
}),
|
||||
);
|
||||
return true;
|
||||
}
|
||||
} else if (!pokemon.status) {
|
||||
const toxic = this.layers > 1;
|
||||
if (
|
||||
pokemon.trySetStatus(!toxic ? StatusEffect.POISON : StatusEffect.TOXIC, true, null, 0, this.getMoveName())
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!pokemon.isGrounded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (simulated) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pokemon.isOfType(PokemonType.POISON)) {
|
||||
// Neutralize the tag and remove it from the field.
|
||||
// Message cannot be moved to `onRemove` as that requires a reference to the neutralizing pokemon
|
||||
this.#neutralized = true;
|
||||
globalScene.arena.removeTagOnSide(this.tagType, this.side);
|
||||
globalScene.phaseManager.queueMessage(
|
||||
i18next.t("arenaTag:toxicSpikesActivateTrapPoison", {
|
||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||
moveName: this.getMoveName(),
|
||||
}),
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Attempt to poison the target, suppressing any immunity messages that arise.
|
||||
const effect = this.layers === 1 ? StatusEffect.POISON : StatusEffect.TOXIC;
|
||||
return pokemon.trySetStatus(effect, null, undefined, this.getMoveName(), false, true);
|
||||
}
|
||||
|
||||
getMatchupScoreMultiplier(pokemon: Pokemon): number {
|
||||
|
@ -563,7 +563,7 @@ export class BeakBlastChargingTag extends BattlerTag {
|
||||
target: pokemon,
|
||||
})
|
||||
) {
|
||||
phaseData.attacker.trySetStatus(StatusEffect.BURN, true, pokemon);
|
||||
phaseData.attacker.trySetStatus(StatusEffect.BURN, pokemon);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1509,7 +1509,7 @@ export class DrowsyTag extends SerializableBattlerTag {
|
||||
|
||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||
if (!super.lapse(pokemon, lapseType)) {
|
||||
pokemon.trySetStatus(StatusEffect.SLEEP, true);
|
||||
pokemon.trySetStatus(StatusEffect.SLEEP);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1859,7 +1859,7 @@ export class ContactSetStatusProtectedTag extends DamageProtectedTag {
|
||||
* @param user - The pokemon that is being attacked and has the tag
|
||||
*/
|
||||
override onContact(attacker: Pokemon, user: Pokemon): void {
|
||||
attacker.trySetStatus(this.#statusEffect, true, user);
|
||||
attacker.trySetStatus(this.#statusEffect, user);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2055,7 +2055,7 @@ export class TruantTag extends AbilityBattlerTag {
|
||||
const lastMove = pokemon.getLastXMoves()[0];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2799,7 +2799,7 @@ export class GulpMissileTag extends SerializableBattlerTag {
|
||||
if (this.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {
|
||||
globalScene.phaseManager.unshiftNew("StatStageChangePhase", attacker.getBattlerIndex(), false, [Stat.DEF], -1);
|
||||
} else {
|
||||
attacker.trySetStatus(StatusEffect.PARALYSIS, true, pokemon);
|
||||
attacker.trySetStatus(StatusEffect.PARALYSIS, pokemon);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -256,7 +256,7 @@ export const noAbilityTypeOverrideMoves: ReadonlySet<MoveId> = new Set([
|
||||
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([
|
||||
MoveId.NONE,
|
||||
MoveId.CHATTER,
|
||||
@ -270,7 +270,7 @@ export const invalidSketchMoves: ReadonlySet<MoveId> = new Set([
|
||||
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([
|
||||
MoveId.MIMIC,
|
||||
MoveId.MIRROR_MOVE,
|
||||
|
@ -89,7 +89,7 @@ import type { AttackMoveResult } from "#types/attack-move-result";
|
||||
import type { Localizable } from "#types/locales";
|
||||
import type { ChargingMove, MoveAttrMap, MoveAttrString, MoveClassMap, MoveKindString } from "#types/move-types";
|
||||
import type { TurnMove } from "#types/turn-move";
|
||||
import { BooleanHolder, type Constructor, isNullOrUndefined, NumberHolder, randSeedFloat, randSeedInt, randSeedItem, toDmgValue } from "#utils/common";
|
||||
import { BooleanHolder, coerceArray, type Constructor, isNullOrUndefined, NumberHolder, randSeedFloat, randSeedInt, randSeedItem, toDmgValue } from "#utils/common";
|
||||
import { getEnumValues } from "#utils/enums";
|
||||
import { toTitleCase } from "#utils/strings";
|
||||
import i18next from "i18next";
|
||||
@ -1184,8 +1184,9 @@ export abstract class MoveAttr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @virtual
|
||||
* @returns the {@linkcode MoveCondition} or {@linkcode MoveConditionFunc} for this {@linkcode Move}
|
||||
* Return this `MoveAttr`'s associated {@linkcode MoveCondition} or {@linkcode MoveConditionFunc}.
|
||||
* The specified condition will be added to all {@linkcode Move}s with this attribute,
|
||||
* and moves **will fail upon use** if _at least 1_ of their attached conditions returns `false`.
|
||||
*/
|
||||
getCondition(): MoveCondition | MoveConditionFunc | null {
|
||||
return null;
|
||||
@ -1298,15 +1299,21 @@ export class MoveEffectAttr extends MoveAttr {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the {@linkcode Move}'s effects are valid to {@linkcode apply}
|
||||
* @virtual
|
||||
* @param user {@linkcode Pokemon} using the move
|
||||
* @param target {@linkcode Pokemon} target of the move
|
||||
* @param move {@linkcode Move} with this attribute
|
||||
* @param args Set of unique arguments needed by this attribute
|
||||
* @returns true if basic application of the ability attribute should be possible
|
||||
* Determine whether this {@linkcode MoveAttr}'s effects are able to {@linkcode apply | be applied} to the target.
|
||||
*
|
||||
* Will **NOT** cause the move to fail upon returning `false` (unlike {@linkcode getCondition};
|
||||
* merely that the effect for this attribute will be nullified.
|
||||
* @param user - The {@linkcode Pokemon} using the move
|
||||
* @param target - The {@linkcode Pokemon} being targeted by the move, or {@linkcode user} if the move is
|
||||
* {@linkcode selfTarget | self-targeting}
|
||||
* @param move - The {@linkcode Move} being used
|
||||
* @param _args - Set of unique arguments needed by this attribute
|
||||
* @returns `true` if basic application of this `MoveAttr`s effects should be possible
|
||||
*/
|
||||
canApply(user: Pokemon, target: Pokemon, move: Move, args?: any[]) {
|
||||
// TODO: Decouple this check from the `apply` step
|
||||
// TODO: Make non-damaging moves fail by default if none of their attributes can apply
|
||||
canApply(user: Pokemon, target: Pokemon, move: Move, _args?: any[]) {
|
||||
// TODO: These checks seem redundant
|
||||
return !! (this.selfTarget ? user.hp && !user.getTag(BattlerTagType.FRENZY) : target.hp)
|
||||
&& (this.selfTarget || !target.getTag(BattlerTagType.PROTECTED) ||
|
||||
move.doesFlagEffectApply({ flag: MoveFlags.IGNORE_PROTECT, user, target }));
|
||||
@ -1945,19 +1952,17 @@ export class AddSubstituteAttr extends MoveEffectAttr {
|
||||
* @see {@linkcode apply}
|
||||
*/
|
||||
export class HealAttr extends MoveEffectAttr {
|
||||
/** The percentage of {@linkcode Stat.HP} to heal */
|
||||
private healRatio: number;
|
||||
/** Should an animation be shown? */
|
||||
private showAnim: boolean;
|
||||
|
||||
constructor(healRatio?: number, showAnim?: boolean, selfTarget?: boolean) {
|
||||
super(selfTarget === undefined || selfTarget);
|
||||
|
||||
this.healRatio = healRatio || 1;
|
||||
this.showAnim = !!showAnim;
|
||||
constructor(
|
||||
/** The percentage of {@linkcode Stat.HP} to heal. */
|
||||
private healRatio: number,
|
||||
/** Whether to display a healing animation when healing the target; default `false` */
|
||||
private showAnim = false,
|
||||
selfTarget = true
|
||||
) {
|
||||
super(selfTarget);
|
||||
}
|
||||
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
@ -1966,15 +1971,65 @@ export class HealAttr extends MoveEffectAttr {
|
||||
* Creates a new {@linkcode PokemonHealPhase}.
|
||||
* This heals the target and shows the appropriate message.
|
||||
*/
|
||||
addHealPhase(target: Pokemon, healRatio: number) {
|
||||
protected addHealPhase(target: Pokemon, healRatio: number) {
|
||||
globalScene.phaseManager.unshiftNew("PokemonHealPhase", target.getBattlerIndex(),
|
||||
toDmgValue(target.getMaxHp() * healRatio), i18next.t("moveTriggers:healHp", { pokemonName: getPokemonNameWithAffix(target) }), true, !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;
|
||||
return Math.round(score / (1 - this.healRatio / 2));
|
||||
}
|
||||
|
||||
// TODO: Change to fail move
|
||||
override canApply(user: Pokemon, target: Pokemon, _move: Move, _args?: any[]): boolean {
|
||||
if (!super.canApply(user, target, _move, _args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const healedPokemon = this.selfTarget ? user : target;
|
||||
if (healedPokemon.isFullHp()) {
|
||||
globalScene.phaseManager.queueMessage(i18next.t("battle:hpIsFull", {
|
||||
pokemonName: getPokemonNameWithAffix(healedPokemon),
|
||||
}))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute to put the user to sleep for a fixed duration, fully heal them and cure their status.
|
||||
* Used for {@linkcode MoveId.REST}.
|
||||
*/
|
||||
export class RestAttr extends HealAttr {
|
||||
private duration: number;
|
||||
|
||||
constructor(duration: number) {
|
||||
super(1, true);
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
const wasSet = user.trySetStatus(StatusEffect.SLEEP, user, this.duration, null, true, true,
|
||||
i18next.t("moveTriggers:restBecameHealthy", {
|
||||
pokemonName: getPokemonNameWithAffix(user),
|
||||
}));
|
||||
return wasSet && super.apply(user, target, move, args);
|
||||
}
|
||||
|
||||
override addHealPhase(user: Pokemon): void {
|
||||
globalScene.phaseManager.unshiftNew("PokemonHealPhase", user.getBattlerIndex(), user.getMaxHp(), null)
|
||||
}
|
||||
|
||||
// TODO: change after HealAttr is changed to fail move
|
||||
override getCondition(): MoveConditionFunc {
|
||||
return (user, target, move) =>
|
||||
super.canApply(user, target, move, [])
|
||||
// Intentionally suppress messages here as we display generic fail msg
|
||||
// TODO: This might have order-of-operation jank
|
||||
&& user.canSetStatus(StatusEffect.SLEEP, true, true, user)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2246,20 +2301,9 @@ export class BoostHealAttr 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;
|
||||
override canApply(user: Pokemon, target: Pokemon, _move: Move, _args?: any[]): boolean {
|
||||
// Don't trigger if not targeting an ally
|
||||
return target === user.getAlly() && super.canApply(user, target, _move, _args);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2270,6 +2314,7 @@ export class HealOnAllyAttr extends HealAttr {
|
||||
* @see {@linkcode apply}
|
||||
* @see {@linkcode getUserBenefitScore}
|
||||
*/
|
||||
// TODO: Make Strength Sap its own attribute that extends off of this one
|
||||
export class HitHealAttr extends MoveEffectAttr {
|
||||
private healRatio: number;
|
||||
private healStat: EffectiveStat | null;
|
||||
@ -2520,49 +2565,50 @@ export class WaterShurikenMultiHitTypeAttr extends ChangeMultiHitTypeAttr {
|
||||
|
||||
export class StatusEffectAttr extends MoveEffectAttr {
|
||||
public effect: StatusEffect;
|
||||
public turnsRemaining?: number;
|
||||
public overrideStatus: boolean = false;
|
||||
|
||||
constructor(effect: StatusEffect, selfTarget?: boolean, turnsRemaining?: number, overrideStatus: boolean = false) {
|
||||
constructor(effect: StatusEffect, selfTarget = false) {
|
||||
super(selfTarget);
|
||||
|
||||
this.effect = effect;
|
||||
this.turnsRemaining = turnsRemaining;
|
||||
this.overrideStatus = overrideStatus;
|
||||
}
|
||||
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
|
||||
const statusCheck = moveChance < 0 || moveChance === 100 || user.randBattleSeedInt(100) < moveChance;
|
||||
if (!statusCheck) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// non-status moves don't play sound effects for failures
|
||||
const quiet = move.category !== MoveCategory.STATUS;
|
||||
if (statusCheck) {
|
||||
const pokemon = this.selfTarget ? user : target;
|
||||
if (user !== target && move.category === MoveCategory.STATUS && !target.canSetStatus(this.effect, quiet, false, user, true)) {
|
||||
return false;
|
||||
}
|
||||
if (((!pokemon.status || this.overrideStatus) || (pokemon.status.effect === this.effect && moveChance < 0))
|
||||
&& pokemon.trySetStatus(this.effect, true, user, this.turnsRemaining, null, this.overrideStatus, quiet)) {
|
||||
applyAbAttrs("ConfusionOnStatusEffectAbAttr", {pokemon: user, opponent: target, move, effect: this.effect});
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
target.trySetStatus(this.effect, user, undefined, null, false, quiet)
|
||||
) {
|
||||
applyAbAttrs("ConfusionOnStatusEffectAbAttr", {pokemon: user, opponent: target, move, effect: this.effect});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, false);
|
||||
const score = (moveChance < 0) ? -10 : Math.floor(moveChance * -0.1);
|
||||
const score = moveChance < 0 ? -10 : Math.floor(moveChance * -0.1);
|
||||
const pokemon = this.selfTarget ? user : target;
|
||||
|
||||
return !pokemon.status && pokemon.canSetStatus(this.effect, true, false, user) ? score : 0;
|
||||
return pokemon.canSetStatus(this.effect, true, false, user) ? score : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute to randomly apply one of several statuses to the target.
|
||||
* Used for {@linkcode Moves.TRI_ATTACK} and {@linkcode Moves.DIRE_CLAW}.
|
||||
*/
|
||||
export class MultiStatusEffectAttr extends StatusEffectAttr {
|
||||
public effects: StatusEffect[];
|
||||
|
||||
constructor(effects: StatusEffect[], selfTarget?: boolean, turnsRemaining?: number, overrideStatus?: boolean) {
|
||||
super(effects[0], selfTarget, turnsRemaining, overrideStatus);
|
||||
constructor(effects: StatusEffect[], selfTarget?: boolean) {
|
||||
super(effects[0], selfTarget);
|
||||
this.effects = effects;
|
||||
}
|
||||
|
||||
@ -2587,7 +2633,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.
|
||||
* The user is then healed after the move has been successfully executed.
|
||||
* @param user - The {@linkcode Pokemon} using the move
|
||||
@ -2595,26 +2641,41 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr {
|
||||
* @returns - Whether the effect was successfully applied to the target.
|
||||
*/
|
||||
apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
|
||||
const statusToApply: StatusEffect | undefined = user.status?.effect ?? (user.hasAbility(AbilityId.COMATOSE) ? StatusEffect.SLEEP : undefined);
|
||||
const statusToApply = user.status?.effect ??
|
||||
(user.hasAbility(AbilityId.COMATOSE) ? StatusEffect.SLEEP : StatusEffect.NONE);
|
||||
|
||||
if (target.status || !statusToApply) {
|
||||
// Bang is justified as condition func returns early if no status is found
|
||||
if (!target.trySetStatus(statusToApply, user)) {
|
||||
return false;
|
||||
} else {
|
||||
const canSetStatus = target.canSetStatus(statusToApply, true, false, user);
|
||||
const trySetStatus = canSetStatus ? target.trySetStatus(statusToApply, true, user) : false;
|
||||
}
|
||||
|
||||
if (trySetStatus && user.status) {
|
||||
// PsychoShiftTag is added to the user if move succeeds so that the user is healed of its status effect after its move
|
||||
user.addTag(BattlerTagType.PSYCHO_SHIFT);
|
||||
if (user.status) {
|
||||
// Add tag to user to heal its status effect after the move ends (unless we have comatose);
|
||||
// occurs after move use to ensure correct Synchronize timing
|
||||
user.addTag(BattlerTagType.PSYCHO_SHIFT)
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
getCondition(): MoveConditionFunc {
|
||||
return (user, target) => {
|
||||
if (target.status?.effect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return trySetStatus;
|
||||
const statusToApply = user.status?.effect ?? (user.hasAbility(AbilityId.COMATOSE) ? StatusEffect.SLEEP : StatusEffect.NONE);
|
||||
return !!statusToApply && target.canSetStatus(statusToApply, false, false, user);
|
||||
}
|
||||
}
|
||||
|
||||
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||
const statusToApply = user.status?.effect ?? (user.hasAbility(AbilityId.COMATOSE) ? StatusEffect.SLEEP : undefined);
|
||||
return !target.status && statusToApply && target.canSetStatus(statusToApply, true, false, user) ? -10 : 0;
|
||||
const statusToApply =
|
||||
user.status?.effect ??
|
||||
(user.hasAbility(AbilityId.COMATOSE) ? StatusEffect.SLEEP : StatusEffect.NONE);
|
||||
|
||||
// TODO: Give this a positive user benefit score
|
||||
return !target.status?.effect && statusToApply && target.canSetStatus(statusToApply, true, false, user) ? -10 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2674,7 +2735,7 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr {
|
||||
* Used for Incinerate and Knock Off.
|
||||
* Not Implemented Cases: (Same applies for Thief)
|
||||
* "If the user faints due to the target's Ability (Rough Skin or Iron Barbs) or held Rocky Helmet, it cannot remove the target's held item."
|
||||
* "If the Pokémon is knocked out by the attack, Sticky Hold does not protect the held item.""
|
||||
* "If the Pokémon is knocked out by the attack, Sticky Hold does not protect the held item."
|
||||
*/
|
||||
export class RemoveHeldItemAttr extends MoveEffectAttr {
|
||||
|
||||
@ -2884,7 +2945,7 @@ export class HealStatusEffectAttr extends MoveEffectAttr {
|
||||
*/
|
||||
constructor(selfTarget: boolean, effects: StatusEffect | StatusEffect[]) {
|
||||
super(selfTarget, { lastHitOnly: true });
|
||||
this.effects = [ effects ].flat(1);
|
||||
this.effects = coerceArray(effects)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2927,7 +2988,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.
|
||||
* 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: Give this `userSleptOrComatoseCondition` by default
|
||||
@ -4411,6 +4472,10 @@ export class SpitUpPowerAttr extends VariablePowerAttr {
|
||||
* Does NOT remove stockpiled stacks.
|
||||
*/
|
||||
export class SwallowHealAttr extends HealAttr {
|
||||
constructor() {
|
||||
super(1)
|
||||
}
|
||||
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
const stockpilingTag = user.getTag(StockpilingTag);
|
||||
|
||||
@ -5912,20 +5977,21 @@ export class ProtectAttr extends AddBattlerTagAttr {
|
||||
getCondition(): MoveConditionFunc {
|
||||
return ((user, target, move): boolean => {
|
||||
let timesUsed = 0;
|
||||
const moveHistory = user.getLastXMoves();
|
||||
let turnMove: TurnMove | undefined;
|
||||
|
||||
while (moveHistory.length) {
|
||||
turnMove = moveHistory.shift();
|
||||
if (!allMoves[turnMove?.move ?? MoveId.NONE].hasAttr("ProtectAttr") || turnMove?.result !== MoveResult.SUCCESS) {
|
||||
for (const turnMove of user.getLastXMoves(-1).slice()) {
|
||||
if (
|
||||
// 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;
|
||||
}
|
||||
timesUsed++;
|
||||
|
||||
timesUsed++
|
||||
}
|
||||
if (timesUsed) {
|
||||
return !user.randBattleSeedInt(Math.pow(3, timesUsed));
|
||||
}
|
||||
return true;
|
||||
|
||||
return timesUsed === 0 || user.randBattleSeedInt(Math.pow(3, timesUsed)) === 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -7139,7 +7205,7 @@ export class CopyMoveAttr extends CallMoveAttr {
|
||||
/**
|
||||
* 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))
|
||||
*/
|
||||
export class RepeatMoveAttr extends MoveEffectAttr {
|
||||
@ -7402,7 +7468,7 @@ const targetMoveCopiableCondition: MoveConditionFunc = (user, target, move) => {
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
@ -7916,7 +7982,7 @@ export class StatusIfBoostedAttr extends MoveEffectAttr {
|
||||
*/
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
if (target.turnData.statStagesIncreased) {
|
||||
target.trySetStatus(this.effect, true, user);
|
||||
target.trySetStatus(this.effect, user);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -7966,7 +8032,7 @@ export class VariableTargetAttr extends MoveAttr {
|
||||
/**
|
||||
* 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 {
|
||||
/**
|
||||
@ -8063,11 +8129,11 @@ const failIfDampCondition: MoveConditionFunc = (user, target, move) => {
|
||||
return !cancelled.value;
|
||||
};
|
||||
|
||||
const userSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => user.status?.effect === StatusEffect.SLEEP || user.hasAbility(AbilityId.COMATOSE);
|
||||
const userSleptOrComatoseCondition: MoveConditionFunc = (user) => user.status?.effect === StatusEffect.SLEEP || user.hasAbility(AbilityId.COMATOSE);
|
||||
|
||||
const targetSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.SLEEP || target.hasAbility(AbilityId.COMATOSE);
|
||||
const targetSleptOrComatoseCondition: MoveConditionFunc = (_user: Pokemon, target: Pokemon, _move: Move) => target.status?.effect === StatusEffect.SLEEP || target.hasAbility(AbilityId.COMATOSE);
|
||||
|
||||
const failIfLastCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => globalScene.phaseManager.phaseQueue.find(phase => phase.is("MovePhase")) !== undefined;
|
||||
const failIfLastCondition: MoveConditionFunc = () => globalScene.phaseManager.findPhase(phase => phase.is("MovePhase")) !== undefined;
|
||||
|
||||
const failIfLastInPartyCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => {
|
||||
const party: Pokemon[] = user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
|
||||
@ -8948,9 +9014,7 @@ export function initMoves() {
|
||||
.attr(MultiHitAttr, MultiHitType._2)
|
||||
.makesContact(false),
|
||||
new SelfStatusMove(MoveId.REST, PokemonType.PSYCHIC, -1, 5, -1, 0, 1)
|
||||
.attr(StatusEffectAttr, StatusEffect.SLEEP, true, 3, true)
|
||||
.attr(HealAttr, 1, true)
|
||||
.condition((user, target, move) => !user.isFullHp() && user.canSetStatus(StatusEffect.SLEEP, true, true, user))
|
||||
.attr(RestAttr, 3)
|
||||
.triageMove(),
|
||||
new AttackMove(MoveId.ROCK_SLIDE, PokemonType.ROCK, MoveCategory.PHYSICAL, 75, 90, 10, 30, 0, 1)
|
||||
.attr(FlinchAttr)
|
||||
@ -9288,14 +9352,16 @@ export function initMoves() {
|
||||
.condition(user => (user.getTag(StockpilingTag)?.stockpiledCount ?? 0) < 3)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.STOCKPILING, true),
|
||||
new AttackMove(MoveId.SPIT_UP, PokemonType.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3)
|
||||
.condition(hasStockpileStacksCondition)
|
||||
.attr(SpitUpPowerAttr, 100)
|
||||
.condition(hasStockpileStacksCondition)
|
||||
.attr(RemoveBattlerTagAttr, [ BattlerTagType.STOCKPILING ], true),
|
||||
new SelfStatusMove(MoveId.SWALLOW, PokemonType.NORMAL, -1, 10, -1, 0, 3)
|
||||
.condition(hasStockpileStacksCondition)
|
||||
.attr(SwallowHealAttr)
|
||||
.condition(hasStockpileStacksCondition)
|
||||
.attr(RemoveBattlerTagAttr, [ BattlerTagType.STOCKPILING ], true)
|
||||
.triageMove(),
|
||||
.triageMove()
|
||||
// TODO: Verify if using Swallow at full HP still consumes stacks or not
|
||||
.edgeCase(),
|
||||
new AttackMove(MoveId.HEAT_WAVE, PokemonType.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3)
|
||||
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
|
||||
.attr(StatusEffectAttr, StatusEffect.BURN)
|
||||
@ -9681,14 +9747,8 @@ export function initMoves() {
|
||||
.unimplemented(),
|
||||
new StatusMove(MoveId.PSYCHO_SHIFT, PokemonType.PSYCHIC, 100, 10, -1, 0, 4)
|
||||
.attr(PsychoShiftEffectAttr)
|
||||
.condition((user, target, move) => {
|
||||
let statusToApply = user.hasAbility(AbilityId.COMATOSE) ? StatusEffect.SLEEP : undefined;
|
||||
if (user.status?.effect && isNonVolatileStatusEffect(user.status.effect)) {
|
||||
statusToApply = user.status.effect;
|
||||
}
|
||||
return !!statusToApply && target.canSetStatus(statusToApply, false, false, user);
|
||||
}
|
||||
),
|
||||
// TODO: Verify status applied if a statused pokemon obtains Comatose (via Transform) and uses Psycho Shift
|
||||
.edgeCase(),
|
||||
new AttackMove(MoveId.TRUMP_CARD, PokemonType.NORMAL, MoveCategory.SPECIAL, -1, -1, 5, -1, 0, 4)
|
||||
.makesContact()
|
||||
.attr(LessPPMorePowerAttr),
|
||||
|
@ -243,8 +243,9 @@ export const FieryFalloutEncounter: MysteryEncounter = MysteryEncounterBuilder.w
|
||||
if (burnable?.length > 0) {
|
||||
const roll = randSeedInt(burnable.length);
|
||||
const chosenPokemon = burnable[roll];
|
||||
if (chosenPokemon.trySetStatus(StatusEffect.BURN)) {
|
||||
if (chosenPokemon.canSetStatus(StatusEffect.BURN, true)) {
|
||||
// Burn applied
|
||||
chosenPokemon.doSetStatus(StatusEffect.BURN);
|
||||
encounter.setDialogueToken("burnedPokemon", chosenPokemon.getNameToRender());
|
||||
encounter.setDialogueToken("abilityName", allAbilities[AbilityId.HEATPROOF].name);
|
||||
queueEncounterMessage(`${namespace}:option.2.target_burned`);
|
||||
|
@ -307,7 +307,7 @@ export function getRandomSpeciesByStarterCost(
|
||||
*/
|
||||
export function koPlayerPokemon(pokemon: PlayerPokemon) {
|
||||
pokemon.hp = 0;
|
||||
pokemon.trySetStatus(StatusEffect.FAINT);
|
||||
pokemon.doSetStatus(StatusEffect.FAINT);
|
||||
pokemon.updateInfo();
|
||||
queueEncounterMessage(
|
||||
i18next.t("battle:fainted", {
|
||||
|
@ -253,7 +253,6 @@ export class PokemonTempSummonData {
|
||||
* Only currently used for positioning the battle cursor.
|
||||
*/
|
||||
turnCount = 1;
|
||||
|
||||
/**
|
||||
* The number of turns this pokemon has spent in the active position since the start of the wave
|
||||
* without switching out.
|
||||
|
@ -1,3 +1,5 @@
|
||||
/** Enum representing all non-volatile status effects. */
|
||||
// TODO: Remove StatusEffect.FAINT
|
||||
export enum StatusEffect {
|
||||
NONE,
|
||||
POISON,
|
||||
|
@ -234,6 +234,11 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
public ivs: number[];
|
||||
public nature: Nature;
|
||||
public moveset: PokemonMove[];
|
||||
/**
|
||||
* This Pokemon's current {@link https://m.bulbapedia.bulbagarden.net/wiki/Status_condition#Non-volatile_status | non-volatile status condition},
|
||||
* or `null` if none exist.
|
||||
* @todo Make private
|
||||
*/
|
||||
public status: Status | null;
|
||||
public friendship: number;
|
||||
public metLevel: number;
|
||||
@ -725,7 +730,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
/**
|
||||
* 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`
|
||||
* @returns A promise that resolves once all the corresponding assets have been loaded.
|
||||
*/
|
||||
@ -1032,7 +1037,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
* @param useIllusion - Whether to consider this Pokemon's illusion if present; default `false`.
|
||||
* @returns This Pokemon's {@linkcode PokemonSpeciesForm}.
|
||||
@ -1088,7 +1093,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
/**
|
||||
* 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`
|
||||
* @returns The {@linkcode PokemonSpeciesForm} of this Pokemon's fusion counterpart.
|
||||
*/
|
||||
@ -1659,7 +1664,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
/**
|
||||
* 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`
|
||||
* @returns the {@linkcode Gender} of this {@linkcode Pokemon}.
|
||||
*/
|
||||
@ -1675,7 +1680,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
/**
|
||||
* 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`
|
||||
* @returns The {@linkcode Gender} of this {@linkcode Pokemon}'s fusion.
|
||||
*/
|
||||
@ -1817,7 +1822,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
/**
|
||||
* 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).
|
||||
* @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.
|
||||
*/
|
||||
getMoveset(ignoreOverride = false): PokemonMove[] {
|
||||
@ -1883,7 +1888,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* Evaluate and return this Pokemon's typing.
|
||||
* @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 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`
|
||||
* @returns An array of {@linkcode PokemonType}s corresponding to this Pokemon's typing (real or percieved).
|
||||
*/
|
||||
@ -2006,7 +2011,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* @param type - The {@linkcode PokemonType} to check
|
||||
* @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 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.
|
||||
*/
|
||||
public isOfType(type: PokemonType, includeTeraType = true, forDefend = false, ignoreOverride = false): boolean {
|
||||
@ -2019,7 +2024,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* Should rarely be called directly in favor of {@linkcode hasAbility} or {@linkcode hasAbilityWithAttr},
|
||||
* 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
|
||||
* @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.
|
||||
*/
|
||||
public getAbility(ignoreOverride = false): Ability {
|
||||
@ -2201,7 +2206,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* Accounts for all the various effects which can disable or modify abilities.
|
||||
* @param ability - The {@linkcode Abilities | Ability} to check for
|
||||
* @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
|
||||
*/
|
||||
public hasAbility(ability: AbilityId, canApply = true, ignoreOverride = false): boolean {
|
||||
@ -2216,7 +2221,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* Accounts for all the various effects which can disable or modify abilities.
|
||||
* @param attrType - The {@linkcode AbAttr | attribute} to check for
|
||||
* @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}.
|
||||
*/
|
||||
public hasAbilityWithAttr(attrType: AbAttrString, canApply = true, ignoreOverride = false): boolean {
|
||||
@ -4466,7 +4471,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* Return the most recently executed {@linkcode TurnMove} this {@linkcode Pokemon} has used that is:
|
||||
* - Not {@linkcode MoveId.NONE}
|
||||
* - 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}
|
||||
* (e.g. ones called by Copycat/Mirror Move); default `true`.
|
||||
* @returns The last move this Pokemon has used satisfying the aforementioned conditions,
|
||||
@ -4735,7 +4740,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* @param reason - The reason for the status application failure -
|
||||
* can be "overlap" (already has same status), "other" (generic fail message)
|
||||
* or a {@linkcode TerrainType} for terrain-based blockages.
|
||||
* Defaults to "other".
|
||||
* Default `"other"`
|
||||
*/
|
||||
queueStatusImmuneMessage(
|
||||
quiet: boolean,
|
||||
@ -4764,15 +4769,20 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a status effect can be applied to the Pokemon.
|
||||
* Check if a status effect can be applied to this {@linkcode Pokemon}.
|
||||
*
|
||||
* @param effect The {@linkcode StatusEffect} whose applicability is being checked
|
||||
* @param quiet Whether in-battle messages should trigger or not
|
||||
* @param overrideStatus Whether the Pokemon's current status can be overriden
|
||||
* @param sourcePokemon The Pokemon that is setting the status effect
|
||||
* @param ignoreField Whether any field effects (weather, terrain, etc.) should be considered
|
||||
* @param effect - The {@linkcode StatusEffect} whose applicability is being checked
|
||||
* @param quiet - Whether to suppress in-battle messages for status checks; default `false`
|
||||
* @param overrideStatus - Whether to allow overriding the Pokemon's current status with a different one; default `false`
|
||||
* @param sourcePokemon - The {@linkcode Pokemon} applying the status effect to the target,
|
||||
* or `null` if the status is applied from a non-Pokemon source (hazards, etc.); default `null`
|
||||
* @param ignoreField - Whether to ignore field effects (weather, terrain, etc.) preventing status application;
|
||||
* default `false`
|
||||
* @returns Whether {@linkcode effect} can be applied to this Pokemon.
|
||||
*/
|
||||
canSetStatus(
|
||||
// TODO: Review and verify the message order precedence in mainline if multiple status-blocking effects are present at once
|
||||
// TODO: Make argument order consistent with `trySetStatus`
|
||||
public canSetStatus(
|
||||
effect: StatusEffect,
|
||||
quiet = false,
|
||||
overrideStatus = false,
|
||||
@ -4780,6 +4790,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
ignoreField = false,
|
||||
): boolean {
|
||||
if (effect !== StatusEffect.FAINT) {
|
||||
// Status-overriding moves (i.e. Rest) fail if their respective status already exists;
|
||||
// all other moves fail if the target already has _any_ status
|
||||
if (overrideStatus ? this.status?.effect === effect : this.status) {
|
||||
this.queueStatusImmuneMessage(quiet, overrideStatus ? "overlap" : "other"); // having different status displays generic fail message
|
||||
return false;
|
||||
@ -4792,73 +4804,62 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
const types = this.getTypes(true, true);
|
||||
|
||||
/* Whether the target is immune to the specific status being applied. */
|
||||
let isImmune = false;
|
||||
/** The reason for a potential blockage; default "other" for type-based. */
|
||||
let reason: "other" | Exclude<TerrainType, TerrainType.NONE> = "other";
|
||||
|
||||
switch (effect) {
|
||||
case StatusEffect.POISON:
|
||||
case StatusEffect.TOXIC: {
|
||||
// Check if the Pokemon is immune to Poison/Toxic or if the source pokemon is canceling the immunity
|
||||
const poisonImmunity = types.map(defType => {
|
||||
// Check if the Pokemon is not immune to Poison/Toxic
|
||||
case StatusEffect.TOXIC:
|
||||
// Check for type based immunities and/or Corrosion from the applier.
|
||||
isImmune = types.some(defType => {
|
||||
// only 1 immunity needed to block
|
||||
if (defType !== PokemonType.POISON && defType !== PokemonType.STEEL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the source Pokemon has an ability that cancels the Poison/Toxic immunity
|
||||
// No source (such as from Toxic Spikes) = blocked by default
|
||||
if (!sourcePokemon) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const cancelImmunity = new BooleanHolder(false);
|
||||
// TODO: Determine if we need to pass `quiet` as the value for simulated in this call
|
||||
if (sourcePokemon) {
|
||||
applyAbAttrs("IgnoreTypeStatusEffectImmunityAbAttr", {
|
||||
pokemon: sourcePokemon,
|
||||
cancelled: cancelImmunity,
|
||||
statusEffect: effect,
|
||||
defenderType: defType,
|
||||
});
|
||||
if (cancelImmunity.value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
applyAbAttrs("IgnoreTypeStatusEffectImmunityAbAttr", {
|
||||
pokemon: sourcePokemon,
|
||||
cancelled: cancelImmunity,
|
||||
statusEffect: effect,
|
||||
defenderType: defType,
|
||||
});
|
||||
return !cancelImmunity.value;
|
||||
});
|
||||
|
||||
if (this.isOfType(PokemonType.POISON) || this.isOfType(PokemonType.STEEL)) {
|
||||
if (poisonImmunity.includes(true)) {
|
||||
this.queueStatusImmuneMessage(quiet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case StatusEffect.PARALYSIS:
|
||||
if (this.isOfType(PokemonType.ELECTRIC)) {
|
||||
this.queueStatusImmuneMessage(quiet);
|
||||
return false;
|
||||
}
|
||||
isImmune = this.isOfType(PokemonType.ELECTRIC);
|
||||
break;
|
||||
case StatusEffect.SLEEP:
|
||||
if (this.isGrounded() && globalScene.arena.terrain?.terrainType === TerrainType.ELECTRIC) {
|
||||
this.queueStatusImmuneMessage(quiet, TerrainType.ELECTRIC);
|
||||
return false;
|
||||
}
|
||||
isImmune = this.isGrounded() && globalScene.arena.getTerrainType() === TerrainType.ELECTRIC;
|
||||
reason = TerrainType.ELECTRIC;
|
||||
break;
|
||||
case StatusEffect.FREEZE:
|
||||
if (
|
||||
case StatusEffect.FREEZE: {
|
||||
const weatherType = globalScene.arena.getWeatherType();
|
||||
isImmune =
|
||||
this.isOfType(PokemonType.ICE) ||
|
||||
(!ignoreField &&
|
||||
globalScene?.arena?.weather?.weatherType &&
|
||||
[WeatherType.SUNNY, WeatherType.HARSH_SUN].includes(globalScene.arena.weather.weatherType))
|
||||
) {
|
||||
this.queueStatusImmuneMessage(quiet);
|
||||
return false;
|
||||
}
|
||||
(!ignoreField && (weatherType === WeatherType.SUNNY || weatherType === WeatherType.HARSH_SUN));
|
||||
break;
|
||||
}
|
||||
case StatusEffect.BURN:
|
||||
if (this.isOfType(PokemonType.FIRE)) {
|
||||
this.queueStatusImmuneMessage(quiet);
|
||||
return false;
|
||||
}
|
||||
isImmune = this.isOfType(PokemonType.FIRE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isImmune) {
|
||||
this.queueStatusImmuneMessage(quiet, reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for cancellations from self/ally abilities
|
||||
const cancelled = new BooleanHolder(false);
|
||||
applyAbAttrs("StatusEffectImmunityAbAttr", { pokemon: this, effect, cancelled, simulated: quiet });
|
||||
if (cancelled.value) {
|
||||
@ -4875,14 +4876,11 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
source: sourcePokemon,
|
||||
});
|
||||
if (cancelled.value) {
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cancelled.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Perform safeguard checks
|
||||
if (sourcePokemon && sourcePokemon !== this && this.isSafeguarded(sourcePokemon)) {
|
||||
if (!quiet) {
|
||||
globalScene.phaseManager.queueMessage(
|
||||
@ -4895,18 +4893,36 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
return true;
|
||||
}
|
||||
|
||||
trySetStatus(
|
||||
effect?: StatusEffect,
|
||||
asPhase = false,
|
||||
/**
|
||||
* Attempt to set this Pokemon's status to the specified condition.
|
||||
* Enqueues a new `ObtainStatusEffectPhase` to trigger animations, etc.
|
||||
* @param effect - The {@linkcode StatusEffect} to set
|
||||
* @param sourcePokemon - The {@linkcode Pokemon} applying the status effect to the target,
|
||||
* or `null` if the status is applied from a non-Pokemon source (hazards, etc.); default `null`
|
||||
* @param sleepTurnsRemaining - The number of turns to set {@linkcode StatusEffect.SLEEP} for;
|
||||
* defaults to a random number between 2 and 4 and is unused for non-Sleep statuses
|
||||
* @param sourceText - The text to show for the source of the status effect, if any; default `null`
|
||||
* @param overrideStatus - Whether to allow overriding the Pokemon's current status with a different one; default `false`
|
||||
* @param quiet - Whether to suppress in-battle messages for status checks; default `true`
|
||||
* @param overrideMessage - String containing text to be displayed upon status setting; defaults to normal key for status
|
||||
* and is used exclusively for Rest
|
||||
* @returns Whether the status effect phase was successfully created.
|
||||
* @see {@linkcode doSetStatus} - alternate function that sets status immediately (albeit without condition checks).
|
||||
*/
|
||||
public trySetStatus(
|
||||
effect: StatusEffect,
|
||||
sourcePokemon: Pokemon | null = null,
|
||||
turnsRemaining = 0,
|
||||
sleepTurnsRemaining?: number,
|
||||
sourceText: string | null = null,
|
||||
overrideStatus?: boolean,
|
||||
quiet = true,
|
||||
overrideMessage?: string,
|
||||
): boolean {
|
||||
// TODO: This needs to propagate failure status for status moves
|
||||
if (!effect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.canSetStatus(effect, quiet, overrideStatus, sourcePokemon)) {
|
||||
return false;
|
||||
}
|
||||
@ -4926,48 +4942,79 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
}
|
||||
}
|
||||
|
||||
if (asPhase) {
|
||||
if (overrideStatus) {
|
||||
this.resetStatus(false);
|
||||
}
|
||||
globalScene.phaseManager.unshiftNew(
|
||||
"ObtainStatusEffectPhase",
|
||||
this.getBattlerIndex(),
|
||||
effect,
|
||||
turnsRemaining,
|
||||
sourceText,
|
||||
sourcePokemon,
|
||||
);
|
||||
return true;
|
||||
if (overrideStatus) {
|
||||
this.resetStatus(false);
|
||||
}
|
||||
|
||||
let sleepTurnsRemaining: NumberHolder;
|
||||
globalScene.phaseManager.unshiftNew(
|
||||
"ObtainStatusEffectPhase",
|
||||
this.getBattlerIndex(),
|
||||
effect,
|
||||
sourcePokemon,
|
||||
sleepTurnsRemaining,
|
||||
sourceText,
|
||||
overrideMessage,
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this Pokemon's {@linkcode status | non-volatile status condition} to the specified effect.
|
||||
* @param effect - The {@linkcode StatusEffect} to set
|
||||
* @remarks
|
||||
* ⚠️ This method does **not** check for feasibility; that is the responsibility of the caller.
|
||||
*/
|
||||
doSetStatus(effect: Exclude<StatusEffect, StatusEffect.SLEEP>): void;
|
||||
/**
|
||||
* Set this Pokemon's {@linkcode status | non-volatile status condition} to the specified effect.
|
||||
* @param effect - {@linkcode StatusEffect.SLEEP}
|
||||
* @param sleepTurnsRemaining - The number of turns to inflict sleep for; defaults to a random number between 2 and 4
|
||||
* @remarks
|
||||
* ⚠️ This method does **not** check for feasibility; that is the responsibility of the caller.
|
||||
*/
|
||||
doSetStatus(effect: StatusEffect.SLEEP, sleepTurnsRemaining?: number): void;
|
||||
/**
|
||||
* Set this Pokemon's {@linkcode status | non-volatile status condition} to the specified effect.
|
||||
* @param effect - The {@linkcode StatusEffect} to set
|
||||
* @param sleepTurnsRemaining - The number of turns to inflict sleep for; defaults to a random number between 2 and 4
|
||||
* and is unused for all non-sleep Statuses
|
||||
* @remarks
|
||||
* ⚠️ This method does **not** check for feasibility; that is the responsibility of the caller.
|
||||
*/
|
||||
doSetStatus(effect: StatusEffect, sleepTurnsRemaining?: number): void;
|
||||
/**
|
||||
* Set this Pokemon's {@linkcode status | non-volatile status condition} to the specified effect.
|
||||
* @param effect - The {@linkcode StatusEffect} to set
|
||||
* @param sleepTurnsRemaining - The number of turns to inflict sleep for; defaults to a random number between 2 and 4
|
||||
* and is unused for all non-sleep Statuses
|
||||
* @remarks
|
||||
* ⚠️ This method does **not** check for feasibility; that is the responsibility of the caller.
|
||||
* @todo Make this and all related fields private and change tests to use a field-based helper or similar
|
||||
*/
|
||||
doSetStatus(
|
||||
effect: StatusEffect,
|
||||
sleepTurnsRemaining = effect !== StatusEffect.SLEEP ? 0 : this.randBattleSeedIntRange(2, 4),
|
||||
): void {
|
||||
if (effect === StatusEffect.SLEEP) {
|
||||
sleepTurnsRemaining = new NumberHolder(this.randBattleSeedIntRange(2, 4));
|
||||
|
||||
this.setFrameRate(4);
|
||||
|
||||
// If the user is invulnerable, lets remove their invulnerability when they fall asleep
|
||||
const invulnerableTags = [
|
||||
// If the user is semi-invulnerable when put asleep (such as due to Yawm),
|
||||
// remove their invulnerability and cancel the upcoming move from the queue
|
||||
const invulnTagTypes = [
|
||||
BattlerTagType.FLYING,
|
||||
BattlerTagType.UNDERGROUND,
|
||||
BattlerTagType.UNDERWATER,
|
||||
BattlerTagType.HIDDEN,
|
||||
BattlerTagType.FLYING,
|
||||
];
|
||||
|
||||
const tag = invulnerableTags.find(t => this.getTag(t));
|
||||
|
||||
if (tag) {
|
||||
this.removeTag(tag);
|
||||
this.getMoveQueue().pop();
|
||||
if (this.findTag(t => invulnTagTypes.includes(t.tagType))) {
|
||||
this.findAndRemoveTags(t => invulnTagTypes.includes(t.tagType));
|
||||
this.getMoveQueue().shift();
|
||||
}
|
||||
}
|
||||
|
||||
sleepTurnsRemaining = sleepTurnsRemaining!; // tell TS compiler it's defined
|
||||
this.status = new Status(effect, 0, sleepTurnsRemaining?.value);
|
||||
|
||||
return true;
|
||||
this.status = new Status(effect, 0, sleepTurnsRemaining);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5094,6 +5141,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
*/
|
||||
resetWaveData(): void {
|
||||
this.waveData = new PokemonWaveData();
|
||||
this.tempSummonData.waveTurnCount = 1;
|
||||
}
|
||||
|
||||
resetTera(): void {
|
||||
|
@ -1733,12 +1733,12 @@ export class TurnStatusEffectModifier extends PokemonHeldItemModifier {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to inflicts the holder with the associated {@linkcode StatusEffect}.
|
||||
* @param pokemon {@linkcode Pokemon} that holds the held item
|
||||
* Attempt to inflict the holder with the associated {@linkcode StatusEffect}.
|
||||
* @param pokemon - The {@linkcode Pokemon} holding the item
|
||||
* @returns `true` if the status effect was applied successfully
|
||||
*/
|
||||
override apply(pokemon: Pokemon): boolean {
|
||||
return pokemon.trySetStatus(this.effect, true, undefined, undefined, this.type.name);
|
||||
return pokemon.trySetStatus(this.effect, pokemon, undefined, this.type.name);
|
||||
}
|
||||
|
||||
getMaxHeldItemCount(_pokemon: Pokemon): number {
|
||||
@ -3605,7 +3605,7 @@ export class EnemyAttackStatusEffectChanceModifier extends EnemyPersistentModifi
|
||||
*/
|
||||
override apply(enemyPokemon: Pokemon): boolean {
|
||||
if (randSeedFloat() <= this.chance * this.getStackCount()) {
|
||||
return enemyPokemon.trySetStatus(this.effect, true);
|
||||
return enemyPokemon.trySetStatus(this.effect);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -265,7 +265,7 @@ export class AttemptCapturePhase extends PokemonPhase {
|
||||
const removePokemon = () => {
|
||||
globalScene.addFaintedEnemyScore(pokemon);
|
||||
pokemon.hp = 0;
|
||||
pokemon.trySetStatus(StatusEffect.FAINT);
|
||||
pokemon.doSetStatus(StatusEffect.FAINT);
|
||||
globalScene.clearEnemyHeldItemModifiers();
|
||||
pokemon.leaveField(true, true, true);
|
||||
};
|
||||
|
@ -45,7 +45,7 @@ export class AttemptRunPhase extends FieldPhase {
|
||||
enemyField.forEach(enemyPokemon => {
|
||||
enemyPokemon.hideInfo().then(() => enemyPokemon.destroy());
|
||||
enemyPokemon.hp = 0;
|
||||
enemyPokemon.trySetStatus(StatusEffect.FAINT);
|
||||
enemyPokemon.doSetStatus(StatusEffect.FAINT);
|
||||
});
|
||||
|
||||
globalScene.phaseManager.pushNew("BattleEndPhase", false);
|
||||
|
@ -58,12 +58,6 @@ export class BattleEndPhase extends BattlePhase {
|
||||
globalScene.phaseManager.unshiftNew("GameOverPhase", true);
|
||||
}
|
||||
|
||||
for (const pokemon of globalScene.getField()) {
|
||||
if (pokemon) {
|
||||
pokemon.tempSummonData.waveTurnCount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (const pokemon of globalScene.getPokemonAllowedInBattle()) {
|
||||
applyAbAttrs("PostBattleAbAttr", { pokemon, victory: this.isVictory });
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ export class FaintPhase extends PokemonPhase {
|
||||
pokemon.lapseTags(BattlerTagLapseType.FAINT);
|
||||
|
||||
pokemon.y -= 150;
|
||||
pokemon.trySetStatus(StatusEffect.FAINT);
|
||||
pokemon.doSetStatus(StatusEffect.FAINT);
|
||||
if (pokemon.isPlayer()) {
|
||||
globalScene.currentBattle.removeFaintedParticipant(pokemon as PlayerPokemon);
|
||||
} else {
|
||||
|
@ -269,8 +269,8 @@ export class MovePhase extends BattlePhase {
|
||||
globalScene.phaseManager.queueMessage(
|
||||
getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)),
|
||||
);
|
||||
this.pokemon.resetStatus();
|
||||
this.pokemon.updateInfo();
|
||||
// cannot use `asPhase=true` as it will cause status to be reset _after_ move condition checks fire
|
||||
this.pokemon.resetStatus(false, false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
public showMoveText(): void {
|
||||
// No text for Moves.NONE, recharging/2-turn moves or interrupted moves
|
||||
if (
|
||||
this.move.moveId === MoveId.NONE ||
|
||||
this.pokemon.getTag(BattlerTagType.RECHARGING) ||
|
||||
@ -658,7 +657,6 @@ export class MovePhase extends BattlePhase {
|
||||
return;
|
||||
}
|
||||
|
||||
// Play message for magic coat reflection
|
||||
// TODO: This should be done by the move...
|
||||
globalScene.phaseManager.queueMessage(
|
||||
i18next.t(isReflected(this.useMode) ? "battle:magicCoatActivated" : "battle:useMove", {
|
||||
|
@ -3,71 +3,64 @@ import { globalScene } from "#app/global-scene";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { CommonBattleAnim } from "#data/battle-anims";
|
||||
import { SpeciesFormChangeStatusEffectTrigger } from "#data/form-change-triggers";
|
||||
import { getStatusEffectObtainText, getStatusEffectOverlapText } from "#data/status-effect";
|
||||
import { getStatusEffectObtainText } from "#data/status-effect";
|
||||
import type { BattlerIndex } from "#enums/battler-index";
|
||||
import { CommonAnim } from "#enums/move-anims-common";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import type { Pokemon } from "#field/pokemon";
|
||||
import { PokemonPhase } from "#phases/pokemon-phase";
|
||||
import { isNullOrUndefined } from "#utils/common";
|
||||
|
||||
export class ObtainStatusEffectPhase extends PokemonPhase {
|
||||
public readonly phaseName = "ObtainStatusEffectPhase";
|
||||
private statusEffect?: StatusEffect;
|
||||
private turnsRemaining?: number;
|
||||
private sourceText?: string | null;
|
||||
private sourcePokemon?: Pokemon | null;
|
||||
|
||||
/**
|
||||
* @param battlerIndex - The {@linkcode BattlerIndex} of the Pokemon obtaining the status effect.
|
||||
* @param statusEffect - The {@linkcode StatusEffect} being applied.
|
||||
* @param sourcePokemon - The {@linkcode Pokemon} applying the status effect to the target,
|
||||
* or `null` if the status is applied from a non-Pokemon source (hazards, etc.); default `null`.
|
||||
* @param sleepTurnsRemaining - The number of turns to set {@linkcode StatusEffect.SLEEP} for;
|
||||
* defaults to a random number between 2 and 4 and is unused for non-Sleep statuses.
|
||||
* @param sourceText - The text to show for the source of the status effect, if any; default `null`.
|
||||
* @param statusMessage - A string containing text to be displayed upon status setting;
|
||||
* defaults to normal key for status if empty or omitted.
|
||||
*/
|
||||
constructor(
|
||||
battlerIndex: BattlerIndex,
|
||||
statusEffect?: StatusEffect,
|
||||
turnsRemaining?: number,
|
||||
sourceText?: string | null,
|
||||
sourcePokemon?: Pokemon | null,
|
||||
private statusEffect: StatusEffect,
|
||||
private sourcePokemon: Pokemon | null = null,
|
||||
private sleepTurnsRemaining?: number,
|
||||
sourceText: string | null = null, // TODO: This should take `undefined` instead of `null`
|
||||
private statusMessage = "",
|
||||
) {
|
||||
super(battlerIndex);
|
||||
|
||||
this.statusEffect = statusEffect;
|
||||
this.turnsRemaining = turnsRemaining;
|
||||
this.sourceText = sourceText;
|
||||
this.sourcePokemon = sourcePokemon;
|
||||
this.statusMessage ||= getStatusEffectObtainText(
|
||||
statusEffect,
|
||||
getPokemonNameWithAffix(this.getPokemon()),
|
||||
sourceText ?? undefined,
|
||||
);
|
||||
}
|
||||
|
||||
start() {
|
||||
const pokemon = this.getPokemon();
|
||||
if (pokemon && !pokemon.status) {
|
||||
if (pokemon.trySetStatus(this.statusEffect, false, this.sourcePokemon)) {
|
||||
if (this.turnsRemaining) {
|
||||
pokemon.status!.sleepTurnsRemaining = this.turnsRemaining;
|
||||
}
|
||||
pokemon.updateInfo(true);
|
||||
new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect! - 1), pokemon).play(false, () => {
|
||||
globalScene.phaseManager.queueMessage(
|
||||
getStatusEffectObtainText(
|
||||
this.statusEffect,
|
||||
getPokemonNameWithAffix(pokemon),
|
||||
this.sourceText ?? undefined,
|
||||
),
|
||||
);
|
||||
if (!isNullOrUndefined(this.statusEffect) && this.statusEffect !== StatusEffect.FAINT) {
|
||||
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeStatusEffectTrigger, true);
|
||||
// If mold breaker etc was used to set this status, it shouldn't apply to abilities activated afterwards
|
||||
globalScene.arena.setIgnoreAbilities(false);
|
||||
applyAbAttrs("PostSetStatusAbAttr", {
|
||||
pokemon,
|
||||
effect: this.statusEffect,
|
||||
sourcePokemon: this.sourcePokemon ?? undefined,
|
||||
});
|
||||
}
|
||||
this.end();
|
||||
|
||||
pokemon.doSetStatus(this.statusEffect, this.sleepTurnsRemaining);
|
||||
pokemon.updateInfo(true);
|
||||
|
||||
new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect - 1), pokemon).play(false, () => {
|
||||
globalScene.phaseManager.queueMessage(this.statusMessage);
|
||||
if (this.statusEffect && this.statusEffect !== StatusEffect.FAINT) {
|
||||
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeStatusEffectTrigger, true);
|
||||
// If the status was applied from a move, ensure abilities are not ignored for follow-up triggers.
|
||||
// TODO: Ensure this isn't breaking any other phases unshifted afterwards
|
||||
globalScene.arena.setIgnoreAbilities(false);
|
||||
applyAbAttrs("PostSetStatusAbAttr", {
|
||||
pokemon,
|
||||
effect: this.statusEffect,
|
||||
sourcePokemon: this.sourcePokemon ?? undefined,
|
||||
});
|
||||
return;
|
||||
}
|
||||
} else if (pokemon.status?.effect === this.statusEffect) {
|
||||
globalScene.phaseManager.queueMessage(
|
||||
getStatusEffectOverlapText(this.statusEffect ?? StatusEffect.NONE, getPokemonNameWithAffix(pokemon)),
|
||||
);
|
||||
}
|
||||
this.end();
|
||||
this.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import { HealAchv } from "#system/achv";
|
||||
import { NumberHolder } from "#utils/common";
|
||||
import i18next from "i18next";
|
||||
|
||||
// TODO: Refactor this - it has far too many arguments
|
||||
export class PokemonHealPhase extends CommonAnimPhase {
|
||||
public readonly phaseName = "PokemonHealPhase";
|
||||
private hpHealed: number;
|
||||
@ -28,7 +29,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
||||
battlerIndex: BattlerIndex,
|
||||
hpHealed: number,
|
||||
message: string | null,
|
||||
showFullHpMessage: boolean,
|
||||
showFullHpMessage = true,
|
||||
skipAnim = false,
|
||||
revive = false,
|
||||
healStatus = false,
|
||||
@ -72,6 +73,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
||||
this.message = null;
|
||||
return super.end();
|
||||
}
|
||||
|
||||
if (healOrDamage) {
|
||||
const hpRestoreMultiplier = new NumberHolder(1);
|
||||
if (!this.revive) {
|
||||
|
@ -38,7 +38,7 @@ describe("Abilities - Analytic", () => {
|
||||
it("should increase damage if the user moves last", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.ARCEUS]);
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.TACKLE);
|
||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||
|
@ -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 () => {
|
||||
game.override.enemyAbility(AbilityId.ANGER_POINT).moveset(MoveId.FALSE_SWIPE);
|
||||
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
|
||||
enemy.setStatStage(Stat.ATK, -6);
|
||||
@ -53,7 +53,7 @@ describe("Ability - Anger Point", () => {
|
||||
.enemyAbility(AbilityId.ANGER_POINT)
|
||||
.ability(AbilityId.SKILL_LINK);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
vi.spyOn(enemy, "getCriticalHitResult").mockReturnValueOnce(true);
|
||||
const angerPointSpy = vi.spyOn(PostReceiveCritStatStageChangeAbAttr.prototype, "apply");
|
||||
game.move.select(MoveId.BULLET_SEED);
|
||||
@ -68,7 +68,7 @@ describe("Ability - Anger Point", () => {
|
||||
.enemyHasPassiveAbility(true)
|
||||
.moveset(MoveId.FALSE_SWIPE);
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
vi.spyOn(enemy, "getCriticalHitResult").mockReturnValueOnce(true);
|
||||
enemy.setStatStage(Stat.ATK, 6);
|
||||
game.move.select(MoveId.FALSE_SWIPE);
|
||||
|
@ -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 () => {
|
||||
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
|
||||
vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([10000, 100, 1000, 200, 100, 100]);
|
||||
console.log(playerPokemon.stats);
|
||||
@ -54,7 +54,7 @@ describe("Abilities - Beast Boost", () => {
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
vi.spyOn(playerPokemon, "stats", "get").mockReturnValue([10000, 1, 1, 100, 100, 100]);
|
||||
|
@ -36,7 +36,7 @@ describe("Abilities - Competitive", () => {
|
||||
it("lower atk and def by 1 via tickle, then increase spatk by 4 via competitive", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FLYGON]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to(TurnInitPhase);
|
||||
|
||||
@ -49,7 +49,7 @@ describe("Abilities - Competitive", () => {
|
||||
game.override.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FLYGON]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.CLOSE_COMBAT);
|
||||
await game.phaseInterceptor.to(TurnInitPhase);
|
||||
|
||||
@ -62,7 +62,7 @@ describe("Abilities - Competitive", () => {
|
||||
game.override.startingHeldItems([{ name: "WHITE_HERB" }]);
|
||||
await game.classicMode.startBattle([SpeciesId.FLYGON]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to(TurnInitPhase);
|
||||
|
||||
|
@ -33,7 +33,7 @@ describe("Abilities - Contrary", () => {
|
||||
it("should invert stat changes when applied", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
|
||||
});
|
||||
@ -43,7 +43,7 @@ describe("Abilities - Contrary", () => {
|
||||
game.override.enemyPassiveAbility(AbilityId.CLEAR_BODY).moveset([MoveId.TAIL_WHIP]);
|
||||
await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
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]);
|
||||
await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
@ -22,25 +23,66 @@ describe("Abilities - Corrosion", () => {
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([MoveId.SPLASH])
|
||||
.battleStyle("single")
|
||||
.criticalHits(false)
|
||||
.enemySpecies(SpeciesId.GRIMER)
|
||||
.enemyAbility(AbilityId.CORROSION)
|
||||
.enemyMoveset(MoveId.TOXIC);
|
||||
.ability(AbilityId.CORROSION)
|
||||
.enemyAbility(AbilityId.NO_GUARD)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
});
|
||||
|
||||
it("If a Poison- or Steel-type Pokémon with this Ability poisons a target with Synchronize, Synchronize does not gain the ability to poison Poison- or Steel-type Pokémon.", async () => {
|
||||
game.override.ability(AbilityId.SYNCHRONIZE);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
it.each<{ name: string; species: SpeciesId }>([
|
||||
{ name: "Poison", species: SpeciesId.GRIMER },
|
||||
{ name: "Steel", species: SpeciesId.KLINK },
|
||||
])("should grant the user the ability to poison $name-type opponents", async ({ species }) => {
|
||||
game.override.enemySpecies(species);
|
||||
await game.classicMode.startBattle([SpeciesId.SALANDIT]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon();
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(playerPokemon!.status).toBeUndefined();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
expect(enemy.status?.effect).toBeUndefined();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
expect(playerPokemon!.status).toBeDefined();
|
||||
expect(enemyPokemon!.status).toBeUndefined();
|
||||
game.move.use(MoveId.POISON_GAS);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
expect(enemy.status?.effect).toBe(StatusEffect.POISON);
|
||||
});
|
||||
|
||||
it("should not affect Toxic Spikes", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.SALANDIT]);
|
||||
|
||||
game.move.use(MoveId.TOXIC_SPIKES);
|
||||
await game.doKillOpponents();
|
||||
await game.toNextWave();
|
||||
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
expect(enemyPokemon.status).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should not affect an opponent's Synchronize ability", async () => {
|
||||
game.override.enemyAbility(AbilityId.SYNCHRONIZE);
|
||||
await game.classicMode.startBattle([SpeciesId.ARBOK]);
|
||||
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
expect(enemyPokemon.status?.effect).toBeUndefined();
|
||||
|
||||
game.move.use(MoveId.TOXIC);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
expect(enemyPokemon.status?.effect).toBe(StatusEffect.TOXIC);
|
||||
expect(playerPokemon.status?.effect).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should affect the user's held Toxic Orb", async () => {
|
||||
game.override.startingHeldItems([{ name: "TOXIC_ORB", count: 1 }]);
|
||||
await game.classicMode.startBattle([SpeciesId.SALAZZLE]);
|
||||
|
||||
const salazzle = game.field.getPlayerPokemon();
|
||||
expect(salazzle.status?.effect).toBeUndefined();
|
||||
|
||||
game.move.use(MoveId.SPLASH);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(salazzle.status?.effect).toBe(StatusEffect.TOXIC);
|
||||
});
|
||||
});
|
||||
|
@ -43,7 +43,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
it("stores inside summonData at end of turn", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
farigiraf.hp = 1; // needed to allow sitrus procs
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -71,7 +71,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
game.override.enemyMoveset([MoveId.SPLASH, MoveId.HEAL_PULSE]);
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
// Dip below half to eat berry
|
||||
farigiraf.hp = farigiraf.getMaxHp() / 2 - 1;
|
||||
|
||||
@ -120,7 +120,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
.enemyMoveset(MoveId.TEATIME);
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
farigiraf.hp = 1; // needed to allow berry procs
|
||||
|
||||
game.move.select(MoveId.STUFF_CHEEKS);
|
||||
@ -148,7 +148,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
it("should reset both arrays on switch", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF, SpeciesId.GIRAFARIG]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
farigiraf.hp = 1;
|
||||
|
||||
// eat berry turn 1, switch out turn 2
|
||||
@ -177,7 +177,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
game.override.enemyAbility(AbilityId.NEUTRALIZING_GAS);
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
farigiraf.hp = 1;
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -199,7 +199,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
const apply = vi.spyOn(CudChewConsumeBerryAbAttr.prototype, "apply");
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
farigiraf.hp = 1;
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -225,7 +225,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
game.override.enemyAbility(AbilityId.UNNERVE);
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
farigiraf.hp = 1;
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -243,7 +243,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
game.override.enemyMoveset(MoveId.INCINERATE);
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
farigiraf.hp = farigiraf.getMaxHp() / 4;
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -262,7 +262,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
.startingHeldItems([]);
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.BUG_BITE);
|
||||
await game.toNextTurn();
|
||||
@ -278,7 +278,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
game.override.passiveAbility(AbilityId.RIPEN);
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
farigiraf.hp = 1;
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -294,7 +294,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
game.override.enemyLevel(1);
|
||||
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
const farigiraf = game.field.getPlayerPokemon();
|
||||
farigiraf.hp = 1;
|
||||
|
||||
game.move.select(MoveId.HYPER_VOICE);
|
||||
@ -307,7 +307,7 @@ describe("Abilities - Cud Chew", () => {
|
||||
// reload and the berry should still be there
|
||||
await game.reload.reloadSession();
|
||||
|
||||
const farigirafReloaded = game.scene.getPlayerPokemon()!;
|
||||
const farigirafReloaded = game.field.getPlayerPokemon();
|
||||
expect(farigirafReloaded.summonData.berriesEatenLast).toEqual([BerryType.SITRUS]);
|
||||
|
||||
const wave1Hp = farigirafReloaded.hp;
|
||||
|
@ -125,7 +125,7 @@ describe("Abilities - Dancer", () => {
|
||||
game.override.battleStyle("double").moveset(MoveId.SPLASH).enemyMoveset([MoveId.SWORDS_DANCE, MoveId.FAKE_OUT]);
|
||||
await game.classicMode.startBattle([SpeciesId.ORICORIO]);
|
||||
|
||||
const oricorio = game.scene.getPlayerPokemon()!;
|
||||
const oricorio = game.field.getPlayerPokemon();
|
||||
expect(oricorio).toBeDefined();
|
||||
|
||||
// get faked out and copy swords dance
|
||||
|
@ -36,7 +36,7 @@ describe("Abilities - Defiant", () => {
|
||||
it("lower atk and def by 1 via tickle, then increase atk by 4 via defiant", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FLYGON]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to(TurnInitPhase);
|
||||
|
||||
@ -48,7 +48,7 @@ describe("Abilities - Defiant", () => {
|
||||
game.override.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FLYGON]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.CLOSE_COMBAT);
|
||||
await game.phaseInterceptor.to(TurnInitPhase);
|
||||
|
||||
@ -61,7 +61,7 @@ describe("Abilities - Defiant", () => {
|
||||
game.override.startingHeldItems([{ name: "WHITE_HERB" }]);
|
||||
await game.classicMode.startBattle([SpeciesId.FLYGON]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to(TurnInitPhase);
|
||||
|
||||
|
@ -145,7 +145,7 @@ describe("Abilities - Desolate Land", () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
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);
|
||||
|
||||
const commandPhase = game.scene.phaseManager.getCurrentPhase() as CommandPhase;
|
||||
|
@ -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 () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const mimikyu = game.scene.getEnemyPokemon()!;
|
||||
const mimikyu = game.field.getEnemyPokemon();
|
||||
const maxHp = mimikyu.getMaxHp();
|
||||
const disguiseDamage = toDmgValue(maxHp / 8);
|
||||
|
||||
@ -54,7 +54,7 @@ describe("Abilities - Disguise", () => {
|
||||
it("doesn't break disguise when attacked with ineffective move", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const mimikyu = game.scene.getEnemyPokemon()!;
|
||||
const mimikyu = game.field.getEnemyPokemon();
|
||||
|
||||
expect(mimikyu.formIndex).toBe(disguisedForm);
|
||||
|
||||
@ -69,7 +69,7 @@ describe("Abilities - Disguise", () => {
|
||||
game.override.moveset([MoveId.SURGING_STRIKES]).enemyLevel(5);
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const mimikyu = game.scene.getEnemyPokemon()!;
|
||||
const mimikyu = game.field.getEnemyPokemon();
|
||||
const maxHp = mimikyu.getMaxHp();
|
||||
const disguiseDamage = toDmgValue(maxHp / 8);
|
||||
|
||||
@ -91,7 +91,7 @@ describe("Abilities - Disguise", () => {
|
||||
it("takes effects from status moves and damage from status effects", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const mimikyu = game.scene.getEnemyPokemon()!;
|
||||
const mimikyu = game.field.getEnemyPokemon();
|
||||
expect(mimikyu.hp).toBe(mimikyu.getMaxHp());
|
||||
|
||||
game.move.select(MoveId.TOXIC_THREAD);
|
||||
@ -109,7 +109,7 @@ describe("Abilities - Disguise", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MIMIKYU, SpeciesId.FURRET]);
|
||||
|
||||
const mimikyu = game.scene.getPlayerPokemon()!;
|
||||
const mimikyu = game.field.getPlayerPokemon();
|
||||
const maxHp = mimikyu.getMaxHp();
|
||||
const disguiseDamage = toDmgValue(maxHp / 8);
|
||||
|
||||
@ -154,7 +154,7 @@ describe("Abilities - Disguise", () => {
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const mimikyu = game.scene.getPlayerPokemon()!;
|
||||
const mimikyu = game.field.getPlayerPokemon();
|
||||
|
||||
expect(mimikyu.formIndex).toBe(bustedForm);
|
||||
|
||||
@ -175,7 +175,7 @@ describe("Abilities - Disguise", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MIMIKYU, SpeciesId.FURRET]);
|
||||
|
||||
const mimikyu1 = game.scene.getPlayerPokemon()!;
|
||||
const mimikyu1 = game.field.getPlayerPokemon();
|
||||
|
||||
expect(mimikyu1.formIndex).toBe(bustedForm);
|
||||
|
||||
@ -190,7 +190,7 @@ describe("Abilities - Disguise", () => {
|
||||
game.override.enemyMoveset([MoveId.ENDURE]);
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const mimikyu = game.scene.getEnemyPokemon()!;
|
||||
const mimikyu = game.field.getEnemyPokemon();
|
||||
mimikyu.hp = 1;
|
||||
|
||||
game.move.select(MoveId.SHADOW_SNEAK);
|
||||
@ -205,7 +205,7 @@ describe("Abilities - Disguise", () => {
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const mimikyu = game.scene.getEnemyPokemon()!;
|
||||
const mimikyu = game.field.getEnemyPokemon();
|
||||
const maxHp = mimikyu.getMaxHp();
|
||||
const disguiseDamage = toDmgValue(maxHp / 8);
|
||||
|
||||
@ -225,6 +225,6 @@ describe("Abilities - Disguise", () => {
|
||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(game.scene.getEnemyPokemon()!.formIndex).toBe(disguisedForm);
|
||||
expect(game.field.getEnemyPokemon().formIndex).toBe(disguisedForm);
|
||||
});
|
||||
});
|
||||
|
@ -35,7 +35,7 @@ describe("Abilities - Dry Skin", () => {
|
||||
it("during sunlight, lose 1/8 of maximum health at the end of each turn", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
// first turn
|
||||
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 () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
enemy.hp = 1;
|
||||
|
||||
@ -72,7 +72,7 @@ describe("Abilities - Dry Skin", () => {
|
||||
game.override.moveset([MoveId.FLAMETHROWER]);
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
const initialHP = 1000;
|
||||
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 () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
enemy.hp = 1;
|
||||
|
||||
@ -109,7 +109,7 @@ describe("Abilities - Dry Skin", () => {
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
enemy.hp = 1;
|
||||
|
||||
@ -123,7 +123,7 @@ describe("Abilities - Dry Skin", () => {
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
enemy.hp = 1;
|
||||
|
||||
@ -145,7 +145,7 @@ describe("Abilities - Dry Skin", () => {
|
||||
it("opposing water moves still heal regardless of accuracy check", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.WATER_GUN);
|
||||
enemy.hp = enemy.hp - 1;
|
||||
|
@ -37,7 +37,7 @@ describe("Abilities - Early Bird", () => {
|
||||
it("reduces Rest's sleep time to 1 turn", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.BELLY_DRUM);
|
||||
await game.toNextTurn();
|
||||
@ -62,7 +62,7 @@ describe("Abilities - Early Bird", () => {
|
||||
it("reduces 3-turn sleep to 1 turn", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
player.status = new Status(StatusEffect.SLEEP, 0, 4);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -81,7 +81,7 @@ describe("Abilities - Early Bird", () => {
|
||||
it("reduces 1-turn sleep to 0 turns", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
player.status = new Status(StatusEffect.SLEEP, 0, 2);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
|
@ -39,7 +39,7 @@ describe("Abilities - Flash Fire", () => {
|
||||
game.override.enemyMoveset([MoveId.EMBER]).moveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
|
||||
const blissey = game.scene.getPlayerPokemon()!;
|
||||
const blissey = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
@ -50,7 +50,7 @@ describe("Abilities - Flash Fire", () => {
|
||||
game.override.enemyMoveset([MoveId.EMBER]).moveset([MoveId.PROTECT]);
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
|
||||
const blissey = game.scene.getPlayerPokemon()!;
|
||||
const blissey = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.PROTECT);
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
@ -61,7 +61,7 @@ describe("Abilities - Flash Fire", () => {
|
||||
game.override.enemyMoveset([MoveId.WILL_O_WISP]).moveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
|
||||
const blissey = game.scene.getPlayerPokemon()!;
|
||||
const blissey = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.move.forceHit();
|
||||
@ -76,7 +76,7 @@ describe("Abilities - Flash Fire", () => {
|
||||
game.override.enemyMoveset([MoveId.EMBER]).moveset(MoveId.SPLASH).statusEffect(StatusEffect.FREEZE);
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
|
||||
const blissey = game.scene.getPlayerPokemon()!;
|
||||
const blissey = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
|
||||
@ -95,8 +95,8 @@ describe("Abilities - Flash Fire", () => {
|
||||
game.doSelectPartyPokemon(1);
|
||||
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
const chansey = game.scene.getPlayerPokemon()!;
|
||||
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(SpeciesId.CHANSEY);
|
||||
const chansey = game.field.getPlayerPokemon();
|
||||
expect(game.field.getPlayerPokemon().species.speciesId).toBe(SpeciesId.CHANSEY);
|
||||
expect(chansey!.getTag(BattlerTagType.FIRE_BOOST)).toBeUndefined();
|
||||
});
|
||||
|
||||
@ -107,7 +107,7 @@ describe("Abilities - Flash Fire", () => {
|
||||
.enemyAbility(AbilityId.FLASH_FIRE)
|
||||
.ability(AbilityId.NONE);
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
const blissey = game.scene.getPlayerPokemon()!;
|
||||
const blissey = game.field.getPlayerPokemon();
|
||||
const initialHP = 1000;
|
||||
blissey.hp = initialHP;
|
||||
|
||||
@ -137,7 +137,7 @@ describe("Abilities - Flash Fire", () => {
|
||||
.enemySpecies(SpeciesId.BLISSEY);
|
||||
await game.classicMode.startBattle([SpeciesId.RATTATA]);
|
||||
|
||||
const blissey = game.scene.getEnemyPokemon()!;
|
||||
const blissey = game.field.getEnemyPokemon();
|
||||
const initialHP = 1000;
|
||||
blissey.hp = initialHP;
|
||||
|
||||
|
@ -27,7 +27,7 @@ describe("Abilities - Flower Gift", () => {
|
||||
|
||||
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);
|
||||
await game.classicMode.startBattle([SpeciesId.CHERRIM]);
|
||||
|
||||
const cherrim = game.scene.getPlayerPokemon()!;
|
||||
const cherrim = game.field.getPlayerPokemon();
|
||||
expect(cherrim.formIndex).toBe(SUNSHINE_FORM);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -188,7 +188,7 @@ describe("Abilities - Flower Gift", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.CHERRIM, SpeciesId.MAGIKARP]);
|
||||
|
||||
const cherrim = game.scene.getPlayerPokemon()!;
|
||||
const cherrim = game.field.getPlayerPokemon();
|
||||
|
||||
expect(cherrim.formIndex).toBe(SUNSHINE_FORM);
|
||||
|
||||
@ -215,7 +215,7 @@ describe("Abilities - Flower Gift", () => {
|
||||
game.override.weather(WeatherType.SUNNY);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.MAGIKARP]);
|
||||
const cherrim = game.scene.getPlayerPokemon()!;
|
||||
const cherrim = game.field.getPlayerPokemon();
|
||||
|
||||
expect(cherrim.formIndex).toBe(SUNSHINE_FORM);
|
||||
|
||||
|
@ -46,7 +46,7 @@ describe("Abilities - Flower Veil", () => {
|
||||
.moveset([MoveId.REST, MoveId.SPLASH])
|
||||
.startingHeldItems([{ name: "FLAME_ORB" }]);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
const user = game.scene.getPlayerPokemon()!;
|
||||
const user = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.REST);
|
||||
await game.move.selectEnemyMove(MoveId.TACKLE);
|
||||
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.phaseInterceptor.to("BerryPhase");
|
||||
const user = game.scene.getPlayerPokemon()!;
|
||||
const user = game.field.getPlayerPokemon();
|
||||
expect(user.getTag(BattlerTagType.DROWSY)).toBeFalsy();
|
||||
expect(ally.getTag(BattlerTagType.DROWSY)).toBeFalsy();
|
||||
});
|
||||
@ -87,7 +87,7 @@ describe("Abilities - Flower Veil", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.move.selectEnemyMove(MoveId.THUNDER_WAVE);
|
||||
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 () => {
|
||||
@ -155,7 +155,7 @@ describe("Abilities - Flower Veil", () => {
|
||||
it("should prevent the drops while retaining the boosts from spicy extract", async () => {
|
||||
game.override.enemyMoveset([MoveId.SPICY_EXTRACT]).moveset([MoveId.SPLASH]);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
const user = game.scene.getPlayerPokemon()!;
|
||||
const user = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
expect(user.getStatStage(Stat.ATK)).toBe(2);
|
||||
|
@ -32,7 +32,7 @@ describe("Abilities - Forecast", () => {
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
|
||||
expect(game.scene.getPlayerPokemon()?.formIndex).toBe(NORMAL_FORM);
|
||||
expect(game.field.getPlayerPokemon().formIndex).toBe(NORMAL_FORM);
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
@ -186,14 +186,14 @@ describe("Abilities - Forecast", () => {
|
||||
game.move.select(MoveId.RAIN_DANCE);
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
expect(game.scene.getPlayerPokemon()?.formIndex).toBe(RAINY_FORM);
|
||||
expect(game.scene.getEnemyPokemon()?.formIndex).not.toBe(RAINY_FORM);
|
||||
expect(game.field.getPlayerPokemon().formIndex).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 () => {
|
||||
game.override.enemyMoveset([MoveId.GASTRO_ACID]).weather(WeatherType.RAIN);
|
||||
await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.PIKACHU]);
|
||||
const castform = game.scene.getPlayerPokemon()!;
|
||||
const castform = game.field.getPlayerPokemon();
|
||||
|
||||
expect(castform.formIndex).toBe(RAINY_FORM);
|
||||
|
||||
@ -233,7 +233,7 @@ describe("Abilities - Forecast", () => {
|
||||
game.doSwitchPokemon(1);
|
||||
await game.phaseInterceptor.to(PostSummonPhase);
|
||||
|
||||
const castform = game.scene.getPlayerPokemon()!;
|
||||
const castform = game.field.getPlayerPokemon();
|
||||
|
||||
// Damage phase should come first
|
||||
await game.phaseInterceptor.to(DamageAnimPhase);
|
||||
@ -248,7 +248,7 @@ describe("Abilities - Forecast", () => {
|
||||
game.override.weather(WeatherType.RAIN);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.MAGIKARP]);
|
||||
const castform = game.scene.getPlayerPokemon()!;
|
||||
const castform = game.field.getPlayerPokemon();
|
||||
|
||||
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 () => {
|
||||
game.override.enemyAbility(AbilityId.DROUGHT);
|
||||
await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.MAGIKARP]);
|
||||
const castform = game.scene.getPlayerPokemon()!;
|
||||
const castform = game.field.getPlayerPokemon();
|
||||
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 () => {
|
||||
game.override.ability(AbilityId.DROUGHT).enemySpecies(SpeciesId.CASTFORM).enemyAbility(AbilityId.FORECAST);
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
const castform = game.scene.getEnemyPokemon()!;
|
||||
const castform = game.field.getEnemyPokemon();
|
||||
expect(castform.formIndex).toBe(SUNNY_FORM);
|
||||
});
|
||||
});
|
||||
|
@ -43,7 +43,7 @@ describe("Abilities - Good As Gold", () => {
|
||||
game.override.enemyMoveset([MoveId.GROWL]);
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
|
||||
|
@ -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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.GALAR_DARMANITAN]);
|
||||
|
||||
const darmanitan = game.scene.getPlayerPokemon()!;
|
||||
const darmanitan = game.field.getPlayerPokemon();
|
||||
const initialAtkStat = darmanitan.getStat(Stat.ATK);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -86,7 +86,7 @@ describe("Abilities - Gorilla Tactics", () => {
|
||||
vi.spyOn(RandomMoveAttr.prototype, "getMoveOverride").mockReturnValue(MoveId.TACKLE);
|
||||
await game.classicMode.startBattle([SpeciesId.GALAR_DARMANITAN]);
|
||||
|
||||
const darmanitan = game.scene.getPlayerPokemon()!;
|
||||
const darmanitan = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.METRONOME);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
@ -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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.DIVE);
|
||||
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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
|
||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT, SpeciesId.MAGIKARP]);
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SURF);
|
||||
await game.toNextTurn();
|
||||
@ -95,7 +95,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||
|
||||
it("changes form during Dive's charge turn", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.DIVE);
|
||||
await game.phaseInterceptor.to("MoveEndPhase");
|
||||
@ -108,7 +108,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||
game.override.enemyMoveset(MoveId.TACKLE);
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
vi.spyOn(enemy, "damageAndUpdate");
|
||||
|
||||
game.move.select(MoveId.SURF);
|
||||
@ -121,7 +121,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||
game.override.enemyMoveset(MoveId.TAIL_WHIP);
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55);
|
||||
|
||||
game.move.select(MoveId.SURF);
|
||||
@ -140,8 +140,8 @@ describe("Abilities - Gulp Missile", () => {
|
||||
game.override.enemyMoveset(MoveId.TACKLE);
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
vi.spyOn(enemy, "damageAndUpdate");
|
||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55);
|
||||
@ -164,8 +164,8 @@ describe("Abilities - Gulp Missile", () => {
|
||||
game.override.enemyMoveset(MoveId.TACKLE);
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
vi.spyOn(enemy, "damageAndUpdate");
|
||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.45);
|
||||
@ -188,7 +188,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||
game.override.enemyMoveset(MoveId.SURF);
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.DIVE);
|
||||
await game.phaseInterceptor.to("BerryPhase", false);
|
||||
@ -201,8 +201,8 @@ describe("Abilities - Gulp Missile", () => {
|
||||
game.override.enemyMoveset(MoveId.TACKLE).enemyAbility(AbilityId.MAGIC_GUARD);
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55);
|
||||
|
||||
@ -225,7 +225,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||
game.override.enemyMoveset(MoveId.THUNDERBOLT);
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SURF);
|
||||
await game.phaseInterceptor.to("FaintPhase");
|
||||
@ -233,7 +233,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||
expect(cramorant.hp).toBe(0);
|
||||
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeUndefined();
|
||||
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 () => {
|
||||
@ -244,21 +244,21 @@ describe("Abilities - Gulp Missile", () => {
|
||||
await game.move.selectEnemyMove(MoveId.SPLASH);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!.formIndex).toBe(GULPING_FORM);
|
||||
expect(game.field.getPlayerPokemon().formIndex).toBe(GULPING_FORM);
|
||||
|
||||
game.move.select(MoveId.SUBSTITUTE);
|
||||
await game.move.selectEnemyMove(MoveId.POWER_TRIP);
|
||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!.formIndex).toBe(GULPING_FORM);
|
||||
expect(game.field.getPlayerPokemon().formIndex).toBe(GULPING_FORM);
|
||||
});
|
||||
|
||||
it("cannot be suppressed", async () => {
|
||||
game.override.enemyMoveset(MoveId.GASTRO_ACID);
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55);
|
||||
|
||||
game.move.select(MoveId.SURF);
|
||||
@ -278,7 +278,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||
game.override.enemyMoveset(MoveId.SKILL_SWAP);
|
||||
await game.classicMode.startBattle([SpeciesId.CRAMORANT]);
|
||||
|
||||
const cramorant = game.scene.getPlayerPokemon()!;
|
||||
const cramorant = game.field.getPlayerPokemon();
|
||||
vi.spyOn(cramorant, "getHpRatio").mockReturnValue(0.55);
|
||||
|
||||
game.move.select(MoveId.SURF);
|
||||
@ -301,6 +301,6 @@ describe("Abilities - Gulp Missile", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
@ -19,7 +19,7 @@ describe("Abilities - Harvest", () => {
|
||||
let game: GameManager;
|
||||
|
||||
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. */
|
||||
function expectBerriesContaining(...berries: ModifierOverride[]): void {
|
||||
@ -64,11 +64,11 @@ describe("Abilities - Harvest", () => {
|
||||
await game.move.selectEnemyMove(MoveId.NUZZLE);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
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");
|
||||
|
||||
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 () => {
|
||||
@ -82,7 +82,7 @@ describe("Abilities - Harvest", () => {
|
||||
.enemyAbility(AbilityId.NEUTRALIZING_GAS);
|
||||
await game.classicMode.startBattle([SpeciesId.MILOTIC]);
|
||||
|
||||
const milotic = game.scene.getPlayerPokemon()!;
|
||||
const milotic = game.field.getPlayerPokemon();
|
||||
expect(milotic).toBeDefined();
|
||||
|
||||
// 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
|
||||
await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
|
||||
|
||||
const regieleki = game.scene.getPlayerPokemon()!;
|
||||
const regieleki = game.field.getPlayerPokemon();
|
||||
regieleki.hp = 1;
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -150,7 +150,7 @@ describe("Abilities - Harvest", () => {
|
||||
.enemyAbility(AbilityId.COMPOUND_EYES);
|
||||
await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
|
||||
|
||||
const regieleki = game.scene.getPlayerPokemon()!;
|
||||
const regieleki = game.field.getPlayerPokemon();
|
||||
regieleki.hp = regieleki.getMaxHp() / 4 + 1;
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -161,7 +161,7 @@ describe("Abilities - Harvest", () => {
|
||||
// ate 1 berry and recovered it
|
||||
expect(regieleki.battleData.berriesEaten).toEqual([]);
|
||||
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
|
||||
game.move.select(MoveId.EARTHQUAKE);
|
||||
@ -170,13 +170,13 @@ describe("Abilities - Harvest", () => {
|
||||
await game.toNextWave();
|
||||
|
||||
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();
|
||||
|
||||
expect(regieleki.battleData.berriesEaten).toEqual([]);
|
||||
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 () => {
|
||||
@ -187,7 +187,7 @@ describe("Abilities - Harvest", () => {
|
||||
game.override.startingHeldItems(initBerries);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
const feebas = game.scene.getPlayerPokemon()!;
|
||||
const feebas = game.field.getPlayerPokemon();
|
||||
feebas.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF];
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -215,7 +215,7 @@ describe("Abilities - Harvest", () => {
|
||||
game.override.startingHeldItems(initBerries);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
player.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF];
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -234,7 +234,7 @@ describe("Abilities - Harvest", () => {
|
||||
await game.move.selectEnemyMove(MoveId.INCINERATE);
|
||||
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 () => {
|
||||
@ -245,7 +245,7 @@ describe("Abilities - Harvest", () => {
|
||||
await game.move.selectEnemyMove(MoveId.KNOCK_OFF);
|
||||
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 () => {
|
||||
@ -257,7 +257,7 @@ describe("Abilities - Harvest", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]);
|
||||
expect(game.field.getPlayerPokemon().battleData.berriesEaten).toEqual([]);
|
||||
expectBerriesContaining(...initBerries);
|
||||
});
|
||||
|
||||
@ -271,8 +271,8 @@ describe("Abilities - Harvest", () => {
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
// pluck triggers harvest for neither side
|
||||
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]);
|
||||
expect(game.scene.getEnemyPokemon()?.battleData.berriesEaten).toEqual([]);
|
||||
expect(game.field.getPlayerPokemon().battleData.berriesEaten).toEqual([]);
|
||||
expect(game.field.getEnemyPokemon().battleData.berriesEaten).toEqual([]);
|
||||
expect(getPlayerBerries()).toEqual([]);
|
||||
});
|
||||
|
||||
@ -293,7 +293,7 @@ describe("Abilities - Harvest", () => {
|
||||
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)
|
||||
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]);
|
||||
expect(game.field.getPlayerPokemon().battleData.berriesEaten).toEqual([]);
|
||||
expectBerriesContaining(...initBerries);
|
||||
});
|
||||
|
||||
@ -303,7 +303,7 @@ describe("Abilities - Harvest", () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MEOWSCARADA]);
|
||||
|
||||
// pre damage
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
player.hp = 1;
|
||||
|
||||
// steal a sitrus and immediately consume it
|
||||
@ -326,7 +326,7 @@ describe("Abilities - Harvest", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toBe([]);
|
||||
expect(game.field.getPlayerPokemon().battleData.berriesEaten).toBe([]);
|
||||
expect(getPlayerBerries()).toEqual([]);
|
||||
});
|
||||
|
||||
@ -339,7 +339,7 @@ describe("Abilities - Harvest", () => {
|
||||
game.move.select(MoveId.NATURAL_GIFT);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toHaveLength(0);
|
||||
expect(game.field.getPlayerPokemon().battleData.berriesEaten).toHaveLength(0);
|
||||
expectBerriesContaining(...initBerries);
|
||||
});
|
||||
});
|
||||
|
@ -46,9 +46,10 @@ describe("Abilities - Healer", () => {
|
||||
game.override.moveset([MoveId.SPLASH, MoveId.LUNAR_DANCE]);
|
||||
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
|
||||
vi.spyOn(user, "getAbility").mockReturnValue(allAbilities[AbilityId.HEALER]);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
// faint the ally
|
||||
game.move.select(MoveId.LUNAR_DANCE, 1);
|
||||
@ -62,9 +63,10 @@ describe("Abilities - Healer", () => {
|
||||
it("should heal the status of an ally if the ally has a status", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP, SpeciesId.MAGIKARP]);
|
||||
const [user, ally] = game.scene.getPlayerField();
|
||||
|
||||
// Only want one magikarp to have the ability.
|
||||
vi.spyOn(user, "getAbility").mockReturnValue(allAbilities[AbilityId.HEALER]);
|
||||
expect(ally.trySetStatus(StatusEffect.BURN)).toBe(true);
|
||||
ally.doSetStatus(StatusEffect.BURN);
|
||||
game.move.select(MoveId.SPLASH);
|
||||
game.move.select(MoveId.SPLASH, 1);
|
||||
|
||||
@ -80,7 +82,7 @@ describe("Abilities - Healer", () => {
|
||||
const [user, ally] = game.scene.getPlayerField();
|
||||
// Only want one magikarp to have the ability.
|
||||
vi.spyOn(user, "getAbility").mockReturnValue(allAbilities[AbilityId.HEALER]);
|
||||
expect(ally.trySetStatus(StatusEffect.BURN)).toBe(true);
|
||||
ally.doSetStatus(StatusEffect.BURN);
|
||||
game.move.select(MoveId.SPLASH);
|
||||
game.move.select(MoveId.SPLASH, 1);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
@ -40,7 +40,7 @@ describe("Abilities - Heatproof", () => {
|
||||
it("reduces Fire type damage by half", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
const initialHP = 1000;
|
||||
enemy.hp = initialHP;
|
||||
|
||||
@ -63,7 +63,7 @@ describe("Abilities - Heatproof", () => {
|
||||
game.override.enemyStatusEffect(StatusEffect.BURN).enemySpecies(SpeciesId.ABRA);
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.toNextTurn();
|
||||
|
@ -62,7 +62,7 @@ describe("Abilities - Honey Gather", () => {
|
||||
game.scene.money = 1000;
|
||||
|
||||
// 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);
|
||||
// Expects next wave so run must succeed
|
||||
vi.spyOn(Overrides, "RUN_SUCCESS_OVERRIDE", "get").mockReturnValue(true);
|
||||
|
@ -35,7 +35,7 @@ describe("Abilities - Hustle", () => {
|
||||
|
||||
it("increases the user's Attack stat by 50%", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon()!;
|
||||
const pikachu = game.field.getPlayerPokemon();
|
||||
const atk = pikachu.stats[Stat.ATK];
|
||||
|
||||
vi.spyOn(pikachu, "getEffectiveStat");
|
||||
@ -49,7 +49,7 @@ describe("Abilities - Hustle", () => {
|
||||
|
||||
it("lowers the accuracy of the user's physical moves by 20%", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon()!;
|
||||
const pikachu = game.field.getPlayerPokemon();
|
||||
|
||||
vi.spyOn(pikachu, "getAccuracyMultiplier");
|
||||
|
||||
@ -61,7 +61,7 @@ describe("Abilities - Hustle", () => {
|
||||
|
||||
it("does not affect non-physical moves", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon()!;
|
||||
const pikachu = game.field.getPlayerPokemon();
|
||||
const spatk = pikachu.stats[Stat.SPATK];
|
||||
|
||||
vi.spyOn(pikachu, "getEffectiveStat");
|
||||
@ -78,8 +78,8 @@ describe("Abilities - Hustle", () => {
|
||||
game.override.startingLevel(100).enemyLevel(30);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const pikachu = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
vi.spyOn(pikachu, "getAccuracyMultiplier");
|
||||
vi.spyOn(allMoves[MoveId.FISSURE], "calculateBattleAccuracy");
|
||||
|
@ -36,7 +36,7 @@ describe("Abilities - Hyper Cutter", () => {
|
||||
it("only prevents ATK drops", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.OCTOLOCK);
|
||||
await game.toNextTurn();
|
||||
|
@ -44,7 +44,7 @@ describe("Abilities - Ice Face", () => {
|
||||
|
||||
await game.phaseInterceptor.to(MoveEndPhase);
|
||||
|
||||
const eiscue = game.scene.getEnemyPokemon()!;
|
||||
const eiscue = game.field.getEnemyPokemon();
|
||||
|
||||
expect(eiscue.isFullHp()).toBe(true);
|
||||
expect(eiscue.formIndex).toBe(noiceForm);
|
||||
@ -57,7 +57,7 @@ describe("Abilities - Ice Face", () => {
|
||||
|
||||
game.move.select(MoveId.SURGING_STRIKES);
|
||||
|
||||
const eiscue = game.scene.getEnemyPokemon()!;
|
||||
const eiscue = game.field.getEnemyPokemon();
|
||||
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined();
|
||||
|
||||
// First hit
|
||||
@ -85,7 +85,7 @@ describe("Abilities - Ice Face", () => {
|
||||
|
||||
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.formIndex).toBe(icefaceForm);
|
||||
@ -99,7 +99,7 @@ describe("Abilities - Ice Face", () => {
|
||||
|
||||
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.formIndex).toBe(icefaceForm);
|
||||
@ -114,7 +114,7 @@ describe("Abilities - Ice Face", () => {
|
||||
|
||||
await game.phaseInterceptor.to(MoveEndPhase);
|
||||
|
||||
const eiscue = game.scene.getEnemyPokemon()!;
|
||||
const eiscue = game.field.getEnemyPokemon();
|
||||
|
||||
expect(eiscue.isFullHp()).toBe(true);
|
||||
expect(eiscue.formIndex).toBe(noiceForm);
|
||||
@ -134,7 +134,7 @@ describe("Abilities - Ice Face", () => {
|
||||
game.move.select(MoveId.SNOWSCAPE);
|
||||
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
let eiscue = game.scene.getPlayerPokemon()!;
|
||||
let eiscue = game.field.getPlayerPokemon();
|
||||
|
||||
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined();
|
||||
expect(eiscue.formIndex).toBe(noiceForm);
|
||||
@ -146,7 +146,7 @@ describe("Abilities - Ice Face", () => {
|
||||
game.doSwitchPokemon(1);
|
||||
|
||||
await game.phaseInterceptor.to(QuietFormChangePhase);
|
||||
eiscue = game.scene.getPlayerPokemon()!;
|
||||
eiscue = game.field.getPlayerPokemon();
|
||||
|
||||
expect(eiscue.formIndex).toBe(icefaceForm);
|
||||
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined);
|
||||
@ -158,7 +158,7 @@ describe("Abilities - Ice Face", () => {
|
||||
await game.classicMode.startBattle([SpeciesId.EISCUE]);
|
||||
|
||||
game.move.select(MoveId.HAIL);
|
||||
const eiscue = game.scene.getPlayerPokemon()!;
|
||||
const eiscue = game.field.getPlayerPokemon();
|
||||
|
||||
await game.phaseInterceptor.to(QuietFormChangePhase);
|
||||
|
||||
@ -179,7 +179,7 @@ describe("Abilities - Ice Face", () => {
|
||||
game.move.select(MoveId.ICE_BEAM);
|
||||
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
let eiscue = game.scene.getPlayerPokemon()!;
|
||||
let eiscue = game.field.getPlayerPokemon();
|
||||
|
||||
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined();
|
||||
expect(eiscue.formIndex).toBe(noiceForm);
|
||||
@ -206,7 +206,7 @@ describe("Abilities - Ice Face", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.EISCUE]);
|
||||
|
||||
const eiscue = game.scene.getPlayerPokemon()!;
|
||||
const eiscue = game.field.getPlayerPokemon();
|
||||
|
||||
expect(eiscue.formIndex).toBe(noiceForm);
|
||||
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined();
|
||||
@ -229,7 +229,7 @@ describe("Abilities - Ice Face", () => {
|
||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(game.scene.getEnemyPokemon()!.formIndex).toBe(icefaceForm);
|
||||
expect(game.field.getEnemyPokemon().formIndex).toBe(icefaceForm);
|
||||
});
|
||||
|
||||
it("cannot be suppressed", async () => {
|
||||
@ -241,7 +241,7 @@ describe("Abilities - Ice Face", () => {
|
||||
|
||||
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.formIndex).toBe(icefaceForm);
|
||||
@ -257,7 +257,7 @@ describe("Abilities - Ice Face", () => {
|
||||
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
const eiscue = game.scene.getEnemyPokemon()!;
|
||||
const eiscue = game.field.getEnemyPokemon();
|
||||
|
||||
expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined();
|
||||
expect(eiscue.formIndex).toBe(icefaceForm);
|
||||
@ -269,10 +269,10 @@ describe("Abilities - Ice Face", () => {
|
||||
|
||||
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.formIndex).toBe(icefaceForm);
|
||||
expect(game.scene.getPlayerPokemon()!.hasAbility(AbilityId.TRACE)).toBe(true);
|
||||
expect(game.field.getPlayerPokemon().hasAbility(AbilityId.TRACE)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
@ -33,7 +33,7 @@ describe("Abilities - Illuminate", () => {
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
|
||||
expect(player.getStatStage(Stat.ACC)).toBe(0);
|
||||
|
||||
|
@ -35,8 +35,8 @@ describe("Abilities - Illusion", () => {
|
||||
|
||||
it("creates illusion at the start", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.ZOROARK, SpeciesId.FEEBAS]);
|
||||
const zoroark = game.scene.getPlayerPokemon()!;
|
||||
const zorua = game.scene.getEnemyPokemon()!;
|
||||
const zoroark = game.field.getPlayerPokemon();
|
||||
const zorua = game.field.getEnemyPokemon();
|
||||
|
||||
expect(!!zoroark.summonData.illusion).equals(true);
|
||||
expect(!!zorua.summonData.illusion).equals(true);
|
||||
@ -48,7 +48,7 @@ describe("Abilities - Illusion", () => {
|
||||
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
const zorua = game.scene.getEnemyPokemon()!;
|
||||
const zorua = game.field.getEnemyPokemon();
|
||||
|
||||
expect(!!zorua.summonData.illusion).equals(false);
|
||||
expect(zorua.name).equals("Zorua");
|
||||
@ -60,7 +60,7 @@ describe("Abilities - Illusion", () => {
|
||||
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
const zorua = game.scene.getEnemyPokemon()!;
|
||||
const zorua = game.field.getEnemyPokemon();
|
||||
|
||||
expect(!!zorua.summonData.illusion).equals(false);
|
||||
});
|
||||
@ -69,7 +69,7 @@ describe("Abilities - Illusion", () => {
|
||||
game.override.enemyAbility(AbilityId.NEUTRALIZING_GAS);
|
||||
await game.classicMode.startBattle([SpeciesId.KOFFING]);
|
||||
|
||||
const zorua = game.scene.getEnemyPokemon()!;
|
||||
const zorua = game.field.getEnemyPokemon();
|
||||
|
||||
expect(!!zorua.summonData.illusion).equals(false);
|
||||
});
|
||||
@ -85,15 +85,15 @@ describe("Abilities - Illusion", () => {
|
||||
game.doSwitchPokemon(1);
|
||||
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 () => {
|
||||
game.override.enemyMoveset([MoveId.FLAMETHROWER, MoveId.PSYCHIC, MoveId.TACKLE]);
|
||||
await game.classicMode.startBattle([SpeciesId.ZOROARK, SpeciesId.FEEBAS]);
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const zoroark = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
const zoroark = game.field.getPlayerPokemon();
|
||||
|
||||
const flameThrower = enemy.getMoveset()[0]!.getMove();
|
||||
const psychic = enemy.getMoveset()[1]!.getMove();
|
||||
@ -125,7 +125,7 @@ describe("Abilities - Illusion", () => {
|
||||
await game.move.forceEnemyMove(MoveId.WILL_O_WISP);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
const zoroark = game.scene.getPlayerPokemon()!;
|
||||
const zoroark = game.field.getPlayerPokemon();
|
||||
expect(!!zoroark.summonData.illusion).equals(true);
|
||||
});
|
||||
|
||||
@ -143,7 +143,7 @@ describe("Abilities - Illusion", () => {
|
||||
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
const zoroark = game.scene.getPlayerPokemon()!;
|
||||
const zoroark = game.field.getPlayerPokemon();
|
||||
|
||||
expect(zoroark.summonData.illusion?.name).equals("Axew");
|
||||
expect(zoroark.getNameToRender(true)).equals("axew nickname");
|
||||
@ -155,7 +155,7 @@ describe("Abilities - Illusion", () => {
|
||||
it("breaks when suppressed", async () => {
|
||||
game.override.moveset(MoveId.GASTRO_ACID);
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
const zorua = game.scene.getEnemyPokemon()!;
|
||||
const zorua = game.field.getEnemyPokemon();
|
||||
|
||||
expect(!!zorua.summonData?.illusion).toBe(true);
|
||||
|
||||
|
@ -58,8 +58,8 @@ describe("Abilities - Infiltrator", () => {
|
||||
])("should bypass the target's $effectName", async ({ tagType, move }) => {
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
const preScreenDmg = enemy.getAttackDamage({ source: player, move: allMoves[move] }).damage;
|
||||
|
||||
@ -74,14 +74,14 @@ describe("Abilities - Infiltrator", () => {
|
||||
it("should bypass the target's Safeguard", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
game.scene.arena.addTag(ArenaTagType.SAFEGUARD, 1, MoveId.NONE, enemy.id, ArenaTagSide.ENEMY, true);
|
||||
|
||||
game.move.select(MoveId.SPORE);
|
||||
game.move.use(MoveId.SPORE);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
await game.phaseInterceptor.to("BerryPhase", false);
|
||||
expect(enemy.status?.effect).toBe(StatusEffect.SLEEP);
|
||||
expect(player.waveData.abilitiesApplied).toContain(AbilityId.INFILTRATOR);
|
||||
});
|
||||
@ -90,8 +90,8 @@ describe("Abilities - Infiltrator", () => {
|
||||
it.todo("should bypass the target's Mist", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const player = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
enemy.addTag(BattlerTagType.SUBSTITUTE, 1, MoveId.NONE, enemy.id);
|
||||
|
||||
|
@ -1,51 +0,0 @@
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Insomnia", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([MoveId.SPLASH])
|
||||
.ability(AbilityId.BALL_FETCH)
|
||||
.battleStyle("single")
|
||||
.criticalHits(false)
|
||||
.enemySpecies(SpeciesId.MAGIKARP)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
});
|
||||
|
||||
it("should remove sleep when gained", async () => {
|
||||
game.override
|
||||
.ability(AbilityId.INSOMNIA)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.moveset(MoveId.SKILL_SWAP)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
enemy?.trySetStatus(StatusEffect.SLEEP);
|
||||
expect(enemy?.status?.effect).toBe(StatusEffect.SLEEP);
|
||||
|
||||
game.move.select(MoveId.SKILL_SWAP);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy?.status).toBeNull();
|
||||
});
|
||||
});
|
@ -32,8 +32,8 @@ describe("Abilities - Intrepid Sword", () => {
|
||||
it("should raise ATK stat stage by 1 on entry", async () => {
|
||||
await game.classicMode.runToSummon([SpeciesId.ZACIAN]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
await game.phaseInterceptor.to(CommandPhase, false);
|
||||
|
||||
|
@ -1,51 +0,0 @@
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Limber", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([MoveId.SPLASH])
|
||||
.ability(AbilityId.BALL_FETCH)
|
||||
.battleStyle("single")
|
||||
.criticalHits(false)
|
||||
.enemySpecies(SpeciesId.MAGIKARP)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
});
|
||||
|
||||
it("should remove paralysis when gained", async () => {
|
||||
game.override
|
||||
.ability(AbilityId.LIMBER)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.moveset(MoveId.SKILL_SWAP)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
enemy?.trySetStatus(StatusEffect.PARALYSIS);
|
||||
expect(enemy?.status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
|
||||
game.move.select(MoveId.SKILL_SWAP);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy?.status).toBeNull();
|
||||
});
|
||||
});
|
@ -42,7 +42,7 @@ describe("Abilities - Magic Bounce", () => {
|
||||
|
||||
game.move.use(MoveId.GROWL);
|
||||
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 () => {
|
||||
@ -53,7 +53,7 @@ describe("Abilities - Magic Bounce", () => {
|
||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||
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 () => {
|
||||
@ -70,12 +70,12 @@ describe("Abilities - Magic Bounce", () => {
|
||||
|
||||
it("should still bounce back a move that would otherwise fail", async () => {
|
||||
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);
|
||||
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 () => {
|
||||
@ -85,7 +85,7 @@ describe("Abilities - Magic Bounce", () => {
|
||||
game.move.select(MoveId.GROWL);
|
||||
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 () => {
|
||||
@ -95,7 +95,7 @@ describe("Abilities - Magic Bounce", () => {
|
||||
game.move.select(MoveId.GROWL);
|
||||
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 () => {
|
||||
@ -105,7 +105,7 @@ describe("Abilities - Magic Bounce", () => {
|
||||
game.move.use(MoveId.GROWL);
|
||||
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 () => {
|
||||
@ -156,7 +156,7 @@ describe("Abilities - Magic Bounce", () => {
|
||||
game.move.select(MoveId.CURSE);
|
||||
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
|
||||
@ -164,8 +164,8 @@ describe("Abilities - Magic Bounce", () => {
|
||||
game.override.moveset([MoveId.SPLASH, MoveId.GROWL, MoveId.ENCORE]).enemyMoveset([MoveId.TACKLE, MoveId.GROWL]);
|
||||
// game.override.ability(AbilityId.MOLD_BREAKER);
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
// Give the player MOLD_BREAKER for this turn to bypass Magic Bounce.
|
||||
const playerAbilitySpy = game.field.mockAbility(playerPokemon, AbilityId.MOLD_BREAKER);
|
||||
@ -194,8 +194,8 @@ describe("Abilities - Magic Bounce", () => {
|
||||
.enemyAbility(AbilityId.MAGIC_BOUNCE);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
// turn 1
|
||||
game.move.select(MoveId.GROWL);
|
||||
@ -237,7 +237,7 @@ describe("Abilities - Magic Bounce", () => {
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const stomping_tantrum = allMoves[MoveId.STOMPING_TANTRUM];
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
vi.spyOn(stomping_tantrum, "calculateBattlePower");
|
||||
|
||||
// Spore gets reflected back onto us
|
||||
@ -260,35 +260,35 @@ describe("Abilities - Magic Bounce", () => {
|
||||
// Turn 1 - thunder wave immunity test
|
||||
game.move.select(MoveId.THUNDER_WAVE);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
expect(game.scene.getPlayerPokemon()!.status).toBeUndefined();
|
||||
expect(game.field.getPlayerPokemon().status).toBeUndefined();
|
||||
|
||||
// Turn 2 - soundproof immunity test
|
||||
game.move.select(MoveId.GROWL);
|
||||
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 () => {
|
||||
game.override.moveset([MoveId.SPORE]);
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const attacker = game.scene.getPlayerPokemon()!;
|
||||
const attacker = game.field.getPlayerPokemon();
|
||||
|
||||
vi.spyOn(attacker, "getAccuracyMultiplier").mockReturnValue(0.0);
|
||||
game.move.select(MoveId.SPORE);
|
||||
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 () => {
|
||||
game.override.moveset([MoveId.SPORE]);
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
const opponent = game.scene.getEnemyPokemon()!;
|
||||
const opponent = game.field.getEnemyPokemon();
|
||||
|
||||
vi.spyOn(opponent, "getAccuracyMultiplier").mockReturnValue(0);
|
||||
game.move.select(MoveId.SPORE);
|
||||
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 () => {
|
||||
@ -332,14 +332,14 @@ describe("Abilities - Magic Bounce", () => {
|
||||
await game.move.selectEnemyMove(MoveId.FLY);
|
||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.TOXIC);
|
||||
expect(game.scene.getPlayerPokemon()!.status).toBeUndefined();
|
||||
expect(game.field.getEnemyPokemon().status?.effect).toBe(StatusEffect.TOXIC);
|
||||
expect(game.field.getPlayerPokemon().status).toBeUndefined();
|
||||
|
||||
game.override.ability(AbilityId.NO_GUARD);
|
||||
game.move.select(MoveId.CHARM);
|
||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.ATK)).toBe(-2);
|
||||
expect(game.scene.getPlayerPokemon()!.getStatStage(Stat.ATK)).toBe(0);
|
||||
expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-2);
|
||||
expect(game.field.getPlayerPokemon().getStatStage(Stat.ATK)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
@ -1,51 +0,0 @@
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Magma Armor", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([MoveId.SPLASH])
|
||||
.ability(AbilityId.BALL_FETCH)
|
||||
.battleStyle("single")
|
||||
.criticalHits(false)
|
||||
.enemySpecies(SpeciesId.MAGIKARP)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
});
|
||||
|
||||
it("should remove freeze when gained", async () => {
|
||||
game.override
|
||||
.ability(AbilityId.MAGMA_ARMOR)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.moveset(MoveId.SKILL_SWAP)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
enemy?.trySetStatus(StatusEffect.FREEZE);
|
||||
expect(enemy?.status?.effect).toBe(StatusEffect.FREEZE);
|
||||
|
||||
game.move.select(MoveId.SKILL_SWAP);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy?.status).toBeNull();
|
||||
});
|
||||
});
|
@ -47,44 +47,44 @@ describe("Abilities - Mimicry", () => {
|
||||
});
|
||||
|
||||
it("Pokemon should revert back to its original, root type once terrain ends", async () => {
|
||||
game.override
|
||||
.moveset([MoveId.SPLASH, MoveId.TRANSFORM])
|
||||
.enemyAbility(AbilityId.MIMICRY)
|
||||
.enemyMoveset([MoveId.SPLASH, MoveId.PSYCHIC_TERRAIN]);
|
||||
game.override.enemyAbility(AbilityId.MIMICRY);
|
||||
await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon();
|
||||
game.move.select(MoveId.TRANSFORM);
|
||||
await game.move.selectEnemyMove(MoveId.PSYCHIC_TERRAIN);
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.use(MoveId.SKILL_SWAP);
|
||||
await game.move.forceEnemyMove(MoveId.PSYCHIC_TERRAIN);
|
||||
await game.toNextTurn();
|
||||
expect(playerPokemon?.getTypes().includes(PokemonType.PSYCHIC)).toBe(true);
|
||||
|
||||
expect(playerPokemon.getTypes()).toEqual([PokemonType.PSYCHIC]);
|
||||
|
||||
if (game.scene.arena.terrain) {
|
||||
game.scene.arena.terrain.turnsLeft = 1;
|
||||
}
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.move.selectEnemyMove(MoveId.SPLASH);
|
||||
game.move.use(MoveId.SPLASH);
|
||||
await game.move.forceEnemyMove(MoveId.SPLASH);
|
||||
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 () => {
|
||||
game.override.enemyMoveset([MoveId.FORESTS_CURSE, MoveId.GRASSY_TERRAIN]);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon();
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.move.selectEnemyMove(MoveId.FORESTS_CURSE);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(playerPokemon?.summonData.addedType).toBe(PokemonType.GRASS);
|
||||
expect(playerPokemon.summonData.addedType).toBe(PokemonType.GRASS);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.move.selectEnemyMove(MoveId.GRASSY_TERRAIN);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(playerPokemon?.summonData.addedType).toBeNull();
|
||||
expect(playerPokemon?.getTypes().includes(PokemonType.GRASS)).toBe(true);
|
||||
expect(playerPokemon.summonData.addedType).toBeNull();
|
||||
expect(playerPokemon.getTypes()).toEqual([PokemonType.GRASS]);
|
||||
});
|
||||
});
|
||||
|
@ -40,8 +40,8 @@ describe("Ability - Mirror Armor", () => {
|
||||
game.override.ability(AbilityId.MIRROR_ARMOR).enemyAbility(AbilityId.INTIMIDATE);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const userPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const userPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
// Enemy has intimidate, enemy should lose -1 atk
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -56,8 +56,8 @@ describe("Ability - Mirror Armor", () => {
|
||||
game.override.enemyAbility(AbilityId.MIRROR_ARMOR).ability(AbilityId.INTIMIDATE);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const userPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const userPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
// Enemy has intimidate, enemy should lose -1 atk
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -112,8 +112,8 @@ describe("Ability - Mirror Armor", () => {
|
||||
game.override.ability(AbilityId.MIRROR_ARMOR).enemyAbility(AbilityId.INTIMIDATE);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const userPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const userPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
// Enemy has intimidate and uses tickle, enemy receives -2 atk and -1 defense
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -153,8 +153,8 @@ describe("Ability - Mirror Armor", () => {
|
||||
game.override.enemyAbility(AbilityId.MIRROR_ARMOR).ability(AbilityId.INTIMIDATE);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const userPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const userPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
// Enemy has intimidate and uses tickle, enemy receives -2 atk and -1 defense
|
||||
game.move.select(MoveId.TICKLE);
|
||||
@ -171,8 +171,8 @@ describe("Ability - Mirror Armor", () => {
|
||||
game.override.enemyAbility(AbilityId.WHITE_SMOKE).ability(AbilityId.MIRROR_ARMOR);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const userPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const userPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
// Enemy has intimidate and uses tickle, enemy has white smoke, no one loses stats
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -189,8 +189,8 @@ describe("Ability - Mirror Armor", () => {
|
||||
game.override.ability(AbilityId.WHITE_SMOKE).enemyAbility(AbilityId.MIRROR_ARMOR);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const userPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const userPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
// Enemy has intimidate and uses tickle, enemy has white smoke, no one loses stats
|
||||
game.move.select(MoveId.TICKLE);
|
||||
@ -207,8 +207,8 @@ describe("Ability - Mirror Armor", () => {
|
||||
game.override.ability(AbilityId.MIRROR_ARMOR);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const userPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const userPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
// Enemy uses octolock, player loses stats at end of turn
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -225,8 +225,8 @@ describe("Ability - Mirror Armor", () => {
|
||||
game.override.enemyAbility(AbilityId.MIRROR_ARMOR);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const userPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const userPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
// Player uses octolock, enemy loses stats at end of turn
|
||||
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);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const userPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const userPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.move.selectEnemyMove(MoveId.SPLASH, BattlerIndex.PLAYER);
|
||||
@ -258,8 +258,8 @@ describe("Ability - Mirror Armor", () => {
|
||||
game.override.ability(AbilityId.MIRROR_ARMOR);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR, SpeciesId.CHARMANDER, SpeciesId.SQUIRTLE]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const userPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const userPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.move.selectEnemyMove(MoveId.STICKY_WEB, BattlerIndex.PLAYER);
|
||||
|
@ -35,7 +35,7 @@ describe("Abilities - Moody", () => {
|
||||
it("should increase one stat stage by 2 and decrease a different stat stage by 1", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.SPLASH);
|
||||
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 () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
// Set all stat stages to -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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
// Set all stat stages to 6
|
||||
vi.spyOn(playerPokemon.summonData, "statStages", "get").mockReturnValue(new Array(BATTLE_STATS.length).fill(6));
|
||||
|
@ -41,7 +41,7 @@ describe("Abilities - Moxie", () => {
|
||||
const moveToUse = MoveId.AERIAL_ACE;
|
||||
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);
|
||||
|
||||
|
@ -37,7 +37,7 @@ describe("Abilities - Mummy", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
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 () => {
|
||||
@ -47,6 +47,6 @@ describe("Abilities - Mummy", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
@ -42,12 +42,12 @@ describe("Abilities - Mycelium Might", () => {
|
||||
* 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]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
const playerIndex = game.scene.getPlayerPokemon()?.getBattlerIndex();
|
||||
const enemyIndex = enemyPokemon?.getBattlerIndex();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
|
||||
const enemyIndex = enemyPokemon.getBattlerIndex();
|
||||
|
||||
game.move.select(MoveId.BABY_DOLL_EYES);
|
||||
|
||||
@ -62,16 +62,16 @@ describe("Abilities - Mycelium Might", () => {
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
// 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);
|
||||
await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
const playerIndex = game.scene.getPlayerPokemon()?.getBattlerIndex();
|
||||
const enemyIndex = enemyPokemon?.getBattlerIndex();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
|
||||
const enemyIndex = enemyPokemon.getBattlerIndex();
|
||||
|
||||
game.move.select(MoveId.BABY_DOLL_EYES);
|
||||
|
||||
@ -85,14 +85,14 @@ describe("Abilities - Mycelium Might", () => {
|
||||
expect(commandOrder).toEqual([playerIndex, enemyIndex]);
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
// 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]);
|
||||
|
||||
const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex();
|
||||
const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex();
|
||||
const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
|
||||
const enemyIndex = game.field.getEnemyPokemon().getBattlerIndex();
|
||||
|
||||
game.move.select(MoveId.QUICK_ATTACK);
|
||||
|
||||
|
@ -46,7 +46,7 @@ describe("Abilities - Neutralizing Gas", () => {
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
// 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 () => {
|
||||
@ -56,7 +56,7 @@ describe("Abilities - Neutralizing Gas", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
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 () => {
|
||||
@ -68,7 +68,7 @@ describe("Abilities - Neutralizing Gas", () => {
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
// 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 () => {
|
||||
@ -79,15 +79,15 @@ describe("Abilities - Neutralizing Gas", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(0);
|
||||
expect(enemyPokemon?.getStatStage(Stat.DEF)).toBe(0);
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(0);
|
||||
expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(0);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
// Enemy removes user's ability, so both abilities are activated
|
||||
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(1);
|
||||
expect(enemyPokemon?.getStatStage(Stat.DEF)).toBe(1);
|
||||
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
|
||||
expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(1);
|
||||
});
|
||||
|
||||
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]);
|
||||
// Neutralising gas user's passive is still active
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(enemyPokemon?.getStatStage(Stat.ATK)).toBe(-1);
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(-1);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
// 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 () => {
|
||||
@ -164,7 +164,7 @@ describe("Abilities - Neutralizing Gas", () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
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);
|
||||
|
||||
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);
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
const weatherChangeAttr = enemy.getAbilityAttrs("PostSummonWeatherChangeAbAttr", false)[0];
|
||||
const weatherChangeSpy = vi.spyOn(weatherChangeAttr, "apply");
|
||||
|
||||
@ -186,7 +186,7 @@ describe("Abilities - Neutralizing Gas", () => {
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
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(weatherChangeSpy).not.toHaveBeenCalled();
|
||||
|
@ -58,10 +58,10 @@ describe.each([
|
||||
it(`should change Normal-type attacks to ${tyName} type and boost their power`, async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const typeSpy = vi.spyOn(playerPokemon, "getMoveType");
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const enemySpy = vi.spyOn(enemyPokemon, "getMoveEffectiveness");
|
||||
const powerSpy = vi.spyOn(allMoves[MoveId.TACKLE], "calculateBattlePower");
|
||||
|
||||
@ -103,10 +103,10 @@ describe.each([
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const tySpy = vi.spyOn(playerPokemon, "getMoveType");
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const enemyEffectivenessSpy = vi.spyOn(enemyPokemon, "getMoveEffectiveness");
|
||||
|
||||
enemyPokemon.hp = Math.floor(enemyPokemon.getMaxHp() * 0.8);
|
||||
@ -137,7 +137,7 @@ describe.each([
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const tySpy = vi.spyOn(playerPokemon, "getMoveType");
|
||||
|
||||
game.move.select(move);
|
||||
@ -149,10 +149,10 @@ describe.each([
|
||||
it("should affect all hits of a Normal-type multi-hit move", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const tySpy = vi.spyOn(playerPokemon, "getMoveType");
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.FURY_SWIPES);
|
||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||
@ -183,7 +183,7 @@ describe.each([
|
||||
expect(boost, "power boost should be defined").toBeDefined();
|
||||
|
||||
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);
|
||||
await game.phaseInterceptor.to("BerryPhase", false);
|
||||
expect(typeSpy, "type was not changed").toHaveLastReturnedWith(ty);
|
||||
|
@ -39,14 +39,14 @@ describe("Abilities - Oblivious", () => {
|
||||
.moveset(MoveId.SKILL_SWAP)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
enemy?.addTag(BattlerTagType.TAUNT);
|
||||
expect(enemy?.getTag(BattlerTagType.TAUNT)).toBeTruthy();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
enemy.addTag(BattlerTagType.TAUNT);
|
||||
expect(enemy.getTag(BattlerTagType.TAUNT)).toBeDefined();
|
||||
|
||||
game.move.select(MoveId.SKILL_SWAP);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy?.getTag(BattlerTagType.TAUNT)).toBeFalsy();
|
||||
expect(enemy.getTag(BattlerTagType.TAUNT)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should remove infatuation when gained", async () => {
|
||||
@ -56,14 +56,15 @@ describe("Abilities - Oblivious", () => {
|
||||
.moveset(MoveId.SKILL_SWAP)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
vi.spyOn(enemy!, "isOppositeGender").mockReturnValue(true);
|
||||
enemy?.addTag(BattlerTagType.INFATUATED, 5, MoveId.JUDGMENT, game.scene.getPlayerPokemon()?.id); // sourceID needs to be defined
|
||||
expect(enemy?.getTag(BattlerTagType.INFATUATED)).toBeTruthy();
|
||||
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
vi.spyOn(enemy, "isOppositeGender").mockReturnValue(true);
|
||||
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);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy?.getTag(BattlerTagType.INFATUATED)).toBeFalsy();
|
||||
expect(enemy.getTag(BattlerTagType.INFATUATED)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
@ -42,8 +42,8 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
let enemyStartingHp = enemyPokemon.hp;
|
||||
|
||||
@ -66,7 +66,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.POWER_UP_PUNCH);
|
||||
|
||||
@ -81,7 +81,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.BABY_DOLL_EYES);
|
||||
|
||||
@ -95,7 +95,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.DOUBLE_HIT);
|
||||
await game.move.forceHit();
|
||||
@ -110,7 +110,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SELF_DESTRUCT);
|
||||
|
||||
@ -124,7 +124,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.ROLLOUT);
|
||||
await game.move.forceHit();
|
||||
@ -139,7 +139,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.DRAGON_RAGE);
|
||||
await game.phaseInterceptor.to("BerryPhase", false);
|
||||
@ -152,8 +152,8 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.SHUCKLE]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.COUNTER);
|
||||
await game.phaseInterceptor.to("DamageAnimPhase");
|
||||
@ -185,7 +185,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.EARTHQUAKE);
|
||||
await game.phaseInterceptor.to("DamageAnimPhase", false);
|
||||
@ -199,7 +199,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.MIND_BLOWN);
|
||||
|
||||
@ -218,8 +218,8 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.CHARIZARD]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.BURN_UP);
|
||||
|
||||
@ -239,7 +239,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.HYPER_BEAM);
|
||||
await game.move.forceHit();
|
||||
@ -259,8 +259,8 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.ANCHOR_SHOT);
|
||||
await game.move.forceHit();
|
||||
@ -283,8 +283,8 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.SMACK_DOWN);
|
||||
await game.move.forceHit();
|
||||
@ -304,7 +304,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP, SpeciesId.BLASTOISE]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.U_TURN);
|
||||
await game.move.forceHit();
|
||||
@ -321,8 +321,8 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.WAKE_UP_SLAP);
|
||||
await game.move.forceHit();
|
||||
@ -342,7 +342,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.TACKLE);
|
||||
|
||||
@ -356,7 +356,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.WATER_GUN);
|
||||
|
||||
@ -369,7 +369,7 @@ describe("Abilities - Parental Bond", () => {
|
||||
game.override.enemyLevel(1000).moveset(MoveId.FUTURE_SIGHT);
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR, SpeciesId.CHARMANDER, SpeciesId.SQUIRTLE]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
vi.spyOn(enemyPokemon, "damageAndUpdate");
|
||||
|
||||
game.move.select(MoveId.FUTURE_SIGHT);
|
||||
|
@ -34,55 +34,55 @@ describe("Abilities - Perish Song", () => {
|
||||
|
||||
it("should trigger when hit with damaging move", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
const cursola = game.scene.getPlayerPokemon();
|
||||
const magikarp = game.scene.getEnemyPokemon();
|
||||
const cursola = game.field.getPlayerPokemon();
|
||||
const magikarp = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(cursola?.summonData.tags[0].turnCount).toBe(3);
|
||||
expect(magikarp?.summonData.tags[0].turnCount).toBe(3);
|
||||
expect(cursola.summonData.tags[0].turnCount).toBe(3);
|
||||
expect(magikarp.summonData.tags[0].turnCount).toBe(3);
|
||||
});
|
||||
|
||||
it("should trigger even when fainting", async () => {
|
||||
game.override.enemyLevel(100).startingLevel(1);
|
||||
await game.classicMode.startBattle([SpeciesId.CURSOLA, SpeciesId.FEEBAS]);
|
||||
const magikarp = game.scene.getEnemyPokemon();
|
||||
const magikarp = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
game.doSelectPartyPokemon(1);
|
||||
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 () => {
|
||||
game.override.enemyMoveset([MoveId.PERISH_SONG, MoveId.AQUA_JET, MoveId.SPLASH]);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS, SpeciesId.CURSOLA]);
|
||||
const feebas = game.scene.getPlayerPokemon();
|
||||
const magikarp = game.scene.getEnemyPokemon();
|
||||
const feebas = game.field.getPlayerPokemon();
|
||||
const magikarp = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.move.selectEnemyMove(MoveId.PERISH_SONG);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(feebas?.summonData.tags[0].turnCount).toBe(3);
|
||||
expect(magikarp?.summonData.tags[0].turnCount).toBe(3);
|
||||
expect(feebas.summonData.tags[0].turnCount).toBe(3);
|
||||
expect(magikarp.summonData.tags[0].turnCount).toBe(3);
|
||||
|
||||
game.doSwitchPokemon(1);
|
||||
await game.move.selectEnemyMove(MoveId.SPLASH);
|
||||
await game.toNextTurn();
|
||||
|
||||
const cursola = game.scene.getPlayerPokemon();
|
||||
expect(cursola?.summonData.tags.length).toBe(0);
|
||||
expect(magikarp?.summonData.tags[0].turnCount).toBe(2);
|
||||
const cursola = game.field.getPlayerPokemon();
|
||||
expect(cursola.summonData.tags.length).toBe(0);
|
||||
expect(magikarp.summonData.tags[0].turnCount).toBe(2);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.move.selectEnemyMove(MoveId.AQUA_JET);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(cursola?.summonData.tags.length).toBe(0);
|
||||
expect(magikarp?.summonData.tags[0].turnCount).toBe(1);
|
||||
expect(cursola.summonData.tags.length).toBe(0);
|
||||
expect(magikarp.summonData.tags[0].turnCount).toBe(1);
|
||||
});
|
||||
|
||||
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])
|
||||
.startingWave(5);
|
||||
await game.classicMode.startBattle([SpeciesId.CURSOLA]);
|
||||
const cursola = game.scene.getPlayerPokemon();
|
||||
const cursola = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.WHIRLWIND);
|
||||
await game.move.selectEnemyMove(MoveId.PERISH_SONG);
|
||||
await game.toNextTurn();
|
||||
|
||||
const magikarp = game.scene.getEnemyPokemon();
|
||||
expect(cursola?.summonData.tags[0].turnCount).toBe(3);
|
||||
expect(magikarp?.summonData.tags.length).toBe(0);
|
||||
const magikarp = game.field.getEnemyPokemon();
|
||||
expect(cursola.summonData.tags[0].turnCount).toBe(3);
|
||||
expect(magikarp.summonData.tags.length).toBe(0);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.move.selectEnemyMove(MoveId.AQUA_JET);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(cursola?.summonData.tags[0].turnCount).toBe(2);
|
||||
expect(magikarp?.summonData.tags.length).toBe(1);
|
||||
expect(magikarp?.summonData.tags[0].turnCount).toBe(3);
|
||||
expect(cursola.summonData.tags[0].turnCount).toBe(2);
|
||||
expect(magikarp.summonData.tags.length).toBe(1);
|
||||
expect(magikarp.summonData.tags[0].turnCount).toBe(3);
|
||||
});
|
||||
});
|
||||
|
@ -42,10 +42,10 @@ describe("Abilities - Protosynthesis", () => {
|
||||
.startingLevel(100)
|
||||
.enemyLevel(100);
|
||||
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.
|
||||
mew.setNature(Nature.HARDY);
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
const def_before_boost = mew.getEffectiveStat(
|
||||
Stat.DEF,
|
||||
undefined,
|
||||
|
@ -43,8 +43,8 @@ describe("Abilities - Quick Draw", () => {
|
||||
test("makes pokemon going first in its priority bracket", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const pokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const pokemon = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
pokemon.hp = 1;
|
||||
enemy.hp = 1;
|
||||
@ -65,8 +65,8 @@ describe("Abilities - Quick Draw", () => {
|
||||
async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const pokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const pokemon = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
pokemon.hp = 1;
|
||||
enemy.hp = 1;
|
||||
@ -85,8 +85,8 @@ describe("Abilities - Quick Draw", () => {
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const pokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const pokemon = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
pokemon.hp = 1;
|
||||
enemy.hp = 1;
|
||||
|
@ -45,7 +45,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const initialEnemyHp = enemyPokemon.hp;
|
||||
|
||||
game.move.select(moveToUse);
|
||||
@ -63,7 +63,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(moveToUse);
|
||||
|
||||
@ -86,7 +86,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||
|
||||
expect(game.scene.arena.terrain).toBeDefined();
|
||||
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 () => {
|
||||
@ -96,7 +96,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const initialEnemyHp = enemyPokemon.hp;
|
||||
|
||||
game.move.select(moveToUse);
|
||||
@ -114,7 +114,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(moveToUse);
|
||||
|
||||
@ -140,7 +140,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const initialEnemyHp = enemyPokemon.hp;
|
||||
|
||||
game.move.select(moveToUse);
|
||||
@ -156,7 +156,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.LEAF_BLADE);
|
||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||
|
@ -38,8 +38,8 @@ describe("Abilities - Shield Dust", () => {
|
||||
it("Shield Dust", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIDGEOT]);
|
||||
|
||||
game.scene.getEnemyPokemon()!.stats[Stat.SPDEF] = 10000;
|
||||
expect(game.scene.getPlayerPokemon()!.formIndex).toBe(0);
|
||||
game.field.getEnemyPokemon().stats[Stat.SPDEF] = 10000;
|
||||
expect(game.field.getPlayerPokemon().formIndex).toBe(0);
|
||||
|
||||
game.move.select(MoveId.AIR_SLASH);
|
||||
|
||||
|
@ -66,7 +66,7 @@ describe("Abilities - SHIELDS DOWN", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
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 () => {
|
||||
@ -78,7 +78,7 @@ describe("Abilities - SHIELDS DOWN", () => {
|
||||
await game.move.selectEnemyMove(MoveId.SPORE);
|
||||
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 () => {
|
||||
@ -89,7 +89,7 @@ describe("Abilities - SHIELDS DOWN", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
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 () => {
|
||||
@ -101,7 +101,7 @@ describe("Abilities - SHIELDS DOWN", () => {
|
||||
|
||||
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
|
||||
@ -122,9 +122,9 @@ describe("Abilities - SHIELDS DOWN", () => {
|
||||
await game.move.selectEnemyMove(MoveId.SPLASH);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(SpeciesId.MINIOR);
|
||||
expect(game.scene.getPlayerPokemon()!.species.formIndex).toBe(0);
|
||||
expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.POISON);
|
||||
expect(game.field.getPlayerPokemon().species.speciesId).toBe(SpeciesId.MINIOR);
|
||||
expect(game.field.getPlayerPokemon().species.formIndex).toBe(0);
|
||||
expect(game.field.getPlayerPokemon().status?.effect).toBe(StatusEffect.POISON);
|
||||
});
|
||||
|
||||
test("should ignore yawn", async () => {
|
||||
@ -136,7 +136,7 @@ describe("Abilities - SHIELDS DOWN", () => {
|
||||
await game.move.selectEnemyMove(MoveId.YAWN);
|
||||
|
||||
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 () => {
|
||||
@ -149,7 +149,7 @@ describe("Abilities - SHIELDS DOWN", () => {
|
||||
|
||||
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.
|
||||
@ -162,7 +162,7 @@ describe("Abilities - SHIELDS DOWN", () => {
|
||||
await game.move.selectEnemyMove(MoveId.SPLASH);
|
||||
|
||||
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 () => {
|
||||
@ -173,7 +173,7 @@ describe("Abilities - SHIELDS DOWN", () => {
|
||||
.startingWave(5)
|
||||
.enemySpecies(SpeciesId.MINIOR);
|
||||
await game.classicMode.startBattle([SpeciesId.REGIELEKI]);
|
||||
const minior = game.scene.getEnemyPokemon()!;
|
||||
const minior = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.THUNDERBOLT);
|
||||
await game.toNextTurn();
|
||||
|
@ -33,7 +33,7 @@ describe("Abilities - Simple", () => {
|
||||
it("should double stat changes when applied", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.SLOWBRO]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(-2);
|
||||
});
|
||||
|
@ -40,7 +40,7 @@ describe("Abilities - Speed Boost", () => {
|
||||
it("should increase speed by 1 stage at end of turn", async () => {
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.toNextTurn();
|
||||
|
||||
@ -53,7 +53,7 @@ describe("Abilities - Speed Boost", () => {
|
||||
game.move.select(MoveId.U_TURN);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.toNextTurn();
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -69,13 +69,13 @@ describe("Abilities - Speed Boost", () => {
|
||||
game.move.select(MoveId.U_TURN);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.toNextTurn();
|
||||
expect(game.scene.getPlayerPokemon()!).toBe(ninjask);
|
||||
expect(game.field.getPlayerPokemon()).toBe(ninjask);
|
||||
expect(ninjask.getStatStage(Stat.SPD)).toBe(0);
|
||||
|
||||
game.move.select(MoveId.U_TURN);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.toNextTurn();
|
||||
expect(game.scene.getPlayerPokemon()!).toBe(shuckle);
|
||||
expect(game.field.getPlayerPokemon()).toBe(shuckle);
|
||||
expect(shuckle.getStatStage(Stat.SPD)).toBe(0);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -88,7 +88,7 @@ describe("Abilities - Speed Boost", () => {
|
||||
|
||||
game.doSwitchPokemon(1);
|
||||
await game.toNextTurn();
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -109,7 +109,7 @@ describe("Abilities - Speed Boost", () => {
|
||||
await game.phaseInterceptor.to(AttemptRunPhase);
|
||||
await game.toNextTurn();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
|
@ -40,8 +40,8 @@ describe("Abilities - Stall", () => {
|
||||
it("Pokemon with Stall should move last in its priority bracket regardless of speed", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.SHUCKLE]);
|
||||
|
||||
const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex();
|
||||
const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex();
|
||||
const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
|
||||
const enemyIndex = game.field.getEnemyPokemon().getBattlerIndex();
|
||||
|
||||
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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.SHUCKLE]);
|
||||
|
||||
const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex();
|
||||
const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex();
|
||||
const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
|
||||
const enemyIndex = game.field.getEnemyPokemon().getBattlerIndex();
|
||||
|
||||
game.move.select(MoveId.TACKLE);
|
||||
|
||||
@ -77,8 +77,8 @@ describe("Abilities - Stall", () => {
|
||||
game.override.ability(AbilityId.STALL);
|
||||
await game.classicMode.startBattle([SpeciesId.SHUCKLE]);
|
||||
|
||||
const playerIndex = game.scene.getPlayerPokemon()!.getBattlerIndex();
|
||||
const enemyIndex = game.scene.getEnemyPokemon()!.getBattlerIndex();
|
||||
const playerIndex = game.field.getPlayerPokemon().getBattlerIndex();
|
||||
const enemyIndex = game.field.getEnemyPokemon().getBattlerIndex();
|
||||
|
||||
game.move.select(MoveId.TACKLE);
|
||||
|
||||
|
95
test/abilities/status-immunity-ab-attrs.test.ts
Normal file
95
test/abilities/status-immunity-ab-attrs.test.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import { allMoves } from "#data/data-lists";
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { MoveResult } from "#enums/move-result";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { StatusEffectAttr } from "#moves/move";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import { toTitleCase } from "#utils/strings";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
describe.each<{ name: string; ability: AbilityId; status: StatusEffect }>([
|
||||
{ name: "Vital Spirit", ability: AbilityId.VITAL_SPIRIT, status: StatusEffect.SLEEP },
|
||||
{ name: "Insomnia", ability: AbilityId.INSOMNIA, status: StatusEffect.SLEEP },
|
||||
{ name: "Immunity", ability: AbilityId.IMMUNITY, status: StatusEffect.POISON },
|
||||
{ name: "Magma Armor", ability: AbilityId.MAGMA_ARMOR, status: StatusEffect.FREEZE },
|
||||
{ name: "Limber", ability: AbilityId.LIMBER, status: StatusEffect.PARALYSIS },
|
||||
{ name: "Thermal Exchange", ability: AbilityId.THERMAL_EXCHANGE, status: StatusEffect.BURN },
|
||||
{ name: "Water Veil", ability: AbilityId.WATER_VEIL, status: StatusEffect.BURN },
|
||||
{ name: "Water Bubble", ability: AbilityId.WATER_BUBBLE, status: StatusEffect.BURN },
|
||||
])("Abilities - $name", ({ ability, status }) => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.battleStyle("single")
|
||||
.criticalHits(false)
|
||||
.enemyLevel(100)
|
||||
.enemySpecies(SpeciesId.MAGIKARP)
|
||||
.enemyAbility(ability)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
|
||||
// Mock Lumina Crash and Spore to be our status-inflicting moves of choice
|
||||
vi.spyOn(allMoves[MoveId.LUMINA_CRASH], "attrs", "get").mockReturnValue([new StatusEffectAttr(status, false)]);
|
||||
vi.spyOn(allMoves[MoveId.SPORE], "attrs", "get").mockReturnValue([new StatusEffectAttr(status, false)]);
|
||||
});
|
||||
|
||||
const statusStr = toTitleCase(StatusEffect[status]);
|
||||
|
||||
it(`should prevent application of ${statusStr} without failing damaging moves`, async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
const karp = game.field.getEnemyPokemon();
|
||||
expect(karp.status?.effect).toBeUndefined();
|
||||
expect(karp.canSetStatus(status)).toBe(false);
|
||||
|
||||
game.move.use(MoveId.LUMINA_CRASH);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
expect(karp.status?.effect).toBeUndefined();
|
||||
expect(game.field.getPlayerPokemon().getLastXMoves()[0].result).toBe(MoveResult.SUCCESS);
|
||||
});
|
||||
|
||||
it(`should cure ${statusStr} upon being gained`, async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
const feebas = game.field.getPlayerPokemon();
|
||||
feebas.doSetStatus(status);
|
||||
expect(feebas.status?.effect).toBe(status);
|
||||
|
||||
game.move.use(MoveId.SPLASH);
|
||||
await game.move.forceEnemyMove(MoveId.SKILL_SWAP);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
expect(feebas.status?.effect).toBeUndefined();
|
||||
});
|
||||
|
||||
// TODO: This does not propagate failures currently
|
||||
it.todo(
|
||||
`should cause status moves inflicting ${statusStr} to count as failed if no other effects can be applied`,
|
||||
async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
game.move.use(MoveId.SPORE);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
const karp = game.field.getEnemyPokemon();
|
||||
expect(karp.status?.effect).toBeUndefined();
|
||||
expect(game.field.getPlayerPokemon().getLastXMoves()[0].result).toBe(MoveResult.FAIL);
|
||||
},
|
||||
);
|
||||
});
|
@ -39,7 +39,7 @@ describe("Abilities - Steely Spirit", () => {
|
||||
it("increases Steel-type moves' power used by the user and its allies by 50%", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU, SpeciesId.SHUCKLE]);
|
||||
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]);
|
||||
|
||||
@ -54,7 +54,7 @@ describe("Abilities - Steely Spirit", () => {
|
||||
|
||||
it("stacks if multiple users with this ability are on the field.", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU, SpeciesId.PIKACHU]);
|
||||
const enemyToCheck = game.scene.getEnemyPokemon()!;
|
||||
const enemyToCheck = game.field.getEnemyPokemon();
|
||||
|
||||
game.scene.getPlayerField().forEach(p => {
|
||||
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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU, SpeciesId.SHUCKLE]);
|
||||
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]);
|
||||
expect(boostSource.hasAbility(AbilityId.STEELY_SPIRIT)).toBe(true);
|
||||
|
@ -32,7 +32,7 @@ describe("Abilities - Super Luck", () => {
|
||||
|
||||
it("should increase the user's crit stage by 1", async () => {
|
||||
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
|
||||
|
||||
game.move.select(MoveId.TACKLE);
|
||||
|
@ -38,7 +38,7 @@ describe("Abilities - Synchronize", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!.status).toBeUndefined();
|
||||
expect(game.field.getPlayerPokemon().status).toBeUndefined();
|
||||
expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase");
|
||||
});
|
||||
|
||||
@ -48,8 +48,8 @@ describe("Abilities - Synchronize", () => {
|
||||
game.move.select(MoveId.THUNDER_WAVE);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
expect(game.field.getPlayerPokemon().status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
expect(game.field.getEnemyPokemon().status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase");
|
||||
});
|
||||
|
||||
@ -60,8 +60,8 @@ describe("Abilities - Synchronize", () => {
|
||||
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!.status?.effect).toBeUndefined();
|
||||
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.SLEEP);
|
||||
expect(game.field.getPlayerPokemon().status?.effect).toBeUndefined();
|
||||
expect(game.field.getEnemyPokemon().status?.effect).toBe(StatusEffect.SLEEP);
|
||||
expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase");
|
||||
});
|
||||
|
||||
@ -76,8 +76,8 @@ describe("Abilities - Synchronize", () => {
|
||||
game.doSwitchPokemon(1);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.POISON);
|
||||
expect(game.scene.getEnemyPokemon()!.status?.effect).toBeUndefined();
|
||||
expect(game.field.getPlayerPokemon().status?.effect).toBe(StatusEffect.POISON);
|
||||
expect(game.field.getEnemyPokemon().status?.effect).toBeUndefined();
|
||||
expect(game.phaseInterceptor.log).not.toContain("ShowAbilityPhase");
|
||||
});
|
||||
|
||||
@ -87,8 +87,8 @@ describe("Abilities - Synchronize", () => {
|
||||
game.move.select(MoveId.THUNDER_WAVE);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!.status?.effect).toBeUndefined();
|
||||
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
expect(game.field.getPlayerPokemon().status?.effect).toBeUndefined();
|
||||
expect(game.field.getEnemyPokemon().status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase");
|
||||
});
|
||||
});
|
||||
|
@ -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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.SNORLAX]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
vi.spyOn(playerPokemon, "getMoveEffectiveness");
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -57,7 +57,7 @@ describe("Abilities - Tera Shell", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.SNORLAX]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
vi.spyOn(playerPokemon, "getMoveEffectiveness");
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -71,7 +71,7 @@ describe("Abilities - Tera Shell", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.AGGRON]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
vi.spyOn(playerPokemon, "getMoveEffectiveness");
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -85,7 +85,7 @@ describe("Abilities - Tera Shell", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.CHARIZARD]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const spy = vi.spyOn(playerPokemon, "getMoveEffectiveness");
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -100,7 +100,7 @@ describe("Abilities - Tera Shell", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.SNORLAX]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const spy = vi.spyOn(playerPokemon, "getMoveEffectiveness");
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
|
@ -1,51 +0,0 @@
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Thermal Exchange", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([MoveId.SPLASH])
|
||||
.ability(AbilityId.BALL_FETCH)
|
||||
.battleStyle("single")
|
||||
.criticalHits(false)
|
||||
.enemySpecies(SpeciesId.MAGIKARP)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
});
|
||||
|
||||
it("should remove burn when gained", async () => {
|
||||
game.override
|
||||
.ability(AbilityId.THERMAL_EXCHANGE)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.moveset(MoveId.SKILL_SWAP)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
enemy?.trySetStatus(StatusEffect.BURN);
|
||||
expect(enemy?.status?.effect).toBe(StatusEffect.BURN);
|
||||
|
||||
game.move.select(MoveId.SKILL_SWAP);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy?.status).toBeNull();
|
||||
});
|
||||
});
|
@ -38,7 +38,7 @@ describe("Abilities - Trace", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
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 () => {
|
||||
@ -48,6 +48,6 @@ describe("Abilities - Trace", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||
expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
@ -64,7 +64,7 @@ describe("Abilities - Unburden", () => {
|
||||
game.override.enemyMoveset(MoveId.FALSE_SWIPE);
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const playerHeldItems = getHeldItemCount(playerPokemon);
|
||||
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 }]);
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const playerHeldItems = getHeldItemCount(playerPokemon);
|
||||
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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const enemyHeldItemCt = getHeldItemCount(enemyPokemon);
|
||||
const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD);
|
||||
|
||||
@ -113,7 +113,7 @@ describe("Abilities - Unburden", () => {
|
||||
it("should activate when an item is knocked off", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const enemyHeldItemCt = getHeldItemCount(enemyPokemon);
|
||||
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
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const enemyHeldItemCt = getHeldItemCount(enemyPokemon);
|
||||
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
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const playerHeldItems = getHeldItemCount(playerPokemon);
|
||||
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
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const enemyHeldItemCt = getHeldItemCount(enemyPokemon);
|
||||
const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD);
|
||||
|
||||
@ -177,11 +177,11 @@ describe("Abilities - Unburden", () => {
|
||||
game.override.startingHeldItems([{ name: "GRIP_CLAW", count: 1 }]);
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const gripClaw = playerPokemon.getHeldItems()[0] as ContactHeldItemTransferChanceModifier;
|
||||
vi.spyOn(gripClaw, "chance", "get").mockReturnValue(100);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const enemyHeldItemCt = getHeldItemCount(enemyPokemon);
|
||||
const initialEnemySpeed = enemyPokemon.getStat(Stat.SPD);
|
||||
|
||||
@ -197,7 +197,7 @@ describe("Abilities - Unburden", () => {
|
||||
game.override.enemyAbility(AbilityId.NEUTRALIZING_GAS).enemyMoveset(MoveId.FALSE_SWIPE);
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const playerHeldItems = getHeldItemCount(playerPokemon);
|
||||
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
|
||||
|
||||
@ -214,7 +214,7 @@ describe("Abilities - Unburden", () => {
|
||||
game.override.moveset(MoveId.STUFF_CHEEKS);
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const playerHeldItemCt = getHeldItemCount(playerPokemon);
|
||||
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
|
||||
|
||||
@ -292,7 +292,7 @@ describe("Abilities - Unburden", () => {
|
||||
game.override.enemyMoveset([MoveId.FALSE_SWIPE, MoveId.WORRY_SEED]);
|
||||
await game.classicMode.startBattle([SpeciesId.PURRLOIN]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const playerHeldItems = getHeldItemCount(playerPokemon);
|
||||
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
|
||||
|
||||
@ -317,7 +317,7 @@ describe("Abilities - Unburden", () => {
|
||||
game.override.startingHeldItems([{ name: "REVIVER_SEED" }]).enemyMoveset([MoveId.WING_ATTACK]);
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const playerHeldItems = getHeldItemCount(playerPokemon);
|
||||
const initialPlayerSpeed = playerPokemon.getStat(Stat.SPD);
|
||||
|
||||
@ -334,7 +334,7 @@ describe("Abilities - Unburden", () => {
|
||||
game.override.enemyMoveset([MoveId.SPLASH, MoveId.THIEF]);
|
||||
await game.classicMode.startBattle([SpeciesId.TREECKO, SpeciesId.FEEBAS]);
|
||||
|
||||
const treecko = game.scene.getPlayerPokemon()!;
|
||||
const treecko = game.field.getPlayerPokemon();
|
||||
const treeckoInitialHeldItems = getHeldItemCount(treecko);
|
||||
const initialSpeed = treecko.getStat(Stat.SPD);
|
||||
|
||||
@ -348,7 +348,7 @@ describe("Abilities - Unburden", () => {
|
||||
await game.move.selectEnemyMove(MoveId.SPLASH);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!).toBe(treecko);
|
||||
expect(game.field.getPlayerPokemon()).toBe(treecko);
|
||||
expect(getHeldItemCount(treecko)).toBeLessThan(treeckoInitialHeldItems);
|
||||
expect(treecko.getEffectiveStat(Stat.SPD)).toBe(initialSpeed);
|
||||
});
|
||||
|
@ -55,7 +55,7 @@ describe("Abilities - Unseen Fist", () => {
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
enemyPokemon.addTag(BattlerTagType.SUBSTITUTE, 0, MoveId.NONE, enemyPokemon.id);
|
||||
|
||||
game.move.select(MoveId.TACKLE);
|
||||
@ -77,10 +77,10 @@ async function testUnseenFistHitResult(
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
const leadPokemon = game.field.getPlayerPokemon();
|
||||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
expect(enemyPokemon).not.toBe(undefined);
|
||||
|
||||
const enemyStartingHp = enemyPokemon.hp;
|
||||
|
@ -1,51 +0,0 @@
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Vital Spirit", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([MoveId.SPLASH])
|
||||
.ability(AbilityId.BALL_FETCH)
|
||||
.battleStyle("single")
|
||||
.criticalHits(false)
|
||||
.enemySpecies(SpeciesId.MAGIKARP)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
});
|
||||
|
||||
it("should remove sleep when gained", async () => {
|
||||
game.override
|
||||
.ability(AbilityId.INSOMNIA)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.moveset(MoveId.SKILL_SWAP)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
enemy?.trySetStatus(StatusEffect.SLEEP);
|
||||
expect(enemy?.status?.effect).toBe(StatusEffect.SLEEP);
|
||||
|
||||
game.move.select(MoveId.SKILL_SWAP);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy?.status).toBeNull();
|
||||
});
|
||||
});
|
@ -42,7 +42,7 @@ describe("Abilities - Volt Absorb", () => {
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(moveToUse);
|
||||
|
||||
@ -62,7 +62,7 @@ describe("Abilities - Volt Absorb", () => {
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.THUNDERBOLT);
|
||||
enemyPokemon.hp = enemyPokemon.hp - 1;
|
||||
@ -83,7 +83,7 @@ describe("Abilities - Volt Absorb", () => {
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.THUNDERBOLT);
|
||||
enemyPokemon.hp = enemyPokemon.hp - 1;
|
||||
|
@ -38,8 +38,8 @@ describe("Abilities - Wandering Spirit", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(AbilityId.BALL_FETCH);
|
||||
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(AbilityId.WANDERING_SPIRIT);
|
||||
expect(game.field.getPlayerPokemon().getAbility().id).toBe(AbilityId.BALL_FETCH);
|
||||
expect(game.field.getEnemyPokemon().getAbility().id).toBe(AbilityId.WANDERING_SPIRIT);
|
||||
});
|
||||
|
||||
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);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(AbilityId.WANDERING_SPIRIT);
|
||||
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(AbilityId.BALL_FETCH);
|
||||
expect(game.field.getPlayerPokemon().getAbility().id).toBe(AbilityId.WANDERING_SPIRIT);
|
||||
expect(game.field.getEnemyPokemon().getAbility().id).toBe(AbilityId.BALL_FETCH);
|
||||
});
|
||||
|
||||
it("should activate post-summon abilities", async () => {
|
||||
@ -60,6 +60,6 @@ describe("Abilities - Wandering Spirit", () => {
|
||||
game.move.select(MoveId.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||
expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
@ -1,51 +0,0 @@
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Water Bubble", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([MoveId.SPLASH])
|
||||
.ability(AbilityId.BALL_FETCH)
|
||||
.battleStyle("single")
|
||||
.criticalHits(false)
|
||||
.enemySpecies(SpeciesId.MAGIKARP)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
});
|
||||
|
||||
it("should remove burn when gained", async () => {
|
||||
game.override
|
||||
.ability(AbilityId.THERMAL_EXCHANGE)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.moveset(MoveId.SKILL_SWAP)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
enemy?.trySetStatus(StatusEffect.BURN);
|
||||
expect(enemy?.status?.effect).toBe(StatusEffect.BURN);
|
||||
|
||||
game.move.select(MoveId.SKILL_SWAP);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy?.status).toBeNull();
|
||||
});
|
||||
});
|
@ -1,51 +0,0 @@
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Water Veil", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([MoveId.SPLASH])
|
||||
.ability(AbilityId.BALL_FETCH)
|
||||
.battleStyle("single")
|
||||
.criticalHits(false)
|
||||
.enemySpecies(SpeciesId.MAGIKARP)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
});
|
||||
|
||||
it("should remove burn when gained", async () => {
|
||||
game.override
|
||||
.ability(AbilityId.THERMAL_EXCHANGE)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.moveset(MoveId.SKILL_SWAP)
|
||||
.enemyMoveset(MoveId.SPLASH);
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
const enemy = game.scene.getEnemyPokemon();
|
||||
enemy?.trySetStatus(StatusEffect.BURN);
|
||||
expect(enemy?.status?.effect).toBe(StatusEffect.BURN);
|
||||
|
||||
game.move.select(MoveId.SKILL_SWAP);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(enemy?.status).toBeNull();
|
||||
});
|
||||
});
|
@ -70,7 +70,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.override.passiveAbility(AbilityId.REGENERATOR).startingLevel(5).enemyLevel(100);
|
||||
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
|
||||
|
||||
const wimpod = game.scene.getPlayerPokemon()!;
|
||||
const wimpod = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
game.doSelectPartyPokemon(1);
|
||||
@ -84,7 +84,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.override.enemyAbility(AbilityId.WIMP_OUT);
|
||||
await game.classicMode.startBattle([SpeciesId.GOLISOPOD, SpeciesId.TYRUNT]);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
enemyPokemon.hp *= 0.52;
|
||||
|
||||
game.move.select(MoveId.FALSE_SWIPE);
|
||||
@ -97,7 +97,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
|
||||
it("Does not trigger when HP already below half", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
|
||||
const wimpod = game.scene.getPlayerPokemon()!;
|
||||
const wimpod = game.field.getPlayerPokemon();
|
||||
wimpod.hp = 5;
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -117,7 +117,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
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();
|
||||
confirmSwitch();
|
||||
});
|
||||
@ -130,7 +130,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
const hasFled = enemyPokemon.switchOutStatus;
|
||||
expect(hasFled).toBe(false);
|
||||
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 () => {
|
||||
game.override.startingLevel(190).startingWave(8).enemyMoveset([MoveId.U_TURN]);
|
||||
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);
|
||||
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 () => {
|
||||
game.override.startingLevel(69).enemyMoveset([MoveId.DRAGON_TAIL]);
|
||||
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
|
||||
|
||||
const wimpod = game.scene.getPlayerPokemon()!;
|
||||
const wimpod = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
game.doSelectPartyPokemon(1);
|
||||
@ -159,7 +159,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
|
||||
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 () => {
|
||||
@ -177,7 +177,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.override.moveset([MoveId.SUBSTITUTE]).enemyMoveset([MoveId.SPLASH]);
|
||||
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
|
||||
|
||||
const wimpod = game.scene.getPlayerPokemon()!;
|
||||
const wimpod = game.field.getPlayerPokemon();
|
||||
wimpod.hp *= 0.52;
|
||||
|
||||
game.move.select(MoveId.SUBSTITUTE);
|
||||
@ -208,7 +208,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
.startingHeldItems([{ name: "SHELL_BELL", count: 4 }]);
|
||||
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));
|
||||
|
||||
@ -219,7 +219,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
expect(game.scene.getPlayerParty()[1]).toBe(wimpod);
|
||||
expect(wimpod.hp).toBeGreaterThan(toDmgValue(wimpod.getMaxHp() / 2));
|
||||
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]);
|
||||
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.doSelectPartyPokemon(1);
|
||||
@ -240,7 +240,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.override.enemyAbility(AbilityId.SHEER_FORCE).enemyMoveset(MoveId.SLUDGE_BOMB).startingLevel(95);
|
||||
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);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
@ -252,7 +252,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.override.statusEffect(StatusEffect.POISON).enemyMoveset([MoveId.SPLASH]);
|
||||
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.doSelectPartyPokemon(1);
|
||||
@ -265,7 +265,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.override.statusEffect(StatusEffect.SLEEP).enemyAbility(AbilityId.BAD_DREAMS);
|
||||
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.doSelectPartyPokemon(1);
|
||||
@ -277,7 +277,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
it("Wimp Out will activate due to leech seed", async () => {
|
||||
game.override.enemyMoveset([MoveId.LEECH_SEED]);
|
||||
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.doSelectPartyPokemon(1);
|
||||
@ -289,7 +289,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
it("Wimp Out will activate due to curse damage", async () => {
|
||||
game.override.enemySpecies(SpeciesId.DUSKNOIR).enemyMoveset([MoveId.CURSE]);
|
||||
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.doSelectPartyPokemon(1);
|
||||
@ -301,7 +301,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
it("Wimp Out will activate due to salt cure damage", async () => {
|
||||
game.override.enemySpecies(SpeciesId.NACLI).enemyMoveset([MoveId.SALT_CURE]).enemyLevel(1);
|
||||
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.doSelectPartyPokemon(1);
|
||||
@ -313,7 +313,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
it("Wimp Out will activate due to damaging trap damage", async () => {
|
||||
game.override.enemySpecies(SpeciesId.MAGIKARP).enemyMoveset([MoveId.WHIRLPOOL]).enemyLevel(1);
|
||||
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.doSelectPartyPokemon(1);
|
||||
@ -331,14 +331,14 @@ describe("Abilities - Wimp Out", () => {
|
||||
.weather(WeatherType.HAIL)
|
||||
.statusEffect(StatusEffect.POISON);
|
||||
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);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.getPlayerParty()[0].getHpRatio()).toEqual(0.51);
|
||||
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 () => {
|
||||
@ -369,7 +369,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
.enemyMoveset([MoveId.SPLASH])
|
||||
.enemyLevel(1);
|
||||
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.doSelectPartyPokemon(1);
|
||||
@ -391,7 +391,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
it("Wimp Out will activate due to Nightmare", async () => {
|
||||
game.override.enemyMoveset([MoveId.NIGHTMARE]).statusEffect(StatusEffect.SLEEP);
|
||||
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.doSelectPartyPokemon(1);
|
||||
@ -417,13 +417,13 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.override.enemyMoveset(MoveId.BULLET_SEED).enemyAbility(AbilityId.SKILL_LINK);
|
||||
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.doSelectPartyPokemon(1);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
expect(enemyPokemon.turnData.hitsLeft).toBe(0);
|
||||
expect(enemyPokemon.turnData.hitCount).toBe(5);
|
||||
confirmSwitch();
|
||||
@ -433,13 +433,13 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.override.enemyMoveset(MoveId.TACKLE).enemyHeldItems([{ name: "MULTI_LENS", count: 1 }]);
|
||||
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.doSelectPartyPokemon(1);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
expect(enemyPokemon.turnData.hitsLeft).toBe(0);
|
||||
expect(enemyPokemon.turnData.hitCount).toBe(2);
|
||||
confirmSwitch();
|
||||
@ -448,13 +448,13 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.override.enemyMoveset(MoveId.TACKLE).enemyAbility(AbilityId.PARENTAL_BOND);
|
||||
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.doSelectPartyPokemon(1);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
expect(enemyPokemon.turnData.hitsLeft).toBe(0);
|
||||
expect(enemyPokemon.turnData.hitCount).toBe(2);
|
||||
confirmSwitch();
|
||||
@ -466,7 +466,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
async () => {
|
||||
game.override.moveset([MoveId.SWORDS_DANCE]).enemyMoveset([MoveId.SWAGGER]);
|
||||
await game.classicMode.startBattle([SpeciesId.WIMPOD, SpeciesId.TYRUNT]);
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
playerPokemon.hp *= 0.51;
|
||||
playerPokemon.setStatStage(Stat.ATK, 6);
|
||||
playerPokemon.addTag(BattlerTagType.CONFUSED);
|
||||
@ -486,7 +486,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
game.override.enemyAbility(AbilityId.WIMP_OUT).startingLevel(5850).startingWave(10);
|
||||
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
|
||||
game.move.select(MoveId.FALSE_SWIPE);
|
||||
|
@ -33,7 +33,7 @@ describe("Abilities - Wind Power", () => {
|
||||
|
||||
it("becomes charged when hit by wind moves", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
const shiftry = game.scene.getEnemyPokemon()!;
|
||||
const shiftry = game.field.getEnemyPokemon();
|
||||
|
||||
expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
|
||||
|
||||
@ -47,7 +47,7 @@ describe("Abilities - Wind Power", () => {
|
||||
game.override.ability(AbilityId.WIND_POWER).enemySpecies(SpeciesId.MAGIKARP);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
|
||||
const shiftry = game.scene.getPlayerPokemon()!;
|
||||
const shiftry = game.field.getPlayerPokemon();
|
||||
|
||||
expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
|
||||
|
||||
@ -61,8 +61,8 @@ describe("Abilities - Wind Power", () => {
|
||||
game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_POWER);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
|
||||
const magikarp = game.scene.getEnemyPokemon()!;
|
||||
const shiftry = game.scene.getPlayerPokemon()!;
|
||||
const magikarp = game.field.getEnemyPokemon();
|
||||
const shiftry = game.field.getPlayerPokemon();
|
||||
|
||||
expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
|
||||
expect(magikarp.getTag(BattlerTagType.CHARGED)).toBeUndefined();
|
||||
@ -79,7 +79,7 @@ describe("Abilities - Wind Power", () => {
|
||||
game.override.enemySpecies(SpeciesId.MAGIKARP);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
|
||||
const shiftry = game.scene.getPlayerPokemon()!;
|
||||
const shiftry = game.field.getPlayerPokemon();
|
||||
|
||||
expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined();
|
||||
|
||||
|
@ -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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
const shiftry = game.scene.getEnemyPokemon()!;
|
||||
const shiftry = game.field.getEnemyPokemon();
|
||||
|
||||
expect(shiftry.getStatStage(Stat.ATK)).toBe(0);
|
||||
|
||||
@ -48,7 +48,7 @@ describe("Abilities - Wind Rider", () => {
|
||||
game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_RIDER);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
|
||||
const shiftry = game.scene.getPlayerPokemon()!;
|
||||
const shiftry = game.field.getPlayerPokemon();
|
||||
|
||||
expect(shiftry.getStatStage(Stat.ATK)).toBe(0);
|
||||
|
||||
@ -63,8 +63,8 @@ describe("Abilities - Wind Rider", () => {
|
||||
game.override.enemySpecies(SpeciesId.MAGIKARP).ability(AbilityId.WIND_RIDER);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
|
||||
const magikarp = game.scene.getEnemyPokemon()!;
|
||||
const shiftry = game.scene.getPlayerPokemon()!;
|
||||
const magikarp = game.field.getEnemyPokemon();
|
||||
const shiftry = game.field.getPlayerPokemon();
|
||||
|
||||
expect(shiftry.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);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.SHIFTRY]);
|
||||
const magikarp = game.scene.getEnemyPokemon()!;
|
||||
const shiftry = game.scene.getPlayerPokemon()!;
|
||||
const magikarp = game.field.getEnemyPokemon();
|
||||
const shiftry = game.field.getPlayerPokemon();
|
||||
|
||||
expect(shiftry.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);
|
||||
|
||||
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.isFullHp()).toBe(true);
|
||||
|
@ -38,7 +38,7 @@ describe("Abilities - ZEN MODE", () => {
|
||||
|
||||
it("shouldn't change form when taking damage if not dropping below 50% HP", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.DARMANITAN]);
|
||||
const darmanitan = game.scene.getPlayerPokemon()!;
|
||||
const darmanitan = game.field.getPlayerPokemon();
|
||||
expect(darmanitan.formIndex).toBe(baseForm);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -52,7 +52,7 @@ describe("Abilities - ZEN MODE", () => {
|
||||
it("should change form when falling below 50% HP", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.DARMANITAN]);
|
||||
|
||||
const darmanitan = game.scene.getPlayerPokemon()!;
|
||||
const darmanitan = game.field.getPlayerPokemon();
|
||||
darmanitan.hp = darmanitan.getMaxHp() / 2 + 1;
|
||||
expect(darmanitan.formIndex).toBe(baseForm);
|
||||
|
||||
@ -65,7 +65,7 @@ describe("Abilities - ZEN MODE", () => {
|
||||
|
||||
it("should stay zen mode when fainted", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.DARMANITAN, SpeciesId.CHARIZARD]);
|
||||
const darmanitan = game.scene.getPlayerPokemon()!;
|
||||
const darmanitan = game.field.getPlayerPokemon();
|
||||
darmanitan.hp = darmanitan.getMaxHp() / 2 + 1;
|
||||
expect(darmanitan.formIndex).toBe(baseForm);
|
||||
|
||||
|
@ -62,7 +62,7 @@ describe("Abilities - ZERO TO HERO", () => {
|
||||
it("should swap to Hero form when switching out during a battle", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PALAFIN, SpeciesId.FEEBAS]);
|
||||
|
||||
const palafin = game.scene.getPlayerPokemon()!;
|
||||
const palafin = game.field.getPlayerPokemon();
|
||||
expect(palafin.formIndex).toBe(baseForm);
|
||||
|
||||
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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PALAFIN, SpeciesId.FEEBAS]);
|
||||
|
||||
const palafin = game.scene.getPlayerPokemon()!;
|
||||
const palafin = game.field.getPlayerPokemon();
|
||||
expect(palafin.formIndex).toBe(baseForm);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
@ -90,7 +90,7 @@ describe("Abilities - ZERO TO HERO", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.PALAFIN, SpeciesId.FEEBAS]);
|
||||
|
||||
const palafin = game.scene.getPlayerPokemon()!;
|
||||
const palafin = game.field.getPlayerPokemon();
|
||||
expect(palafin.formIndex).toBe(heroForm);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
|
@ -84,7 +84,7 @@ describe("Arena - Gravity", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
|
||||
const pidgeot = game.scene.getEnemyPokemon()!;
|
||||
const pidgeot = game.field.getEnemyPokemon();
|
||||
vi.spyOn(pidgeot, "getAttackTypeEffectiveness");
|
||||
|
||||
// Try earthquake on 1st turn (fails!);
|
||||
@ -113,7 +113,7 @@ describe("Arena - Gravity", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
|
||||
const pidgeot = game.scene.getEnemyPokemon()!;
|
||||
const pidgeot = game.field.getEnemyPokemon();
|
||||
vi.spyOn(pidgeot, "getAttackTypeEffectiveness");
|
||||
|
||||
// Setup Gravity on 1st turn
|
||||
@ -136,8 +136,8 @@ describe("Arena - Gravity", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.CHARIZARD]);
|
||||
|
||||
const charizard = game.scene.getPlayerPokemon()!;
|
||||
const snorlax = game.scene.getEnemyPokemon()!;
|
||||
const charizard = game.field.getPlayerPokemon();
|
||||
const snorlax = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
|
||||
|
@ -42,7 +42,7 @@ describe("Arena - Psychic Terrain", () => {
|
||||
game.move.select(MoveId.DARK_VOID);
|
||||
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 () => {
|
||||
|
@ -52,8 +52,8 @@ describe("Weather - Hail", () => {
|
||||
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp());
|
||||
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");
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp());
|
||||
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp() - Math.max(Math.floor(enemyPokemon.getMaxHp() / 16), 1));
|
||||
|
@ -51,8 +51,8 @@ describe("Weather - Sandstorm", () => {
|
||||
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
|
||||
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp());
|
||||
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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.ROCKRUFF]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
const playerSpdef = playerPokemon.getStat(Stat.SPDEF);
|
||||
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);
|
||||
expect(enemyPokemon.getEffectiveStat(Stat.SPDEF)).toBe(enemySpdef);
|
||||
});
|
||||
|
@ -36,8 +36,8 @@ describe("Weather - Strong Winds", () => {
|
||||
game.override.enemySpecies(SpeciesId.RAYQUAZA);
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const pikachu = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.THUNDERBOLT);
|
||||
|
||||
@ -47,8 +47,8 @@ describe("Weather - Strong Winds", () => {
|
||||
|
||||
it("electric type move is neutral for flying type pokemon", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const pikachu = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.THUNDERBOLT);
|
||||
|
||||
@ -58,8 +58,8 @@ describe("Weather - Strong Winds", () => {
|
||||
|
||||
it("ice type move is neutral for flying type pokemon", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const pikachu = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
const pikachu = game.scene.getPlayerPokemon()!;
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const pikachu = game.field.getPlayerPokemon();
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.ROCK_SLIDE);
|
||||
|
||||
@ -83,7 +83,7 @@ describe("Weather - Strong Winds", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
enemy.hp = 1;
|
||||
|
||||
game.move.use(MoveId.SPLASH);
|
||||
|
@ -37,10 +37,10 @@ describe("Test Ability Swapping", () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
game.scene.getPlayerPokemon()?.setTempAbility(allAbilities[AbilityId.INTIMIDATE]);
|
||||
game.field.getPlayerPokemon().setTempAbility(allAbilities[AbilityId.INTIMIDATE]);
|
||||
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 () => {
|
||||
@ -48,7 +48,7 @@ describe("Test Ability Swapping", () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
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");
|
||||
|
||||
expect(game.scene.arena.weather?.weatherType).toBeUndefined();
|
||||
@ -59,10 +59,10 @@ describe("Test Ability Swapping", () => {
|
||||
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||
|
||||
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");
|
||||
|
||||
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
|
||||
@ -73,6 +73,6 @@ describe("Test Ability Swapping", () => {
|
||||
game.move.select(MoveId.ROLE_PLAY);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||
expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
@ -35,8 +35,8 @@ describe("Battle order", () => {
|
||||
it("opponent faster than player 50 vs 150", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
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(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 () => {
|
||||
await game.classicMode.startBattle([SpeciesId.BULBASAUR]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
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(enemyPokemon, "stats", "get").mockReturnValue([20, 20, 20, 20, 20, 50]); // set enemyPokemon's speed to 50
|
||||
|
||||
|
@ -293,7 +293,7 @@ describe("Phase - Battle Phase", () => {
|
||||
.startingHeldItems([{ name: "TEMP_STAT_STAGE_BOOSTER", type: Stat.ACC }]);
|
||||
|
||||
await game.classicMode.startBattle();
|
||||
game.scene.getPlayerPokemon()!.hp = 1;
|
||||
game.field.getPlayerPokemon().hp = 1;
|
||||
game.move.select(moveToUse);
|
||||
|
||||
await game.phaseInterceptor.to(BattleEndPhase);
|
||||
|
@ -38,10 +38,10 @@ describe("Battle Mechanics - Damage Calculation", () => {
|
||||
it("Tackle deals expected base damage", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.CHARIZARD]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
const playerPokemon = game.field.getPlayerPokemon();
|
||||
vi.spyOn(playerPokemon, "getEffectiveStat").mockReturnValue(80);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
const enemyPokemon = game.field.getEnemyPokemon();
|
||||
vi.spyOn(enemyPokemon, "getEffectiveStat").mockReturnValue(90);
|
||||
|
||||
// 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]);
|
||||
|
||||
const aggron = game.scene.getEnemyPokemon()!;
|
||||
const aggron = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.select(MoveId.TACKLE);
|
||||
|
||||
@ -75,7 +75,7 @@ describe("Battle Mechanics - Damage Calculation", () => {
|
||||
dmg_redux_modifier.stackCount = 1000;
|
||||
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);
|
||||
|
||||
@ -89,8 +89,8 @@ describe("Battle Mechanics - Damage Calculation", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||
|
||||
const magikarp = game.scene.getPlayerPokemon()!;
|
||||
const dragonite = game.scene.getEnemyPokemon()!;
|
||||
const magikarp = game.field.getPlayerPokemon();
|
||||
const dragonite = game.field.getEnemyPokemon();
|
||||
|
||||
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]);
|
||||
|
||||
const magikarp = game.scene.getPlayerPokemon()!;
|
||||
const aggron = game.scene.getEnemyPokemon()!;
|
||||
const magikarp = game.field.getPlayerPokemon();
|
||||
const aggron = game.field.getEnemyPokemon();
|
||||
|
||||
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]);
|
||||
|
||||
const shedinja = game.scene.getPlayerPokemon()!;
|
||||
const shedinja = game.field.getPlayerPokemon();
|
||||
|
||||
game.move.select(MoveId.JUMP_KICK);
|
||||
|
||||
@ -126,7 +126,7 @@ describe("Battle Mechanics - Damage Calculation", () => {
|
||||
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
|
||||
const charizard = game.scene.getEnemyPokemon()!;
|
||||
const charizard = game.field.getEnemyPokemon();
|
||||
|
||||
if (charizard.getMaxHp() % 2 === 1) {
|
||||
expect(charizard.hp).toBeGreaterThan(charizard.getMaxHp() / 2);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user