From 80026590b82903d6eb49fe5b012f415a460292ef Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Fri, 6 Jun 2025 21:56:00 -0400 Subject: [PATCH] Renamed `MoveUseType` to `MoveUseMode`; applied review comments --- src/data/abilities/ability.ts | 10 +- src/data/arena-tag.ts | 4 +- src/data/battler-tags.ts | 8 +- src/data/moves/move.ts | 16 +-- .../encounters/absolute-avarice-encounter.ts | 4 +- .../encounters/clowning-around-encounter.ts | 8 +- .../encounters/dancing-lessons-encounter.ts | 4 +- .../encounters/fiery-fallout-encounter.ts | 6 +- .../slumbering-snorlax-encounter.ts | 4 +- .../encounters/the-strong-stuff-encounter.ts | 6 +- .../encounters/trash-to-treasure-encounter.ts | 6 +- .../encounters/uncommon-breed-encounter.ts | 4 +- .../mystery-encounters/mystery-encounter.ts | 4 +- .../utils/encounter-phase-utils.ts | 2 +- .../{move-use-type.ts => move-use-mode.ts} | 111 +++++++++--------- src/field/pokemon.ts | 41 +++---- src/phases/command-phase.ts | 24 ++-- src/phases/move-charge-phase.ts | 19 +-- src/phases/move-effect-phase.ts | 20 ++-- src/phases/move-phase.ts | 73 ++++++------ src/phases/turn-start-phase.ts | 4 +- .../version_migration/versions/v1_10_0.ts | 6 +- src/ui/fight-ui-handler.ts | 6 +- test/moves/after_you.test.ts | 6 +- test/moves/copycat.test.ts | 4 +- test/moves/dig.test.ts | 3 +- test/moves/disable.test.ts | 12 +- test/moves/instruct.test.ts | 14 +-- test/moves/last-resort.test.ts | 12 +- test/moves/metronome.test.ts | 4 +- test/moves/quash.test.ts | 6 +- .../fun-and-games-encounter.test.ts | 16 +-- test/testUtils/gameManager.ts | 1 - test/testUtils/helpers/moveHelper.ts | 10 +- 34 files changed, 238 insertions(+), 240 deletions(-) rename src/enums/{move-use-type.ts => move-use-mode.ts} (53%) diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 075da480a31..b59e0de4f0f 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -74,7 +74,7 @@ import type { BattlerIndex } from "#app/battle"; import type Move from "#app/data/moves/move"; import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag"; import { SelectBiomePhase } from "#app/phases/select-biome-phase"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; import { noAbilityTypeOverrideMoves } from "../moves/invalid-moves"; export class BlockRecoilDamageAttr extends AbAttr { @@ -4451,10 +4451,10 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr { // If the move is an AttackMove or a StatusMove the Dancer must replicate the move on the source of the Dance if (move.getMove() instanceof AttackMove || move.getMove() instanceof StatusMove) { const target = this.getTarget(dancer, source, targets); - globalScene.unshiftPhase(new MovePhase(dancer, target, move, MoveUseType.INDIRECT)); + globalScene.unshiftPhase(new MovePhase(dancer, target, move, MoveUseMode.INDIRECT)); } else if (move.getMove() instanceof SelfStatusMove) { // If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself - globalScene.unshiftPhase(new MovePhase(dancer, [ dancer.getBattlerIndex() ], move, MoveUseType.INDIRECT)) + globalScene.unshiftPhase(new MovePhase(dancer, [ dancer.getBattlerIndex() ], move, MoveUseMode.INDIRECT)) } } } @@ -7175,12 +7175,12 @@ export function initAbilities() { .bypassFaint(), new Ability(AbilityId.DANCER, 7) .attr(PostDancingMoveAbAttr) - .edgeCase(), /* Incorrect interations with: * Petal Dance (should not lock in or count down timer; currently does both) * Flinches (due to tag being removed earlier) * Failed/protected moves (should not trigger if original move is protected against) */ + .edgeCase(), new Ability(AbilityId.BATTERY, 7) .attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL ], 1.3), new Ability(AbilityId.FLUFFY, 7) @@ -7324,8 +7324,8 @@ export function initAbilities() { .edgeCase(), // interacts incorrectly with rock head. It's meant to switch abilities before recoil would apply so that a pokemon with rock head would lose rock head first and still take the recoil new Ability(AbilityId.GORILLA_TACTICS, 8) .attr(GorillaTacticsAbAttr) - .edgeCase(), // TODO: Verify whether Gorilla Tactics increases struggle's power or not + .edgeCase(), new Ability(AbilityId.NEUTRALIZING_GAS, 8) .attr(PostSummonAddArenaTagAbAttr, true, ArenaTagType.NEUTRALIZING_GAS, 0) .attr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr) diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index 29fddb6b496..d9d1d334c3b 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -30,7 +30,7 @@ import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { CommonAnimPhase } from "#app/phases/common-anim-phase"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; export enum ArenaTagSide { BOTH, @@ -896,7 +896,7 @@ export class DelayedAttackTag extends ArenaTag { // We currently only add the entry on the turn of the _attack_ and always make it a follow up // (meaning it's never targetable by Spite) globalScene.unshiftPhase( - new MoveEffectPhase(this.sourceId!, [this.targetIndex], allMoves[this.sourceMove!], MoveUseType.FOLLOW_UP), + new MoveEffectPhase(this.sourceId!, [this.targetIndex], allMoves[this.sourceMove!], MoveUseMode.FOLLOW_UP), ); // TODO: are those bangs correct? } diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index b5b12dd9889..ad530bf5859 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -44,7 +44,7 @@ import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat import { StatusEffect } from "#enums/status-effect"; import { WeatherType } from "#enums/weather-type"; import { isNullOrUndefined } from "#app/utils/common"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; import { invalidEncoreMoves } from "./moves/invalid-moves"; export enum BattlerTagLapseType { @@ -443,7 +443,7 @@ export class RechargingTag extends BattlerTag { super.onAdd(pokemon); // Queue a placeholder move for the Pokemon to "use" next turn. - pokemon.pushMoveQueue({ move: MoveId.NONE, targets: [], useType: MoveUseType.NORMAL }); + pokemon.pushMoveQueue({ move: MoveId.NONE, targets: [], useMode: MoveUseMode.NORMAL }); } /** Cancels the source's move this turn and queues a "__ must recharge!" message */ @@ -692,7 +692,7 @@ export class InterruptedTag extends BattlerTag { move: MoveId.NONE, result: MoveResult.OTHER, targets: [], - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }); } @@ -1175,7 +1175,7 @@ export class EncoreTag extends MoveRestrictionBattlerTag { const lastMove = pokemon.getLastXMoves(1)[0]; globalScene.tryReplacePhase( m => m instanceof MovePhase && m.pokemon === pokemon, - new MovePhase(pokemon, lastMove.targets ?? [], movesetMove, MoveUseType.NORMAL), + new MovePhase(pokemon, lastMove.targets ?? [], movesetMove, MoveUseMode.NORMAL), ); } } diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 4126933e564..fbb116ee1d4 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -123,7 +123,7 @@ import { MoveEffectTrigger } from "#enums/MoveEffectTrigger"; import { MultiHitType } from "#enums/MultiHitType"; import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves, invalidSketchMoves } from "./invalid-moves"; import { SelectBiomePhase } from "#app/phases/select-biome-phase"; -import { isVirtual, MoveUseType } from "#enums/move-use-type"; +import { isVirtual, MoveUseMode } from "#enums/move-use-mode"; type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean; @@ -3070,7 +3070,7 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr { overridden.value = true; globalScene.unshiftPhase(new MoveAnimPhase(new MoveChargeAnim(this.chargeAnim, move.id, user))); globalScene.queueMessage(this.chargeText.replace("{TARGET}", getPokemonNameWithAffix(target)).replace("{USER}", getPokemonNameWithAffix(user))); - user.pushMoveHistory({ move: move.id, targets: [ target.getBattlerIndex() ], result: MoveResult.OTHER, useType: MoveUseType.NORMAL }); + user.pushMoveHistory({ move: move.id, targets: [ target.getBattlerIndex() ], result: MoveResult.OTHER, useMode: MoveUseMode.NORMAL }); const side = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; globalScene.arena.addTag(this.tagType, 3, move.id, user.id, side, false, target.getBattlerIndex()); } else { @@ -5423,7 +5423,7 @@ export class FrenzyAttr extends MoveEffectAttr { if (!user.getTag(BattlerTagType.FRENZY) && user.getMoveQueue().length === 0) { const turnCount = user.randBattleSeedIntRange(1, 2); // excludes initial use for (let i = 0; i < turnCount; i++) { - user.pushMoveQueue({ move: move.id, targets: [ target.getBattlerIndex() ], useType: MoveUseType.IGNORE_PP }); + user.pushMoveQueue({ move: move.id, targets: [ target.getBattlerIndex() ], useMode: MoveUseMode.IGNORE_PP }); } user.addTag(BattlerTagType.FRENZY, turnCount, move.id, user.id); } else { @@ -6768,7 +6768,7 @@ class CallMoveAttr extends OverrideMoveEffectAttr { ? target.getBattlerIndex() : moveTargets.targets[user.randBattleSeedInt(moveTargets.targets.length)]]; globalScene.unshiftPhase(new LoadMoveAnimPhase(move.id)); - globalScene.unshiftPhase(new MovePhase(user, targets, new PokemonMove(move.id), MoveUseType.FOLLOW_UP)); + globalScene.unshiftPhase(new MovePhase(user, targets, new PokemonMove(move.id), MoveUseMode.FOLLOW_UP)); return true; } } @@ -6997,7 +6997,7 @@ export class NaturePowerAttr extends OverrideMoveEffectAttr { // Load the move's animation if we didn't already and unshift a new usage phase globalScene.unshiftPhase(new LoadMoveAnimPhase(moveId)); - globalScene.unshiftPhase(new MovePhase(user, [ target.getBattlerIndex() ], new PokemonMove(moveId), MoveUseType.FOLLOW_UP)); + globalScene.unshiftPhase(new MovePhase(user, [ target.getBattlerIndex() ], new PokemonMove(moveId), MoveUseMode.FOLLOW_UP)); return true; } } @@ -7083,7 +7083,7 @@ export class RepeatMoveAttr extends MoveEffectAttr { targetPokemonName: getPokemonNameWithAffix(target) })); target.turnData.extraTurns++; - globalScene.appendToPhase(new MovePhase(target, moveTargets, movesetMove, MoveUseType.NORMAL), MoveEndPhase); + globalScene.appendToPhase(new MovePhase(target, moveTargets, movesetMove, MoveUseMode.NORMAL), MoveEndPhase); return true; } @@ -7829,7 +7829,7 @@ export class LastResortAttr extends MoveAttr { const movesInHistory = new Set( user.getMoveHistory() - .filter(m => !isVirtual(m.useType)) // Last resort ignores virtual moves + .filter(m => !isVirtual(m.useMode)) // Last resort ignores virtual moves .map(m => m.move) ); @@ -7913,7 +7913,7 @@ export class ForceLastAttr extends MoveEffectAttr { globalScene.phaseQueue.splice( globalScene.phaseQueue.indexOf(prependPhase), 0, - new MovePhase(target, [ ...targetMovePhase.targets ], targetMovePhase.move, targetMovePhase.useType, true) + new MovePhase(target, [ ...targetMovePhase.targets ], targetMovePhase.move, targetMovePhase.useMode, true) ); } } diff --git a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts index db64e423eff..61541b2bd09 100644 --- a/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts +++ b/src/data/mystery-encounters/encounters/absolute-avarice-encounter.ts @@ -38,7 +38,7 @@ import type { BerryType } from "#enums/berry-type"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { Stat } from "#enums/stat"; import i18next from "i18next"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; /** the i18n namespace for this encounter */ const namespace = "mysteryEncounters/absoluteAvarice"; @@ -304,7 +304,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde sourceBattlerIndex: BattlerIndex.ENEMY, targets: [BattlerIndex.ENEMY], move: new PokemonMove(MoveId.STUFF_CHEEKS), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }); await transitionMysteryEncounterIntroVisuals(true, true, 500); diff --git a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts index f0f7a89b815..3a718e35a3f 100644 --- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts +++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts @@ -49,7 +49,7 @@ import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { EncounterAnim } from "#enums/encounter-anims"; import { Challenges } from "#enums/challenges"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/clowningAround"; @@ -210,19 +210,19 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder sourceBattlerIndex: BattlerIndex.ENEMY, targets: [BattlerIndex.ENEMY_2], move: new PokemonMove(MoveId.ROLE_PLAY), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }, { sourceBattlerIndex: BattlerIndex.ENEMY_2, targets: [BattlerIndex.PLAYER], move: new PokemonMove(MoveId.TAUNT), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }, { sourceBattlerIndex: BattlerIndex.ENEMY_2, targets: [BattlerIndex.PLAYER_2], move: new PokemonMove(MoveId.TAUNT), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }, ); diff --git a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts index fa6c17aae8c..69d41c54946 100644 --- a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts +++ b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts @@ -41,7 +41,7 @@ import { PokeballType } from "#enums/pokeball"; import { SpeciesId } from "#enums/species-id"; import { Stat } from "#enums/stat"; import i18next from "i18next"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; /** the i18n namespace for this encounter */ const namespace = "mysteryEncounters/dancingLessons"; @@ -217,7 +217,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder sourceBattlerIndex: BattlerIndex.ENEMY, targets: [BattlerIndex.PLAYER], move: new PokemonMove(MoveId.REVELATION_DANCE), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }); await hideOricorioPokemon(); diff --git a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts index 304b6a6c9b9..c5000b09fbf 100644 --- a/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts +++ b/src/data/mystery-encounters/encounters/fiery-fallout-encounter.ts @@ -48,7 +48,7 @@ import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { Stat } from "#enums/stat"; import { Ability } from "#app/data/abilities/ability-class"; import { FIRE_RESISTANT_ABILITIES } from "#app/data/mystery-encounters/requirements/requirement-groups"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/fieryFallout"; @@ -195,13 +195,13 @@ export const FieryFalloutEncounter: MysteryEncounter = MysteryEncounterBuilder.w sourceBattlerIndex: BattlerIndex.ENEMY, targets: [BattlerIndex.PLAYER], move: new PokemonMove(MoveId.FIRE_SPIN), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }, { sourceBattlerIndex: BattlerIndex.ENEMY_2, targets: [BattlerIndex.PLAYER_2], move: new PokemonMove(MoveId.FIRE_SPIN), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }, ); await initBattleWithEnemyConfig(globalScene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]); diff --git a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts index 579872256e8..7fb4dbf946c 100644 --- a/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts +++ b/src/data/mystery-encounters/encounters/slumbering-snorlax-encounter.ts @@ -31,7 +31,7 @@ import { BerryType } from "#enums/berry-type"; import { Stat } from "#enums/stat"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { randSeedInt } from "#app/utils/common"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; /** i18n namespace for the encounter */ const namespace = "mysteryEncounters/slumberingSnorlax"; @@ -138,7 +138,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil sourceBattlerIndex: BattlerIndex.ENEMY, targets: [BattlerIndex.PLAYER], move: new PokemonMove(MoveId.SNORE), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }); await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]); }, diff --git a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts index 7249cda6e8d..6eae0d73538 100644 --- a/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-strong-stuff-encounter.ts @@ -29,7 +29,7 @@ import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { Stat } from "#enums/stat"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/theStrongStuff"; @@ -212,13 +212,13 @@ export const TheStrongStuffEncounter: MysteryEncounter = MysteryEncounterBuilder sourceBattlerIndex: BattlerIndex.ENEMY, targets: [BattlerIndex.PLAYER], move: new PokemonMove(MoveId.GASTRO_ACID), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }, { sourceBattlerIndex: BattlerIndex.ENEMY, targets: [BattlerIndex.PLAYER], move: new PokemonMove(MoveId.STEALTH_ROCK), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }, ); diff --git a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts index d86e6dcff7f..b8a9a301dbc 100644 --- a/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts +++ b/src/data/mystery-encounters/encounters/trash-to-treasure-encounter.ts @@ -28,7 +28,7 @@ import { BattlerIndex } from "#app/battle"; import { PokemonMove } from "#app/field/pokemon"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { randSeedInt } from "#app/utils/common"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; /** the i18n namespace for this encounter */ const namespace = "mysteryEncounters/trashToTreasure"; @@ -208,13 +208,13 @@ export const TrashToTreasureEncounter: MysteryEncounter = MysteryEncounterBuilde sourceBattlerIndex: BattlerIndex.ENEMY, targets: [BattlerIndex.PLAYER], move: new PokemonMove(MoveId.TOXIC), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }, { sourceBattlerIndex: BattlerIndex.ENEMY, targets: [BattlerIndex.ENEMY], move: new PokemonMove(MoveId.STOCKPILE), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }, ); await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]); diff --git a/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts b/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts index 5be120210de..8ddfe8ffcd1 100644 --- a/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts +++ b/src/data/mystery-encounters/encounters/uncommon-breed-encounter.ts @@ -38,7 +38,7 @@ import { BerryModifier } from "#app/modifier/modifier"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { Stat } from "#enums/stat"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/uncommonBreed"; @@ -179,7 +179,7 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder. sourceBattlerIndex: BattlerIndex.ENEMY, targets: [target], move: pokemonMove, - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }); } diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index 142eb618b7a..0593eafb74e 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -28,14 +28,14 @@ import type { GameModes } from "#app/game-mode"; import type { EncounterAnim } from "#enums/encounter-anims"; import type { Challenges } from "#enums/challenges"; import { globalScene } from "#app/global-scene"; -import type { MoveUseType } from "#enums/move-use-type"; +import type { MoveUseMode } from "#enums/move-use-mode"; export interface EncounterStartOfBattleEffect { sourcePokemon?: Pokemon; sourceBattlerIndex?: BattlerIndex; targets: BattlerIndex[]; move: PokemonMove; - useType: MoveUseType; // TODO: This should always be ignore PP... + useMode: MoveUseMode; // TODO: This should always be ignore PP... } const DEFAULT_MAX_ALLOWED_ENCOUNTERS = 2; diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index b2e330a44cf..d47d9d68e4e 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -987,7 +987,7 @@ export function handleMysteryEncounterBattleStartEffects() { effects.forEach(effect => { const source: EnemyPokemon | Pokemon = effect.sourcePokemon ?? globalScene.getField()[effect.sourceBattlerIndex ?? 0]; - globalScene.pushPhase(new MovePhase(source, effect.targets, effect.move, effect.useType)); + globalScene.pushPhase(new MovePhase(source, effect.targets, effect.move, effect.useMode)); }); // Pseudo turn end phase to reset flinch states, Endure, etc. diff --git a/src/enums/move-use-type.ts b/src/enums/move-use-mode.ts similarity index 53% rename from src/enums/move-use-type.ts rename to src/enums/move-use-mode.ts index b1160fd9645..355fe638ffa 100644 --- a/src/enums/move-use-type.ts +++ b/src/enums/move-use-mode.ts @@ -2,16 +2,16 @@ import type { PostDancingMoveAbAttr } from "#app/data/abilities/ability"; import type { BattlerTagLapseType } from "#app/data/battler-tags"; /** - * Enum representing all the possible ways a given move can be executed. + * Enum representing all the possible means through which a given move can be executed. * Each one inherits the properties (or exclusions) of all types preceding it. - * Properties newly found on a given use type will be **bolded**, + * Properties newly found on a given use mode will be **bolded**, * while oddities breaking a previous trend will be listed in _italics_. - * Callers should refrain from performing non-equality checks on `MoveUseTypes` directly, + * Callers should refrain from performing non-equality checks on `MoveUseMode`s directly, * instead using the available helper functions * ({@linkcode isVirtual}, {@linkcode isIgnoreStatus}, {@linkcode isIgnorePP} and {@linkcode isReflected}). */ -export enum MoveUseType { +export enum MoveUseMode { /** * This move was used normally (i.e. clicking on the button) or called via Instruct. * It deducts PP from the user's moveset (failing if out of PP), and interacts normally with other moves and abilities. @@ -20,11 +20,11 @@ export enum MoveUseType { /** * This move was called by an effect that ignores PP, such as a consecutively executed move (e.g. Outrage). - + * * PP-ignoring moves (as their name implies) **do not consume PP** when used * and **will not fail** if none is left prior to execution. - * All other effects remain identical to {@linkcode MoveUseType.NORMAL}. - + * All other effects remain identical to {@linkcode MoveUseMode.NORMAL}. + * * PP can still be reduced by other effects (such as Spite or Eerie Spell). */ IGNORE_PP = 2, @@ -32,11 +32,11 @@ export enum MoveUseType { /** * This move was called indirectly by an out-of-turn effect other than Instruct or the user's previous move. * Currently only used by {@linkcode PostDancingMoveAbAttr | Dancer}. - - * Indirect moves ignore PP checks similar to {@linkcode MoveUseType.IGNORE_PP}, but additionally **cannot be copied** + * + * Indirect moves ignore PP checks similar to {@linkcode MoveUseMode.IGNORE_PP}, but additionally **cannot be copied** * by all move-copying effects (barring reflection). * They are also **"skipped over" by most moveset and move history-related effects** (PP reduction, Last Resort, etc). - + * * They still respect the user's volatile status conditions and confusion (though will uniquely _cure freeze and sleep before use_). */ INDIRECT = 3, @@ -47,7 +47,7 @@ export enum MoveUseType { * Follow-up moves **bypass cancellation** from all **non-volatile status conditions** and **{@linkcode BattlerTagLapseType.MOVE}-type effects** * (having been checked already on the calling move). - * They are _not ignored_ by other move-calling moves and abilities (unlike {@linkcode MoveUseType.FOLLOW_UP} and {@linkcode MoveUseType.REFLECTED}), + * They are _not ignored_ by other move-calling moves and abilities (unlike {@linkcode MoveUseMode.FOLLOW_UP} and {@linkcode MoveUseMode.REFLECTED}), * but still inherit the former's disregard for moveset-related effects. */ FOLLOW_UP = 4, @@ -55,92 +55,93 @@ export enum MoveUseType { /** * This move was reflected by Magic Coat or Magic Bounce. - * Reflected moves ignore all the same cancellation checks as {@linkcode MoveUseType.INDIRECT} - * and retain the same copy prevention as {@linkcode MoveUseType.FOLLOW_UP}, but additionally + * Reflected moves ignore all the same cancellation checks as {@linkcode MoveUseMode.INDIRECT} + * and retain the same copy prevention as {@linkcode MoveUseMode.FOLLOW_UP}, but additionally * **cannot be reflected by other reflecting effects**. */ REFLECTED = 5 + // TODO: Add use type TRANSPARENT for Future Sight and Doom Desire to prevent move history pushing } // # HELPER FUNCTIONS -// Please update the markdown tables if any new `MoveUseType`s get added. +// Please update the markdown tables if any new `MoveUseMode`s get added. /** - * Check if a given {@linkcode MoveUseType} is virtual (i.e. called by another move or effect). - * Virtual moves are ignored by most moveset-related effects and pre-move cancellation checks. - * @param useType - The {@linkcode MoveUseType} to check. - * @returns Whether {@linkcode useType} is virtual. + * Check if a given {@linkcode MoveUseMode} is virtual (i.e. called by another move or effect). + * Virtual moves are ignored by most moveset-related effects due to not being executed directly. + * @returns Whether {@linkcode useMode} is virtual. * @remarks * This function is equivalent to the following truth table: * * | Use Type | Returns | * |------------------------------------|---------| - * | {@linkcode MoveUseType.NORMAL} | `false` | - * | {@linkcode MoveUseType.IGNORE_PP} | `false` | - * | {@linkcode MoveUseType.INDIRECT} | `true` | - * | {@linkcode MoveUseType.FOLLOW_UP} | `true` | - * | {@linkcode MoveUseType.REFLECTED} | `true` | + * | {@linkcode MoveUseMode.NORMAL} | `false` | + * | {@linkcode MoveUseMode.IGNORE_PP} | `false` | + * | {@linkcode MoveUseMode.INDIRECT} | `true` | + * | {@linkcode MoveUseMode.FOLLOW_UP} | `true` | + * | {@linkcode MoveUseMode.REFLECTED} | `true` | */ -export function isVirtual(useType: MoveUseType): boolean { - return useType >= MoveUseType.INDIRECT +export function isVirtual(useMode: MoveUseMode): boolean { + return useMode >= MoveUseMode.INDIRECT } /** - * Check if a given {@linkcode MoveUseType} should ignore pre-move cancellation checks. - * @param useType - The {@linkcode MoveUseType} to check. - * @returns Whether {@linkcode useType} should ignore status checks. + * Check if a given {@linkcode MoveUseMode} should ignore pre-move cancellation checks + * from {@linkcode StatusEffect.PARALYSIS} and {@linkcode BattlerTagLapseType.MOVE}-type effects. + * @param useMode - The {@linkcode MoveUseMode} to check. + * @returns Whether {@linkcode useMode} should ignore status and otehr cancellation checks. * @remarks * This function is equivalent to the following truth table: * * | Use Type | Returns | * |------------------------------------|---------| - * | {@linkcode MoveUseType.NORMAL} | `false` | - * | {@linkcode MoveUseType.IGNORE_PP} | `false` | - * | {@linkcode MoveUseType.INDIRECT} | `false` | - * | {@linkcode MoveUseType.FOLLOW_UP} | `true` | - * | {@linkcode MoveUseType.REFLECTED} | `true` | + * | {@linkcode MoveUseMode.NORMAL} | `false` | + * | {@linkcode MoveUseMode.IGNORE_PP} | `false` | + * | {@linkcode MoveUseMode.INDIRECT} | `false` | + * | {@linkcode MoveUseMode.FOLLOW_UP} | `true` | + * | {@linkcode MoveUseMode.REFLECTED} | `true` | */ -export function isIgnoreStatus(useType: MoveUseType): boolean { - return useType >= MoveUseType.FOLLOW_UP; +export function isIgnoreStatus(useMode: MoveUseMode): boolean { + return useMode >= MoveUseMode.FOLLOW_UP; } /** - * Check if a given {@linkcode MoveUseType} should ignore PP. + * Check if a given {@linkcode MoveUseMode} should ignore PP. * PP-ignoring moves will ignore normal PP consumption as well as associated failure checks. - * @param useType - The {@linkcode MoveUseType} to check. - * @returns Whether {@linkcode useType} ignores PP. + * @param useMode - The {@linkcode MoveUseMode} to check. + * @returns Whether {@linkcode useMode} ignores PP. * @remarks * This function is equivalent to the following truth table: * * | Use Type | Returns | * |------------------------------------|---------| - * | {@linkcode MoveUseType.NORMAL} | `false` | - * | {@linkcode MoveUseType.IGNORE_PP} | `true` | - * | {@linkcode MoveUseType.INDIRECT} | `true` | - * | {@linkcode MoveUseType.FOLLOW_UP} | `true` | - * | {@linkcode MoveUseType.REFLECTED} | `true` | + * | {@linkcode MoveUseMode.NORMAL} | `false` | + * | {@linkcode MoveUseMode.IGNORE_PP} | `true` | + * | {@linkcode MoveUseMode.INDIRECT} | `true` | + * | {@linkcode MoveUseMode.FOLLOW_UP} | `true` | + * | {@linkcode MoveUseMode.REFLECTED} | `true` | */ -export function isIgnorePP(useType: MoveUseType): boolean { - return useType >= MoveUseType.IGNORE_PP; +export function isIgnorePP(useMode: MoveUseMode): boolean { + return useMode >= MoveUseMode.IGNORE_PP; } /** - * Check if a given {@linkcode MoveUseType} is reflected. + * Check if a given {@linkcode MoveUseMode} is reflected. * Reflected moves cannot be reflected, copied, or cancelled by status effects, * nor will they trigger {@linkcode PostDancingMoveAbAttr | Dancer}. - * @param useType - The {@linkcode MoveUseType} to check. - * @returns Whether {@linkcode useType} is reflected. + * @param useMode - The {@linkcode MoveUseMode} to check. + * @returns Whether {@linkcode useMode} is reflected. * @remarks * This function is equivalent to the following truth table: * * | Use Type | Returns | * |------------------------------------|---------| - * | {@linkcode MoveUseType.NORMAL} | `false` | - * | {@linkcode MoveUseType.IGNORE_PP} | `false` | - * | {@linkcode MoveUseType.INDIRECT} | `false` | - * | {@linkcode MoveUseType.FOLLOW_UP} | `false` | - * | {@linkcode MoveUseType.REFLECTED} | `true` | + * | {@linkcode MoveUseMode.NORMAL} | `false` | + * | {@linkcode MoveUseMode.IGNORE_PP} | `false` | + * | {@linkcode MoveUseMode.INDIRECT} | `false` | + * | {@linkcode MoveUseMode.FOLLOW_UP} | `false` | + * | {@linkcode MoveUseMode.REFLECTED} | `true` | */ -export function isReflected(useType: MoveUseType): boolean { - return useType === MoveUseType.REFLECTED; +export function isReflected(useMode: MoveUseMode): boolean { + return useMode === MoveUseMode.REFLECTED; } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 418b63567e7..5b1cb11b5f1 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -256,7 +256,7 @@ import { MoveFlags } from "#enums/MoveFlags"; import { timedEventManager } from "#app/global-event-manager"; import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader"; import { ResetStatusPhase } from "#app/phases/reset-status-phase"; -import { isVirtual, isIgnorePP, MoveUseType } from "#enums/move-use-type"; +import { isVirtual, isIgnorePP, MoveUseMode } from "#enums/move-use-mode"; export enum LearnMoveSituation { MISC, @@ -4383,9 +4383,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * Return the most recently executed {@linkcode TurnMove} this {@linkcode Pokemon} has used that is: * - Not {@linkcode MoveId.NONE} - * - Non-virtual ({@linkcode MoveUseType | useType} < {@linkcode MoveUseType.INDIRECT}) + * - Non-virtual ({@linkcode MoveUseMode | useMode} < {@linkcode MoveUseMode.INDIRECT}) * @param ignoreStruggle - Whether to additionally ignore {@linkcode Moves.STRUGGLE}; default `false` - * @param ignoreFollowUp - Whether to ignore moves with a use type of {@linkcode MoveUseType.FOLLOW_UP} + * @param ignoreFollowUp - Whether to ignore moves with a use type of {@linkcode MoveUseMode.FOLLOW_UP} * (e.g. ones called by Copycat/Mirror Move); default `true`. * @returns The last move this Pokemon has used satisfying the aforementioned conditions, * or `undefined` if no applicable moves have been used since switching in. @@ -4395,7 +4395,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { m => m.move !== MoveId.NONE && (!ignoreStruggle || m.move !== MoveId.STRUGGLE) && - (!isVirtual(m.useType) || (!ignoreFollowUp && m.useType === MoveUseType.FOLLOW_UP)), + (!isVirtual(m.useMode) || (!ignoreFollowUp && m.useMode === MoveUseMode.FOLLOW_UP)), ); } @@ -6237,22 +6237,23 @@ export class EnemyPokemon extends Pokemon { */ // TODO: split this up and move it elsewhere getNextMove(): TurnMove { - // If this Pokemon has a move already queued, return it. + // If this Pokemon has a usable move already queued, return it, + // removing all unusable moves before it in the queue. const moveQueue = this.getMoveQueue(); for (const [i, queuedMove] of moveQueue.entries()) { - const moveIndex = this.getMoveset().findIndex(m => m.moveId === queuedMove.move); + const movesetMove = this.getMoveset().find(m => m.moveId === queuedMove.move); // If the queued move was called indirectly, ignore all PP and usability checks. - // Otherwise, ensure that the move being used is actually usable - // TODO: Virtual moves shouldn't use the move queue - if ( - isVirtual(queuedMove.useType) || - (moveIndex > -1 && this.getMoveset()[moveIndex].isUsable(this, isIgnorePP(queuedMove.useType))) - ) { - moveQueue.splice(0, i); // TODO: This may be redundant and definitely should not be done here + // Otherwise, ensure that the move being used is actually usable & in our moveset. + // TODO: What should happen if a pokemon forgets a charging move mid-use? + if (isVirtual(queuedMove.useMode) || movesetMove?.isUsable(this, isIgnorePP(queuedMove.useMode))) { + moveQueue.splice(0, i); // TODO: This should not be done here return queuedMove; } } + // We went through the entire queue without a match; clear the entire thing. + this.summonData.moveQueue = []; + // Filter out any moves this Pokemon cannot use let movePool = this.getMoveset().filter(m => m.isUsable(this)); // If no moves are left, use Struggle. Otherwise, continue with move selection @@ -6262,7 +6263,7 @@ export class EnemyPokemon extends Pokemon { return { move: movePool[0].moveId, targets: this.getNextTargets(movePool[0].moveId), - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }; } // If a move is forced because of Encore, use it. @@ -6274,7 +6275,7 @@ export class EnemyPokemon extends Pokemon { return { move: encoreMove.moveId, targets: this.getNextTargets(encoreMove.moveId), - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }; } } @@ -6282,7 +6283,7 @@ export class EnemyPokemon extends Pokemon { // No enemy should spawn with this AI type in-game case AiType.RANDOM: { const moveId = movePool[globalScene.randBattleSeedInt(movePool.length)].moveId; - return { move: moveId, targets: this.getNextTargets(moveId), useType: MoveUseType.NORMAL }; + return { move: moveId, targets: this.getNextTargets(moveId), useMode: MoveUseMode.NORMAL }; } case AiType.SMART_RANDOM: case AiType.SMART: { @@ -6454,7 +6455,7 @@ export class EnemyPokemon extends Pokemon { return { move: sortedMovePool[r]!.moveId, targets: moveTargets[sortedMovePool[r]!.moveId], - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }; } } @@ -6464,7 +6465,7 @@ export class EnemyPokemon extends Pokemon { return { move: MoveId.STRUGGLE, targets: this.getNextTargets(MoveId.STRUGGLE), - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }; } @@ -6800,7 +6801,7 @@ interface IllusionData { export interface TurnMove { move: MoveId; targets: BattlerIndex[]; - useType: MoveUseType; + useMode: MoveUseMode; result?: MoveResult; turn?: number; } @@ -6825,7 +6826,7 @@ export class PokemonSummonData { * A queue of moves yet to be executed, used by charging, recharging and frenzy moves. * So long as this array is nonempty, this Pokemon's corresponding `CommandPhase` will be skipped over entirely * in favor of using the queued move. - * TODO: Clean up a lot of the code surrounding the move queue. It's intertwined with the + * TODO: Clean up a lot of the code surrounding the move queue. */ public moveQueue: TurnMove[] = []; public tags: BattlerTag[] = []; diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts index b79c75525e9..10a2dadc321 100644 --- a/src/phases/command-phase.ts +++ b/src/phases/command-phase.ts @@ -23,7 +23,7 @@ import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { isNullOrUndefined } from "#app/utils/common"; import { ArenaTagSide } from "#app/data/arena-tag"; import { ArenaTagType } from "#app/enums/arena-tag-type"; -import { isVirtual, isIgnorePP, MoveUseType } from "#enums/move-use-type"; +import { isVirtual, isIgnorePP, MoveUseMode } from "#enums/move-use-mode"; export class CommandPhase extends FieldPhase { protected fieldIndex: number; @@ -81,7 +81,7 @@ export class CommandPhase extends FieldPhase { ) { globalScene.currentBattle.turnCommands[this.fieldIndex] = { command: Command.FIGHT, - move: { move: MoveId.NONE, targets: [], useType: MoveUseType.NORMAL }, + move: { move: MoveId.NONE, targets: [], useMode: MoveUseMode.NORMAL }, skip: true, }; } @@ -104,13 +104,13 @@ export class CommandPhase extends FieldPhase { moveQueue.length && moveQueue[0] && moveQueue[0].move && - !isVirtual(moveQueue[0].useType) && + !isVirtual(moveQueue[0].useMode) && (!playerPokemon.getMoveset().find(m => m.moveId === moveQueue[0].move) || !playerPokemon .getMoveset() [playerPokemon.getMoveset().findIndex(m => m.moveId === moveQueue[0].move)].isUsable( playerPokemon, - isIgnorePP(moveQueue[0].useType), + isIgnorePP(moveQueue[0].useMode), )) ) { moveQueue.shift(); @@ -120,15 +120,15 @@ export class CommandPhase extends FieldPhase { if (moveQueue.length > 0) { const queuedMove = moveQueue[0]; if (!queuedMove.move) { - this.handleCommand(Command.FIGHT, -1, MoveUseType.NORMAL); + this.handleCommand(Command.FIGHT, -1, MoveUseMode.NORMAL); } else { const moveIndex = playerPokemon.getMoveset().findIndex(m => m.moveId === queuedMove.move); if ( (moveIndex > -1 && - playerPokemon.getMoveset()[moveIndex].isUsable(playerPokemon, isIgnorePP(queuedMove.useType))) || - isVirtual(queuedMove.useType) + playerPokemon.getMoveset()[moveIndex].isUsable(playerPokemon, isIgnorePP(queuedMove.useMode))) || + isVirtual(queuedMove.useMode) ) { - this.handleCommand(Command.FIGHT, moveIndex, queuedMove.useType, queuedMove); + this.handleCommand(Command.FIGHT, moveIndex, queuedMove.useMode, queuedMove); } else { globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); } @@ -148,21 +148,21 @@ export class CommandPhase extends FieldPhase { /** * TODO: Remove `args` and clean this thing up - * Code will need to be copied over from pkty except replacing the `virtual` and `ignorePP` args with a corresponding `MoveUseType`. + * Code will need to be copied over from pkty except replacing the `virtual` and `ignorePP` args with a corresponding `MoveUseMode`. */ handleCommand(command: Command, cursor: number, ...args: any[]): boolean { const playerPokemon = globalScene.getPlayerField()[this.fieldIndex]; let success = false; switch (command) { - // TODO: We don't need 2 args for this - moveUseType is carried over from queuedMove + // TODO: We don't need 2 args for this - moveUseMode is carried over from queuedMove case Command.TERA: case Command.FIGHT: let useStruggle = false; const turnMove: TurnMove | undefined = args.length === 2 ? (args[1] as TurnMove) : undefined; if ( cursor === -1 || - playerPokemon.trySelectMove(cursor, isIgnorePP(args[0] as MoveUseType)) || + playerPokemon.trySelectMove(cursor, isIgnorePP(args[0] as MoveUseMode)) || (useStruggle = cursor > -1 && !playerPokemon.getMoveset().filter(m => m.isUsable(playerPokemon)).length) ) { let moveId: MoveId; @@ -179,7 +179,7 @@ export class CommandPhase extends FieldPhase { const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, - move: { move: moveId, targets: [], useType: args[0] }, + move: { move: moveId, targets: [], useMode: args[0] }, args: args, }; const preTurnCommand: TurnCommand = { diff --git a/src/phases/move-charge-phase.ts b/src/phases/move-charge-phase.ts index e520e1cf2f0..827949c31ff 100644 --- a/src/phases/move-charge-phase.ts +++ b/src/phases/move-charge-phase.ts @@ -10,7 +10,7 @@ import { MovePhase } from "#app/phases/move-phase"; import { PokemonPhase } from "#app/phases/pokemon-phase"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MoveEndPhase } from "#app/phases/move-end-phase"; -import type { MoveUseType } from "#enums/move-use-type"; +import type { MoveUseMode } from "#enums/move-use-mode"; /** * Phase for the "charging turn" of two-turn moves (e.g. Dig). @@ -21,21 +21,21 @@ export class MoveChargePhase extends PokemonPhase { /** The field index targeted by the move (Charging moves assume single target) */ public targetIndex: BattlerIndex; - /** The {@linkcode MoveUseType} of the move that triggered the charge; passed on from move phase */ - private useType: MoveUseType; + /** The {@linkcode MoveUseMode} of the move that triggered the charge; passed on from move phase */ + private useMode: MoveUseMode; /** * Create a new MoveChargePhase. * @param battlerIndex - The {@linkcode BattlerIndex} of the user. * @param targetIndex - The {@linkcode BattlerIndex} of the target. * @param move - The {@linkcode PokemonMove} being used - * @param useType - The move's {@linkcode MoveUseType} + * @param useMode - The move's {@linkcode MoveUseMode} */ - constructor(battlerIndex: BattlerIndex, targetIndex: BattlerIndex, move: PokemonMove, useType: MoveUseType) { + constructor(battlerIndex: BattlerIndex, targetIndex: BattlerIndex, move: PokemonMove, useMode: MoveUseMode) { super(battlerIndex); this.move = move; this.targetIndex = targetIndex; - this.useType = useType; + this.useMode = useMode; } public override start() { @@ -65,6 +65,7 @@ export class MoveChargePhase extends PokemonPhase { /** Checks the move's instant charge conditions, then ends this phase. */ public override end() { const user = this.getUserPokemon(); + // Checked for `ChargingMove` in `this.start()` const move = this.move.getMove() as ChargingMove; const instantCharge = new BooleanHolder(false); @@ -74,9 +75,9 @@ export class MoveChargePhase extends PokemonPhase { // Otherwise, add the attack portion to the user's move queue to execute next turn. if (instantCharge.value) { globalScene.tryRemovePhase(phase => phase instanceof MoveEndPhase && phase.getPokemon() === user); - globalScene.unshiftPhase(new MovePhase(user, [this.targetIndex], this.move, this.useType)); + globalScene.unshiftPhase(new MovePhase(user, [this.targetIndex], this.move, this.useMode)); } else { - user.pushMoveQueue({ move: move.id, targets: [this.targetIndex], useType: this.useType }); + user.pushMoveQueue({ move: move.id, targets: [this.targetIndex], useMode: this.useMode }); } // Add this move's charging phase to the user's move history @@ -84,7 +85,7 @@ export class MoveChargePhase extends PokemonPhase { move: this.move.moveId, targets: [this.targetIndex], result: MoveResult.OTHER, - useType: this.useType, + useMode: this.useMode, }); super.end(); diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index d802c36b875..514d5c87bfb 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -78,14 +78,14 @@ import type Move from "#app/data/moves/move"; import { isFieldTargeted } from "#app/data/moves/move-utils"; import { FaintPhase } from "./faint-phase"; import { DamageAchv } from "#app/system/achv"; -import { isVirtual, isReflected, MoveUseType } from "#enums/move-use-type"; +import { isVirtual, isReflected, MoveUseMode } from "#enums/move-use-mode"; export type HitCheckEntry = [HitCheckResult, TypeDamageMultiplier]; export class MoveEffectPhase extends PokemonPhase { public move: Move; protected targets: BattlerIndex[]; - protected useType: MoveUseType; + protected useMode: MoveUseMode; /** The result of the hit check against each target */ private hitChecks: HitCheckEntry[]; @@ -110,12 +110,12 @@ export class MoveEffectPhase extends PokemonPhase { private queuedPhases: Phase[] = []; /** - * @param useType - The {@linkcode MoveUseType} corresponding to how this move was used. + * @param useMode - The {@linkcode MoveUseMode} corresponding to how this move was used. */ - constructor(battlerIndex: BattlerIndex, targets: BattlerIndex[], move: Move, useType: MoveUseType) { + constructor(battlerIndex: BattlerIndex, targets: BattlerIndex[], move: Move, useMode: MoveUseMode) { super(battlerIndex); this.move = move; - this.useType = useType; + this.useMode = useMode; /** * In double battles, if the right Pokemon selects a spread move and the left Pokemon dies @@ -201,7 +201,7 @@ export class MoveEffectPhase extends PokemonPhase { this.queuedPhases.push(new HideAbilityPhase()); } - this.queuedPhases.push(new MovePhase(target, newTargets, new PokemonMove(this.move.id), MoveUseType.REFLECTED)); + this.queuedPhases.push(new MovePhase(target, newTargets, new PokemonMove(this.move.id), MoveUseMode.REFLECTED)); } /** @@ -302,7 +302,7 @@ export class MoveEffectPhase extends PokemonPhase { this.getFirstTarget() ?? null, move, overridden, - isVirtual(this.useType), + isVirtual(this.useMode), ); // If other effects were overriden, stop this phase before they can be applied @@ -343,7 +343,7 @@ export class MoveEffectPhase extends PokemonPhase { move: this.move.id, targets: this.targets, result: MoveResult.PENDING, - useType: this.useType, + useMode: this.useMode, }; const fieldMove = isFieldTargeted(move); @@ -567,7 +567,7 @@ export class MoveEffectPhase extends PokemonPhase { } // Reflected moves cannot be reflected again - if (!isReflected(this.useType) && move.doesFlagEffectApply({ flag: MoveFlags.REFLECTABLE, user, target })) { + if (!isReflected(this.useMode) && move.doesFlagEffectApply({ flag: MoveFlags.REFLECTABLE, user, target })) { return [HitCheckResult.REFLECTED, 0]; } @@ -732,7 +732,7 @@ export class MoveEffectPhase extends PokemonPhase { /** @returns A new `MoveEffectPhase` with the same properties as this phase */ protected getNewHitPhase(): MoveEffectPhase { - return new MoveEffectPhase(this.battlerIndex, this.targets, this.move, this.useType); + return new MoveEffectPhase(this.battlerIndex, this.targets, this.move, this.useMode); } /** Removes all substitutes that were broken by this phase's invoked move */ diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index 4b0054566f2..245fca361dc 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -50,13 +50,13 @@ import { BattlerTagType } from "#enums/battler-tag-type"; import { MoveId } from "#enums/move-id"; import { StatusEffect } from "#enums/status-effect"; import i18next from "i18next"; -import { isVirtual, isIgnorePP, isReflected, MoveUseType, isIgnoreStatus } from "#enums/move-use-type"; +import { isVirtual, isIgnorePP, isReflected, MoveUseMode, isIgnoreStatus } from "#enums/move-use-mode"; export class MovePhase extends BattlePhase { protected _pokemon: Pokemon; protected _move: PokemonMove; protected _targets: BattlerIndex[]; - protected _useType: MoveUseType; + public readonly useMode: MoveUseMode; // Made public for quash protected forcedLast: boolean; /** Whether the current move should fail but still use PP */ @@ -81,14 +81,6 @@ export class MovePhase extends BattlePhase { this._move = move; } - public get useType(): MoveUseType { - return this._useType; - } - - protected set useType(useType: MoveUseType) { - this._useType = useType; - } - public get targets(): BattlerIndex[] { return this._targets; } @@ -101,17 +93,17 @@ export class MovePhase extends BattlePhase { * Create a new MovePhase for using moves. * @param pokemon - The {@linkcode Pokemon} using the move * @param move - The {@linkcode PokemonMove} to use - * @param useType - The {@linkcode MoveUseType} corresponding to this move's means of execution (usually `MoveUseType.NORMAL`). - * Not marked optional to ensure callers correctly pass on `useTypes`. + * @param useMode - The {@linkcode MoveUseMode} corresponding to this move's means of execution (usually `MoveUseMode.NORMAL`). + * Not marked optional to ensure callers correctly pass on `useModes`. * @param forcedLast - Whether to force this phase to occur last in order (for {@linkcode MoveId.QUASH}); default `false` */ - constructor(pokemon: Pokemon, targets: BattlerIndex[], move: PokemonMove, useType: MoveUseType, forcedLast = false) { + constructor(pokemon: Pokemon, targets: BattlerIndex[], move: PokemonMove, useMode: MoveUseMode, forcedLast = false) { super(); this.pokemon = pokemon; this.targets = targets; this.move = move; - this.useType = useType; + this.useMode = useMode; this.forcedLast = forcedLast; } @@ -123,7 +115,7 @@ export class MovePhase extends BattlePhase { public canMove(ignoreDisableTags = false): boolean { return ( this.pokemon.isActive(true) && - this.move.isUsable(this.pokemon, isIgnorePP(this.useType), ignoreDisableTags) && + this.move.isUsable(this.pokemon, isIgnorePP(this.useMode), ignoreDisableTags) && this.targets.length > 0 ); } @@ -149,16 +141,18 @@ export class MovePhase extends BattlePhase { public start(): void { super.start(); - console.log(MoveId[this.move.moveId], MoveUseType[this.useType]); - - if (!this.useType) { - console.warn(`Unexpected MoveUseType of ${this.useType} during move phase!`); - this.useType = MoveUseType.NORMAL; + // Cover our bases - if we have no use type + if (!this.useMode) { + console.warn(`Unexpected MoveUseMode of ${this.useMode} during move phase!`); + // @ts-expect-error - useMode is readonly and shouldn't normally be assigned to + this.useMode = MoveUseMode.NORMAL; } + console.log(MoveId[this.move.moveId], MoveUseMode[this.useMode]); + + // Check if move is unusable (e.g. running out of PP due to a mid-turn Spite + // or the user no longer being on field), ending the phase early if not. if (!this.canMove(true)) { - // Check if move is unusable (e.g. running out of PP due to a mid-turn Spite - // or the user no longer being on field). if (this.pokemon.isActive(true)) { this.fail(); this.showMoveText(); @@ -171,7 +165,7 @@ export class MovePhase extends BattlePhase { this.pokemon.turnData.acted = true; // Reset hit-related turn data when starting follow-up moves (e.g. Metronomed moves, Dancer repeats) - if (isVirtual(this.useType)) { + if (isVirtual(this.useMode)) { this.pokemon.turnData.hitsLeft = -1; this.pokemon.turnData.hitCount = 0; } @@ -181,7 +175,7 @@ export class MovePhase extends BattlePhase { this.move.getMove().doesFlagEffectApply({ flag: MoveFlags.IGNORE_ABILITIES, user: this.pokemon, - isFollowUp: isVirtual(this.useType), // Sunsteel strike and co. don't work when called indirectly + isFollowUp: isVirtual(this.useMode), // Sunsteel strike and co. don't work when called indirectly }) ) { globalScene.arena.setIgnoreAbilities(true, this.pokemon.getBattlerIndex()); @@ -234,12 +228,12 @@ export class MovePhase extends BattlePhase { */ protected resolvePreMoveStatusEffects(): void { // Skip for follow ups/reflected moves, no status condition or post turn statuses (e.g. Poison/Toxic) - if (!this.pokemon.status || this.pokemon.status?.isPostTurn() || isIgnoreStatus(this.useType)) { + if (!this.pokemon.status || this.pokemon.status?.isPostTurn() || isIgnoreStatus(this.useMode)) { return; } if ( - this.useType === MoveUseType.INDIRECT && + this.useMode === MoveUseMode.INDIRECT && [StatusEffect.SLEEP, StatusEffect.FREEZE].includes(this.pokemon.status.effect) ) { // Dancer thaws out or wakes up a frozen/sleeping user prior to use @@ -321,7 +315,7 @@ export class MovePhase extends BattlePhase { // TODO: does this intentionally happen before the no targets/MoveId.NONE on queue cancellation case is checked? // (In other words, check if truant can proc on a move w/o targets) - if (!isIgnoreStatus(this.useType) && this.canMove() && !this.cancelled) { + if (!isIgnoreStatus(this.useMode) && this.canMove() && !this.cancelled) { this.pokemon.lapseTags(BattlerTagLapseType.MOVE); } } @@ -376,12 +370,13 @@ export class MovePhase extends BattlePhase { // Clear out any two turn moves once they've been used. // TODO: Refactor move queues and remove this assignment; // Move queues should be handled by the calling `CommandPhase` or a manager for it - this.useType = moveQueue.shift()?.useType ?? this.useType; + // @ts-expect-error - useMode is readonly and shouldn't normally be assigned to + this.useMode = moveQueue.shift()?.useMode ?? this.useMode; if (this.pokemon.getTag(BattlerTagType.CHARGING)?.sourceMove === this.move.moveId) { this.pokemon.lapseTag(BattlerTagType.CHARGING); } - if (!isIgnorePP(this.useType)) { + if (!isIgnorePP(this.useMode)) { // "commit" to using the move, deducting PP. const ppUsed = 1 + this.getPpIncreaseFromPressure(targets); @@ -430,7 +425,7 @@ export class MovePhase extends BattlePhase { if (success) { const move = this.move.getMove(); applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, move); - globalScene.unshiftPhase(new MoveEffectPhase(this.pokemon.getBattlerIndex(), this.targets, move, this.useType)); + globalScene.unshiftPhase(new MoveEffectPhase(this.pokemon.getBattlerIndex(), this.targets, move, this.useMode)); } else { if ([MoveId.ROAR, MoveId.WHIRLWIND, MoveId.TRICK_OR_TREAT, MoveId.FORESTS_CURSE].includes(this.move.moveId)) { applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove()); @@ -440,7 +435,7 @@ export class MovePhase extends BattlePhase { move: this.move.moveId, targets: this.targets, result: MoveResult.FAIL, - useType: this.useType, + useMode: this.useMode, }); const failureMessage = move.getFailedText(this.pokemon, targets[0], move); @@ -460,10 +455,10 @@ export class MovePhase extends BattlePhase { } // Handle Dancer, which triggers immediately after a move is used (rather than waiting on `this.end()`). - // Note the MoveUseType check here prevents an infinite Dancer loop. + // Note the MoveUseMode check here prevents an infinite Dancer loop. if ( this.move.getMove().hasFlag(MoveFlags.DANCE_MOVE) && - ![MoveUseType.INDIRECT, MoveUseType.REFLECTED].includes(this.useType) + ![MoveUseMode.INDIRECT, MoveUseMode.REFLECTED].includes(this.useMode) ) { // TODO: Fix in dancer PR to move to MEP for hit checks globalScene.getField(true).forEach(pokemon => { @@ -486,7 +481,7 @@ export class MovePhase extends BattlePhase { move: this.move.moveId, targets: this.targets, result: MoveResult.FAIL, - useType: this.useType, + useMode: this.useMode, }); const failureMessage = move.getFailedText(this.pokemon, targets[0], move); @@ -502,7 +497,7 @@ export class MovePhase extends BattlePhase { applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove()); globalScene.unshiftPhase( - new MoveChargePhase(this.pokemon.getBattlerIndex(), this.targets[0], this.move, this.useType), + new MoveChargePhase(this.pokemon.getBattlerIndex(), this.targets[0], this.move, this.useMode), ); } @@ -511,7 +506,7 @@ export class MovePhase extends BattlePhase { */ public end(): void { globalScene.unshiftPhase( - new MoveEndPhase(this.pokemon.getBattlerIndex(), this.getActiveTargetPokemon(), isVirtual(this.useType)), + new MoveEndPhase(this.pokemon.getBattlerIndex(), this.getActiveTargetPokemon(), isVirtual(this.useMode)), ); super.end(); @@ -641,7 +636,7 @@ export class MovePhase extends BattlePhase { protected handlePreMoveFailures(): void { if (this.cancelled || this.failed) { if (this.failed) { - const ppUsed = isIgnorePP(this.useType) ? 0 : 1; + const ppUsed = isIgnorePP(this.useMode) ? 0 : 1; if (ppUsed) { this.move.usePp(); @@ -658,7 +653,7 @@ export class MovePhase extends BattlePhase { move: MoveId.NONE, result: MoveResult.FAIL, targets: this.targets, - useType: this.useType, + useMode: this.useMode, }); this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); @@ -682,7 +677,7 @@ export class MovePhase extends BattlePhase { } globalScene.queueMessage( - i18next.t(isReflected(this.useType) ? "battle:magicCoatActivated" : "battle:useMove", { + i18next.t(isReflected(this.useMode) ? "battle:magicCoatActivated" : "battle:useMove", { pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), moveName: this.move.getName(), }), diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index bc48a6f9069..e9f89a203e8 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -181,11 +181,11 @@ export class TurnStartPhase extends FieldPhase { } if (pokemon.isPlayer() && turnCommand.cursor === -1) { globalScene.pushPhase( - new MovePhase(pokemon, turnCommand.targets || turnCommand.move!.targets, move, turnCommand.move!.useType), + new MovePhase(pokemon, turnCommand.targets || turnCommand.move!.targets, move, turnCommand.move!.useMode), ); //TODO: is the bang correct here? } else { globalScene.pushPhase( - new MovePhase(pokemon, turnCommand.targets || turnCommand.move!.targets, move, queuedMove.useType), + new MovePhase(pokemon, turnCommand.targets || turnCommand.move!.targets, move, queuedMove.useMode), ); // TODO: is the bang correct here? } break; diff --git a/src/system/version_migration/versions/v1_10_0.ts b/src/system/version_migration/versions/v1_10_0.ts index d1e3e559e58..52b27c94e53 100644 --- a/src/system/version_migration/versions/v1_10_0.ts +++ b/src/system/version_migration/versions/v1_10_0.ts @@ -2,7 +2,7 @@ import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator"; import type { BattlerIndex } from "#app/battle"; import type { MoveResult, TurnMove } from "#app/field/pokemon"; import type { SessionSaveData } from "#app/system/game-data"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; import type { MoveId } from "#enums/move-id"; /** Prior signature of `TurnMove`; used to ensure parity */ @@ -16,7 +16,7 @@ interface OldTurnMove { } /** - * Fix player pokemon move history entries with updated `MoveUseTypes`, + * Fix player pokemon move history entries with updated `MoveUseModes`, * based on the prior values of `virtual` and `ignorePP`. * Needed to ensure Last Resort and move-calling moves still work OK. * @param data - {@linkcode SystemSaveData} @@ -31,7 +31,7 @@ const fixMoveHistory: SessionSaveMigrator = { turn: tm.turn, // NOTE: This unfortuately has to mis-classify Dancer and Magic Bounce-induced moves as `FOLLOW_UP`, // given we previously had _no way_ of distinguishing them from follow-up moves post hoc. - useType: tm.virtual ? MoveUseType.FOLLOW_UP : tm.ignorePP ? MoveUseType.IGNORE_PP : MoveUseType.NORMAL, + useMode: tm.virtual ? MoveUseMode.FOLLOW_UP : tm.ignorePP ? MoveUseMode.IGNORE_PP : MoveUseMode.NORMAL, }); data.party.forEach(pkmn => { pkmn.summonData.moveHistory = (pkmn.summonData.moveHistory as OldTurnMove[]).map(mapTurnMove); diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index c2184fe522c..4674e0aa6e6 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -15,7 +15,7 @@ import type Pokemon from "#app/field/pokemon"; import type { CommandPhase } from "#app/phases/command-phase"; import MoveInfoOverlay from "./move-info-overlay"; import { BattleType } from "#enums/battle-type"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; export default class FightUiHandler extends UiHandler implements InfoToggle { public static readonly MOVES_CONTAINER_NAME = "moves"; @@ -154,7 +154,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { { // Attempts to back out of the move selection pane are blocked in certain MEs const { battleType, mysteryEncounter } = globalScene.currentBattle; - if (battleType === BattleType.MYSTERY_ENCOUNTER || !mysteryEncounter?.skipToFightInput) { + if (battleType !== BattleType.MYSTERY_ENCOUNTER || !mysteryEncounter?.skipToFightInput) { ui.setMode(UiMode.COMMAND, this.fieldIndex); success = true; } @@ -162,7 +162,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle { break; case Button.ACTION: if ( - (globalScene.getCurrentPhase() as CommandPhase).handleCommand(this.fromCommand, cursor, MoveUseType.NORMAL) + (globalScene.getCurrentPhase() as CommandPhase).handleCommand(this.fromCommand, cursor, MoveUseMode.NORMAL) ) { success = true; } else { diff --git a/test/moves/after_you.test.ts b/test/moves/after_you.test.ts index 8ae106db86e..52a1a1b4e71 100644 --- a/test/moves/after_you.test.ts +++ b/test/moves/after_you.test.ts @@ -2,7 +2,7 @@ import { BattlerIndex } from "#app/battle"; import { AbilityId } from "#enums/ability-id"; import { MoveResult } from "#app/field/pokemon"; import { MovePhase } from "#app/phases/move-phase"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import GameManager from "#test/testUtils/gameManager"; @@ -63,7 +63,7 @@ describe("Moves - After You", () => { }); // TODO: Enable once rampaging moves and move queue are fixed. - // Currently does literally nothing because `MoveUseType` is overridden from move queue + // Currently does literally nothing because `MoveUseMode` is overridden from move queue // within `MovePhase`, but should be enabled once that jank is removed it.todo("should maintain PP ignore status of rampaging moves", async () => { game.override.moveset([]); @@ -91,7 +91,7 @@ describe("Moves - After You", () => { expect(rattata.getLastXMoves()[0]).toMatchObject({ move: MoveId.OUTRAGE, result: MoveResult.SUCCESS, - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }); }); }); diff --git a/test/moves/copycat.test.ts b/test/moves/copycat.test.ts index 5040b72c033..5b3920bfd0b 100644 --- a/test/moves/copycat.test.ts +++ b/test/moves/copycat.test.ts @@ -3,7 +3,7 @@ import { RandomMoveAttr } from "#app/data/moves/move"; import { Stat } from "#app/enums/stat"; import { MoveResult } from "#app/field/pokemon"; import { AbilityId } from "#enums/ability-id"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import GameManager from "#test/testUtils/gameManager"; @@ -75,7 +75,7 @@ describe("Moves - Copycat", () => { expect(enemy.getLastXMoves()[0]).toMatchObject({ move: MoveId.SWORDS_DANCE, result: MoveResult.SUCCESS, - useType: MoveUseType.FOLLOW_UP, + useMode: MoveUseMode.FOLLOW_UP, }); expect(enemy.getStatStage(Stat.ATK)).toBe(2); }); diff --git a/test/moves/dig.test.ts b/test/moves/dig.test.ts index 4be7cbfe143..51d5f459bca 100644 --- a/test/moves/dig.test.ts +++ b/test/moves/dig.test.ts @@ -57,7 +57,8 @@ describe("Moves - Dig", () => { expect(playerPokemon.getMoveHistory()).toHaveLength(2); }); - it("should deduct PP only on the 2nd turn of the move", async () => { + // TODO: Verify this on cartridge double battles + it.todo("should deduct PP only on the 2nd turn of the move", async () => { game.override.moveset([]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]); diff --git a/test/moves/disable.test.ts b/test/moves/disable.test.ts index 1cace6a7f86..e5dd45e8c48 100644 --- a/test/moves/disable.test.ts +++ b/test/moves/disable.test.ts @@ -1,12 +1,13 @@ import { BattlerIndex } from "#app/battle"; import { MoveResult } from "#app/field/pokemon"; import { AbilityId } from "#enums/ability-id"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import { Stat } from "#enums/stat"; import GameManager from "#test/testUtils/gameManager"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { RandomMoveAttr } from "#app/data/moves/move"; describe("Moves - Disable", () => { let phaserGame: Phaser.Game; @@ -110,7 +111,7 @@ describe("Moves - Disable", () => { enemyMon.pushMoveHistory({ move: MoveId.SPLASH, targets: [BattlerIndex.ENEMY], - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }); game.move.select(MoveId.DISABLE); @@ -128,11 +129,11 @@ describe("Moves - Disable", () => { { name: "Copycat", moveId: MoveId.COPYCAT }, { name: "Metronome", moveId: MoveId.METRONOME }, ])("should ignore virtual moves called by $name", async ({ moveId }) => { - game.override.enemyMoveset(moveId); + vi.spyOn(RandomMoveAttr.prototype, "getMoveOverride").mockReturnValue(MoveId.ABSORB); await game.classicMode.startBattle([SpeciesId.PIKACHU]); const playerMon = game.scene.getPlayerPokemon()!; - playerMon.pushMoveHistory({ move: MoveId.SPLASH, targets: [BattlerIndex.ENEMY], useType: MoveUseType.NORMAL }); + playerMon.pushMoveHistory({ move: MoveId.SPLASH, targets: [BattlerIndex.ENEMY], useMode: MoveUseMode.NORMAL }); game.scene.currentBattle.lastMove = MoveId.SPLASH; game.move.select(MoveId.DISABLE); @@ -150,7 +151,6 @@ describe("Moves - Disable", () => { ).toBe(false); }); - it("should ignore dancer copied moves, even if also in moveset", async () => { game.override .enemyAbility(AbilityId.DANCER) diff --git a/test/moves/instruct.test.ts b/test/moves/instruct.test.ts index 534d0ff386e..e1dfc20ee48 100644 --- a/test/moves/instruct.test.ts +++ b/test/moves/instruct.test.ts @@ -4,7 +4,7 @@ import type Pokemon from "#app/field/pokemon"; import { MoveResult } from "#app/field/pokemon"; import type { MovePhase } from "#app/phases/move-phase"; import { AbilityId } from "#enums/ability-id"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import GameManager from "#test/testUtils/gameManager"; @@ -250,7 +250,7 @@ describe("Moves - Instruct", () => { move: MoveId.SEED_BOMB, targets: [BattlerIndex.ENEMY], result: MoveResult.SUCCESS, - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }); game.doSwitchPokemon(1); @@ -316,7 +316,7 @@ describe("Moves - Instruct", () => { move: MoveId.SONIC_BOOM, targets: [BattlerIndex.PLAYER], result: MoveResult.SUCCESS, - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }); game.move.select(MoveId.INSTRUCT); @@ -343,7 +343,7 @@ describe("Moves - Instruct", () => { move: MoveId.ELECTRO_DRIFT, targets: [BattlerIndex.PLAYER], result: MoveResult.SUCCESS, - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }); game.move.select(MoveId.SPLASH); @@ -361,7 +361,7 @@ describe("Moves - Instruct", () => { move: MoveId.WHIRLWIND, targets: [BattlerIndex.PLAYER], result: MoveResult.SUCCESS, - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }); game.move.select(MoveId.INSTRUCT); @@ -417,7 +417,7 @@ describe("Moves - Instruct", () => { move: MoveId.VINE_WHIP, targets: [BattlerIndex.ENEMY], result: MoveResult.SUCCESS, - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }); // Attempt to instruct banette after having been sent airborne @@ -453,7 +453,7 @@ describe("Moves - Instruct", () => { move: MoveId.VINE_WHIP, targets: [BattlerIndex.ENEMY], result: MoveResult.SUCCESS, - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }); game.move.select(MoveId.VINE_WHIP, BattlerIndex.PLAYER); diff --git a/test/moves/last-resort.test.ts b/test/moves/last-resort.test.ts index 6b532393456..acbdf499802 100644 --- a/test/moves/last-resort.test.ts +++ b/test/moves/last-resort.test.ts @@ -1,7 +1,7 @@ import { BattlerIndex } from "#app/battle"; import { MoveResult } from "#app/field/pokemon"; import { AbilityId } from "#enums/ability-id"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import GameManager from "#test/testUtils/gameManager"; @@ -54,19 +54,19 @@ describe("Moves - Last Resort", () => { expectLastResortFail(); // Splash (1/3) - blissey.pushMoveHistory({ move: MoveId.SPLASH, targets: [BattlerIndex.PLAYER], useType: MoveUseType.NORMAL }); + blissey.pushMoveHistory({ move: MoveId.SPLASH, targets: [BattlerIndex.PLAYER], useMode: MoveUseMode.NORMAL }); game.move.select(MoveId.LAST_RESORT); await game.phaseInterceptor.to("TurnEndPhase"); expectLastResortFail(); // Growl (2/3) - blissey.pushMoveHistory({ move: MoveId.GROWL, targets: [BattlerIndex.ENEMY], useType: MoveUseType.NORMAL }); + blissey.pushMoveHistory({ move: MoveId.GROWL, targets: [BattlerIndex.ENEMY], useMode: MoveUseMode.NORMAL }); game.move.select(MoveId.LAST_RESORT); await game.phaseInterceptor.to("TurnEndPhase"); expectLastResortFail(); // Were last resort itself counted, it would error here // Growth (3/3) - blissey.pushMoveHistory({ move: MoveId.GROWTH, targets: [BattlerIndex.PLAYER], useType: MoveUseType.NORMAL }); + blissey.pushMoveHistory({ move: MoveId.GROWTH, targets: [BattlerIndex.PLAYER], useMode: MoveUseMode.NORMAL }); game.move.select(MoveId.LAST_RESORT); await game.phaseInterceptor.to("TurnEndPhase"); expect(game.scene.getPlayerPokemon()?.getLastXMoves()[0]).toEqual( @@ -118,12 +118,12 @@ describe("Moves - Last Resort", () => { expect.objectContaining({ move: MoveId.LAST_RESORT, result: MoveResult.SUCCESS, - useType: MoveUseType.FOLLOW_UP, + useMode: MoveUseMode.FOLLOW_UP, }), expect.objectContaining({ move: MoveId.SLEEP_TALK, result: MoveResult.SUCCESS, - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }), ]); }); diff --git a/test/moves/metronome.test.ts b/test/moves/metronome.test.ts index 13fb57f8ee5..7a0591ea419 100644 --- a/test/moves/metronome.test.ts +++ b/test/moves/metronome.test.ts @@ -7,7 +7,7 @@ import { Stat } from "#app/enums/stat"; import { MoveResult } from "#app/field/pokemon"; import { CommandPhase } from "#app/phases/command-phase"; import { BattlerTagType } from "#enums/battler-tag-type"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import GameManager from "#test/testUtils/gameManager"; @@ -113,7 +113,7 @@ describe("Moves - Metronome", () => { expect(player.getLastXMoves()[0]).toMatchObject({ move: MoveId.SOLAR_BEAM, result: MoveResult.SUCCESS, - useType: MoveUseType.FOLLOW_UP, + useMode: MoveUseMode.FOLLOW_UP, }); }); diff --git a/test/moves/quash.test.ts b/test/moves/quash.test.ts index da602f071b5..609bb07a420 100644 --- a/test/moves/quash.test.ts +++ b/test/moves/quash.test.ts @@ -7,7 +7,7 @@ import { MoveResult } from "#app/field/pokemon"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { describe, beforeAll, afterEach, beforeEach, it, expect } from "vitest"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; describe("Moves - Quash", () => { let phaserGame: Phaser.Game; @@ -60,7 +60,7 @@ describe("Moves - Quash", () => { }); // TODO: Enable once rampaging moves and move queue are fixed. - // Currently does literally nothing because `MoveUseType` is overridden from move queue + // Currently does literally nothing because `MoveUseMode` is overridden from move queue // within `MovePhase`, but should be enabled once that jank is removed it.todo("should maintain PP ignore status of rampaging moves", async () => { game.override.moveset([]); @@ -88,7 +88,7 @@ describe("Moves - Quash", () => { expect(rattata.getLastXMoves()[0]).toMatchObject({ move: MoveId.OUTRAGE, result: MoveResult.SUCCESS, - useType: MoveUseType.IGNORE_PP, + useMode: MoveUseMode.IGNORE_PP, }); }); diff --git a/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts b/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts index 9c305f14ea4..238b82c8be0 100644 --- a/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts +++ b/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts @@ -24,7 +24,7 @@ import { FunAndGamesEncounter } from "#app/data/mystery-encounters/encounters/fu import { MoveId } from "#enums/move-id"; import { Command } from "#app/ui/command-ui-handler"; import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; const namespace = "mysteryEncounters/funAndGames"; const defaultParty = [SpeciesId.LAPRAS, SpeciesId.GENGAR, SpeciesId.ABRA]; @@ -155,15 +155,15 @@ describe("Fun And Games! - Mystery Encounter", () => { }); // Turn 1 - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseType.NORMAL); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseMode.NORMAL); await game.phaseInterceptor.to(CommandPhase); // Turn 2 - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseType.NORMAL); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseMode.NORMAL); await game.phaseInterceptor.to(CommandPhase); // Turn 3 - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseType.NORMAL); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseMode.NORMAL); await game.phaseInterceptor.to(SelectModifierPhase, false); // Rewards @@ -182,7 +182,7 @@ describe("Fun And Games! - Mystery Encounter", () => { // Skip minigame scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0; - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseType.NORMAL); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseMode.NORMAL); await game.phaseInterceptor.to(SelectModifierPhase, false); // Rewards @@ -211,7 +211,7 @@ describe("Fun And Games! - Mystery Encounter", () => { const wobbuffet = scene.getEnemyPokemon()!; wobbuffet.hp = Math.floor(0.2 * wobbuffet.getMaxHp()); scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0; - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseType.NORMAL); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseMode.NORMAL); await game.phaseInterceptor.to(SelectModifierPhase, false); // Rewards @@ -241,7 +241,7 @@ describe("Fun And Games! - Mystery Encounter", () => { const wobbuffet = scene.getEnemyPokemon()!; wobbuffet.hp = Math.floor(0.1 * wobbuffet.getMaxHp()); scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0; - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseType.NORMAL); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseMode.NORMAL); await game.phaseInterceptor.to(SelectModifierPhase, false); // Rewards @@ -271,7 +271,7 @@ describe("Fun And Games! - Mystery Encounter", () => { const wobbuffet = scene.getEnemyPokemon()!; wobbuffet.hp = 1; scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0; - (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseType.NORMAL); + (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, 0, MoveUseMode.NORMAL); await game.phaseInterceptor.to(SelectModifierPhase, false); // Rewards diff --git a/test/testUtils/gameManager.ts b/test/testUtils/gameManager.ts index 4ff4940e6a7..c1217b09948 100644 --- a/test/testUtils/gameManager.ts +++ b/test/testUtils/gameManager.ts @@ -55,7 +55,6 @@ import TextInterceptor from "#test/testUtils/TextInterceptor"; import { AES, enc } from "crypto-js"; import fs from "node:fs"; import { expect, vi } from "vitest"; -import { MoveUseType } from "#enums/move-use-type"; /** * Class to manage the game state and transitions between phases. diff --git a/test/testUtils/helpers/moveHelper.ts b/test/testUtils/helpers/moveHelper.ts index c973810ff1c..75d7e04a3d7 100644 --- a/test/testUtils/helpers/moveHelper.ts +++ b/test/testUtils/helpers/moveHelper.ts @@ -12,7 +12,7 @@ import { UiMode } from "#enums/ui-mode"; import { getMovePosition } from "#test/testUtils/gameManagerUtils"; import { GameManagerHelper } from "#test/testUtils/helpers/gameManagerHelper"; import { vi } from "vitest"; -import { MoveUseType } from "#enums/move-use-type"; +import { MoveUseMode } from "#enums/move-use-mode"; /** * Helper to handle a Pokemon's move @@ -61,7 +61,7 @@ export class MoveHelper extends GameManagerHelper { (this.game.scene.getCurrentPhase() as CommandPhase).handleCommand( Command.FIGHT, movePosition, - MoveUseType.NORMAL, + MoveUseMode.NORMAL, ); }); @@ -89,7 +89,7 @@ export class MoveHelper extends GameManagerHelper { ); }); this.game.onNextPrompt("CommandPhase", UiMode.FIGHT, () => { - (this.game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.TERA, movePosition, MoveUseType.NORMAL); + (this.game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.TERA, movePosition, MoveUseMode.NORMAL); }); if (targetIndex !== null) { @@ -185,7 +185,7 @@ export class MoveHelper extends GameManagerHelper { target !== undefined && !legalTargets.multiple && legalTargets.targets.includes(target) ? [target] : enemy.getNextTargets(moveId), - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }); /** @@ -228,7 +228,7 @@ export class MoveHelper extends GameManagerHelper { target !== undefined && !legalTargets.multiple && legalTargets.targets.includes(target) ? [target] : enemy.getNextTargets(moveId), - useType: MoveUseType.NORMAL, + useMode: MoveUseMode.NORMAL, }); /**