diff --git a/src/data/moves/move-condition.ts b/src/data/moves/move-condition.ts index e6db80277d7..37ac36b0e42 100644 --- a/src/data/moves/move-condition.ts +++ b/src/data/moves/move-condition.ts @@ -156,7 +156,7 @@ export const failAgainstFinalBossCondition = new MoveCondition((_user, target) = * a high-priority attack (after factoring in priority-boosting effects) and * hasn't moved yet this turn. */ -export const UpperHandCondition = new MoveCondition((_user, target) => { +export const upperHandCondition = new MoveCondition((_user, target) => { const targetCommand = globalScene.currentBattle.turnCommands[target.getBattlerIndex()]; return ( targetCommand?.command === Command.FIGHT && @@ -252,13 +252,13 @@ export class MoveRestriction { * @remarks * Used by {@link https://bulbapedia.bulbagarden.net/wiki/Blood_Moon_(move) | Blood Moon} and {@link https://bulbapedia.bulbagarden.net/wiki/Gigaton_Hammer_(move) | Gigaton Hammer} */ -export const ConsecutiveUseRestriction = new MoveRestriction( +export const consecutiveUseRestriction = new MoveRestriction( (user, move) => user.getLastXMoves(1)[0]?.move === move.id, "battle:moveDisabledConsecutive", ); /** Prevents a move from being selected if Gravity is in effect */ -export const GravityUseRestriction = new MoveRestriction( +export const gravityUseRestriction = new MoveRestriction( () => globalScene.arena.hasTag(ArenaTagType.GRAVITY), "battle:moveDisabledGravity", ); diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 4be5c8a04f5..aa4ecf13c1e 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -82,7 +82,7 @@ import { } from "#modifiers/modifier"; import { applyMoveAttrs } from "#moves/apply-attrs"; import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSketchMoves, invalidSleepTalkMoves } from "#moves/invalid-moves"; -import { ConsecutiveUseRestriction, counterAttackConditionBoth, counterAttackConditionPhysical, counterAttackConditionSpecial, failAgainstFinalBossCondition, FailIfInsufficientHpCondition, failIfTargetNotAttackingCondition, failTeleportCondition, FirstMoveCondition, GravityUseRestriction, lastResortCondition, MoveCondition, MoveRestriction, UpperHandCondition } from "#moves/move-condition"; +import { consecutiveUseRestriction, counterAttackConditionBoth, counterAttackConditionPhysical, counterAttackConditionSpecial, failAgainstFinalBossCondition, FailIfInsufficientHpCondition, failIfTargetNotAttackingCondition, failTeleportCondition, FirstMoveCondition, gravityUseRestriction, lastResortCondition, MoveCondition, MoveRestriction, upperHandCondition } from "#moves/move-condition"; import { frenzyMissFunc, getCounterAttackTarget, getMoveTargets } from "#moves/move-utils"; import { PokemonMove } from "#moves/pokemon-move"; import { MovePhase } from "#phases/move-phase"; @@ -172,8 +172,14 @@ export abstract class Move implements Localizable { * @see {@link https://www.smogon.com/forums/threads/sword-shield-battle-mechanics-research.3655528/page-54#post-8548957} */ private conditionsSeq3: MoveCondition[] = []; +<<<<<<< HEAD /** Conditions that must be false for a move to be able to be selected. * +======= + /** + * Conditions that must be false for a move to be able to be selected. + * +>>>>>>> 02f941b3a05 (PR review changes) * @remarks Different from {@linkcode conditions}, which is checked when the move is invoked */ private restrictions: MoveRestriction[] = []; @@ -452,7 +458,7 @@ export abstract class Move implements Localizable { * @returns `this` for method chaining */ public restriction(restriction: MoveRestriction): this; - /** + /** * Adds a restriction condition to this move. * The move will not be selectable if at least 1 of its restrictions is met. * @param restriction - The function or `MoveRestriction` that evaluates to `true` if the move is restricted from @@ -476,7 +482,12 @@ export abstract class Move implements Localizable { * is false * @returns `this` for method chaining */ - public restriction(restriction: T, i18nkey?: string, alsoCondition: typeof restriction extends MoveRestriction ? false : boolean = false, conditionSeq = 4): this { + public restriction( + restriction: T, + i18nkey?: string, + alsoCondition: typeof restriction extends MoveRestriction ? false : boolean = false, + conditionSeq = 4, + ): this { if (typeof restriction === "function") { this.restrictions.push(new MoveRestriction(restriction)); if (alsoCondition) { @@ -700,7 +711,7 @@ export abstract class Move implements Localizable { } /** - * Sets the {@linkcode MoveFlags.GRAVITY} flag for the calling Move and adds {@linkcode GravityUseRestriction} to the + * Sets the {@linkcode MoveFlags.GRAVITY} flag for the calling Move and adds {@linkcode gravityUseRestriction} to the * move's restrictions. * * @returns `this` @@ -713,7 +724,7 @@ export abstract class Move implements Localizable { */ affectedByGravity(): this { this.setFlag(MoveFlags.GRAVITY, true); - this.restrictions.push(GravityUseRestriction); + this.restrictions.push(gravityUseRestriction); return this; } @@ -859,9 +870,9 @@ export abstract class Move implements Localizable { * * @param user - The Pokemon using the move * @returns - An array whose first element is `false` if the move is restricted, and the second element is a string - * with the reason for the restriction, otherwise, `false` and the empty string. + * with the reason for the restriction, otherwise, `true` and the empty string. */ - public checkRestrictions(user: Pokemon): [boolean, string] { + public checkRestrictions(user: Pokemon): [isUsable: boolean, restrictionMessage: string] { for (const restriction of this.restrictions) { if (restriction.apply(user, this)) { return [false, restriction.getSelectionDeniedText(user, this)]; @@ -10034,7 +10045,6 @@ export function initMoves() { .condition((_user, target, _move) => target.getTag(BattlerTagType.INGRAIN) == null && target.getTag(BattlerTagType.IGNORE_FLYING) == null) .attr(AddBattlerTagAttr, BattlerTagType.TELEKINESIS, false, true, 3) .attr(AddBattlerTagAttr, BattlerTagType.FLOATING, false, true, 3) - .affectedByGravity() .reflectable(), new StatusMove(MoveId.MAGIC_ROOM, PokemonType.PSYCHIC, -1, 10, -1, 0, 5) .ignoresProtect() @@ -10677,10 +10687,7 @@ export function initMoves() { .attr(HealOnAllyAttr, 0.5, true, false) .ballBombMove() // Fail if used against an ally that is affected by heal block, during the second failure check - .condition( - (user, target) => target.isOpponent(user) || !!target.getTag(BattlerTagType.HEAL_BLOCK), - 2 - ), + .condition((user, target) => target.isOpponent(user) || !!target.getTag(BattlerTagType.HEAL_BLOCK), 2), new AttackMove(MoveId.ANCHOR_SHOT, PokemonType.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, 100, 0, 7) .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1, 1, true), new StatusMove(MoveId.PSYCHIC_TERRAIN, PokemonType.PSYCHIC, -1, 10, -1, 0, 7) @@ -10693,11 +10700,8 @@ export function initMoves() { new AttackMove(MoveId.POWER_TRIP, PokemonType.DARK, MoveCategory.PHYSICAL, 20, 100, 10, -1, 0, 7) .attr(PositiveStatStagePowerAttr), new AttackMove(MoveId.BURN_UP, PokemonType.FIRE, MoveCategory.SPECIAL, 130, 100, 5, -1, 0, 7) - .condition( - // Pass `true` to `ForDefend` as it should fail if the user is terastallized to a type that is not FIRE - user => user.isOfType(PokemonType.FIRE, true, true), - 2 - ) + // Pass `true` to `ForDefend` as it should fail if the user is terastallized to a type that is not FIRE + .condition(user => user.isOfType(PokemonType.FIRE, true, true), 2) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) .attr(AddBattlerTagAttr, BattlerTagType.BURNED_UP, true, false) .attr(RemoveTypeAttr, PokemonType.FIRE, (user) => { @@ -10798,10 +10802,7 @@ export function initMoves() { .attr(AddBattlerTagHeaderAttr, BattlerTagType.SHELL_TRAP) .target(MoveTarget.ALL_NEAR_ENEMIES) // Fails if the user was not hit by a physical attack during the turn - .condition( - user => user.getTag(ShellTrapTag)?.activated === true, - 3 - ), + .condition(user => user.getTag(ShellTrapTag)?.activated === true, 3), new AttackMove(MoveId.FLEUR_CANNON, PokemonType.FAIRY, MoveCategory.SPECIAL, 130, 90, 5, -1, 0, 7) .attr(StatStageChangeAttr, [ Stat.SPATK ], -2, true), new AttackMove(MoveId.PSYCHIC_FANGS, PokemonType.PSYCHIC, MoveCategory.PHYSICAL, 85, 100, 10, -1, 0, 7) @@ -10949,11 +10950,8 @@ export function initMoves() { new SelfStatusMove(MoveId.NO_RETREAT, PokemonType.FIGHTING, -1, 5, -1, 0, 8) .attr(StatStageChangeAttr, [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ], 1, true) .attr(AddBattlerTagAttr, BattlerTagType.NO_RETREAT, true, true /* NOT ADDED if already trapped */) - .condition( - // fails if the user is currently trapped specifically from no retreat - user => user.getTag(TrappedTag)?.tagType !== BattlerTagType.NO_RETREAT, - 2 - ), + // fails if the user is currently trapped specifically from no retreat + .condition(user => user.getTag(TrappedTag)?.tagType !== BattlerTagType.NO_RETREAT, 2), new StatusMove(MoveId.TAR_SHOT, PokemonType.ROCK, 100, 15, -1, 0, 8) .attr(StatStageChangeAttr, [ Stat.SPD ], -1) .attr(AddBattlerTagAttr, BattlerTagType.TAR_SHOT, false) @@ -11515,18 +11513,15 @@ export function initMoves() { .slicingMove() .triageMove(), new AttackMove(MoveId.DOUBLE_SHOCK, PokemonType.ELECTRIC, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 9) - .condition( - // Pass `true` to `isOfType` to fail if the user is terastallized to a type other than ELECTRIC - user => user.isOfType(PokemonType.ELECTRIC, true, true), - 2 - ) + // Pass `true` to `isOfType` to fail if the user is terastallized to a type other than ELECTRIC + .condition(user => user.isOfType(PokemonType.ELECTRIC, true, true), 2) .attr(AddBattlerTagAttr, BattlerTagType.DOUBLE_SHOCKED, true, false) .attr(RemoveTypeAttr, PokemonType.ELECTRIC, (user) => { globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:usedUpAllElectricity", { pokemonName: getPokemonNameWithAffix(user) })); }), new AttackMove(MoveId.GIGATON_HAMMER, PokemonType.STEEL, MoveCategory.PHYSICAL, 160, 100, 5, -1, 0, 9) .makesContact(false) - .restriction(ConsecutiveUseRestriction), + .restriction(consecutiveUseRestriction), new AttackMove(MoveId.COMEUPPANCE, PokemonType.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 9) .attr(CounterDamageAttr, 1.5) .attr(CounterRedirectAttr) @@ -11552,7 +11547,7 @@ export function initMoves() { .attr(ConfuseAttr) .makesContact(false), new AttackMove(MoveId.BLOOD_MOON, PokemonType.NORMAL, MoveCategory.SPECIAL, 140, 100, 5, -1, 0, 9) - .restriction(ConsecutiveUseRestriction), + .restriction(consecutiveUseRestriction), new AttackMove(MoveId.MATCHA_GOTCHA, PokemonType.GRASS, MoveCategory.SPECIAL, 80, 90, 15, 20, 0, 9) .attr(HitHealAttr) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) @@ -11613,7 +11608,7 @@ export function initMoves() { .attr(AddBattlerTagAttr, BattlerTagType.HEAL_BLOCK, false, false, 2), new AttackMove(MoveId.UPPER_HAND, PokemonType.FIGHTING, MoveCategory.PHYSICAL, 65, 100, 15, 100, 3, 9) .attr(FlinchAttr) - .condition(UpperHandCondition, 3), + .condition(upperHandCondition, 3), new AttackMove(MoveId.MALIGNANT_CHAIN, PokemonType.POISON, MoveCategory.SPECIAL, 100, 100, 5, 50, 0, 9) .attr(StatusEffectAttr, StatusEffect.TOXIC) ); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index a1e542fdb02..7ea3e71da85 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3138,7 +3138,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { * @param ignorePp - Whether to ignore PP when checking if the move is usable (defaults to false) * @returns A tuple containing a boolean indicating if the move can be selected, and a string with the reason if it cannot be selected */ - public trySelectMove(moveIndex: number, ignorePp?: boolean): [boolean, string] { + public trySelectMove(moveIndex: number, ignorePp?: boolean): [isUsable: boolean, failureMessage: string] { const move = this.getMoveset().length > moveIndex ? this.getMoveset()[moveIndex] : null; return move?.isUsable(this, ignorePp, true) ?? [false, ""]; } diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index f6111c861a2..5265820447f 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -1,3 +1,7 @@ +// biome-ignore-start lint/correctness/noUnusedImports: Used in a tsdoc comment +import type { Move, PreUseInterruptAttr } from "#types/move-types"; +// biome-ignore-end lint/correctness/noUnusedImports: Used in a tsdoc comment + import { applyAbAttrs } from "#abilities/apply-ab-attrs"; import { MOVE_COLOR } from "#app/constants/colors"; import { globalScene } from "#app/global-scene"; @@ -28,8 +32,6 @@ import type { Pokemon } from "#field/pokemon"; import { applyMoveAttrs } from "#moves/apply-attrs"; import { frenzyMissFunc } from "#moves/move-utils"; import type { PokemonMove } from "#moves/pokemon-move"; -// biome-ignore lint/correctness/noUnusedImports: Used in a tsdoc comment -import type { Move, PreUseInterruptAttr } from "#types/move-types"; import { applyChallenges } from "#utils/challenge-utils"; import { BooleanHolder, NumberHolder } from "#utils/common"; import { enumValueToKey } from "#utils/enums"; @@ -205,7 +207,7 @@ export class MovePhase extends PokemonPhase { * * @remarks * Other than powder, each failure condition is mutually exclusive (as they are tied to specific moves), so order does not matter. - * Notably, this failure check only includes failure conditions intrinsic to the move itself, ther than Powder (which marks the end of this failure check) + * Notably, this failure check only includes failure conditions intrinsic to the move itself, other than Powder (which marks the end of this failure check) * * * - Pollen puff used on an ally that is under effect of heal block @@ -512,13 +514,14 @@ export class MovePhase extends PokemonPhase { * - Checking if the pokemon will thaw from random chance, OR from a thawing move. * Thawing from a freeze move is not applied until AFTER all other failure checks. * - Activating the freeze status effect (cancelling the move, playing the message, and displaying the animation) + * @returns Whether the move was cancelled due to the pokemon being frozen */ protected checkFreeze(): boolean { if (this.pokemon.status?.effect !== StatusEffect.FREEZE) { return false; } - // For some reason, dancer will immediately its user + // For some reason, dancer will immediately thaw its user if (this.useMode === MoveUseMode.INDIRECT) { this.pokemon.resetStatus(false); return false; @@ -644,6 +647,7 @@ export class MovePhase extends PokemonPhase { * Lapse the tag type and check if the move is cancelled from it. Meant to be used during the first failure check * @param tag - The tag type whose lapse method will be called with {@linkcode BattlerTagLapseType.PRE_MOVE} * @param checkIgnoreStatus - Whether to check {@link isIgnoreStatus} for the current {@linkcode MoveUseMode} to skip this check + * @returns Whether the move was cancelled due to a `BattlerTag` effect */ private checkTagCancel(tag: BattlerTagType): boolean { this.pokemon.lapseTag(tag, BattlerTagLapseType.PRE_MOVE); @@ -652,7 +656,7 @@ export class MovePhase extends PokemonPhase { /** * Handle move failures due to Gravity, cancelling the move and showing the failure text - * @returns - Whether the move was cancelled due to Gravity + * @returns Whether the move was cancelled due to Gravity */ private checkGravity(): boolean { const move = this.move.getMove(); @@ -721,7 +725,7 @@ export class MovePhase extends PokemonPhase { /* At this point, delayed moves (future sight, wish, doom desire) are issued, and if they occur, are Then, combined pledge moves are checked for. Interestingly, the "wasMoveEffective" flag is set to false if the delay occurs - In either case, the phase should end here without proceeding + In either case, the phase should end here without proceeding */ const move = this.move.getMove(); diff --git a/src/utils/pokemon-utils.ts b/src/utils/pokemon-utils.ts index 8bb7d76a028..454bd93a54c 100644 --- a/src/utils/pokemon-utils.ts +++ b/src/utils/pokemon-utils.ts @@ -1,11 +1,13 @@ +// biome-ignore-start lint/correctness/noUnusedImports: Used in a TSDoc comment +import type { Pokemon } from "#field/pokemon"; +// biome-ignore-end lint/correctness/noUnusedImports: Used in a TSDoc comment + import { globalScene } from "#app/global-scene"; import { POKERUS_STARTER_COUNT, speciesStarterCosts } from "#balance/starters"; import { allSpecies } from "#data/data-lists"; import type { PokemonSpecies, PokemonSpeciesForm } from "#data/pokemon-species"; import { BattlerIndex } from "#enums/battler-index"; import type { SpeciesId } from "#enums/species-id"; -// biome-ignore lint/correctness/noUnusedImports: Used in a TSDoc comment -import type { Pokemon } from "#field/pokemon"; import { randSeedItem } from "./common"; /** diff --git a/test/moves/dig.test.ts b/test/moves/dig.test.ts index d0693250416..28cbf2882a6 100644 --- a/test/moves/dig.test.ts +++ b/test/moves/dig.test.ts @@ -90,7 +90,7 @@ describe("Moves - Dig", () => { expect(enemyPokemon.getLastXMoves(1)[0].result).toBe(MoveResult.SUCCESS); }); - it("should expend PP when the attack phase is cancelled", async () => { + it("should expend PP when the attack phase is cancelled by sleep", async () => { game.override.enemyAbility(AbilityId.NO_GUARD).enemyMoveset(MoveId.SPORE); await game.classicMode.startBattle([SpeciesId.MAGIKARP]); diff --git a/test/moves/dive.test.ts b/test/moves/dive.test.ts index 564b1886e17..1ce07803f00 100644 --- a/test/moves/dive.test.ts +++ b/test/moves/dive.test.ts @@ -74,7 +74,7 @@ describe("Moves - Dive", () => { expect(enemyPokemon.getLastXMoves(1)[0].result).toBe(MoveResult.SUCCESS); }); - it("should expend PP when the attack phase is cancelled", async () => { + it("should expend PP when the attack phase is cancelled by sleep", async () => { game.override.enemyAbility(AbilityId.NO_GUARD).enemyMoveset(MoveId.SPORE); await game.classicMode.startBattle([SpeciesId.MAGIKARP]); diff --git a/test/ui/type-hints.test.ts b/test/ui/type-hints.test.ts index c637bfcd724..9f1c030e3a2 100644 --- a/test/ui/type-hints.test.ts +++ b/test/ui/type-hints.test.ts @@ -84,7 +84,7 @@ describe("UI - Type Hints", () => { await game.phaseInterceptor.to("CommandPhase"); }); - it("should show the proper hint for a move in doubles after one of the enemy pokemon flees", async () => { + it("should show the proper hint for a move in doubles after one of the enemy pokemon faints", async () => { game.override .enemySpecies(SpeciesId.ABRA) .moveset([MoveId.SPLASH, MoveId.SHADOW_BALL, MoveId.SOAK])