Move application to applyPostSummonAbAttrs and stop assuming no other phases in queue

This commit is contained in:
Dean 2025-03-13 13:23:13 -07:00
parent ca05b94dbe
commit 6995c8c0c0
3 changed files with 64 additions and 39 deletions

View File

@ -5164,6 +5164,7 @@ function applySingleAbAttrs<TAttr extends AbAttr>(
args: any[],
gainedMidTurn = false,
simulated = false,
priorityCondition?: (p: number) => boolean,
showAbilityInstant = false,
messages: string[] = []
) {
@ -5172,7 +5173,10 @@ function applySingleAbAttrs<TAttr extends AbAttr>(
}
const ability = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
if (gainedMidTurn && ability.getAttrs(attrType).some(attr => attr instanceof PostSummonAbAttr && !attr.shouldActivateOnGain())) {
if (
gainedMidTurn && ability.getAttrs(attrType).some(attr => attr instanceof PostSummonAbAttr && !attr.shouldActivateOnGain())
|| (priorityCondition && !priorityCondition(ability.postSummonPriority))
) {
return;
}
@ -5453,6 +5457,19 @@ export class PostDamageForceSwitchAbAttr extends PostDamageAbAttr {
return this.helper.getFailedText(target);
}
}
/**
* Main Function for handling ability application. Applies both the normal ability and passive of the Pokemon
* @param attrType The type of {@linkcode AbAttr} to apply
* @param pokemon The {@linkcode Pokemon} whose abilities should be applied
* @param applyFunc The {@linkcode AbAttrApplyFunc} corresponding to {@linkcode attrType}
* @param args Extra arguments, handled by individual {@linkcode AbAttr}s
* @param showAbilityInstant If `true`, show the ability bar instantly instead of queuing it
* @param simulated `true` if the call is simulated and the battle state should not be changes
* @param messages Array of messages which will be added to if the ability displays a message
* @param gainedMidTurn `true` if the ability is activating because it was gained during the battle
* @param priorityCondition If defined, only abilities with priority that meets the condition will be applied
*/
function applyAbAttrsInternal<TAttr extends AbAttr>(
attrType: Constructor<TAttr>,
pokemon: Pokemon | null,
@ -5461,11 +5478,12 @@ function applyAbAttrsInternal<TAttr extends AbAttr>(
showAbilityInstant = false,
simulated = false,
messages: string[] = [],
gainedMidTurn = false
gainedMidTurn = false,
priorityCondition?: (p: number) => boolean
) {
for (const passive of [ false, true ]) {
if (pokemon) {
applySingleAbAttrs(pokemon, passive, attrType, applyFunc, args, gainedMidTurn, simulated, showAbilityInstant, messages);
applySingleAbAttrs(pokemon, passive, attrType, applyFunc, args, gainedMidTurn, simulated, priorityCondition, showAbilityInstant, messages);
globalScene.clearPhaseQueueSplice();
}
}
@ -5714,6 +5732,7 @@ export function applyPostSummonAbAttrs(
attrType: Constructor<PostSummonAbAttr>,
pokemon: Pokemon,
simulated = false,
priorityCondition?: (p: number) => boolean,
...args: any[]
): void {
applyAbAttrsInternal<PostSummonAbAttr>(
@ -5723,6 +5742,9 @@ export function applyPostSummonAbAttrs(
args,
false,
simulated,
[],
false,
priorityCondition
);
}
@ -6002,20 +6024,6 @@ export function applyOnLoseAbAttrs(pokemon: Pokemon, passive = false, simulated
applySingleAbAttrs<PreLeaveFieldAbAttr>(pokemon, passive, PreLeaveFieldAbAttr, (attr, passive) => attr.applyPreLeaveField(pokemon, passive, simulated, [ ...args, true ]), args, true, simulated);
}
/**
* Applies only abilities whose priority meets a condition
*
* @param condition Apply to abilities whose priority meets the condition
*/
export function applyPriorityBasedAbAttrs(pokemon: Pokemon, condition: (p: number) => boolean, simulated: boolean = false, ...args: any[]) {
for (const passive of [ false, true ]) {
const ability: Ability = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
if (condition(ability.postSummonPriority)) {
applySingleAbAttrs<PostSummonAbAttr>(pokemon, passive, PostSummonAbAttr, (attr, passive) => attr.applyPostSummon(pokemon, passive, simulated, args), args, false, simulated)
}
}
}
function queueShowAbility(pokemon: Pokemon, passive: boolean): void {
globalScene.unshiftPhase(new ShowAbilityPhase(pokemon.id, passive));
globalScene.clearPhaseQueueSplice();

View File

@ -1,5 +1,5 @@
import type { BattlerIndex } from "#app/battle";
import { applyPriorityBasedAbAttrs } from "#app/data/ability";
import { applyPostSummonAbAttrs, PostSummonAbAttr } from "#app/data/ability";
import { PokemonPhase } from "#app/phases/pokemon-phase";
/**
@ -20,7 +20,7 @@ export class PostSummonActivateAbilityPhase extends PokemonPhase {
start() {
super.start();
applyPriorityBasedAbAttrs(this.getPokemon(), (p: number) => p === this.priority);
applyPostSummonAbAttrs(PostSummonAbAttr, this.getPokemon(), false, (p: number) => p === this.priority);
this.end();
}

View File

@ -1,6 +1,6 @@
import { globalScene } from "#app/global-scene";
import type { BattlerIndex } from "#app/battle";
import { applyAbAttrs, applyPriorityBasedAbAttrs, CommanderAbAttr, PostSummonAbAttr } from "#app/data/ability";
import { applyAbAttrs, applyPostSummonAbAttrs, CommanderAbAttr, PostSummonAbAttr } from "#app/data/ability";
import { ArenaTrapTag } from "#app/data/arena-tag";
import { StatusEffect } from "#app/enums/status-effect";
import { PokemonPhase } from "./pokemon-phase";
@ -23,21 +23,24 @@ export class PostSummonPhase extends PokemonPhase {
super.start();
const pokemon = this.getPokemon();
let indexAfterPostSummon = globalScene.phaseQueue.findIndex(phase => !(phase instanceof PostSummonPhase));
indexAfterPostSummon = indexAfterPostSummon === -1 ? globalScene.phaseQueue.length : indexAfterPostSummon;
if (
!this.ordered &&
globalScene.findPhase(phase => phase instanceof PostSummonPhase && phase.getPokemon() !== pokemon)
) {
globalScene.pushPhase(new PostSummonPhase(pokemon.getBattlerIndex(), true));
globalScene.phaseQueue.splice(indexAfterPostSummon++, 0, new PostSummonPhase(pokemon.getBattlerIndex(), true));
this.orderPostSummonPhases();
this.queueAbilityActivationPhases(indexAfterPostSummon);
this.end();
return;
}
if (!this.ordered) {
applyPriorityBasedAbAttrs(pokemon, (p: number) => p > 0);
applyPostSummonAbAttrs(PostSummonAbAttr, pokemon, false, (p: number) => p > 0);
}
if (pokemon.status?.effect === StatusEffect.TOXIC) {
@ -52,9 +55,11 @@ export class PostSummonPhase extends PokemonPhase {
) {
pokemon.lapseTag(BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON);
}
if (!this.ordered) {
applyPriorityBasedAbAttrs(pokemon, (p: number) => p <= 0);
applyPostSummonAbAttrs(PostSummonAbAttr, pokemon, false, (p: number) => p <= 0);
}
const field = pokemon.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
for (const p of field) {
applyAbAttrs(CommanderAbAttr, p, null, false);
@ -63,6 +68,9 @@ export class PostSummonPhase extends PokemonPhase {
this.end();
}
/**
* Sorts the {@linkcode PostSummonPhase}s in the queue by effective speed
*/
private orderPostSummonPhases() {
globalScene.sortPhaseType(
PostSummonPhase,
@ -70,28 +78,37 @@ export class PostSummonPhase extends PokemonPhase {
phaseB.getPokemon().getEffectiveStat(Stat.SPD) - phaseA.getPokemon().getEffectiveStat(Stat.SPD),
);
const positivePriorityPhases: PostSummonActivateAbilityPhase[] = [];
const zeroNegativePriorityPhases: PostSummonActivateAbilityPhase[] = [];
for (let i = 0; i < globalScene.phaseQueue.length && globalScene.phaseQueue[i] instanceof PostSummonPhase; i++) {
(globalScene.phaseQueue[i] as PostSummonPhase).ordered = true;
}
}
globalScene.phaseQueue.forEach((phase: PostSummonPhase) => {
phase.ordered = true;
/**
* Adds {@linkcode PostSummonActivateAbilityPhase}s for all {@linkcode PostSummonPhase}s in the queue
* @param endIndex The index of the first non-{@linkcode PostSummonPhase} Phase in the queue, or the length if none exists
*/
private queueAbilityActivationPhases(endIndex: number) {
const abilityPhases: PostSummonActivateAbilityPhase[] = [];
globalScene.phaseQueue.slice(0, endIndex).forEach((phase: PostSummonPhase) => {
const phasePokemon = phase.getPokemon();
for (const priority of phasePokemon.getAbilityPriorities()) {
(priority > 0 ? positivePriorityPhases : zeroNegativePriorityPhases).push(
new PostSummonActivateAbilityPhase(phasePokemon.getBattlerIndex(), priority),
phasePokemon
.getAbilityPriorities()
.forEach(priority =>
abilityPhases.push(new PostSummonActivateAbilityPhase(phasePokemon.getBattlerIndex(), priority)),
);
}
});
for (const phaseList of [positivePriorityPhases, zeroNegativePriorityPhases]) {
phaseList.sort(
(phaseA: PostSummonActivateAbilityPhase, phaseB: PostSummonActivateAbilityPhase) =>
phaseB.getPriority() - phaseA.getPriority(),
);
}
abilityPhases.sort(
(phaseA: PostSummonActivateAbilityPhase, phaseB: PostSummonActivateAbilityPhase) =>
phaseB.getPriority() - phaseA.getPriority(),
);
globalScene.unshiftPhase(...positivePriorityPhases);
zeroNegativePriorityPhases.forEach(phase => globalScene.pushPhase(phase));
let zeroIndex = abilityPhases.findIndex(phase => phase.getPriority() === 0);
zeroIndex = zeroIndex === -1 ? abilityPhases.length : zeroIndex;
globalScene.unshiftPhase(...abilityPhases.slice(0, zeroIndex));
globalScene.phaseQueue.splice(endIndex, 0, ...abilityPhases.slice(zeroIndex));
}
}