mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-14 11:29:28 +02:00
Merge 018a0091f3
into 6c0253ada4
This commit is contained in:
commit
3723b68c2e
@ -44,6 +44,30 @@ export abstract class PhasePriorityQueue {
|
||||
public clear(): void {
|
||||
this.queue.splice(0, this.queue.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to remove one or more Phases from the current queue.
|
||||
* @param phaseFilter - The function to select phases for removal
|
||||
* @param removeCount - The maximum number of phases to remove, or `all` to remove all matching phases;
|
||||
* default `1`
|
||||
* @returns The number of successfully removed phases
|
||||
* @todo Remove this eventually once the patchwork bug this is used for is fixed
|
||||
*/
|
||||
public tryRemovePhase(phaseFilter: (phase: Phase) => boolean, removeCount: number | "all" = 1): number {
|
||||
if (typeof removeCount === "string") {
|
||||
removeCount = Number.MAX_SAFE_INTEGER; // For the lulz
|
||||
}
|
||||
let numRemoved = 0;
|
||||
let phaseIndex = this.queue.findIndex(phaseFilter);
|
||||
if (phaseIndex === -1) {
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
this.queue.splice(phaseIndex, 1);
|
||||
numRemoved++;
|
||||
} while (numRemoved < removeCount || (phaseIndex = this.queue.findIndex(phaseFilter)) !== -1);
|
||||
return removeCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,6 +103,7 @@ export class PostSummonPhasePriorityQueue extends PhasePriorityQueue {
|
||||
private queueAbilityPhase(phase: PostSummonPhase): void {
|
||||
const phasePokemon = phase.getPokemon();
|
||||
|
||||
console.log(phasePokemon.getNameToRender());
|
||||
phasePokemon.getAbilityPriorities().forEach((priority, idx) => {
|
||||
this.queue.push(new PostSummonActivateAbilityPhase(phasePokemon.getBattlerIndex(), priority, !!idx));
|
||||
globalScene.phaseManager.appendToPhase(
|
||||
|
@ -355,14 +355,23 @@ export class PhaseManager {
|
||||
if (this.phaseQueuePrependSpliceIndex > -1) {
|
||||
this.clearPhaseQueueSplice();
|
||||
}
|
||||
if (this.phaseQueuePrepend.length) {
|
||||
while (this.phaseQueuePrepend.length) {
|
||||
const poppedPhase = this.phaseQueuePrepend.pop();
|
||||
if (poppedPhase) {
|
||||
this.phaseQueue.unshift(poppedPhase);
|
||||
}
|
||||
this.phaseQueue.unshift(...this.phaseQueuePrepend);
|
||||
this.phaseQueuePrepend.splice(0);
|
||||
|
||||
const unactivatedConditionalPhases: [() => boolean, Phase][] = [];
|
||||
// Check if there are any conditional phases queued
|
||||
for (const [condition, phase] of this.conditionalQueue) {
|
||||
// Evaluate the condition associated with the phase
|
||||
if (condition()) {
|
||||
// If the condition is met, add the phase to the phase queue
|
||||
this.pushPhase(phase);
|
||||
} else {
|
||||
// If the condition is not met, re-add the phase back to the end of the conditional queue
|
||||
unactivatedConditionalPhases.push([condition, phase]);
|
||||
}
|
||||
}
|
||||
this.conditionalQueue = unactivatedConditionalPhases;
|
||||
|
||||
if (!this.phaseQueue.length) {
|
||||
this.populatePhaseQueue();
|
||||
// Clear the conditionalQueue if there are no phases left in the phaseQueue
|
||||
@ -371,24 +380,6 @@ export class PhaseManager {
|
||||
|
||||
this.currentPhase = this.phaseQueue.shift() ?? null;
|
||||
|
||||
const unactivatedConditionalPhases: [() => boolean, Phase][] = [];
|
||||
// Check if there are any conditional phases queued
|
||||
while (this.conditionalQueue?.length) {
|
||||
// Retrieve the first conditional phase from the queue
|
||||
const conditionalPhase = this.conditionalQueue.shift();
|
||||
// Evaluate the condition associated with the phase
|
||||
if (conditionalPhase?.[0]()) {
|
||||
// If the condition is met, add the phase to the phase queue
|
||||
this.pushPhase(conditionalPhase[1]);
|
||||
} else if (conditionalPhase) {
|
||||
// If the condition is not met, re-add the phase back to the front of the conditional queue
|
||||
unactivatedConditionalPhases.push(conditionalPhase);
|
||||
} else {
|
||||
console.warn("condition phase is undefined/null!", conditionalPhase);
|
||||
}
|
||||
}
|
||||
this.conditionalQueue.push(...unactivatedConditionalPhases);
|
||||
|
||||
if (this.currentPhase) {
|
||||
console.log(`%cStart Phase ${this.currentPhase.constructor.name}`, "color:green;");
|
||||
this.currentPhase.start();
|
||||
@ -520,6 +511,25 @@ export class PhaseManager {
|
||||
this.dynamicPhaseQueues[type].push(phase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to remove one or more Phases from the given DynamicPhaseQueue, removing the equivalent amount of {@linkcode ActivatePriorityQueuePhase}s from the queue.
|
||||
* @param type - The {@linkcode DynamicPhaseType} to check
|
||||
* @param phaseFilter - The function to select phases for removal
|
||||
* @param removeCount - The maximum number of phases to remove, or `all` to remove all matching phases;
|
||||
* default `1`
|
||||
* @todo Remove this eventually once the patchwork bug this is used for is fixed
|
||||
*/
|
||||
public tryRemoveDynamicPhase(
|
||||
type: DynamicPhaseType,
|
||||
phaseFilter: (phase: Phase) => boolean,
|
||||
removeCount: number | "all" = 1,
|
||||
): void {
|
||||
const numRemoved = this.dynamicPhaseQueues[type].tryRemovePhase(phaseFilter, removeCount);
|
||||
for (let x = 0; x < numRemoved; x++) {
|
||||
this.tryRemovePhase(p => p.is("ActivatePriorityQueuePhase"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshifts the top phase from the corresponding dynamic queue onto {@linkcode phaseQueue}
|
||||
* @param type {@linkcode DynamicPhaseType} The type of dynamic phase to start
|
||||
|
@ -2,6 +2,7 @@ import { globalScene } from "#app/global-scene";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { BattleStyle } from "#enums/battle-style";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { DynamicPhaseType } from "#enums/dynamic-phase-type";
|
||||
import { SwitchType } from "#enums/switch-type";
|
||||
import { UiMode } from "#enums/ui-mode";
|
||||
import { BattlePhase } from "#phases/battle-phase";
|
||||
@ -66,6 +67,17 @@ export class CheckSwitchPhase extends BattlePhase {
|
||||
UiMode.CONFIRM,
|
||||
() => {
|
||||
globalScene.ui.setMode(UiMode.MESSAGE);
|
||||
/*
|
||||
Remove any pending `ActivatePriorityQueuePhase`s for the currently leaving Pokemon produced by the prior `SwitchSummonPhase`.
|
||||
This is required to avoid triggering on-switch abilities twice on initial entrance.
|
||||
TODO: Separate the animations from `SwitchSummonPhase` to another phase and call that on initial switch - this is a band-aid fix
|
||||
TODO: Confirm with @emdeann what the maximum number of these things that gets unshifted can be
|
||||
*/
|
||||
globalScene.phaseManager.tryRemoveDynamicPhase(
|
||||
DynamicPhaseType.POST_SUMMON,
|
||||
p => p.is("PostSummonPhase") && p.getPokemon() === pokemon,
|
||||
4,
|
||||
);
|
||||
globalScene.phaseManager.unshiftNew("SwitchPhase", SwitchType.INITIAL_SWITCH, this.fieldIndex, false, true);
|
||||
this.end();
|
||||
},
|
||||
|
@ -35,13 +35,43 @@ describe("Abilities - Intimidate", () => {
|
||||
it("should lower all opponents' ATK by 1 stage on entry and switch", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MIGHTYENA, SpeciesId.POOCHYENA]);
|
||||
|
||||
const [mightyena, poochyena] = game.scene.getPlayerParty();
|
||||
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
expect(enemy.getStatStage(Stat.ATK)).toBe(-1);
|
||||
expect(mightyena).toHaveAbilityApplied(AbilityId.INTIMIDATE);
|
||||
|
||||
game.doSwitchPokemon(1);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(poochyena.isActive()).toBe(true);
|
||||
expect(enemy.getStatStage(Stat.ATK)).toBe(-2);
|
||||
expect(poochyena).toHaveAbilityApplied(AbilityId.INTIMIDATE);
|
||||
});
|
||||
|
||||
it("should trigger once on initial switch prompt without cancelling opposing abilities", async () => {
|
||||
await game.classicMode.runToSummon([SpeciesId.MIGHTYENA, SpeciesId.POOCHYENA]);
|
||||
await game.classicMode.startBattleWithSwitch(1);
|
||||
|
||||
const [poochyena, mightyena] = game.scene.getPlayerParty();
|
||||
expect(poochyena.species.speciesId).toBe(SpeciesId.POOCHYENA);
|
||||
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
expect(enemy).toHaveStatStage(Stat.ATK, -1);
|
||||
expect(poochyena).toHaveStatStage(Stat.ATK, -1);
|
||||
|
||||
expect(poochyena).toHaveAbilityApplied(AbilityId.INTIMIDATE);
|
||||
expect(mightyena).not.toHaveAbilityApplied(AbilityId.INTIMIDATE);
|
||||
});
|
||||
|
||||
it("should activate on reload with single party", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.MIGHTYENA]);
|
||||
|
||||
expect(game.field.getEnemyPokemon()).toHaveStatStage(Stat.ATK, -1);
|
||||
|
||||
await game.reload.reloadSession();
|
||||
|
||||
expect(game.field.getEnemyPokemon()).toHaveStatStage(Stat.ATK, -1);
|
||||
});
|
||||
|
||||
it("should lower ATK of all opponents in a double battle", async () => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { getGameMode } from "#app/game-mode";
|
||||
import overrides from "#app/overrides";
|
||||
import { BattleStyle } from "#enums/battle-style";
|
||||
import { Button } from "#enums/buttons";
|
||||
import { GameModes } from "#enums/game-modes";
|
||||
import { Nature } from "#enums/nature";
|
||||
import type { SpeciesId } from "#enums/species-id";
|
||||
@ -100,4 +101,33 @@ export class ClassicModeHelper extends GameManagerHelper {
|
||||
await this.game.phaseInterceptor.to(CommandPhase);
|
||||
console.log("==================[New Turn]==================");
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue inputs to switch at the start of the next battle, and then start it.
|
||||
* @param pokemonIndex - The 0-indexed position of the party pokemon to switch to.
|
||||
* Should never be called with 0 as that will select the currently active pokemon and freeze
|
||||
* @returns A Promise that resolves once the battle has been started and the switch prompt resolved
|
||||
* @todo Make this work for double battles
|
||||
* @example
|
||||
* ```ts
|
||||
* await game.classicMode.runToSummon([SpeciesId.MIGHTYENA, SpeciesId.POOCHYENA])
|
||||
* await game.startBattleWithSwitch(1);
|
||||
* ```
|
||||
*/
|
||||
public async startBattleWithSwitch(pokemonIndex: number): Promise<void> {
|
||||
this.game.scene.battleStyle = BattleStyle.SWITCH;
|
||||
this.game.onNextPrompt(
|
||||
"CheckSwitchPhase",
|
||||
UiMode.CONFIRM,
|
||||
() => {
|
||||
this.game.scene.ui.getHandler().setCursor(0);
|
||||
this.game.scene.ui.getHandler().processInput(Button.ACTION);
|
||||
},
|
||||
() => this.game.isCurrentPhase("CommandPhase") || this.game.isCurrentPhase("TurnInitPhase"),
|
||||
);
|
||||
this.game.doSelectPartyPokemon(pokemonIndex);
|
||||
|
||||
await this.game.phaseInterceptor.to("CommandPhase");
|
||||
console.log("==================[New Battle (Initial Switch)]==================");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user