mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-03 23:12:20 +02:00
Add new priority queues
This commit is contained in:
parent
7c6189e812
commit
5f098545f5
@ -79,6 +79,7 @@ import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag";
|
||||
import { noAbilityTypeOverrideMoves } from "../moves/invalid-moves";
|
||||
import type { Localizable } from "#app/@types/locales";
|
||||
import { applyAbAttrs } from "./apply-ab-attrs";
|
||||
import { MovePriorityModifier } from "#enums/move-priority-modifier";
|
||||
|
||||
export class Ability implements Localizable {
|
||||
public id: AbilityId;
|
||||
@ -4978,6 +4979,31 @@ export class ChangeMovePriorityAbAttr extends AbAttr {
|
||||
}
|
||||
}
|
||||
|
||||
export class ChangeMovePriorityModifierAbAttr extends AbAttr {
|
||||
private newModifier: MovePriorityModifier;
|
||||
private moveFunc: (pokemon: Pokemon, move: Move) => boolean;
|
||||
|
||||
constructor(moveFunc: (pokemon: Pokemon, move: Move) => boolean, newModifier: MovePriorityModifier) {
|
||||
super(false);
|
||||
this.newModifier = newModifier;
|
||||
this.moveFunc = moveFunc;
|
||||
}
|
||||
|
||||
override canApply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, args: any[]): boolean {
|
||||
return this.moveFunc(pokemon, args[0] as Move);
|
||||
}
|
||||
|
||||
override apply(
|
||||
_pokemon: Pokemon,
|
||||
_passive: boolean,
|
||||
_simulated: boolean,
|
||||
_cancelled: BooleanHolder | null,
|
||||
args: any[],
|
||||
): void {
|
||||
(args[1] as NumberHolder).value = this.newModifier;
|
||||
}
|
||||
}
|
||||
|
||||
export class IgnoreContactAbAttr extends AbAttr {}
|
||||
|
||||
export class PreWeatherEffectAbAttr extends AbAttr {
|
||||
@ -7219,7 +7245,12 @@ export class BypassSpeedChanceAbAttr extends AbAttr {
|
||||
const move = turnCommand?.move?.move ? allMoves[turnCommand.move.move] : null;
|
||||
const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL;
|
||||
return (
|
||||
!simulated && !bypassSpeed.value && pokemon.randBattleSeedInt(100) < this.chance && isCommandFight && isDamageMove
|
||||
!simulated &&
|
||||
!bypassSpeed.value &&
|
||||
pokemon.randBattleSeedInt(100) < this.chance &&
|
||||
isCommandFight &&
|
||||
isDamageMove &&
|
||||
pokemon.canAddTag(BattlerTagType.BYPASS_SPEED)
|
||||
);
|
||||
}
|
||||
|
||||
@ -7228,17 +7259,16 @@ export class BypassSpeedChanceAbAttr extends AbAttr {
|
||||
* @param {Pokemon} _pokemon {@linkcode Pokemon} the Pokemon applying this ability
|
||||
* @param {boolean} _passive N/A
|
||||
* @param {BooleanHolder} _cancelled N/A
|
||||
* @param {any[]} args [0] {@linkcode BooleanHolder} set to true when the ability activated
|
||||
* @param {any[]} _args N/A
|
||||
*/
|
||||
override apply(
|
||||
_pokemon: Pokemon,
|
||||
pokemon: Pokemon,
|
||||
_passive: boolean,
|
||||
_simulated: boolean,
|
||||
_cancelled: BooleanHolder,
|
||||
args: any[],
|
||||
_args: any[],
|
||||
): void {
|
||||
const bypassSpeed = args[0] as BooleanHolder;
|
||||
bypassSpeed.value = true;
|
||||
pokemon.addTag(BattlerTagType.BYPASS_SPEED);
|
||||
}
|
||||
|
||||
getTriggerMessage(pokemon: Pokemon, _abilityName: string, ..._args: any[]): string {
|
||||
@ -7270,7 +7300,6 @@ export class PreventBypassSpeedChanceAbAttr extends AbAttr {
|
||||
|
||||
/**
|
||||
* @argument {boolean} bypassSpeed - determines if a Pokemon is able to bypass speed at the moment
|
||||
* @argument {boolean} canCheckHeldItems - determines if a Pokemon has access to Quick Claw's effects or not
|
||||
*/
|
||||
override apply(
|
||||
_pokemon: Pokemon,
|
||||
@ -7280,9 +7309,7 @@ export class PreventBypassSpeedChanceAbAttr extends AbAttr {
|
||||
args: any[],
|
||||
): void {
|
||||
const bypassSpeed = args[0] as BooleanHolder;
|
||||
const canCheckHeldItems = args[1] as BooleanHolder;
|
||||
bypassSpeed.value = false;
|
||||
canCheckHeldItems.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7814,6 +7841,7 @@ const AbilityAttrs = Object.freeze({
|
||||
BlockStatusDamageAbAttr,
|
||||
BlockOneHitKOAbAttr,
|
||||
ChangeMovePriorityAbAttr,
|
||||
ChangeMovePriorityModifierAbAttr,
|
||||
IgnoreContactAbAttr,
|
||||
PreWeatherEffectAbAttr,
|
||||
PreWeatherDamageAbAttr,
|
||||
@ -8230,7 +8258,7 @@ export function initAbilities() {
|
||||
.attr(AlwaysHitAbAttr)
|
||||
.attr(DoubleBattleChanceAbAttr),
|
||||
new Ability(AbilityId.STALL, 4)
|
||||
.attr(ChangeMovePriorityAbAttr, (_pokemon, _move: Move) => true, -0.2),
|
||||
.attr(ChangeMovePriorityModifierAbAttr, (_pokemon, _move: Move) => true, MovePriorityModifier.LAST_IN_BRACKET),
|
||||
new Ability(AbilityId.TECHNICIAN, 4)
|
||||
.attr(MovePowerBoostAbAttr, (user, target, move) => {
|
||||
const power = new NumberHolder(move.power);
|
||||
@ -8957,7 +8985,7 @@ export function initAbilities() {
|
||||
.attr(TypeImmunityHealAbAttr, PokemonType.GROUND)
|
||||
.ignorable(),
|
||||
new Ability(AbilityId.MYCELIUM_MIGHT, 9)
|
||||
.attr(ChangeMovePriorityAbAttr, (_pokemon, move) => move.category === MoveCategory.STATUS, -0.2)
|
||||
.attr(ChangeMovePriorityModifierAbAttr, (_pokemon, move) => move.category === MoveCategory.STATUS, MovePriorityModifier.LAST_IN_BRACKET)
|
||||
.attr(PreventBypassSpeedChanceAbAttr, (_pokemon, move) => move.category === MoveCategory.STATUS)
|
||||
.attr(MoveAbilityBypassAbAttr, (_pokemon, move: Move) => move.category === MoveCategory.STATUS),
|
||||
new Ability(AbilityId.MINDS_EYE, 9)
|
||||
|
@ -3421,6 +3421,23 @@ export class GrudgeTag extends BattlerTag {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag to allow the affected Pokemon's move to go first in its priority bracket.
|
||||
* Used for {@link https://bulbapedia.bulbagarden.net/wiki/Quick_Draw_(Ability) Quick Draw}
|
||||
* and {@link https://bulbapedia.bulbagarden.net/wiki/Quick_Claw Quick Claw}.
|
||||
*/
|
||||
export class BypassSpeedTag extends BattlerTag {
|
||||
constructor() {
|
||||
super(BattlerTagType.BYPASS_SPEED, BattlerTagLapseType.TURN_END, 1);
|
||||
}
|
||||
|
||||
override canAdd(pokemon: Pokemon): boolean {
|
||||
const cancelled = new BooleanHolder(false);
|
||||
applyAbAttrs("PreventBypassSpeedChanceAbAttr", pokemon, null, false, cancelled);
|
||||
return !cancelled.value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag used to heal the user of Psycho Shift of its status effect if Psycho Shift succeeds in transferring its status effect to the target Pokemon
|
||||
*/
|
||||
@ -3668,6 +3685,8 @@ export function getBattlerTag(
|
||||
return new PsychoShiftTag();
|
||||
case BattlerTagType.MAGIC_COAT:
|
||||
return new MagicCoatTag();
|
||||
case BattlerTagType.BYPASS_SPEED:
|
||||
return new BypassSpeedTag();
|
||||
case BattlerTagType.NONE:
|
||||
default:
|
||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||
|
@ -100,6 +100,7 @@ import { SelectBiomePhase } from "#app/phases/select-biome-phase";
|
||||
import { ChargingMove, MoveAttrMap, MoveAttrString, MoveKindString, MoveClassMap } from "#app/@types/move-types";
|
||||
import { applyMoveAttrs } from "./apply-attrs";
|
||||
import { frenzyMissFunc, getMoveTargets } from "./move-utils";
|
||||
import { MovePriorityModifier } from "#enums/move-priority-modifier";
|
||||
|
||||
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
||||
export type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean;
|
||||
@ -867,6 +868,13 @@ export default abstract class Move implements Localizable {
|
||||
return priority.value;
|
||||
}
|
||||
|
||||
getPriorityModifier(user: Pokemon, simulated = true): MovePriorityModifier {
|
||||
const modifierHolder = new NumberHolder(MovePriorityModifier.NORMAL);
|
||||
applyAbAttrs("ChangeMovePriorityModifierAbAttr", user, null, simulated, this, modifierHolder);
|
||||
modifierHolder.value = user.getTag(BattlerTagType.BYPASS_SPEED) ? MovePriorityModifier.FIRST_IN_BRACKET : modifierHolder.value;
|
||||
return modifierHolder.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the [Expected Power](https://en.wikipedia.org/wiki/Expected_value) per turn
|
||||
* of this move, taking into account multi hit moves, accuracy, and the number of turns it
|
||||
|
@ -1,97 +0,0 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import type { Phase } from "#app/phase";
|
||||
import { ActivatePriorityQueuePhase } from "#app/phases/activate-priority-queue-phase";
|
||||
import type { PostSummonPhase } from "#app/phases/post-summon-phase";
|
||||
import { PostSummonActivateAbilityPhase } from "#app/phases/post-summon-activate-ability-phase";
|
||||
import { Stat } from "#enums/stat";
|
||||
import { BooleanHolder } from "#app/utils/common";
|
||||
import { TrickRoomTag } from "#app/data/arena-tag";
|
||||
import { DynamicPhaseType } from "#enums/dynamic-phase-type";
|
||||
|
||||
/**
|
||||
* Stores a list of {@linkcode Phase}s
|
||||
*
|
||||
* Dynamically updates ordering to always pop the highest "priority", based on implementation of {@linkcode reorder}
|
||||
*/
|
||||
export abstract class PhasePriorityQueue {
|
||||
protected abstract queue: Phase[];
|
||||
|
||||
/**
|
||||
* Sorts the elements in the queue
|
||||
*/
|
||||
public abstract reorder(): void;
|
||||
|
||||
/**
|
||||
* Calls {@linkcode reorder} and shifts the queue
|
||||
* @returns The front element of the queue after sorting
|
||||
*/
|
||||
public pop(): Phase | undefined {
|
||||
this.reorder();
|
||||
return this.queue.shift();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a phase to the queue
|
||||
* @param phase The phase to add
|
||||
*/
|
||||
public push(phase: Phase): void {
|
||||
this.queue.push(phase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all phases from the queue
|
||||
*/
|
||||
public clear(): void {
|
||||
this.queue.splice(0, this.queue.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Priority Queue for {@linkcode PostSummonPhase} and {@linkcode PostSummonActivateAbilityPhase}
|
||||
*
|
||||
* Orders phases first by ability priority, then by the {@linkcode Pokemon}'s effective speed
|
||||
*/
|
||||
export class PostSummonPhasePriorityQueue extends PhasePriorityQueue {
|
||||
protected override queue: PostSummonPhase[] = [];
|
||||
|
||||
public override reorder(): void {
|
||||
this.queue.sort((phaseA: PostSummonPhase, phaseB: PostSummonPhase) => {
|
||||
if (phaseA.getPriority() === phaseB.getPriority()) {
|
||||
return (
|
||||
(phaseB.getPokemon().getEffectiveStat(Stat.SPD) - phaseA.getPokemon().getEffectiveStat(Stat.SPD)) *
|
||||
(isTrickRoom() ? -1 : 1)
|
||||
);
|
||||
}
|
||||
|
||||
return phaseB.getPriority() - phaseA.getPriority();
|
||||
});
|
||||
}
|
||||
|
||||
public override push(phase: PostSummonPhase): void {
|
||||
super.push(phase);
|
||||
this.queueAbilityPhase(phase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues all necessary {@linkcode PostSummonActivateAbilityPhase}s for each pushed {@linkcode PostSummonPhase}
|
||||
* @param phase The {@linkcode PostSummonPhase} that was pushed onto the queue
|
||||
*/
|
||||
private queueAbilityPhase(phase: PostSummonPhase): void {
|
||||
const phasePokemon = phase.getPokemon();
|
||||
|
||||
phasePokemon.getAbilityPriorities().forEach((priority, idx) => {
|
||||
this.queue.push(new PostSummonActivateAbilityPhase(phasePokemon.getBattlerIndex(), priority, !!idx));
|
||||
globalScene.phaseManager.appendToPhase(
|
||||
new ActivatePriorityQueuePhase(DynamicPhaseType.POST_SUMMON),
|
||||
"ActivatePriorityQueuePhase",
|
||||
(p: ActivatePriorityQueuePhase) => p.getType() === DynamicPhaseType.POST_SUMMON,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function isTrickRoom(): boolean {
|
||||
const speedReversed = new BooleanHolder(false);
|
||||
globalScene.arena.applyTags(TrickRoomTag, false, speedReversed);
|
||||
return speedReversed.value;
|
||||
}
|
@ -95,4 +95,5 @@ export enum BattlerTagType {
|
||||
ENDURE_TOKEN = "ENDURE_TOKEN",
|
||||
POWDER = "POWDER",
|
||||
MAGIC_COAT = "MAGIC_COAT",
|
||||
BYPASS_SPEED = "BYPASS_SPEED"
|
||||
}
|
||||
|
5
src/enums/move-priority-modifier.ts
Normal file
5
src/enums/move-priority-modifier.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export enum MovePriorityModifier {
|
||||
LAST_IN_BRACKET = 0,
|
||||
NORMAL,
|
||||
FIRST_IN_BRACKET,
|
||||
}
|
@ -12,7 +12,6 @@ import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import Overrides from "#app/overrides";
|
||||
import { LearnMoveType } from "#enums/learn-move-type";
|
||||
import type { VoucherType } from "#app/system/voucher";
|
||||
import { Command } from "#enums/command";
|
||||
import { addTextObject, TextStyle } from "#app/ui/text";
|
||||
import { BooleanHolder, hslToHex, isNullOrUndefined, NumberHolder, randSeedFloat, toDmgValue } from "#app/utils/common";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
@ -1588,30 +1587,16 @@ export class BypassSpeedChanceModifier extends PokemonHeldItemModifier {
|
||||
return new BypassSpeedChanceModifier(this.type, this.pokemonId, this.stackCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if {@linkcode BypassSpeedChanceModifier} should be applied
|
||||
* @param pokemon the {@linkcode Pokemon} that holds the item
|
||||
* @param doBypassSpeed {@linkcode BooleanHolder} that is `true` if speed should be bypassed
|
||||
* @returns `true` if {@linkcode BypassSpeedChanceModifier} should be applied
|
||||
*/
|
||||
override shouldApply(pokemon?: Pokemon, doBypassSpeed?: BooleanHolder): boolean {
|
||||
return super.shouldApply(pokemon, doBypassSpeed) && !!doBypassSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies {@linkcode BypassSpeedChanceModifier}
|
||||
* @param pokemon the {@linkcode Pokemon} that holds the item
|
||||
* @param doBypassSpeed {@linkcode BooleanHolder} that is `true` if speed should be bypassed
|
||||
* @returns `true` if {@linkcode BypassSpeedChanceModifier} has been applied
|
||||
*/
|
||||
override apply(pokemon: Pokemon, doBypassSpeed: BooleanHolder): boolean {
|
||||
if (!doBypassSpeed.value && pokemon.randBattleSeedInt(10) < this.getStackCount()) {
|
||||
doBypassSpeed.value = true;
|
||||
const isCommandFight =
|
||||
globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()]?.command === Command.FIGHT;
|
||||
override apply(pokemon: Pokemon): boolean {
|
||||
if (pokemon.randBattleSeedInt(10) < this.getStackCount() && pokemon.addTag(BattlerTagType.BYPASS_SPEED)) {
|
||||
const hasQuickClaw = this.type.is("PokemonHeldItemModifierType") && this.type.id === "QUICK_CLAW";
|
||||
|
||||
if (isCommandFight && hasQuickClaw) {
|
||||
if (hasQuickClaw) {
|
||||
globalScene.phaseManager.queueMessage(
|
||||
i18next.t("modifier:bypassSpeedChanceApply", {
|
||||
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||
|
28
src/queues/move-phase-priority-queue.ts
Normal file
28
src/queues/move-phase-priority-queue.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import type { MovePhase } from "#app/phases/move-phase";
|
||||
import { PokemonPhasePriorityQueue } from "#app/queues/pokemon-phase-priority-queue";
|
||||
|
||||
export class MovePhasePriorityQueue extends PokemonPhasePriorityQueue<MovePhase> {
|
||||
public override reorder(): void {
|
||||
super.reorder();
|
||||
this.sortPostSpeed();
|
||||
}
|
||||
|
||||
private sortPostSpeed(): void {
|
||||
this.queue.sort((a: MovePhase, b: MovePhase) => {
|
||||
const priority = [a, b].map(movePhase => {
|
||||
const move = movePhase.move.getMove();
|
||||
return move.getPriority(movePhase.pokemon, true);
|
||||
});
|
||||
|
||||
const priorityModifiers = [a, b].map(movePhase =>
|
||||
movePhase.move.getMove().getPriorityModifier(movePhase.pokemon),
|
||||
);
|
||||
|
||||
if (priority[0] === priority[1] && priorityModifiers[0] !== priorityModifiers[1]) {
|
||||
return priorityModifiers[0] - priorityModifiers[1];
|
||||
}
|
||||
|
||||
return priority[0] - priority[1];
|
||||
});
|
||||
}
|
||||
}
|
43
src/queues/phase-priority-queue.ts
Normal file
43
src/queues/phase-priority-queue.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import type { Phase } from "#app/phase";
|
||||
|
||||
/**
|
||||
* Stores a list of {@linkcode Phase}s
|
||||
*
|
||||
* Dynamically updates ordering to always pop the highest "priority", based on implementation of {@linkcode reorder}
|
||||
*/
|
||||
export abstract class PhasePriorityQueue<T extends Phase> {
|
||||
protected queue: T[] = [];
|
||||
|
||||
/**
|
||||
* Sorts the elements in the queue
|
||||
*/
|
||||
public abstract reorder(): void;
|
||||
|
||||
/**
|
||||
* Calls {@linkcode reorder} and shifts the queue
|
||||
* @returns The front element of the queue after sorting
|
||||
*/
|
||||
public pop(): T | undefined {
|
||||
this.reorder();
|
||||
return this.queue.shift();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a phase to the queue
|
||||
* @param phase The phase to add
|
||||
*/
|
||||
public push(phase: T): void {
|
||||
this.queue.push(phase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all phases from the queue
|
||||
*/
|
||||
public clear(): void {
|
||||
this.queue.splice(0, this.queue.length);
|
||||
}
|
||||
|
||||
public isEmpty(): boolean {
|
||||
return !this.queue.length;
|
||||
}
|
||||
}
|
10
src/queues/pokemon-phase-priority-queue.ts
Normal file
10
src/queues/pokemon-phase-priority-queue.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import type { PartyMemberPokemonPhase } from "#app/phases/party-member-pokemon-phase";
|
||||
import type { PokemonPhase } from "#app/phases/pokemon-phase";
|
||||
import { PhasePriorityQueue } from "#app/queues/phase-priority-queue";
|
||||
import { sortInSpeedOrder } from "#app/utils/speed-order";
|
||||
|
||||
export class PokemonPhasePriorityQueue<T extends PokemonPhase | PartyMemberPokemonPhase> extends PhasePriorityQueue<T> {
|
||||
public override reorder(): void {
|
||||
this.queue = sortInSpeedOrder(this.queue);
|
||||
}
|
||||
}
|
42
src/queues/post-summon-phase-priority-queue.ts
Normal file
42
src/queues/post-summon-phase-priority-queue.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { ActivatePriorityQueuePhase } from "#app/phases/activate-priority-queue-phase";
|
||||
import { PostSummonActivateAbilityPhase } from "#app/phases/post-summon-activate-ability-phase";
|
||||
import type { PostSummonPhase } from "#app/phases/post-summon-phase";
|
||||
import { PokemonPhasePriorityQueue } from "#app/queues/pokemon-phase-priority-queue";
|
||||
|
||||
/**
|
||||
* Priority Queue for {@linkcode PostSummonPhase} and {@linkcode PostSummonActivateAbilityPhase}
|
||||
*
|
||||
* Orders phases first by ability priority, then by the {@linkcode Pokemon}'s effective speed
|
||||
*/
|
||||
|
||||
export class PostSummonPhasePriorityQueue extends PokemonPhasePriorityQueue<PostSummonPhase> {
|
||||
public override reorder(): void {
|
||||
super.reorder();
|
||||
this.queue.sort((phaseA: PostSummonPhase, phaseB: PostSummonPhase) => {
|
||||
return phaseB.getPriority() - phaseA.getPriority();
|
||||
});
|
||||
}
|
||||
|
||||
public override push(phase: PostSummonPhase): void {
|
||||
super.push(phase);
|
||||
this.queueAbilityPhase(phase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues all necessary {@linkcode PostSummonActivateAbilityPhase}s for each pushed {@linkcode PostSummonPhase}
|
||||
* @param phase The {@linkcode PostSummonPhase} that was pushed onto the queue
|
||||
*/
|
||||
private queueAbilityPhase(phase: PostSummonPhase): void {
|
||||
const phasePokemon = phase.getPokemon();
|
||||
|
||||
phasePokemon.getAbilityPriorities().forEach((priority, idx) => {
|
||||
this.queue.push(new PostSummonActivateAbilityPhase(phasePokemon.getBattlerIndex(), priority, !!idx));
|
||||
globalScene.phaseManager.appendToPhase(
|
||||
new ActivatePriorityQueuePhase("PostSummonPhase"),
|
||||
"ActivatePriorityQueuePhase",
|
||||
(p: ActivatePriorityQueuePhase) => p.getType() === "PostSummonPhase",
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
46
src/utils/speed-order.ts
Normal file
46
src/utils/speed-order.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import Pokemon from "#app/field/pokemon";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { BooleanHolder, randSeedShuffle } from "#app/utils/common";
|
||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||
import { Stat } from "#enums/stat";
|
||||
|
||||
export interface hasPokemon {
|
||||
getPokemon(): Pokemon;
|
||||
}
|
||||
|
||||
export function sortInSpeedOrder<T extends Pokemon | hasPokemon>(pokemonList: T[]): T[] {
|
||||
pokemonList = shuffle(pokemonList);
|
||||
sortBySpeed(pokemonList);
|
||||
return pokemonList;
|
||||
}
|
||||
|
||||
/** Randomly shuffles the queue. */
|
||||
function shuffle<T extends Pokemon | hasPokemon>(pokemonList: T[]): T[] {
|
||||
// This is seeded with the current turn to prevent an inconsistency where it
|
||||
// was varying based on how long since you last reloaded
|
||||
globalScene.executeWithSeedOffset(
|
||||
() => {
|
||||
pokemonList = randSeedShuffle(pokemonList);
|
||||
},
|
||||
globalScene.currentBattle.turn * 1000 + pokemonList.length,
|
||||
globalScene.waveSeed,
|
||||
);
|
||||
return pokemonList;
|
||||
}
|
||||
|
||||
function sortBySpeed<T extends Pokemon | hasPokemon>(pokemonList: T[]): void {
|
||||
pokemonList.sort((a, b) => {
|
||||
const [aSpeed, bSpeed] = [a, b].map(pkmn =>
|
||||
pkmn instanceof Pokemon ? pkmn.getEffectiveStat(Stat.SPD) : pkmn.getPokemon().getEffectiveStat(Stat.SPD),
|
||||
);
|
||||
return bSpeed - aSpeed;
|
||||
});
|
||||
|
||||
/** 'true' if Trick Room is on the field. */
|
||||
const speedReversed = new BooleanHolder(false);
|
||||
globalScene.arena.applyTags(ArenaTagType.TRICK_ROOM, false, speedReversed);
|
||||
|
||||
if (speedReversed.value) {
|
||||
pokemonList.reverse();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user