diff --git a/sim/battle-actions.ts b/sim/battle-actions.ts index 6b25f6a32e1c..c2c8d9fe101b 100644 --- a/sim/battle-actions.ts +++ b/sim/battle-actions.ts @@ -169,38 +169,43 @@ export class BattleActions { return true; } runSwitch(pokemon: Pokemon) { - if (this.battle.gen >= 5) { + const battle = this.battle; + if (battle.gen >= 5) { const switchersIn = [pokemon]; - for (let a = this.battle.queue.peek(); a?.choice === 'runSwitch'; a = this.battle.queue.peek()) { - const nextSwitch = this.battle.queue.shift(); + for (let a = battle.queue.peek(); a?.choice === 'runSwitch'; a = battle.queue.peek()) { + const nextSwitch = battle.queue.shift(); switchersIn.push(nextSwitch!.pokemon!); } - this.battle.prng.shuffle(this.battle.speedTieResolution); - this.battle.fieldEvent('SwitchIn', switchersIn); + const allActive = battle.getAllActive(true); + battle.speedSort(allActive); + battle.speedOrder = allActive.map((a) => a.side.n * battle.sides.length + a.position); + battle.fieldEvent('SwitchIn', switchersIn); - if (!pokemon.hp) return false; - pokemon.isStarted = true; - pokemon.draggedIn = null; + for (const poke of allActive) { + if (!poke.hp) continue; + poke.isStarted = true; + poke.draggedIn = null; + } return true; } - this.battle.runEvent('EntryHazard', pokemon); + battle.runEvent('EntryHazard', pokemon); - this.battle.runEvent('SwitchIn', pokemon); + battle.runEvent('SwitchIn', pokemon); - if (this.battle.gen <= 2) { + if (battle.gen <= 2) { // pokemon.lastMove is reset for all Pokemon on the field after a switch. This affects Mirror Move. - for (const poke of this.battle.getAllActive()) poke.lastMove = null; - if (!pokemon.side.faintedThisTurn && pokemon.draggedIn !== this.battle.turn) { - this.battle.runEvent('AfterSwitchInSelf', pokemon); + for (const poke of battle.getAllActive()) poke.lastMove = null; + if (!pokemon.side.faintedThisTurn && pokemon.draggedIn !== battle.turn) { + battle.runEvent('AfterSwitchInSelf', pokemon); } } if (!pokemon.hp) return false; pokemon.isStarted = true; if (!pokemon.fainted) { - this.battle.singleEvent('Start', pokemon.getAbility(), pokemon.abilityState, pokemon); - this.battle.singleEvent('Start', pokemon.getItem(), pokemon.itemState, pokemon); + battle.singleEvent('Start', pokemon.getAbility(), pokemon.abilityState, pokemon); + battle.singleEvent('Start', pokemon.getItem(), pokemon.itemState, pokemon); } - if (this.battle.gen === 4) { + if (battle.gen === 4) { for (const foeActive of pokemon.foes()) { foeActive.removeVolatile('substitutebroken'); } diff --git a/sim/battle.ts b/sim/battle.ts index 19cda7e045db..a69a480ca424 100644 --- a/sim/battle.ts +++ b/sim/battle.ts @@ -174,7 +174,7 @@ export class Battle { lastDamage: number; effectOrder: number; quickClawRoll: boolean; - speedTieResolution: number[]; + speedOrder: number[]; teamGenerator: ReturnType | null; @@ -262,9 +262,9 @@ export class Battle { this.lastDamage = 0; this.effectOrder = 0; this.quickClawRoll = false; - this.speedTieResolution = []; + this.speedOrder = []; for (let i = 0; i < this.activePerHalf * 2; i++) { - this.speedTieResolution.push(i / (this.activePerHalf * 2)); + this.speedOrder.push(i); } this.teamGenerator = null; @@ -954,14 +954,14 @@ export class Battle { } } if (handler.effectHolder && (handler.effectHolder as Pokemon).getStat) { - handler.speed = (handler.effectHolder as Pokemon).speed; + const pokemon = (handler.effectHolder as Pokemon); + handler.speed = pokemon.speed; if (callbackName.endsWith('SwitchIn')) { // Pokemon speeds including ties are resolved before all onSwitchIn handlers and aren't re-sorted in-between - // so we add a fractional speed to each Pokemon's respective event handlers by using their unique field position - // to index a randomly shuffled array of sequential numbers - const allSlots = 'abcdef'; - const speedTieIndex = allSlots.indexOf((handler.effectHolder as Pokemon).getSlot().charAt(2)); - handler.speed += this.speedTieResolution[speedTieIndex]; + // so we subtract a fractional speed to each Pokemon's respective event handlers by using the index of their + // unique field position in a pre-sorted-by-speed array + const fieldPositionValue = pokemon.side.n * this.sides.length + pokemon.position; + handler.speed -= this.speedOrder.indexOf(fieldPositionValue) / (this.activePerHalf * 2); } } return handler; @@ -1248,11 +1248,11 @@ export class Battle { return pokemonList; } - getAllActive() { + getAllActive(includeFainted?: boolean) { const pokemonList: Pokemon[] = []; for (const side of this.sides) { for (const pokemon of side.active) { - if (pokemon && !pokemon.fainted) { + if (pokemon && (includeFainted || !pokemon.fainted)) { pokemonList.push(pokemon); } } diff --git a/test/sim/abilities/pastelveil.js b/test/sim/abilities/pastelveil.js index d685f755618c..841010cc3285 100644 --- a/test/sim/abilities/pastelveil.js +++ b/test/sim/abilities/pastelveil.js @@ -29,7 +29,7 @@ describe('Pastel Veil', function () { {species: 'wynaut', moves: ['sleeptalk']}, {species: 'wynaut', moves: ['sleeptalk']}, ], [ - {species: 'croagunk', moves: ['skillswap', 'sleeptalk']}, + {species: 'croagunk', moves: ['sleeptalk', 'skillswap']}, {species: 'wynaut', ability: 'compoundeyes', moves: ['poisongas']}, ]]); battle.makeChoices('auto', 'move skillswap 1, move poisongas');