diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 8c078dce67c..042b29cc72e 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -19,8 +19,6 @@ import { CopyMoveAttr, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr, - type MoveAttr, - ForceSwitchOutAttr, } from "#app/data/moves/move"; import { allMoves } from "../data-lists"; import { ArenaTagSide } from "#app/data/arena-tag"; @@ -69,7 +67,7 @@ import { BerryUsedEvent } from "#app/events/battle-scene"; // Type imports -import { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; +import { PokemonMove } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import type { Weather } from "#app/data/weather"; import type { BattlerTag } from "#app/data/battler-tags"; @@ -1302,6 +1300,7 @@ export class PokemonTypeChangeAbAttr extends PreAttackAbAttr { if (!pokemon.isTerastallized && move.id !== Moves.STRUGGLE && /** + * Skip moves that call other moves because these moves generate a following move that will trigger this ability attribute * @see {@link https://bulbapedia.bulbagarden.net/wiki/Category:Moves_that_call_other_moves} */ !move.findAttr((attr) => @@ -5630,19 +5629,19 @@ export class PostDamageForceSwitchAbAttr extends ForceSwitch(PostDamageAbAttr) { const currentPhase = globalScene.getCurrentPhase() as MoveEffectPhase; const currentMove = currentPhase.move; - // will not activate from self-induced HP cutting... + // will not activate from self-induced HP cutting, // TODO: Verify that Fillet Away and Clangorous Soul proc wimp out const hpCutMoves = new Set([ Moves.CURSE, Moves.BELLY_DRUM, Moves.SUBSTITUTE, Moves.PAIN_SPLIT, Moves.CLANGOROUS_SOUL, Moves.FILLET_AWAY]); // NB: Given this attribute is only applied after _taking damage_ or recieving a damaging attack, - // a failed Substitute or non-ghost type Curse will not trigger this ability to begin with. + // a failed Substitute or non-Ghost type Curse will not trigger this code. const notHpCut = !hpCutMoves.has(currentMove.id) - // will not activate for forced switch moves (which trigger before wimp out activates)... + // will not activate for forced switch moves (which trigger before wimp out activates), const notForceSwitched = ![Moves.DRAGON_TAIL, Moves.CIRCLE_THROW].includes(currentMove.id) // and will not activate if the Pokemon is currently in the air from Sky Drop. - // TODO: Make this check the user's tags once Sky Drop is fully implemented - - // we could be sky dropped by another Pokemon or take indirect damage while skybound (both of which render this check moot) + // TODO: Make this check the user's tags and move to main `canApply` block once Sky Drop is fully implemented - + // we could be sky dropped by another Pokemon or take indirect damage while skybound (both of which render this check useless) const lastMove = source?.getLastXMoves()[0] const notSkyDropped = !(lastMove?.move === Moves.SKY_DROP && lastMove.result === MoveResult.OTHER) @@ -5655,7 +5654,7 @@ export class PostDamageForceSwitchAbAttr extends ForceSwitch(PostDamageAbAttr) { * or is still above it after the hit. * @param pokemon - The {@linkcode Pokemon} with this ability * @param damage - The amount of damage taken. - * @returns `true` if this Pokemon was knocked below half after `damage` was applied + * @returns Whether the Pokemon was knocked below half after `damage` was applied */ private wasKnockedBelowHalf(pokemon: Pokemon, damage: number) { // NB: This occurs in `MoveEffectPhase` _after_ attack damage has been dealt, @@ -5669,7 +5668,7 @@ export class PostDamageForceSwitchAbAttr extends ForceSwitch(PostDamageAbAttr) { * * @param pokemon The Pokémon that took damage. */ - public override applyPostDamage(pokemon: Pokemon, _damage: number, _simulated: boolean, _source: Pokemon | undefined, args: any[]): void { + public override applyPostDamage(pokemon: Pokemon): void { this.doSwitch(pokemon); } } diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 5e066ffd434..f48e02e281f 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -752,7 +752,7 @@ export class ConfusedTag extends BattlerTag { } /** - * Tick down this Pokemon's confusion duration, randomly interrupting its move if not cured/ + * Tick down this Pokemon's confusion duration, randomly interrupting its move if not cured. * @param pokemon - The {@linkcode Pokemon} with this tag * @param lapseType - The {@linkcode BattlerTagLapseType | lapse type} triggering this tag's effects. * @returns Whether the tag should be kept. @@ -774,7 +774,7 @@ export class ConfusedTag extends BattlerTag { // 1/3 chance of hitting self with a 40 base power move const shouldInterruptMove = Overrides.CONFUSION_ACTIVATION_OVERRIDE ?? pokemon.randBattleSeedInt(3) === 0; if (shouldInterruptMove) { - // TODO: Are these calculations correct? We really shouldn't hardcode the damage formula here... + // TODO: Are these calculations correct? We probably shouldn't hardcode the damage formula here... const atk = pokemon.getEffectiveStat(Stat.ATK); const def = pokemon.getEffectiveStat(Stat.DEF); const damage = toDmgValue( diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 6ea9762a933..d91673222ca 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -6925,15 +6925,15 @@ export class PokemonTurnData { public hitsLeft = -1; /** * The final amount of damage dealt by this Pokemon's last attack against each of its targets, - * mapped by their respective `BattlerIndex`es. + * indexed by their respective `BattlerIndex`es. * Reset to an empty array upon attempting to use a move, * and is used to calculate various damage-related effects (Shell Bell, U-Turn + Wimp Out interactions, etc.). */ + // TODO: move this or something like it to some sort of "move in flight" object public lastMoveDamageDealt: number[] = []; /** * The amount of damage dealt by this Pokemon's last hit. * Used to calculate recoil damage amounts. - * TODO: Merge with `lastMoveDamageDealt` if any spread recoil moves are added */ public singleHitDamageDealt = 0; // TODO: Make this into a "damage taken last" counter for metal burst and co. diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts index 2bcbaaf717e..91ef134d751 100644 --- a/src/phases/faint-phase.ts +++ b/src/phases/faint-phase.ts @@ -30,9 +30,9 @@ import { SwitchPhase } from "./switch-phase"; import { SwitchSummonPhase } from "./switch-summon-phase"; import { ToggleDoublePositionPhase } from "./toggle-double-position-phase"; import { VictoryPhase } from "./victory-phase"; +import { isNullOrUndefined } from "#app/utils/common"; import { FRIENDSHIP_LOSS_FROM_FAINT } from "#app/data/balance/starters"; import { BattlerTagType } from "#enums/battler-tag-type"; -import { isNullOrUndefined } from "#app/utils/common"; export class FaintPhase extends PokemonPhase { /** @@ -170,7 +170,7 @@ export class FaintPhase extends PokemonPhase { */ globalScene.unshiftPhase(new ToggleDoublePositionPhase(true)); } else { - // If previous conditions weren't met, push a phase to prompt the player to select a pokemon from their party. + // If previous conditions weren't met, push a phase to prompt the player to select a new pokemon from their party. globalScene.pushPhase(new SwitchPhase(SwitchType.SWITCH, this.fieldIndex, true, false)); } } else { diff --git a/test/abilities/arena_trap.test.ts b/test/abilities/arena_trap.test.ts index 9a27af3bde9..746e8c7eed0 100644 --- a/test/abilities/arena_trap.test.ts +++ b/test/abilities/arena_trap.test.ts @@ -43,6 +43,8 @@ describe("Abilities - Arena Trap", () => { const enemy = game.scene.getEnemyPokemon()!; + // flee stuff goes here + game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { // no switch out command should be queued due to arena trap expect(game.scene.currentBattle.turnCommands[0]).toBeNull(); @@ -59,14 +61,6 @@ describe("Abilities - Arena Trap", () => { abilityName: allAbilities[Abilities.ARENA_TRAP].name, }), ); - - game.override.ability(Abilities.RUN_AWAY); - - // do switch stuff - - await game.toNextTurn(); - - expect(game.scene.currentBattle.waveIndex).toBe(2); }); it("should interrupt player switch attempt and display message", async () => { diff --git a/test/abilities/disguise.test.ts b/test/abilities/disguise.test.ts index 0e62b8ad448..c25966a9ee8 100644 --- a/test/abilities/disguise.test.ts +++ b/test/abilities/disguise.test.ts @@ -47,7 +47,7 @@ describe("Abilities - Disguise", () => { await game.phaseInterceptor.to("MoveEndPhase"); - expect(mimikyu.hp).equals(maxHp - disguiseDamage); + expect(mimikyu.hp).toBe(maxHp - disguiseDamage); expect(mimikyu.formIndex).toBe(bustedForm); }); @@ -80,12 +80,12 @@ describe("Abilities - Disguise", () => { // First hit await game.phaseInterceptor.to("MoveEffectPhase"); - expect(mimikyu.hp).equals(maxHp - disguiseDamage); + expect(mimikyu.hp).toBe(maxHp - disguiseDamage); expect(mimikyu.formIndex).toBe(disguisedForm); // Second hit await game.phaseInterceptor.to("MoveEffectPhase"); - expect(mimikyu.hp).lessThan(maxHp - disguiseDamage); + expect(mimikyu.hp).toBeLessThan(maxHp - disguiseDamage); expect(mimikyu.formIndex).toBe(bustedForm); }); @@ -120,7 +120,7 @@ describe("Abilities - Disguise", () => { await game.phaseInterceptor.to("TurnEndPhase"); expect(mimikyu.formIndex).toBe(bustedForm); - expect(mimikyu.hp).equals(maxHp - disguiseDamage); + expect(mimikyu.hp).toBe(maxHp - disguiseDamage); await game.toNextTurn(); game.doSwitchPokemon(1); @@ -186,7 +186,7 @@ describe("Abilities - Disguise", () => { await game.toNextTurn(); game.move.select(Moves.SPLASH); await game.doKillOpponents(); - await game.phaseInterceptor.to("QuietFormChangePhase"); + await game.phaseInterceptor.to("ReturnPhase"); expect(mimikyu1.formIndex).toBe(disguisedForm); });