diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index c0391a9a173..3dfe3af63a7 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -251,7 +251,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.shiny = false; } - this.calculateStats(); + if (!dataSource) { + this.calculateStats(); + } } diff --git a/src/phases/title-phase.ts b/src/phases/title-phase.ts index c74dca97f5c..4c89b725c2d 100644 --- a/src/phases/title-phase.ts +++ b/src/phases/title-phase.ts @@ -293,7 +293,7 @@ export class TitlePhase extends Phase { } for (const achv of Object.keys(this.scene.gameData.achvUnlocks)) { - if (vouchers.hasOwnProperty(achv)) { + if (vouchers.hasOwnProperty(achv) && achv !== "CLASSIC_VICTORY") { this.scene.validateVoucher(vouchers[achv]); } } diff --git a/src/test/evolution.test.ts b/src/test/evolution.test.ts index 41088c17bcb..f9123cf6d9a 100644 --- a/src/test/evolution.test.ts +++ b/src/test/evolution.test.ts @@ -1,9 +1,11 @@ import { pokemonEvolutions, SpeciesFormEvolution, SpeciesWildEvolutionDelay } from "#app/data/pokemon-evolutions"; import { Abilities } from "#app/enums/abilities"; +import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { SPLASH_ONLY } from "./utils/testUtils"; describe("Evolution", () => { let phaserGame: Phaser.Game; @@ -89,4 +91,61 @@ describe("Evolution", () => { expect(speciesFormEvo.wildDelay).toBe(SpeciesWildEvolutionDelay.NONE); }); + + it("should increase both HP and max HP when evolving", async () => { + game.override.moveset([Moves.SURF]) + .enemySpecies(Species.GOLEM) + .enemyMoveset(SPLASH_ONLY) + .startingWave(21) + .startingLevel(16) + .enemyLevel(50); + + await game.startBattle([Species.TOTODILE]); + + const totodile = game.scene.getPlayerPokemon()!; + const hpBefore = totodile.hp; + + expect(totodile.hp).toBe(totodile.getMaxHp()); + + const golem = game.scene.getEnemyPokemon()!; + golem.hp = 1; + + expect(golem.hp).toBe(1); + + game.move.select(Moves.SURF); + await game.phaseInterceptor.to("EndEvolutionPhase"); + + expect(totodile.hp).toBe(totodile.getMaxHp()); + expect(totodile.hp).toBeGreaterThan(hpBefore); + }, TIMEOUT); + + it("should not fully heal HP when evolving", async () => { + game.override.moveset([Moves.SURF]) + .enemySpecies(Species.GOLEM) + .enemyMoveset(SPLASH_ONLY) + .startingWave(21) + .startingLevel(13) + .enemyLevel(30); + + await game.startBattle([Species.CYNDAQUIL]); + + const cyndaquil = game.scene.getPlayerPokemon()!; + cyndaquil.hp = Math.floor(cyndaquil.getMaxHp() / 2); + const hpBefore = cyndaquil.hp; + const maxHpBefore = cyndaquil.getMaxHp(); + + expect(cyndaquil.hp).toBe(Math.floor(cyndaquil.getMaxHp() / 2)); + + const golem = game.scene.getEnemyPokemon()!; + golem.hp = 1; + + expect(golem.hp).toBe(1); + + game.move.select(Moves.SURF); + await game.phaseInterceptor.to("EndEvolutionPhase"); + + expect(cyndaquil.getMaxHp()).toBeGreaterThan(maxHpBefore); + expect(cyndaquil.hp).toBeGreaterThan(hpBefore); + expect(cyndaquil.hp).toBeLessThan(cyndaquil.getMaxHp()); + }, TIMEOUT); }); diff --git a/src/test/utils/mocks/mockTextureManager.ts b/src/test/utils/mocks/mockTextureManager.ts index b26d03441fe..ca8065bef97 100644 --- a/src/test/utils/mocks/mockTextureManager.ts +++ b/src/test/utils/mocks/mockTextureManager.ts @@ -7,6 +7,8 @@ import MockSprite from "#test/utils/mocks/mocksContainer/mockSprite"; import MockText from "#test/utils/mocks/mocksContainer/mockText"; import MockTexture from "#test/utils/mocks/mocksContainer/mockTexture"; import { MockGameObject } from "./mockGameObject"; +import { vi } from "vitest"; +import { MockVideoGameObject } from "./mockVideoGameObject"; /** * Stub class for Phaser.Textures.TextureManager @@ -34,6 +36,7 @@ export default class MockTextureManager { text: this.text.bind(this), bitmapText: this.text.bind(this), displayList: this.displayList, + video: vi.fn(() => new MockVideoGameObject()), }; } diff --git a/src/test/utils/mocks/mockVideoGameObject.ts b/src/test/utils/mocks/mockVideoGameObject.ts new file mode 100644 index 00000000000..96f03542bbc --- /dev/null +++ b/src/test/utils/mocks/mockVideoGameObject.ts @@ -0,0 +1,13 @@ +import { vi } from "vitest"; +import { MockGameObject } from "./mockGameObject"; + +/** Mocks video-related stuff */ +export class MockVideoGameObject implements MockGameObject { + constructor() {} + + public play = vi.fn(); + public stop = vi.fn(() => this); + public setOrigin = vi.fn(); + public setScale = vi.fn(); + public setVisible = vi.fn(); +} diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index ca3d55137fa..de65405abff 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -6,7 +6,9 @@ import { CommandPhase } from "#app/phases/command-phase"; import { DamagePhase } from "#app/phases/damage-phase"; import { EggLapsePhase } from "#app/phases/egg-lapse-phase"; import { EncounterPhase } from "#app/phases/encounter-phase"; +import { EndEvolutionPhase } from "#app/phases/end-evolution-phase"; import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; +import { EvolutionPhase } from "#app/phases/evolution-phase"; import { FaintPhase } from "#app/phases/faint-phase"; import { LoginPhase } from "#app/phases/login-phase"; import { MessagePhase } from "#app/phases/message-phase"; @@ -92,6 +94,8 @@ export default class PhaseInterceptor { [SwitchPhase, this.startPhase], [SwitchSummonPhase, this.startPhase], [PartyHealPhase, this.startPhase], + [EvolutionPhase, this.startPhase], + [EndEvolutionPhase, this.startPhase], ]; private endBySetMode = [