mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-16 04:19:32 +02:00
Fixed intimidate bugs fr fr
This commit is contained in:
parent
2d6267b668
commit
018a0091f3
@ -44,6 +44,30 @@ export abstract class PhasePriorityQueue {
|
|||||||
public clear(): void {
|
public clear(): void {
|
||||||
this.queue.splice(0, this.queue.length);
|
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 {
|
private queueAbilityPhase(phase: PostSummonPhase): void {
|
||||||
const phasePokemon = phase.getPokemon();
|
const phasePokemon = phase.getPokemon();
|
||||||
|
|
||||||
|
console.log(phasePokemon.getNameToRender());
|
||||||
phasePokemon.getAbilityPriorities().forEach((priority, idx) => {
|
phasePokemon.getAbilityPriorities().forEach((priority, idx) => {
|
||||||
this.queue.push(new PostSummonActivateAbilityPhase(phasePokemon.getBattlerIndex(), priority, !!idx));
|
this.queue.push(new PostSummonActivateAbilityPhase(phasePokemon.getBattlerIndex(), priority, !!idx));
|
||||||
globalScene.phaseManager.appendToPhase(
|
globalScene.phaseManager.appendToPhase(
|
||||||
|
@ -355,14 +355,23 @@ export class PhaseManager {
|
|||||||
if (this.phaseQueuePrependSpliceIndex > -1) {
|
if (this.phaseQueuePrependSpliceIndex > -1) {
|
||||||
this.clearPhaseQueueSplice();
|
this.clearPhaseQueueSplice();
|
||||||
}
|
}
|
||||||
if (this.phaseQueuePrepend.length) {
|
this.phaseQueue.unshift(...this.phaseQueuePrepend);
|
||||||
while (this.phaseQueuePrepend.length) {
|
this.phaseQueuePrepend.splice(0);
|
||||||
const poppedPhase = this.phaseQueuePrepend.pop();
|
|
||||||
if (poppedPhase) {
|
const unactivatedConditionalPhases: [() => boolean, Phase][] = [];
|
||||||
this.phaseQueue.unshift(poppedPhase);
|
// 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) {
|
if (!this.phaseQueue.length) {
|
||||||
this.populatePhaseQueue();
|
this.populatePhaseQueue();
|
||||||
// Clear the conditionalQueue if there are no phases left in the phaseQueue
|
// 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;
|
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) {
|
if (this.currentPhase) {
|
||||||
console.log(`%cStart Phase ${this.currentPhase.constructor.name}`, "color:green;");
|
console.log(`%cStart Phase ${this.currentPhase.constructor.name}`, "color:green;");
|
||||||
this.currentPhase.start();
|
this.currentPhase.start();
|
||||||
@ -520,6 +511,25 @@ export class PhaseManager {
|
|||||||
this.dynamicPhaseQueues[type].push(phase);
|
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}
|
* Unshifts the top phase from the corresponding dynamic queue onto {@linkcode phaseQueue}
|
||||||
* @param type {@linkcode DynamicPhaseType} The type of dynamic phase to start
|
* @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 { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { BattleStyle } from "#enums/battle-style";
|
import { BattleStyle } from "#enums/battle-style";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
import { DynamicPhaseType } from "#enums/dynamic-phase-type";
|
||||||
import { SwitchType } from "#enums/switch-type";
|
import { SwitchType } from "#enums/switch-type";
|
||||||
import { UiMode } from "#enums/ui-mode";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import { BattlePhase } from "#phases/battle-phase";
|
import { BattlePhase } from "#phases/battle-phase";
|
||||||
@ -66,6 +67,17 @@ export class CheckSwitchPhase extends BattlePhase {
|
|||||||
UiMode.CONFIRM,
|
UiMode.CONFIRM,
|
||||||
() => {
|
() => {
|
||||||
globalScene.ui.setMode(UiMode.MESSAGE);
|
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);
|
globalScene.phaseManager.unshiftNew("SwitchPhase", SwitchType.INITIAL_SWITCH, this.fieldIndex, false, true);
|
||||||
this.end();
|
this.end();
|
||||||
},
|
},
|
||||||
|
@ -35,31 +35,45 @@ describe("Abilities - Intimidate", () => {
|
|||||||
it("should lower all opponents' ATK by 1 stage on entry and switch", async () => {
|
it("should lower all opponents' ATK by 1 stage on entry and switch", async () => {
|
||||||
await game.classicMode.startBattle([SpeciesId.MIGHTYENA, SpeciesId.POOCHYENA]);
|
await game.classicMode.startBattle([SpeciesId.MIGHTYENA, SpeciesId.POOCHYENA]);
|
||||||
|
|
||||||
|
const [mightyena, poochyena] = game.scene.getPlayerParty();
|
||||||
|
|
||||||
const enemy = game.field.getEnemyPokemon();
|
const enemy = game.field.getEnemyPokemon();
|
||||||
expect(enemy.getStatStage(Stat.ATK)).toBe(-1);
|
expect(enemy.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
|
expect(mightyena).toHaveAbilityApplied(AbilityId.INTIMIDATE);
|
||||||
|
|
||||||
game.doSwitchPokemon(1);
|
game.doSwitchPokemon(1);
|
||||||
await game.toNextTurn();
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(poochyena.isActive()).toBe(true);
|
||||||
expect(enemy.getStatStage(Stat.ATK)).toBe(-2);
|
expect(enemy.getStatStage(Stat.ATK)).toBe(-2);
|
||||||
|
expect(poochyena).toHaveAbilityApplied(AbilityId.INTIMIDATE);
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: This fails due to a limitation in our switching logic - the animations and field entry occur concurrently
|
it("should trigger once on initial switch prompt without cancelling opposing abilities", async () => {
|
||||||
// inside `SummonPhase`, unshifting 2 `PostSummmonPhase`s and proccing intimidate twice
|
|
||||||
it.todo("should lower all opponents' ATK by 1 stage on initial switch prompt", async () => {
|
|
||||||
await game.classicMode.runToSummon([SpeciesId.MIGHTYENA, SpeciesId.POOCHYENA]);
|
await game.classicMode.runToSummon([SpeciesId.MIGHTYENA, SpeciesId.POOCHYENA]);
|
||||||
await game.classicMode.startBattleWithSwitch(1);
|
await game.classicMode.startBattleWithSwitch(1);
|
||||||
|
|
||||||
const [poochyena, mightyena] = game.scene.getPlayerField();
|
const [poochyena, mightyena] = game.scene.getPlayerParty();
|
||||||
expect(poochyena.species.speciesId).toBe(SpeciesId.POOCHYENA);
|
expect(poochyena.species.speciesId).toBe(SpeciesId.POOCHYENA);
|
||||||
|
|
||||||
const enemy = game.field.getEnemyPokemon();
|
const enemy = game.field.getEnemyPokemon();
|
||||||
expect(enemy).toHaveStatStage(Stat.ATK, -1);
|
expect(enemy).toHaveStatStage(Stat.ATK, -1);
|
||||||
|
expect(poochyena).toHaveStatStage(Stat.ATK, -1);
|
||||||
|
|
||||||
expect(poochyena).toHaveAbilityApplied(AbilityId.INTIMIDATE);
|
expect(poochyena).toHaveAbilityApplied(AbilityId.INTIMIDATE);
|
||||||
expect(mightyena).not.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 () => {
|
it("should lower ATK of all opponents in a double battle", async () => {
|
||||||
game.override.battleStyle("double");
|
game.override.battleStyle("double");
|
||||||
await game.classicMode.startBattle([SpeciesId.MIGHTYENA]);
|
await game.classicMode.startBattle([SpeciesId.MIGHTYENA]);
|
||||||
|
Loading…
Reference in New Issue
Block a user