Add quick draw application

This commit is contained in:
Dean 2025-06-15 13:58:43 -07:00
parent d8fb44240f
commit 2b6c918fb9
3 changed files with 33 additions and 44 deletions

View File

@ -7238,17 +7238,13 @@ export class BypassSpeedChanceAbAttr extends AbAttr {
this.chance = chance; this.chance = chance;
} }
override canApply(pokemon: Pokemon, _passive: boolean, simulated: boolean, args: any[]): boolean { override canApply(pokemon: Pokemon, _passive: boolean, simulated: boolean, _args: any[]): boolean {
const bypassSpeed = args[0] as BooleanHolder;
const turnCommand = globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()]; const turnCommand = globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
const isCommandFight = turnCommand?.command === Command.FIGHT;
const move = turnCommand?.move?.move ? allMoves[turnCommand.move.move] : null; const move = turnCommand?.move?.move ? allMoves[turnCommand.move.move] : null;
const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL; const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL;
return ( return (
!simulated && !simulated &&
!bypassSpeed.value &&
pokemon.randBattleSeedInt(100) < this.chance && pokemon.randBattleSeedInt(100) < this.chance &&
isCommandFight &&
isDamageMove && isDamageMove &&
pokemon.canAddTag(BattlerTagType.BYPASS_SPEED) pokemon.canAddTag(BattlerTagType.BYPASS_SPEED)
); );

View File

@ -8,6 +8,7 @@ import { SwitchType } from "#enums/switch-type";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { applyInSpeedOrder } from "#app/utils/speed-order"; import { applyInSpeedOrder } from "#app/utils/speed-order";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
export class TurnStartPhase extends FieldPhase { export class TurnStartPhase extends FieldPhase {
public readonly phaseName = "TurnStartPhase"; public readonly phaseName = "TurnStartPhase";
@ -53,27 +54,26 @@ export class TurnStartPhase extends FieldPhase {
super.start(); super.start();
const field = globalScene.getField(); const field = globalScene.getField();
const activeField = globalScene.getField(true);
const moveOrder = this.getCommandOrder(); const moveOrder = this.getCommandOrder();
let orderIndex = 0; let orderIndex = 0;
applyInSpeedOrder( applyInSpeedOrder(activeField, (p: Pokemon) => {
field.filter(p => p?.isActive(true)), const preTurnCommand = globalScene.currentBattle.preTurnCommands[p.getBattlerIndex()];
(p: Pokemon) => {
const preTurnCommand = globalScene.currentBattle.preTurnCommands[p.getBattlerIndex()];
if (preTurnCommand?.skip) { if (preTurnCommand?.skip) {
return; return;
} }
switch (preTurnCommand?.command) { switch (preTurnCommand?.command) {
case Command.TERA: case Command.TERA:
globalScene.phaseManager.pushNew("TeraPhase", p); globalScene.phaseManager.pushNew("TeraPhase", p);
} }
}, });
);
const phaseManager = globalScene.phaseManager; const phaseManager = globalScene.phaseManager;
applyInSpeedOrder(activeField, (p: Pokemon) => applyAbAttrs("BypassSpeedChanceAbAttr", p, null));
for (const o of moveOrder) { for (const o of moveOrder) {
const pokemon = field[o]; const pokemon = field[o];

View File

@ -5,7 +5,7 @@ import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
describe("Abilities - Quick Draw", () => { describe("Abilities - Quick Draw", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -25,7 +25,6 @@ describe("Abilities - Quick Draw", () => {
game = new GameManager(phaserGame); game = new GameManager(phaserGame);
game.override.battleStyle("single"); game.override.battleStyle("single");
game.override.starterSpecies(SpeciesId.MAGIKARP);
game.override.ability(AbilityId.QUICK_DRAW); game.override.ability(AbilityId.QUICK_DRAW);
game.override.moveset([MoveId.TACKLE, MoveId.TAIL_WHIP]); game.override.moveset([MoveId.TACKLE, MoveId.TAIL_WHIP]);
@ -41,8 +40,8 @@ describe("Abilities - Quick Draw", () => {
).mockReturnValue(100); ).mockReturnValue(100);
}); });
test("makes pokemon going first in its priority bracket", async () => { it("makes pokemon go first in its priority bracket", async () => {
await game.classicMode.startBattle(); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const pokemon = game.scene.getPlayerPokemon()!; const pokemon = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
@ -56,35 +55,29 @@ describe("Abilities - Quick Draw", () => {
expect(pokemon.isFainted()).toBe(false); expect(pokemon.isFainted()).toBe(false);
expect(enemy.isFainted()).toBe(true); expect(enemy.isFainted()).toBe(true);
expect(pokemon.waveData.abilitiesApplied).contain(AbilityId.QUICK_DRAW); expect(pokemon.waveData.abilitiesApplied).contain(AbilityId.QUICK_DRAW);
}, 20000); });
test( it("is not triggered by non damaging moves", async () => {
"does not triggered by non damage moves", await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
{
retry: 5,
},
async () => {
await game.classicMode.startBattle();
const pokemon = game.scene.getPlayerPokemon()!; const pokemon = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
pokemon.hp = 1; pokemon.hp = 1;
enemy.hp = 1; enemy.hp = 1;
game.move.select(MoveId.TAIL_WHIP); game.move.select(MoveId.TAIL_WHIP);
await game.phaseInterceptor.to(FaintPhase, false); await game.phaseInterceptor.to(FaintPhase, false);
expect(pokemon.isFainted()).toBe(true); expect(pokemon.isFainted()).toBe(true);
expect(enemy.isFainted()).toBe(false); expect(enemy.isFainted()).toBe(false);
expect(pokemon.waveData.abilitiesApplied).not.contain(AbilityId.QUICK_DRAW); expect(pokemon.waveData.abilitiesApplied).not.contain(AbilityId.QUICK_DRAW);
}, });
);
test("does not increase priority", async () => { it("does not increase priority", async () => {
game.override.enemyMoveset([MoveId.EXTREME_SPEED]); game.override.enemyMoveset([MoveId.EXTREME_SPEED]);
await game.classicMode.startBattle(); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
const pokemon = game.scene.getPlayerPokemon()!; const pokemon = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
@ -98,5 +91,5 @@ describe("Abilities - Quick Draw", () => {
expect(pokemon.isFainted()).toBe(true); expect(pokemon.isFainted()).toBe(true);
expect(enemy.isFainted()).toBe(false); expect(enemy.isFainted()).toBe(false);
expect(pokemon.waveData.abilitiesApplied).contain(AbilityId.QUICK_DRAW); expect(pokemon.waveData.abilitiesApplied).contain(AbilityId.QUICK_DRAW);
}, 20000); });
}); });