Fixed tests
This commit is contained in:
parent
102554cdb7
commit
024b413611
|
@ -4058,11 +4058,11 @@ export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr {
|
|||
}
|
||||
|
||||
override canApplyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
|
||||
// check if we have at least 1 recoverable berry
|
||||
// check if we have at least 1 recoverable berry (at least 1 berry in berriesEaten is not capped)
|
||||
const cappedBerries = new Set(
|
||||
globalScene.getModifiers(BerryModifier, pokemon.isPlayer()).filter(
|
||||
(bm) => bm.pokemonId === pokemon.id && bm.getCountUnderMax() < 1
|
||||
).map((bm) => bm.berryType)
|
||||
).map(bm => bm.berryType)
|
||||
);
|
||||
|
||||
const hasBerryUnderCap = pokemon.battleData.berriesEaten.some(
|
||||
|
@ -4156,7 +4156,7 @@ export class RepeatBerryNextTurnAbAttr extends PostTurnAbAttr {
|
|||
/**
|
||||
* Cause this {@linkcode Pokemon} to regurgitate and eat all berries
|
||||
* inside its `berriesEatenLast` array.
|
||||
* @param pokemon - The pokemon having the tummy ache
|
||||
* @param pokemon - The {@linkcode Pokemon} having a bad tummy ache
|
||||
* @param _passive - N/A
|
||||
* @param _simulated - N/A
|
||||
* @param _cancelled - N/A
|
||||
|
@ -4175,19 +4175,22 @@ export class RepeatBerryNextTurnAbAttr extends PostTurnAbAttr {
|
|||
const bMod = new BerryModifier(new BerryModifierType(berryType), pokemon.id, berryType, 1);
|
||||
globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(bMod)); // trigger message
|
||||
}
|
||||
|
||||
// uncomment to make cheek pouch work with cud chew
|
||||
// applyAbAttrs(HealFromBerryUseAbAttr, pokemon, new BooleanHolder(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns `true` if the pokemon ate anything this turn (we move it into `battleData`)
|
||||
* @returns always `true`
|
||||
*/
|
||||
override canApplyPostTurn(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean {
|
||||
this.showAbility = false; // don't show popup for turn end berry moving (should ideally be hidden)
|
||||
return !!pokemon.turnData.berriesEaten.length;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move this {@linkcode Pokemon}'s `berriesEaten` array inside `PokemonTurnData`
|
||||
* into its `summonData`.
|
||||
* Move this {@linkcode Pokemon}'s `berriesEaten` array from `PokemonTurnData`
|
||||
* into `PokemonSummonData`.
|
||||
* @param pokemon The {@linkcode Pokemon} having a nice snack
|
||||
* @param _passive N/A
|
||||
* @param _simulated N/A
|
||||
|
|
|
@ -406,7 +406,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
dataSource?.exp || getLevelTotalExp(this.level, species.growthRate);
|
||||
this.levelExp = dataSource?.levelExp || 0;
|
||||
|
||||
// TODO?: Maybe instead of using such a giant if statement, maybe some optional chaining/null coaclescing would look better
|
||||
if (dataSource) {
|
||||
this.id = dataSource.id;
|
||||
this.hp = dataSource.hp;
|
||||
|
@ -454,8 +453,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
this.customPokemonData = new CustomPokemonData(
|
||||
dataSource.customPokemonData,
|
||||
);
|
||||
this.summonData = dataSource.summonData;
|
||||
this.battleData = dataSource.battleData;
|
||||
this.teraType = dataSource.teraType;
|
||||
this.isTerastallized = dataSource.isTerastallized;
|
||||
this.stellarTypesBoosted = dataSource.stellarTypesBoosted ?? [];
|
||||
|
@ -524,6 +521,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
this.stellarTypesBoosted = [];
|
||||
}
|
||||
|
||||
this.summonData = new PokemonSummonData(dataSource?.summonData);
|
||||
this.battleData = new PokemonBattleData(dataSource?.battleData);
|
||||
|
||||
this.generateName();
|
||||
|
||||
if (!species.isObtainable()) {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { RepeatBerryNextTurnAbAttr } from "#app/data/abilities/ability";
|
||||
import { getBerryEffectFunc } from "#app/data/berry";
|
||||
import Pokemon from "#app/field/pokemon";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { BerryType } from "#enums/berry-type";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import { Stat } from "#enums/stat";
|
||||
import GameManager from "#test/testUtils/gameManager";
|
||||
import i18next from "i18next";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
|
@ -23,7 +24,6 @@ describe("Abilities - Cud Chew", () => {
|
|||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -40,7 +40,7 @@ describe("Abilities - Cud Chew", () => {
|
|||
});
|
||||
|
||||
describe("tracks berries eaten", () => {
|
||||
it("stores inside battledata at end of turn", async () => {
|
||||
it("stores inside summonData at end of turn", async () => {
|
||||
await game.classicMode.startBattle([Species.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
|
@ -66,32 +66,44 @@ describe("Abilities - Cud Chew", () => {
|
|||
expect(farigiraf.turnData.berriesEaten).toEqual([]);
|
||||
});
|
||||
|
||||
it("shouldn't show ability popup for end-of-turn storage", async () => {
|
||||
it("shows ability popup for eating berry, even if berry is useless", async () => {
|
||||
const abDisplaySpy = vi.spyOn(globalScene, "queueAbilityDisplay");
|
||||
game.override.enemyMoveset([Moves.SPLASH, Moves.HEAL_PULSE]);
|
||||
await game.classicMode.startBattle([Species.FARIGIRAF]);
|
||||
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
farigiraf.hp = 1; // needed to allow sitrus procs
|
||||
// Dip below half to eat berry
|
||||
farigiraf.hp = farigiraf.getMaxHp() / 2 - 1;
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.forceEnemyMove(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
// doesn't trigger since cud chew hasn't eaten berry yet
|
||||
expect(farigiraf.summonData.berriesEatenLast).toContain(BerryType.SITRUS);
|
||||
expect(abDisplaySpy).not.toHaveBeenCalledWith(farigiraf);
|
||||
await game.toNextTurn();
|
||||
|
||||
// get heal pulsed back to full before the cud chew proc
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
await game.forceEnemyMove(Moves.HEAL_PULSE);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
// globalScene.queueAbilityDisplay should be called twice: once to show cud chew before regurgitating berries,
|
||||
// once to hide after finishing application
|
||||
// globalScene.queueAbilityDisplay should be called twice:
|
||||
// once to show cud chew text before regurgitating berries,
|
||||
// once to hide ability text after finishing.
|
||||
expect(abDisplaySpy).toBeCalledTimes(2);
|
||||
expect(abDisplaySpy.mock.calls[0][0]).toBe(farigiraf);
|
||||
expect(abDisplaySpy.mock.calls[0][2]).toBe(true);
|
||||
expect(abDisplaySpy.mock.calls[1][0]).toBe(farigiraf);
|
||||
expect(abDisplaySpy.mock.calls[1][2]).toBe(false);
|
||||
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
// should display messgae
|
||||
expect(game.textInterceptor.getLatestMessage()).toBe(
|
||||
i18next.t("battle:hpIsFull", {
|
||||
pokemonName: getPokemonNameWithAffix(farigiraf),
|
||||
}),
|
||||
);
|
||||
|
||||
// not called again at turn end
|
||||
expect(abDisplaySpy).toBeCalledTimes(2);
|
||||
|
@ -114,7 +126,7 @@ describe("Abilities - Cud Chew", () => {
|
|||
game.move.select(Moves.STUFF_CHEEKS);
|
||||
await game.toNextTurn();
|
||||
|
||||
// Ate 2 petayas from moves + 1 of each at turn end
|
||||
// Ate 2 petayas from moves + 1 of each at turn end; all 4 get moved on turn end
|
||||
expect(farigiraf.summonData.berriesEatenLast).toEqual([
|
||||
BerryType.PETAYA,
|
||||
BerryType.PETAYA,
|
||||
|
@ -123,23 +135,14 @@ describe("Abilities - Cud Chew", () => {
|
|||
]);
|
||||
expect(farigiraf.turnData.berriesEaten).toEqual([]);
|
||||
|
||||
game.move.select(Moves.STUFF_CHEEKS);
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.toNextTurn();
|
||||
|
||||
// previous berries moved into summon data; newly eaten berries move into turn data
|
||||
expect(farigiraf.summonData.berriesEatenLast).toEqual([
|
||||
BerryType.PETAYA,
|
||||
BerryType.PETAYA,
|
||||
BerryType.PETAYA,
|
||||
BerryType.LIECHI,
|
||||
]);
|
||||
expect(farigiraf.turnData.berriesEaten).toEqual([BerryType.PETAYA, BerryType.LIECHI, BerryType.LIECHI]);
|
||||
expect(farigiraf.getStatStage(Stat.ATK)).toBe(4); // 1 --> 2+1
|
||||
|
||||
await game.toNextTurn();
|
||||
|
||||
// 1st array overridden after turn end
|
||||
expect(farigiraf.summonData.berriesEatenLast).toEqual([BerryType.PETAYA, BerryType.LIECHI, BerryType.LIECHI]);
|
||||
// previous berries eaten and deleted from summon data as remaining eaten berries move to replace them
|
||||
expect(farigiraf.summonData.berriesEatenLast).toEqual([BerryType.LIECHI, BerryType.LIECHI]);
|
||||
expect(farigiraf.turnData.berriesEaten).toEqual([]);
|
||||
expect(farigiraf.getStatStage(Stat.SPATK)).toBe(6); // 3+0+3
|
||||
expect(farigiraf.getStatStage(Stat.ATK)).toBe(4); // 1+2+1
|
||||
});
|
||||
|
||||
it("resets array on switch", async () => {
|
||||
|
@ -246,24 +249,26 @@ describe("Abilities - Cud Chew", () => {
|
|||
expect(farigiraf.hp).toBeLessThan(farigiraf.getMaxHp() / 4);
|
||||
});
|
||||
|
||||
it("works with pluck even if berry is useless", async () => {
|
||||
const bSpy = vi.fn(getBerryEffectFunc);
|
||||
it("works with pluck", async () => {
|
||||
game.override
|
||||
.enemySpecies(Species.BLAZIKEN)
|
||||
.enemyHeldItems([{ name: "BERRY", type: BerryType.SITRUS, count: 1 }])
|
||||
.enemyHeldItems([{ name: "BERRY", type: BerryType.PETAYA, count: 1 }])
|
||||
.startingHeldItems([]);
|
||||
await game.classicMode.startBattle([Species.FARIGIRAF]);
|
||||
|
||||
game.move.select(Moves.BUG_BITE);
|
||||
await game.toNextTurn();
|
||||
const farigiraf = game.scene.getPlayerPokemon()!;
|
||||
|
||||
game.move.select(Moves.BUG_BITE);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(bSpy).toBeCalledTimes(2);
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.toNextTurn();
|
||||
|
||||
// berry effect triggered twice - once for bug bite, once for cud chew
|
||||
expect(farigiraf.getStatStage(Stat.SPATK)).toBe(2);
|
||||
});
|
||||
|
||||
it("works with Ripen", async () => {
|
||||
const bSpy = vi.fn(getBerryEffectFunc);
|
||||
game.override.passiveAbility(Abilities.RIPEN);
|
||||
await game.classicMode.startBattle([Species.FARIGIRAF]);
|
||||
|
||||
|
@ -277,7 +282,6 @@ describe("Abilities - Cud Chew", () => {
|
|||
|
||||
// Rounding errors only ever cost a maximum of 4 hp
|
||||
expect(farigiraf.getInverseHp()).toBeLessThanOrEqual(3);
|
||||
expect(bSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("is preserved on reload/wave clear", async () => {
|
||||
|
|
|
@ -36,7 +36,6 @@ describe("Abilities - Harvest", () => {
|
|||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -146,15 +145,26 @@ describe("Abilities - Harvest", () => {
|
|||
expect(regielekiReloaded.battleData.berriesEaten).toEqual([BerryType.PETAYA]);
|
||||
});
|
||||
|
||||
it("cannot restore capped berries", async () => {
|
||||
it("cannot restore capped berries, even if an ally has one under cap", async () => {
|
||||
const initBerries: ModifierOverride[] = [
|
||||
{ name: "BERRY", type: BerryType.LUM, count: 2 },
|
||||
{ name: "BERRY", type: BerryType.STARF, count: 2 },
|
||||
];
|
||||
game.override.startingHeldItems(initBerries);
|
||||
await game.classicMode.startBattle([Species.FEEBAS]);
|
||||
const player = game.scene.getPlayerPokemon()!;
|
||||
player.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF];
|
||||
await game.classicMode.startBattle([Species.FEEBAS, Species.BELLOSSOM]);
|
||||
|
||||
const [feebas, bellossom] = game.scene.getPlayerParty();
|
||||
feebas.battleData.berriesEaten = [BerryType.LUM, BerryType.STARF];
|
||||
|
||||
// get rid of bellossom's modifiers and add a sitrus
|
||||
await game.scene.removePartyMemberModifiers(1);
|
||||
const newMod = game.scene
|
||||
.getModifiers(BerryModifier, true)
|
||||
.find(b => b.berryType === BerryType.SITRUS)
|
||||
?.clone()!;
|
||||
expect(newMod).toBeDefined();
|
||||
newMod.pokemonId = bellossom.id;
|
||||
game.scene.addModifier(newMod, true);
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.forceEnemyMove(Moves.SPLASH);
|
||||
|
@ -166,7 +176,9 @@ describe("Abilities - Harvest", () => {
|
|||
vi.spyOn(Phaser.Math.RND, "integerInRange").mockReturnValue(0);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
// recovered a starf,
|
||||
expectBerriesContaining({ name: "BERRY", type: BerryType.STARF, count: 3 });
|
||||
expect(game.scene.getModifiers(BerryModifier, true).filter(b => b.pokemonId === bellossom.id)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("does nothing if all berries are capped", async () => {
|
||||
|
|
|
@ -4,7 +4,7 @@ import GameManager from "#test/testUtils/gameManager";
|
|||
import { Species } from "#enums/species";
|
||||
import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Stat, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat";
|
||||
import { Stat, EFFECTIVE_STATS } from "#enums/stat";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
|
||||
|
@ -49,30 +49,18 @@ describe("Moves - Transform", () => {
|
|||
expect(player.getAbility()).toBe(enemy.getAbility());
|
||||
expect(player.getGender()).toBe(enemy.getGender());
|
||||
|
||||
// copies all stats except hp
|
||||
expect(player.getStat(Stat.HP, false)).not.toBe(enemy.getStat(Stat.HP));
|
||||
for (const s of EFFECTIVE_STATS) {
|
||||
expect(player.getStat(s, false)).toBe(enemy.getStat(s, false));
|
||||
}
|
||||
|
||||
for (const s of BATTLE_STATS) {
|
||||
expect(player.getStatStage(s)).toBe(enemy.getStatStage(s));
|
||||
}
|
||||
expect(player.getStatStages()).toEqual(enemy.getStatStages());
|
||||
|
||||
const playerMoveset = player.getMoveset();
|
||||
const enemyMoveset = enemy.getMoveset();
|
||||
// move IDs are equal
|
||||
expect(player.getMoveset().map(m => m.moveId)).toEqual(enemy.getMoveset().map(m => m.moveId));
|
||||
|
||||
expect(playerMoveset.length).toBe(enemyMoveset.length);
|
||||
for (let i = 0; i < playerMoveset.length && i < enemyMoveset.length; i++) {
|
||||
expect(playerMoveset[i]?.moveId).toBe(enemyMoveset[i]?.moveId);
|
||||
}
|
||||
|
||||
const playerTypes = player.getTypes();
|
||||
const enemyTypes = enemy.getTypes();
|
||||
|
||||
expect(playerTypes.length).toBe(enemyTypes.length);
|
||||
for (let i = 0; i < playerTypes.length && i < enemyTypes.length; i++) {
|
||||
expect(playerTypes[i]).toBe(enemyTypes[i]);
|
||||
}
|
||||
expect(player.getTypes()).toEqual(enemy.getTypes());
|
||||
});
|
||||
|
||||
it("should copy in-battle overridden stats", async () => {
|
||||
|
|
|
@ -73,6 +73,6 @@ export class ReloadHelper extends GameManagerHelper {
|
|||
}
|
||||
|
||||
await this.game.phaseInterceptor.to(CommandPhase);
|
||||
console.log("==================[New Turn]==================");
|
||||
console.log("==================[New Turn (Reloaded)]==================");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue