Update to use priority numbers instead of a boolean

This commit is contained in:
Dean 2025-03-12 01:33:05 -07:00
parent d36f2105f1
commit 78882d4be2
4 changed files with 65 additions and 33 deletions

View File

@ -56,18 +56,18 @@ export class Ability implements Localizable {
public name: string;
public description: string;
public generation: number;
public postSummonPriority: number;
public isBypassFaint: boolean;
public isIgnorable: boolean;
public isPriority: boolean;
public attrs: AbAttr[];
public conditions: AbAttrCondition[];
constructor(id: Abilities, generation: number, isPriority: boolean = false) {
constructor(id: Abilities, generation: number, postSummonPriority: number = 0) {
this.id = id;
this.nameAppend = "";
this.generation = generation;
this.isPriority = isPriority;
this.postSummonPriority = postSummonPriority;
this.attrs = [];
this.conditions = [];
@ -6003,14 +6003,14 @@ export function applyOnLoseAbAttrs(pokemon: Pokemon, passive = false, simulated
}
/**
* Applies only abilities that are priority or are not, based on parameters
* Applies only abilities whose priority meets a condition
*
* @param priority If true, apply only priority abilities. If false, apply only non-priority abilities
* @param condition Apply to abilities whose priority meets the condition
*/
export function applyPriorityBasedAbAttrs(pokemon: Pokemon, priority: boolean, simulated: boolean = false, ...args: any[]) {
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 (ability.isPriority == priority) {
if (condition(ability.postSummonPriority)) {
applySingleAbAttrs<PostSummonAbAttr>(pokemon, passive, PostSummonAbAttr, (attr, passive) => attr.applyPostSummon(pokemon, passive, simulated, args), args, false, simulated)
}
}
@ -6904,7 +6904,7 @@ export function initAbilities() {
.edgeCase(), // interacts incorrectly with rock head. It's meant to switch abilities before recoil would apply so that a pokemon with rock head would lose rock head first and still take the recoil
new Ability(Abilities.GORILLA_TACTICS, 8)
.attr(GorillaTacticsAbAttr),
new Ability(Abilities.NEUTRALIZING_GAS, 8, true)
new Ability(Abilities.NEUTRALIZING_GAS, 8, 2)
.attr(PostSummonAddArenaTagAbAttr, ArenaTagType.NEUTRALIZING_GAS, 0)
.attr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr)
.attr(UncopiableAbilityAbAttr)
@ -6937,14 +6937,14 @@ export function initAbilities() {
.attr(PostVictoryStatStageChangeAbAttr, Stat.ATK, 1),
new Ability(Abilities.GRIM_NEIGH, 8)
.attr(PostVictoryStatStageChangeAbAttr, Stat.SPATK, 1),
new Ability(Abilities.AS_ONE_GLASTRIER, 8, true)
new Ability(Abilities.AS_ONE_GLASTRIER, 8, 1)
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonAsOneGlastrier", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))
.attr(PreventBerryUseAbAttr)
.attr(PostVictoryStatStageChangeAbAttr, Stat.ATK, 1)
.attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr)
.attr(UnsuppressableAbilityAbAttr),
new Ability(Abilities.AS_ONE_SPECTRIER, 8, true)
new Ability(Abilities.AS_ONE_SPECTRIER, 8, 1)
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonAsOneSpectrier", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))
.attr(PreventBerryUseAbAttr)
.attr(PostVictoryStatStageChangeAbAttr, Stat.SPATK, 1)

View File

@ -2265,11 +2265,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return false;
}
/**
* @returns If either of the Pokemon's abilities have priority activation
*/
public hasPriorityAbility() {
return [this.getAbility(), this.getPassiveAbility()].some(ability => ability.isPriority);
public getAbilityPriorities(): Set<number> {
return new Set([ this.getAbility().postSummonPriority, this.getPassiveAbility().postSummonPriority ]);
}
/**

View File

@ -7,7 +7,7 @@ import { PokemonPhase } from "./pokemon-phase";
import { MysteryEncounterPostSummonTag } from "#app/data/battler-tags";
import { BattlerTagType } from "#enums/battler-tag-type";
import { Stat } from "#enums/stat";
import { PriorityAbilityActivationPhase } from "#app/phases/priority-ability-activation-phase";
import { PostSummonActivateAbilityPhase } from "#app/phases/priority-ability-activation-phase";
export class PostSummonPhase extends PokemonPhase {
/** Represents whether or not this phase has already been placed in the correct (speed) order */
@ -29,24 +29,15 @@ export class PostSummonPhase extends PokemonPhase {
globalScene.findPhase(phase => phase instanceof PostSummonPhase && phase.getPokemon() !== pokemon)
) {
globalScene.pushPhase(new PostSummonPhase(pokemon.getBattlerIndex(), true));
globalScene.phaseQueue.sort(
(phaseA: PostSummonPhase, phaseB: PostSummonPhase) =>
phaseB.getPokemon().getEffectiveStat(Stat.SPD) - phaseA.getPokemon().getEffectiveStat(Stat.SPD),
);
globalScene.phaseQueue.forEach((phase: PostSummonPhase) => {
phase.ordered = true;
const phasePokemon = phase.getPokemon();
if (phasePokemon.hasPriorityAbility()) {
globalScene.unshiftPhase(new PriorityAbilityActivationPhase(this.getPokemon().getBattlerIndex()));
}
});
this.orderPostSummonPhases();
this.end();
return;
}
if (!this.ordered) {
applyPriorityBasedAbAttrs(pokemon, true);
applyPriorityBasedAbAttrs(pokemon, (p: number) => p > 0);
}
if (pokemon.status?.effect === StatusEffect.TOXIC) {
@ -61,8 +52,9 @@ export class PostSummonPhase extends PokemonPhase {
) {
pokemon.lapseTag(BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON);
}
applyPriorityBasedAbAttrs(pokemon, false);
if (!this.ordered) {
applyPriorityBasedAbAttrs(pokemon, (p: number) => p <= 0);
}
const field = pokemon.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
for (const p of field) {
applyAbAttrs(CommanderAbAttr, p, null, false);
@ -70,4 +62,35 @@ export class PostSummonPhase extends PokemonPhase {
this.end();
}
private orderPostSummonPhases() {
globalScene.phaseQueue.sort(
(phaseA: PostSummonPhase, phaseB: PostSummonPhase) =>
phaseB.getPokemon().getEffectiveStat(Stat.SPD) - phaseA.getPokemon().getEffectiveStat(Stat.SPD),
);
const positivePriorityPhases: PostSummonActivateAbilityPhase[] = [];
const zeroNegativePriorityPhases: PostSummonActivateAbilityPhase[] = [];
globalScene.phaseQueue.forEach((phase: PostSummonPhase) => {
phase.ordered = true;
const phasePokemon = phase.getPokemon();
for (const priority of phasePokemon.getAbilityPriorities()) {
(priority > 0 ? positivePriorityPhases : zeroNegativePriorityPhases).push(
new PostSummonActivateAbilityPhase(phasePokemon.getBattlerIndex(), priority),
);
}
});
for (const phaseList of [positivePriorityPhases, zeroNegativePriorityPhases]) {
phaseList.sort(
(phaseA: PostSummonActivateAbilityPhase, phaseB: PostSummonActivateAbilityPhase) =>
phaseB.getPriority() - phaseA.getPriority(),
);
}
globalScene.unshiftPhase(...positivePriorityPhases);
zeroNegativePriorityPhases.forEach(phase => globalScene.pushPhase(phase));
}
}

View File

@ -1,19 +1,31 @@
import type { BattlerIndex } from "#app/battle";
import { applyPriorityBasedAbAttrs } from "#app/data/ability";
import { PokemonPhase } from "#app/phases/pokemon-phase";
/**
* Phase to apply (post-summon) ability attributes for "priority" abilities
* Phase to apply (post-summon) ability attributes for abilities with nonzero priority
*
* Priority abilities activate before others and before hazards
*
* @see Example - {@link https://bulbapedia.bulbagarden.net/wiki/Neutralizing_Gas_(Ability) | Neutralizing Gas}
*/
export class PriorityAbilityActivationPhase extends PokemonPhase {
export class PostSummonActivateAbilityPhase extends PokemonPhase {
private priority: number;
constructor(battlerIndex: BattlerIndex, priority: number) {
super(battlerIndex);
this.priority = priority;
}
start() {
super.start();
applyPriorityBasedAbAttrs(this.getPokemon(), true);
applyPriorityBasedAbAttrs(this.getPokemon(), (p: number) => p === this.priority);
this.end();
}
public getPriority() {
return this.priority;
}
}