mirror of
				https://github.com/pagefaultgames/pokerogue.git
				synced 2025-10-31 08:25:58 +01:00 
			
		
		
		
	* WIP * Fixed Dancer last hit, flinch move interaction * Fixed steadfast interaction * Fixed comment + flaky test --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
		
			
				
	
	
		
			144 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { BattlerIndex } from "#app/battle";
 | |
| import { MoveResult } from "#app/field/pokemon";
 | |
| import type { MovePhase } from "#app/phases/move-phase";
 | |
| import { AbilityId } from "#enums/ability-id";
 | |
| import { MoveId } from "#enums/move-id";
 | |
| import { SpeciesId } from "#enums/species-id";
 | |
| import { Stat } from "#enums/stat";
 | |
| import GameManager from "#test/testUtils/gameManager";
 | |
| import Phaser from "phaser";
 | |
| import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
 | |
| 
 | |
| describe("Abilities - Dancer", () => {
 | |
|   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("double");
 | |
|   });
 | |
| 
 | |
|   // Reference Link: https://bulbapedia.bulbagarden.net/wiki/Dancer_(Ability)
 | |
| 
 | |
|   it("triggers when dance moves are used, doesn't consume extra PP", async () => {
 | |
|     game.override.enemyAbility(AbilityId.DANCER).enemySpecies(SpeciesId.MAGIKARP).enemyMoveset(MoveId.VICTORY_DANCE);
 | |
|     await game.classicMode.startBattle([SpeciesId.ORICORIO, SpeciesId.FEEBAS]);
 | |
| 
 | |
|     const [oricorio, feebas] = game.scene.getPlayerField();
 | |
|     game.move.changeMoveset(oricorio, [MoveId.SWORDS_DANCE, MoveId.VICTORY_DANCE, MoveId.SPLASH]);
 | |
|     game.move.changeMoveset(feebas, [MoveId.SWORDS_DANCE, MoveId.SPLASH]);
 | |
| 
 | |
|     game.move.select(MoveId.SPLASH);
 | |
|     game.move.select(MoveId.SWORDS_DANCE, 1);
 | |
|     await game.setTurnOrder([BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2]);
 | |
|     await game.phaseInterceptor.to("MovePhase"); // feebas uses swords dance
 | |
|     await game.phaseInterceptor.to("MovePhase", false); // oricorio copies swords dance
 | |
| 
 | |
|     let currentPhase = game.scene.getCurrentPhase() as MovePhase;
 | |
|     expect(currentPhase.pokemon).toBe(oricorio);
 | |
|     expect(currentPhase.move.moveId).toBe(MoveId.SWORDS_DANCE);
 | |
| 
 | |
|     await game.phaseInterceptor.to("MoveEndPhase"); // end oricorio's move
 | |
|     await game.phaseInterceptor.to("MovePhase"); // magikarp 1 copies swords dance
 | |
|     await game.phaseInterceptor.to("MovePhase"); // magikarp 2 copies swords dance
 | |
|     await game.phaseInterceptor.to("MovePhase"); // magikarp (left) uses victory dance
 | |
|     await game.phaseInterceptor.to("MovePhase", false); // oricorio copies magikarp's victory dance
 | |
| 
 | |
|     currentPhase = game.scene.getCurrentPhase() as MovePhase;
 | |
|     expect(currentPhase.pokemon).toBe(oricorio);
 | |
|     expect(currentPhase.move.moveId).toBe(MoveId.VICTORY_DANCE);
 | |
| 
 | |
|     await game.phaseInterceptor.to("BerryPhase"); // finish the turn
 | |
| 
 | |
|     // doesn't use PP if copied move is also in moveset
 | |
|     expect(oricorio.moveset[0]?.ppUsed).toBe(0);
 | |
|     expect(oricorio.moveset[1]?.ppUsed).toBe(0);
 | |
|   });
 | |
| 
 | |
|   // TODO: Enable after Dancer rework to not push to move history
 | |
|   it.todo("should not count as the last move used for mirror move/instruct", async () => {
 | |
|     game.override
 | |
|       .moveset([MoveId.FIERY_DANCE, MoveId.REVELATION_DANCE])
 | |
|       .enemyMoveset([MoveId.INSTRUCT, MoveId.MIRROR_MOVE, MoveId.SPLASH])
 | |
|       .enemySpecies(SpeciesId.SHUCKLE)
 | |
|       .enemyLevel(10);
 | |
|     await game.classicMode.startBattle([SpeciesId.ORICORIO, SpeciesId.FEEBAS]);
 | |
| 
 | |
|     const [oricorio] = game.scene.getPlayerField();
 | |
|     const [, shuckle2] = game.scene.getEnemyField();
 | |
| 
 | |
|     game.move.select(MoveId.REVELATION_DANCE, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2);
 | |
|     game.move.select(MoveId.FIERY_DANCE, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2);
 | |
|     await game.move.selectEnemyMove(MoveId.INSTRUCT, BattlerIndex.PLAYER);
 | |
|     await game.move.selectEnemyMove(MoveId.MIRROR_MOVE, BattlerIndex.PLAYER);
 | |
|     await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2, BattlerIndex.ENEMY]);
 | |
|     await game.phaseInterceptor.to("MovePhase"); // Oricorio rev dance
 | |
|     await game.phaseInterceptor.to("MovePhase"); // Feebas fiery dance
 | |
|     await game.phaseInterceptor.to("MovePhase"); // Oricorio fiery dance (from dancer)
 | |
|     await game.phaseInterceptor.to("MoveEndPhase", false);
 | |
|     // dancer copied move doesn't appear in move history
 | |
|     expect(oricorio.getLastXMoves(-1)[0].move).toBe(MoveId.REVELATION_DANCE);
 | |
| 
 | |
|     await game.phaseInterceptor.to("MovePhase"); // shuckle 2 mirror moves oricorio
 | |
|     await game.phaseInterceptor.to("MovePhase"); // calls instructed rev dance
 | |
|     let currentPhase = game.scene.getCurrentPhase() as MovePhase;
 | |
|     expect(currentPhase.pokemon).toBe(shuckle2);
 | |
|     expect(currentPhase.move.moveId).toBe(MoveId.REVELATION_DANCE);
 | |
| 
 | |
|     await game.phaseInterceptor.to("MovePhase"); // shuckle 1 instructs oricorio
 | |
|     await game.phaseInterceptor.to("MovePhase");
 | |
|     currentPhase = game.scene.getCurrentPhase() as MovePhase;
 | |
|     expect(currentPhase.pokemon).toBe(oricorio);
 | |
|     expect(currentPhase.move.moveId).toBe(MoveId.REVELATION_DANCE);
 | |
|   });
 | |
| 
 | |
|   it("should not break subsequent last hit only moves", async () => {
 | |
|     game.override.battleStyle("single");
 | |
|     await game.classicMode.startBattle([SpeciesId.ORICORIO, SpeciesId.FEEBAS]);
 | |
| 
 | |
|     const [oricorio, feebas] = game.scene.getPlayerParty();
 | |
| 
 | |
|     game.move.use(MoveId.BATON_PASS);
 | |
|     game.doSelectPartyPokemon(1);
 | |
|     await game.move.forceEnemyMove(MoveId.SWORDS_DANCE);
 | |
|     await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
 | |
|     await game.phaseInterceptor.to("TurnEndPhase");
 | |
| 
 | |
|     expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase");
 | |
|     expect(game.field.getPlayerPokemon()).toBe(feebas);
 | |
|     expect(feebas.getStatStage(Stat.ATK)).toBe(2);
 | |
|     expect(oricorio.isOnField()).toBe(false);
 | |
|     expect(oricorio.visible).toBe(false);
 | |
|   });
 | |
| 
 | |
|   it("should not trigger while flinched", async () => {
 | |
|     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()!;
 | |
|     expect(oricorio).toBeDefined();
 | |
| 
 | |
|     // get faked out and copy swords dance
 | |
|     game.move.select(MoveId.SPLASH);
 | |
|     await game.move.forceEnemyMove(MoveId.SWORDS_DANCE);
 | |
|     await game.move.forceEnemyMove(MoveId.FAKE_OUT, BattlerIndex.PLAYER);
 | |
|     await game.phaseInterceptor.to("TurnEndPhase");
 | |
| 
 | |
|     expect(oricorio.getLastXMoves(-1)[0]).toMatchObject({
 | |
|       move: MoveId.NONE,
 | |
|       result: MoveResult.FAIL,
 | |
|     });
 | |
|     expect(oricorio.getStatStage(Stat.ATK)).toBe(0);
 | |
|   });
 | |
| });
 |