mirror of
				https://github.com/pagefaultgames/pokerogue.git
				synced 2025-11-04 02:11:19 +01:00 
			
		
		
		
	* Extract Mode enum out of UI and into its own file Reduces circular imports from 909 to 773 * Move around utility files Reduces cyclical dependencies from 773 to 765 * Remove starterColors and bypassLogin from battle-scene Reduces cyclical dependencies from 765 to 623 * Fix test runner error * Update import for bypassLogin in test * Update mocks for utils in tests * Fix broken tests * Update selectWithTera override * Update path for utils in ab-attr.ts * Update path for utils in ability-class.ts * Fix utils import path in healer.test.ts
		
			
				
	
	
		
			212 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
// biome-ignore lint/style/noNamespaceImport: Necessary for mocks
 | 
						|
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
 | 
						|
import { Status } from "#app/data/status-effect";
 | 
						|
import { CommandPhase } from "#app/phases/command-phase";
 | 
						|
import { MessagePhase } from "#app/phases/message-phase";
 | 
						|
import {
 | 
						|
  MysteryEncounterBattlePhase,
 | 
						|
  MysteryEncounterOptionSelectedPhase,
 | 
						|
  MysteryEncounterPhase,
 | 
						|
  MysteryEncounterRewardsPhase,
 | 
						|
} from "#app/phases/mystery-encounter-phases";
 | 
						|
import { VictoryPhase } from "#app/phases/victory-phase";
 | 
						|
import type MessageUiHandler from "#app/ui/message-ui-handler";
 | 
						|
import type MysteryEncounterUiHandler from "#app/ui/mystery-encounter-ui-handler";
 | 
						|
import type PartyUiHandler from "#app/ui/party-ui-handler";
 | 
						|
import type OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler";
 | 
						|
import { UiMode } from "#enums/ui-mode";
 | 
						|
import { isNullOrUndefined } from "#app/utils/common";
 | 
						|
import { Button } from "#enums/buttons";
 | 
						|
import { StatusEffect } from "#enums/status-effect";
 | 
						|
import type GameManager from "#test/testUtils/gameManager";
 | 
						|
import { expect, vi } from "vitest";
 | 
						|
 | 
						|
/**
 | 
						|
 * Runs a {@linkcode MysteryEncounter} to either the start of a battle, or to the {@linkcode MysteryEncounterRewardsPhase}, depending on the option selected
 | 
						|
 * @param game
 | 
						|
 * @param optionNo Human number, not index
 | 
						|
 * @param secondaryOptionSelect
 | 
						|
 * @param isBattle If selecting option should lead to battle, set to `true`
 | 
						|
 */
 | 
						|
export async function runMysteryEncounterToEnd(
 | 
						|
  game: GameManager,
 | 
						|
  optionNo: number,
 | 
						|
  secondaryOptionSelect?: { pokemonNo: number; optionNo?: number },
 | 
						|
  isBattle = false,
 | 
						|
) {
 | 
						|
  vi.spyOn(EncounterPhaseUtils, "selectPokemonForOption");
 | 
						|
  await runSelectMysteryEncounterOption(game, optionNo, secondaryOptionSelect);
 | 
						|
 | 
						|
  // run the selected options phase
 | 
						|
  game.onNextPrompt(
 | 
						|
    "MysteryEncounterOptionSelectedPhase",
 | 
						|
    UiMode.MESSAGE,
 | 
						|
    () => {
 | 
						|
      const uiHandler = game.scene.ui.getHandler<MysteryEncounterUiHandler>();
 | 
						|
      uiHandler.processInput(Button.ACTION);
 | 
						|
    },
 | 
						|
    () => game.isCurrentPhase(MysteryEncounterBattlePhase) || game.isCurrentPhase(MysteryEncounterRewardsPhase),
 | 
						|
  );
 | 
						|
 | 
						|
  if (isBattle) {
 | 
						|
    game.onNextPrompt(
 | 
						|
      "CheckSwitchPhase",
 | 
						|
      UiMode.CONFIRM,
 | 
						|
      () => {
 | 
						|
        game.setMode(UiMode.MESSAGE);
 | 
						|
        game.endPhase();
 | 
						|
      },
 | 
						|
      () => game.isCurrentPhase(CommandPhase),
 | 
						|
    );
 | 
						|
 | 
						|
    game.onNextPrompt(
 | 
						|
      "CheckSwitchPhase",
 | 
						|
      UiMode.MESSAGE,
 | 
						|
      () => {
 | 
						|
        game.setMode(UiMode.MESSAGE);
 | 
						|
        game.endPhase();
 | 
						|
      },
 | 
						|
      () => game.isCurrentPhase(CommandPhase),
 | 
						|
    );
 | 
						|
 | 
						|
    // If a battle is started, fast forward to end of the battle
 | 
						|
    game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => {
 | 
						|
      game.scene.clearPhaseQueue();
 | 
						|
      game.scene.clearPhaseQueueSplice();
 | 
						|
      game.scene.unshiftPhase(new VictoryPhase(0));
 | 
						|
      game.endPhase();
 | 
						|
    });
 | 
						|
 | 
						|
    // Handle end of battle trainer messages
 | 
						|
    game.onNextPrompt("TrainerVictoryPhase", UiMode.MESSAGE, () => {
 | 
						|
      const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
 | 
						|
      uiHandler.processInput(Button.ACTION);
 | 
						|
    });
 | 
						|
 | 
						|
    // Handle egg hatch dialogue
 | 
						|
    game.onNextPrompt("EggLapsePhase", UiMode.MESSAGE, () => {
 | 
						|
      const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
 | 
						|
      uiHandler.processInput(Button.ACTION);
 | 
						|
    });
 | 
						|
 | 
						|
    await game.phaseInterceptor.to(CommandPhase);
 | 
						|
  } else {
 | 
						|
    await game.phaseInterceptor.to(MysteryEncounterRewardsPhase);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export async function runSelectMysteryEncounterOption(
 | 
						|
  game: GameManager,
 | 
						|
  optionNo: number,
 | 
						|
  secondaryOptionSelect?: { pokemonNo: number; optionNo?: number },
 | 
						|
) {
 | 
						|
  // Handle any eventual queued messages (e.g. weather phase, etc.)
 | 
						|
  game.onNextPrompt(
 | 
						|
    "MessagePhase",
 | 
						|
    UiMode.MESSAGE,
 | 
						|
    () => {
 | 
						|
      const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
 | 
						|
      uiHandler.processInput(Button.ACTION);
 | 
						|
    },
 | 
						|
    () => game.isCurrentPhase(MysteryEncounterOptionSelectedPhase),
 | 
						|
  );
 | 
						|
 | 
						|
  if (game.isCurrentPhase(MessagePhase)) {
 | 
						|
    await game.phaseInterceptor.run(MessagePhase);
 | 
						|
  }
 | 
						|
 | 
						|
  // dispose of intro messages
 | 
						|
  game.onNextPrompt(
 | 
						|
    "MysteryEncounterPhase",
 | 
						|
    UiMode.MESSAGE,
 | 
						|
    () => {
 | 
						|
      const uiHandler = game.scene.ui.getHandler<MysteryEncounterUiHandler>();
 | 
						|
      uiHandler.processInput(Button.ACTION);
 | 
						|
    },
 | 
						|
    () => game.isCurrentPhase(MysteryEncounterOptionSelectedPhase),
 | 
						|
  );
 | 
						|
 | 
						|
  await game.phaseInterceptor.to(MysteryEncounterPhase, true);
 | 
						|
 | 
						|
  // select the desired option
 | 
						|
  const uiHandler = game.scene.ui.getHandler<MysteryEncounterUiHandler>();
 | 
						|
  uiHandler.unblockInput(); // input are blocked by 1s to prevent accidental input. Tests need to handle that
 | 
						|
 | 
						|
  switch (optionNo) {
 | 
						|
    case 2:
 | 
						|
      uiHandler.processInput(Button.RIGHT);
 | 
						|
      break;
 | 
						|
    case 3:
 | 
						|
      uiHandler.processInput(Button.DOWN);
 | 
						|
      break;
 | 
						|
    case 4:
 | 
						|
      uiHandler.processInput(Button.RIGHT);
 | 
						|
      uiHandler.processInput(Button.DOWN);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      // no movement needed. Default cursor position
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!isNullOrUndefined(secondaryOptionSelect?.pokemonNo)) {
 | 
						|
    await handleSecondaryOptionSelect(game, secondaryOptionSelect.pokemonNo, secondaryOptionSelect.optionNo);
 | 
						|
  } else {
 | 
						|
    uiHandler.processInput(Button.ACTION);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
async function handleSecondaryOptionSelect(game: GameManager, pokemonNo: number, optionNo?: number) {
 | 
						|
  // Handle secondary option selections
 | 
						|
  const partyUiHandler = game.scene.ui.handlers[UiMode.PARTY] as PartyUiHandler;
 | 
						|
  vi.spyOn(partyUiHandler, "show");
 | 
						|
 | 
						|
  const encounterUiHandler = game.scene.ui.getHandler<MysteryEncounterUiHandler>();
 | 
						|
  encounterUiHandler.processInput(Button.ACTION);
 | 
						|
 | 
						|
  await vi.waitFor(() => expect(partyUiHandler.show).toHaveBeenCalled());
 | 
						|
 | 
						|
  for (let i = 1; i < pokemonNo; i++) {
 | 
						|
    partyUiHandler.processInput(Button.DOWN);
 | 
						|
  }
 | 
						|
 | 
						|
  // Open options on Pokemon
 | 
						|
  partyUiHandler.processInput(Button.ACTION);
 | 
						|
  // Click "Select" on Pokemon options
 | 
						|
  partyUiHandler.processInput(Button.ACTION);
 | 
						|
 | 
						|
  // If there is a second choice to make after selecting a Pokemon
 | 
						|
  if (!isNullOrUndefined(optionNo)) {
 | 
						|
    // Wait for Summary menu to close and second options to spawn
 | 
						|
    const secondOptionUiHandler = game.scene.ui.handlers[UiMode.OPTION_SELECT] as OptionSelectUiHandler;
 | 
						|
    vi.spyOn(secondOptionUiHandler, "show");
 | 
						|
    await vi.waitFor(() => expect(secondOptionUiHandler.show).toHaveBeenCalled());
 | 
						|
 | 
						|
    // Navigate down to the correct option
 | 
						|
    for (let i = 1; i < optionNo!; i++) {
 | 
						|
      secondOptionUiHandler.processInput(Button.DOWN);
 | 
						|
    }
 | 
						|
 | 
						|
    // Select the option
 | 
						|
    secondOptionUiHandler.processInput(Button.ACTION);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * For any {@linkcode MysteryEncounter} that has a battle, can call this to skip battle and proceed to {@linkcode MysteryEncounterRewardsPhase}
 | 
						|
 * @param game
 | 
						|
 * @param runRewardsPhase
 | 
						|
 */
 | 
						|
export async function skipBattleRunMysteryEncounterRewardsPhase(game: GameManager, runRewardsPhase = true) {
 | 
						|
  game.scene.clearPhaseQueue();
 | 
						|
  game.scene.clearPhaseQueueSplice();
 | 
						|
  game.scene.getEnemyParty().forEach(p => {
 | 
						|
    p.hp = 0;
 | 
						|
    p.status = new Status(StatusEffect.FAINT);
 | 
						|
    game.scene.field.remove(p);
 | 
						|
  });
 | 
						|
  game.scene.pushPhase(new VictoryPhase(0));
 | 
						|
  game.phaseInterceptor.superEndPhase();
 | 
						|
  game.setMode(UiMode.MESSAGE);
 | 
						|
  await game.phaseInterceptor.to(MysteryEncounterRewardsPhase, runRewardsPhase);
 | 
						|
}
 |