Renamed MoveUseType to MoveUseMode; applied review comments

This commit is contained in:
Bertie690 2025-06-06 21:56:00 -04:00
parent 6c75f2429d
commit 80026590b8
34 changed files with 238 additions and 240 deletions

View File

@ -74,7 +74,7 @@ import type { BattlerIndex } from "#app/battle";
import type Move from "#app/data/moves/move"; import type Move from "#app/data/moves/move";
import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag"; import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag";
import { SelectBiomePhase } from "#app/phases/select-biome-phase"; 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"; import { noAbilityTypeOverrideMoves } from "../moves/invalid-moves";
export class BlockRecoilDamageAttr extends AbAttr { 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 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) { if (move.getMove() instanceof AttackMove || move.getMove() instanceof StatusMove) {
const target = this.getTarget(dancer, source, targets); 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) { } else if (move.getMove() instanceof SelfStatusMove) {
// If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself // 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(), .bypassFaint(),
new Ability(AbilityId.DANCER, 7) new Ability(AbilityId.DANCER, 7)
.attr(PostDancingMoveAbAttr) .attr(PostDancingMoveAbAttr)
.edgeCase(),
/* Incorrect interations with: /* Incorrect interations with:
* Petal Dance (should not lock in or count down timer; currently does both) * Petal Dance (should not lock in or count down timer; currently does both)
* Flinches (due to tag being removed earlier) * Flinches (due to tag being removed earlier)
* Failed/protected moves (should not trigger if original move is protected against) * Failed/protected moves (should not trigger if original move is protected against)
*/ */
.edgeCase(),
new Ability(AbilityId.BATTERY, 7) new Ability(AbilityId.BATTERY, 7)
.attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL ], 1.3), .attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL ], 1.3),
new Ability(AbilityId.FLUFFY, 7) 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 .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) new Ability(AbilityId.GORILLA_TACTICS, 8)
.attr(GorillaTacticsAbAttr) .attr(GorillaTacticsAbAttr)
.edgeCase(),
// TODO: Verify whether Gorilla Tactics increases struggle's power or not // TODO: Verify whether Gorilla Tactics increases struggle's power or not
.edgeCase(),
new Ability(AbilityId.NEUTRALIZING_GAS, 8) new Ability(AbilityId.NEUTRALIZING_GAS, 8)
.attr(PostSummonAddArenaTagAbAttr, true, ArenaTagType.NEUTRALIZING_GAS, 0) .attr(PostSummonAddArenaTagAbAttr, true, ArenaTagType.NEUTRALIZING_GAS, 0)
.attr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr) .attr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr)

View File

@ -30,7 +30,7 @@ import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CommonAnimPhase } from "#app/phases/common-anim-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 { export enum ArenaTagSide {
BOTH, 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 // 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) // (meaning it's never targetable by Spite)
globalScene.unshiftPhase( 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? ); // TODO: are those bangs correct?
} }

View File

@ -44,7 +44,7 @@ import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import { isNullOrUndefined } from "#app/utils/common"; 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"; import { invalidEncoreMoves } from "./moves/invalid-moves";
export enum BattlerTagLapseType { export enum BattlerTagLapseType {
@ -443,7 +443,7 @@ export class RechargingTag extends BattlerTag {
super.onAdd(pokemon); super.onAdd(pokemon);
// Queue a placeholder move for the Pokemon to "use" next turn. // 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 */ /** 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, move: MoveId.NONE,
result: MoveResult.OTHER, result: MoveResult.OTHER,
targets: [], targets: [],
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}); });
} }
@ -1175,7 +1175,7 @@ export class EncoreTag extends MoveRestrictionBattlerTag {
const lastMove = pokemon.getLastXMoves(1)[0]; const lastMove = pokemon.getLastXMoves(1)[0];
globalScene.tryReplacePhase( globalScene.tryReplacePhase(
m => m instanceof MovePhase && m.pokemon === pokemon, m => m instanceof MovePhase && m.pokemon === pokemon,
new MovePhase(pokemon, lastMove.targets ?? [], movesetMove, MoveUseType.NORMAL), new MovePhase(pokemon, lastMove.targets ?? [], movesetMove, MoveUseMode.NORMAL),
); );
} }
} }

View File

@ -123,7 +123,7 @@ import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
import { MultiHitType } from "#enums/MultiHitType"; import { MultiHitType } from "#enums/MultiHitType";
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves, invalidSketchMoves } from "./invalid-moves"; import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves, invalidSketchMoves } from "./invalid-moves";
import { SelectBiomePhase } from "#app/phases/select-biome-phase"; 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 MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean; type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean;
@ -3070,7 +3070,7 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr {
overridden.value = true; overridden.value = true;
globalScene.unshiftPhase(new MoveAnimPhase(new MoveChargeAnim(this.chargeAnim, move.id, user))); globalScene.unshiftPhase(new MoveAnimPhase(new MoveChargeAnim(this.chargeAnim, move.id, user)));
globalScene.queueMessage(this.chargeText.replace("{TARGET}", getPokemonNameWithAffix(target)).replace("{USER}", getPokemonNameWithAffix(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; const side = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
globalScene.arena.addTag(this.tagType, 3, move.id, user.id, side, false, target.getBattlerIndex()); globalScene.arena.addTag(this.tagType, 3, move.id, user.id, side, false, target.getBattlerIndex());
} else { } else {
@ -5423,7 +5423,7 @@ export class FrenzyAttr extends MoveEffectAttr {
if (!user.getTag(BattlerTagType.FRENZY) && user.getMoveQueue().length === 0) { if (!user.getTag(BattlerTagType.FRENZY) && user.getMoveQueue().length === 0) {
const turnCount = user.randBattleSeedIntRange(1, 2); // excludes initial use const turnCount = user.randBattleSeedIntRange(1, 2); // excludes initial use
for (let i = 0; i < turnCount; i++) { 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); user.addTag(BattlerTagType.FRENZY, turnCount, move.id, user.id);
} else { } else {
@ -6768,7 +6768,7 @@ class CallMoveAttr extends OverrideMoveEffectAttr {
? target.getBattlerIndex() ? target.getBattlerIndex()
: moveTargets.targets[user.randBattleSeedInt(moveTargets.targets.length)]]; : moveTargets.targets[user.randBattleSeedInt(moveTargets.targets.length)]];
globalScene.unshiftPhase(new LoadMoveAnimPhase(move.id)); 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; 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 // Load the move's animation if we didn't already and unshift a new usage phase
globalScene.unshiftPhase(new LoadMoveAnimPhase(moveId)); 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; return true;
} }
} }
@ -7083,7 +7083,7 @@ export class RepeatMoveAttr extends MoveEffectAttr {
targetPokemonName: getPokemonNameWithAffix(target) targetPokemonName: getPokemonNameWithAffix(target)
})); }));
target.turnData.extraTurns++; 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; return true;
} }
@ -7829,7 +7829,7 @@ export class LastResortAttr extends MoveAttr {
const movesInHistory = new Set<MoveId>( const movesInHistory = new Set<MoveId>(
user.getMoveHistory() 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) .map(m => m.move)
); );
@ -7913,7 +7913,7 @@ export class ForceLastAttr extends MoveEffectAttr {
globalScene.phaseQueue.splice( globalScene.phaseQueue.splice(
globalScene.phaseQueue.indexOf(prependPhase), globalScene.phaseQueue.indexOf(prependPhase),
0, 0,
new MovePhase(target, [ ...targetMovePhase.targets ], targetMovePhase.move, targetMovePhase.useType, true) new MovePhase(target, [ ...targetMovePhase.targets ], targetMovePhase.move, targetMovePhase.useMode, true)
); );
} }
} }

View File

@ -38,7 +38,7 @@ import type { BerryType } from "#enums/berry-type";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import i18next from "i18next"; import i18next from "i18next";
import { MoveUseType } from "#enums/move-use-type"; import { MoveUseMode } from "#enums/move-use-mode";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounters/absoluteAvarice"; const namespace = "mysteryEncounters/absoluteAvarice";
@ -304,7 +304,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY], targets: [BattlerIndex.ENEMY],
move: new PokemonMove(MoveId.STUFF_CHEEKS), move: new PokemonMove(MoveId.STUFF_CHEEKS),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}); });
await transitionMysteryEncounterIntroVisuals(true, true, 500); await transitionMysteryEncounterIntroVisuals(true, true, 500);

View File

@ -49,7 +49,7 @@ import { CustomPokemonData } from "#app/data/custom-pokemon-data";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { EncounterAnim } from "#enums/encounter-anims"; import { EncounterAnim } from "#enums/encounter-anims";
import { Challenges } from "#enums/challenges"; 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 */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/clowningAround"; const namespace = "mysteryEncounters/clowningAround";
@ -210,19 +210,19 @@ export const ClowningAroundEncounter: MysteryEncounter = MysteryEncounterBuilder
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY_2], targets: [BattlerIndex.ENEMY_2],
move: new PokemonMove(MoveId.ROLE_PLAY), move: new PokemonMove(MoveId.ROLE_PLAY),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.PLAYER], targets: [BattlerIndex.PLAYER],
move: new PokemonMove(MoveId.TAUNT), move: new PokemonMove(MoveId.TAUNT),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.PLAYER_2], targets: [BattlerIndex.PLAYER_2],
move: new PokemonMove(MoveId.TAUNT), move: new PokemonMove(MoveId.TAUNT),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}, },
); );

View File

@ -41,7 +41,7 @@ import { PokeballType } from "#enums/pokeball";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import i18next from "i18next"; import i18next from "i18next";
import { MoveUseType } from "#enums/move-use-type"; import { MoveUseMode } from "#enums/move-use-mode";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounters/dancingLessons"; const namespace = "mysteryEncounters/dancingLessons";
@ -217,7 +217,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [BattlerIndex.PLAYER],
move: new PokemonMove(MoveId.REVELATION_DANCE), move: new PokemonMove(MoveId.REVELATION_DANCE),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}); });
await hideOricorioPokemon(); await hideOricorioPokemon();

View File

@ -48,7 +48,7 @@ import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { Ability } from "#app/data/abilities/ability-class"; import { Ability } from "#app/data/abilities/ability-class";
import { FIRE_RESISTANT_ABILITIES } from "#app/data/mystery-encounters/requirements/requirement-groups"; 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 */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/fieryFallout"; const namespace = "mysteryEncounters/fieryFallout";
@ -195,13 +195,13 @@ export const FieryFalloutEncounter: MysteryEncounter = MysteryEncounterBuilder.w
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [BattlerIndex.PLAYER],
move: new PokemonMove(MoveId.FIRE_SPIN), move: new PokemonMove(MoveId.FIRE_SPIN),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY_2, sourceBattlerIndex: BattlerIndex.ENEMY_2,
targets: [BattlerIndex.PLAYER_2], targets: [BattlerIndex.PLAYER_2],
move: new PokemonMove(MoveId.FIRE_SPIN), move: new PokemonMove(MoveId.FIRE_SPIN),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}, },
); );
await initBattleWithEnemyConfig(globalScene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]); await initBattleWithEnemyConfig(globalScene.currentBattle.mysteryEncounter!.enemyPartyConfigs[0]);

View File

@ -31,7 +31,7 @@ import { BerryType } from "#enums/berry-type";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { CustomPokemonData } from "#app/data/custom-pokemon-data";
import { randSeedInt } from "#app/utils/common"; 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 */ /** i18n namespace for the encounter */
const namespace = "mysteryEncounters/slumberingSnorlax"; const namespace = "mysteryEncounters/slumberingSnorlax";
@ -138,7 +138,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [BattlerIndex.PLAYER],
move: new PokemonMove(MoveId.SNORE), move: new PokemonMove(MoveId.SNORE),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}); });
await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]); await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]);
}, },

View File

@ -29,7 +29,7 @@ import { CustomPokemonData } from "#app/data/custom-pokemon-data";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; 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 */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/theStrongStuff"; const namespace = "mysteryEncounters/theStrongStuff";
@ -212,13 +212,13 @@ export const TheStrongStuffEncounter: MysteryEncounter = MysteryEncounterBuilder
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [BattlerIndex.PLAYER],
move: new PokemonMove(MoveId.GASTRO_ACID), move: new PokemonMove(MoveId.GASTRO_ACID),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [BattlerIndex.PLAYER],
move: new PokemonMove(MoveId.STEALTH_ROCK), move: new PokemonMove(MoveId.STEALTH_ROCK),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}, },
); );

View File

@ -28,7 +28,7 @@ import { BattlerIndex } from "#app/battle";
import { PokemonMove } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { randSeedInt } from "#app/utils/common"; 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 */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounters/trashToTreasure"; const namespace = "mysteryEncounters/trashToTreasure";
@ -208,13 +208,13 @@ export const TrashToTreasureEncounter: MysteryEncounter = MysteryEncounterBuilde
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.PLAYER], targets: [BattlerIndex.PLAYER],
move: new PokemonMove(MoveId.TOXIC), move: new PokemonMove(MoveId.TOXIC),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}, },
{ {
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY], targets: [BattlerIndex.ENEMY],
move: new PokemonMove(MoveId.STOCKPILE), move: new PokemonMove(MoveId.STOCKPILE),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}, },
); );
await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]); await initBattleWithEnemyConfig(encounter.enemyPartyConfigs[0]);

View File

@ -38,7 +38,7 @@ import { BerryModifier } from "#app/modifier/modifier";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; 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 */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/uncommonBreed"; const namespace = "mysteryEncounters/uncommonBreed";
@ -179,7 +179,7 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
sourceBattlerIndex: BattlerIndex.ENEMY, sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [target], targets: [target],
move: pokemonMove, move: pokemonMove,
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}); });
} }

View File

@ -28,14 +28,14 @@ import type { GameModes } from "#app/game-mode";
import type { EncounterAnim } from "#enums/encounter-anims"; import type { EncounterAnim } from "#enums/encounter-anims";
import type { Challenges } from "#enums/challenges"; import type { Challenges } from "#enums/challenges";
import { globalScene } from "#app/global-scene"; 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 { export interface EncounterStartOfBattleEffect {
sourcePokemon?: Pokemon; sourcePokemon?: Pokemon;
sourceBattlerIndex?: BattlerIndex; sourceBattlerIndex?: BattlerIndex;
targets: BattlerIndex[]; targets: BattlerIndex[];
move: PokemonMove; 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; const DEFAULT_MAX_ALLOWED_ENCOUNTERS = 2;

View File

@ -987,7 +987,7 @@ export function handleMysteryEncounterBattleStartEffects() {
effects.forEach(effect => { effects.forEach(effect => {
const source: EnemyPokemon | Pokemon = const source: EnemyPokemon | Pokemon =
effect.sourcePokemon ?? globalScene.getField()[effect.sourceBattlerIndex ?? 0]; 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. // Pseudo turn end phase to reset flinch states, Endure, etc.

View File

@ -2,16 +2,16 @@ import type { PostDancingMoveAbAttr } from "#app/data/abilities/ability";
import type { BattlerTagLapseType } from "#app/data/battler-tags"; 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. * 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_. * 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 * instead using the available helper functions
* ({@linkcode isVirtual}, {@linkcode isIgnoreStatus}, {@linkcode isIgnorePP} and {@linkcode isReflected}). * ({@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. * 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. * 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). * 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 * PP-ignoring moves (as their name implies) **do not consume PP** when used
* and **will not fail** if none is left prior to execution. * 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). * PP can still be reduced by other effects (such as Spite or Eerie Spell).
*/ */
IGNORE_PP = 2, 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. * 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}. * 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). * 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 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_). * They still respect the user's volatile status conditions and confusion (though will uniquely _cure freeze and sleep before use_).
*/ */
INDIRECT = 3, 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** * 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). * (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. * but still inherit the former's disregard for moveset-related effects.
*/ */
FOLLOW_UP = 4, FOLLOW_UP = 4,
@ -55,92 +55,93 @@ export enum MoveUseType {
/** /**
* This move was reflected by Magic Coat or Magic Bounce. * This move was reflected by Magic Coat or Magic Bounce.
* Reflected moves ignore all the same cancellation checks as {@linkcode MoveUseType.INDIRECT} * Reflected moves ignore all the same cancellation checks as {@linkcode MoveUseMode.INDIRECT}
* and retain the same copy prevention as {@linkcode MoveUseType.FOLLOW_UP}, but additionally * and retain the same copy prevention as {@linkcode MoveUseMode.FOLLOW_UP}, but additionally
* **cannot be reflected by other reflecting effects**. * **cannot be reflected by other reflecting effects**.
*/ */
REFLECTED = 5 REFLECTED = 5
// TODO: Add use type TRANSPARENT for Future Sight and Doom Desire to prevent move history pushing
} }
// # HELPER FUNCTIONS // # 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). * 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 and pre-move cancellation checks. * Virtual moves are ignored by most moveset-related effects due to not being executed directly.
* @param useType - The {@linkcode MoveUseType} to check. * @returns Whether {@linkcode useMode} is virtual.
* @returns Whether {@linkcode useType} is virtual.
* @remarks * @remarks
* This function is equivalent to the following truth table: * This function is equivalent to the following truth table:
* *
* | Use Type | Returns | * | Use Type | Returns |
* |------------------------------------|---------| * |------------------------------------|---------|
* | {@linkcode MoveUseType.NORMAL} | `false` | * | {@linkcode MoveUseMode.NORMAL} | `false` |
* | {@linkcode MoveUseType.IGNORE_PP} | `false` | * | {@linkcode MoveUseMode.IGNORE_PP} | `false` |
* | {@linkcode MoveUseType.INDIRECT} | `true` | * | {@linkcode MoveUseMode.INDIRECT} | `true` |
* | {@linkcode MoveUseType.FOLLOW_UP} | `true` | * | {@linkcode MoveUseMode.FOLLOW_UP} | `true` |
* | {@linkcode MoveUseType.REFLECTED} | `true` | * | {@linkcode MoveUseMode.REFLECTED} | `true` |
*/ */
export function isVirtual(useType: MoveUseType): boolean { export function isVirtual(useMode: MoveUseMode): boolean {
return useType >= MoveUseType.INDIRECT return useMode >= MoveUseMode.INDIRECT
} }
/** /**
* Check if a given {@linkcode MoveUseType} should ignore pre-move cancellation checks. * Check if a given {@linkcode MoveUseMode} should ignore pre-move cancellation checks
* @param useType - The {@linkcode MoveUseType} to check. * from {@linkcode StatusEffect.PARALYSIS} and {@linkcode BattlerTagLapseType.MOVE}-type effects.
* @returns Whether {@linkcode useType} should ignore status checks. * @param useMode - The {@linkcode MoveUseMode} to check.
* @returns Whether {@linkcode useMode} should ignore status and otehr cancellation checks.
* @remarks * @remarks
* This function is equivalent to the following truth table: * This function is equivalent to the following truth table:
* *
* | Use Type | Returns | * | Use Type | Returns |
* |------------------------------------|---------| * |------------------------------------|---------|
* | {@linkcode MoveUseType.NORMAL} | `false` | * | {@linkcode MoveUseMode.NORMAL} | `false` |
* | {@linkcode MoveUseType.IGNORE_PP} | `false` | * | {@linkcode MoveUseMode.IGNORE_PP} | `false` |
* | {@linkcode MoveUseType.INDIRECT} | `false` | * | {@linkcode MoveUseMode.INDIRECT} | `false` |
* | {@linkcode MoveUseType.FOLLOW_UP} | `true` | * | {@linkcode MoveUseMode.FOLLOW_UP} | `true` |
* | {@linkcode MoveUseType.REFLECTED} | `true` | * | {@linkcode MoveUseMode.REFLECTED} | `true` |
*/ */
export function isIgnoreStatus(useType: MoveUseType): boolean { export function isIgnoreStatus(useMode: MoveUseMode): boolean {
return useType >= MoveUseType.FOLLOW_UP; 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. * PP-ignoring moves will ignore normal PP consumption as well as associated failure checks.
* @param useType - The {@linkcode MoveUseType} to check. * @param useMode - The {@linkcode MoveUseMode} to check.
* @returns Whether {@linkcode useType} ignores PP. * @returns Whether {@linkcode useMode} ignores PP.
* @remarks * @remarks
* This function is equivalent to the following truth table: * This function is equivalent to the following truth table:
* *
* | Use Type | Returns | * | Use Type | Returns |
* |------------------------------------|---------| * |------------------------------------|---------|
* | {@linkcode MoveUseType.NORMAL} | `false` | * | {@linkcode MoveUseMode.NORMAL} | `false` |
* | {@linkcode MoveUseType.IGNORE_PP} | `true` | * | {@linkcode MoveUseMode.IGNORE_PP} | `true` |
* | {@linkcode MoveUseType.INDIRECT} | `true` | * | {@linkcode MoveUseMode.INDIRECT} | `true` |
* | {@linkcode MoveUseType.FOLLOW_UP} | `true` | * | {@linkcode MoveUseMode.FOLLOW_UP} | `true` |
* | {@linkcode MoveUseType.REFLECTED} | `true` | * | {@linkcode MoveUseMode.REFLECTED} | `true` |
*/ */
export function isIgnorePP(useType: MoveUseType): boolean { export function isIgnorePP(useMode: MoveUseMode): boolean {
return useType >= MoveUseType.IGNORE_PP; 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, * Reflected moves cannot be reflected, copied, or cancelled by status effects,
* nor will they trigger {@linkcode PostDancingMoveAbAttr | Dancer}. * nor will they trigger {@linkcode PostDancingMoveAbAttr | Dancer}.
* @param useType - The {@linkcode MoveUseType} to check. * @param useMode - The {@linkcode MoveUseMode} to check.
* @returns Whether {@linkcode useType} is reflected. * @returns Whether {@linkcode useMode} is reflected.
* @remarks * @remarks
* This function is equivalent to the following truth table: * This function is equivalent to the following truth table:
* *
* | Use Type | Returns | * | Use Type | Returns |
* |------------------------------------|---------| * |------------------------------------|---------|
* | {@linkcode MoveUseType.NORMAL} | `false` | * | {@linkcode MoveUseMode.NORMAL} | `false` |
* | {@linkcode MoveUseType.IGNORE_PP} | `false` | * | {@linkcode MoveUseMode.IGNORE_PP} | `false` |
* | {@linkcode MoveUseType.INDIRECT} | `false` | * | {@linkcode MoveUseMode.INDIRECT} | `false` |
* | {@linkcode MoveUseType.FOLLOW_UP} | `false` | * | {@linkcode MoveUseMode.FOLLOW_UP} | `false` |
* | {@linkcode MoveUseType.REFLECTED} | `true` | * | {@linkcode MoveUseMode.REFLECTED} | `true` |
*/ */
export function isReflected(useType: MoveUseType): boolean { export function isReflected(useMode: MoveUseMode): boolean {
return useType === MoveUseType.REFLECTED; return useMode === MoveUseMode.REFLECTED;
} }

View File

@ -256,7 +256,7 @@ import { MoveFlags } from "#enums/MoveFlags";
import { timedEventManager } from "#app/global-event-manager"; import { timedEventManager } from "#app/global-event-manager";
import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader"; import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader";
import { ResetStatusPhase } from "#app/phases/reset-status-phase"; 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 { export enum LearnMoveSituation {
MISC, 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: * Return the most recently executed {@linkcode TurnMove} this {@linkcode Pokemon} has used that is:
* - Not {@linkcode MoveId.NONE} * - 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 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`. * (e.g. ones called by Copycat/Mirror Move); default `true`.
* @returns The last move this Pokemon has used satisfying the aforementioned conditions, * @returns The last move this Pokemon has used satisfying the aforementioned conditions,
* or `undefined` if no applicable moves have been used since switching in. * 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 =>
m.move !== MoveId.NONE && m.move !== MoveId.NONE &&
(!ignoreStruggle || m.move !== MoveId.STRUGGLE) && (!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 // TODO: split this up and move it elsewhere
getNextMove(): TurnMove { 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(); const moveQueue = this.getMoveQueue();
for (const [i, queuedMove] of moveQueue.entries()) { 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. // If the queued move was called indirectly, ignore all PP and usability checks.
// Otherwise, ensure that the move being used is actually usable // Otherwise, ensure that the move being used is actually usable & in our moveset.
// TODO: Virtual moves shouldn't use the move queue // TODO: What should happen if a pokemon forgets a charging move mid-use?
if ( if (isVirtual(queuedMove.useMode) || movesetMove?.isUsable(this, isIgnorePP(queuedMove.useMode))) {
isVirtual(queuedMove.useType) || moveQueue.splice(0, i); // TODO: This should not be done here
(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
return queuedMove; 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 // Filter out any moves this Pokemon cannot use
let movePool = this.getMoveset().filter(m => m.isUsable(this)); let movePool = this.getMoveset().filter(m => m.isUsable(this));
// If no moves are left, use Struggle. Otherwise, continue with move selection // If no moves are left, use Struggle. Otherwise, continue with move selection
@ -6262,7 +6263,7 @@ export class EnemyPokemon extends Pokemon {
return { return {
move: movePool[0].moveId, move: movePool[0].moveId,
targets: this.getNextTargets(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. // If a move is forced because of Encore, use it.
@ -6274,7 +6275,7 @@ export class EnemyPokemon extends Pokemon {
return { return {
move: encoreMove.moveId, move: encoreMove.moveId,
targets: this.getNextTargets(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 // No enemy should spawn with this AI type in-game
case AiType.RANDOM: { case AiType.RANDOM: {
const moveId = movePool[globalScene.randBattleSeedInt(movePool.length)].moveId; 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_RANDOM:
case AiType.SMART: { case AiType.SMART: {
@ -6454,7 +6455,7 @@ export class EnemyPokemon extends Pokemon {
return { return {
move: sortedMovePool[r]!.moveId, move: sortedMovePool[r]!.moveId,
targets: moveTargets[sortedMovePool[r]!.moveId], targets: moveTargets[sortedMovePool[r]!.moveId],
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}; };
} }
} }
@ -6464,7 +6465,7 @@ export class EnemyPokemon extends Pokemon {
return { return {
move: MoveId.STRUGGLE, move: MoveId.STRUGGLE,
targets: this.getNextTargets(MoveId.STRUGGLE), targets: this.getNextTargets(MoveId.STRUGGLE),
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}; };
} }
@ -6800,7 +6801,7 @@ interface IllusionData {
export interface TurnMove { export interface TurnMove {
move: MoveId; move: MoveId;
targets: BattlerIndex[]; targets: BattlerIndex[];
useType: MoveUseType; useMode: MoveUseMode;
result?: MoveResult; result?: MoveResult;
turn?: number; turn?: number;
} }
@ -6825,7 +6826,7 @@ export class PokemonSummonData {
* A queue of moves yet to be executed, used by charging, recharging and frenzy moves. * 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 * So long as this array is nonempty, this Pokemon's corresponding `CommandPhase` will be skipped over entirely
* in favor of using the queued move. * 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 moveQueue: TurnMove[] = [];
public tags: BattlerTag[] = []; public tags: BattlerTag[] = [];

View File

@ -23,7 +23,7 @@ import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import { isNullOrUndefined } from "#app/utils/common"; import { isNullOrUndefined } from "#app/utils/common";
import { ArenaTagSide } from "#app/data/arena-tag"; import { ArenaTagSide } from "#app/data/arena-tag";
import { ArenaTagType } from "#app/enums/arena-tag-type"; 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 { export class CommandPhase extends FieldPhase {
protected fieldIndex: number; protected fieldIndex: number;
@ -81,7 +81,7 @@ export class CommandPhase extends FieldPhase {
) { ) {
globalScene.currentBattle.turnCommands[this.fieldIndex] = { globalScene.currentBattle.turnCommands[this.fieldIndex] = {
command: Command.FIGHT, command: Command.FIGHT,
move: { move: MoveId.NONE, targets: [], useType: MoveUseType.NORMAL }, move: { move: MoveId.NONE, targets: [], useMode: MoveUseMode.NORMAL },
skip: true, skip: true,
}; };
} }
@ -104,13 +104,13 @@ export class CommandPhase extends FieldPhase {
moveQueue.length && moveQueue.length &&
moveQueue[0] && moveQueue[0] &&
moveQueue[0].move && moveQueue[0].move &&
!isVirtual(moveQueue[0].useType) && !isVirtual(moveQueue[0].useMode) &&
(!playerPokemon.getMoveset().find(m => m.moveId === moveQueue[0].move) || (!playerPokemon.getMoveset().find(m => m.moveId === moveQueue[0].move) ||
!playerPokemon !playerPokemon
.getMoveset() .getMoveset()
[playerPokemon.getMoveset().findIndex(m => m.moveId === moveQueue[0].move)].isUsable( [playerPokemon.getMoveset().findIndex(m => m.moveId === moveQueue[0].move)].isUsable(
playerPokemon, playerPokemon,
isIgnorePP(moveQueue[0].useType), isIgnorePP(moveQueue[0].useMode),
)) ))
) { ) {
moveQueue.shift(); moveQueue.shift();
@ -120,15 +120,15 @@ export class CommandPhase extends FieldPhase {
if (moveQueue.length > 0) { if (moveQueue.length > 0) {
const queuedMove = moveQueue[0]; const queuedMove = moveQueue[0];
if (!queuedMove.move) { if (!queuedMove.move) {
this.handleCommand(Command.FIGHT, -1, MoveUseType.NORMAL); this.handleCommand(Command.FIGHT, -1, MoveUseMode.NORMAL);
} else { } else {
const moveIndex = playerPokemon.getMoveset().findIndex(m => m.moveId === queuedMove.move); const moveIndex = playerPokemon.getMoveset().findIndex(m => m.moveId === queuedMove.move);
if ( if (
(moveIndex > -1 && (moveIndex > -1 &&
playerPokemon.getMoveset()[moveIndex].isUsable(playerPokemon, isIgnorePP(queuedMove.useType))) || playerPokemon.getMoveset()[moveIndex].isUsable(playerPokemon, isIgnorePP(queuedMove.useMode))) ||
isVirtual(queuedMove.useType) isVirtual(queuedMove.useMode)
) { ) {
this.handleCommand(Command.FIGHT, moveIndex, queuedMove.useType, queuedMove); this.handleCommand(Command.FIGHT, moveIndex, queuedMove.useMode, queuedMove);
} else { } else {
globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex); globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex);
} }
@ -148,21 +148,21 @@ export class CommandPhase extends FieldPhase {
/** /**
* TODO: Remove `args` and clean this thing up * 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 { handleCommand(command: Command, cursor: number, ...args: any[]): boolean {
const playerPokemon = globalScene.getPlayerField()[this.fieldIndex]; const playerPokemon = globalScene.getPlayerField()[this.fieldIndex];
let success = false; let success = false;
switch (command) { 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.TERA:
case Command.FIGHT: case Command.FIGHT:
let useStruggle = false; let useStruggle = false;
const turnMove: TurnMove | undefined = args.length === 2 ? (args[1] as TurnMove) : undefined; const turnMove: TurnMove | undefined = args.length === 2 ? (args[1] as TurnMove) : undefined;
if ( if (
cursor === -1 || 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) (useStruggle = cursor > -1 && !playerPokemon.getMoveset().filter(m => m.isUsable(playerPokemon)).length)
) { ) {
let moveId: MoveId; let moveId: MoveId;
@ -179,7 +179,7 @@ export class CommandPhase extends FieldPhase {
const turnCommand: TurnCommand = { const turnCommand: TurnCommand = {
command: Command.FIGHT, command: Command.FIGHT,
cursor: cursor, cursor: cursor,
move: { move: moveId, targets: [], useType: args[0] }, move: { move: moveId, targets: [], useMode: args[0] },
args: args, args: args,
}; };
const preTurnCommand: TurnCommand = { const preTurnCommand: TurnCommand = {

View File

@ -10,7 +10,7 @@ import { MovePhase } from "#app/phases/move-phase";
import { PokemonPhase } from "#app/phases/pokemon-phase"; import { PokemonPhase } from "#app/phases/pokemon-phase";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { MoveEndPhase } from "#app/phases/move-end-phase"; 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). * 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) */ /** The field index targeted by the move (Charging moves assume single target) */
public targetIndex: BattlerIndex; public targetIndex: BattlerIndex;
/** The {@linkcode MoveUseType} of the move that triggered the charge; passed on from move phase */ /** The {@linkcode MoveUseMode} of the move that triggered the charge; passed on from move phase */
private useType: MoveUseType; private useMode: MoveUseMode;
/** /**
* Create a new MoveChargePhase. * Create a new MoveChargePhase.
* @param battlerIndex - The {@linkcode BattlerIndex} of the user. * @param battlerIndex - The {@linkcode BattlerIndex} of the user.
* @param targetIndex - The {@linkcode BattlerIndex} of the target. * @param targetIndex - The {@linkcode BattlerIndex} of the target.
* @param move - The {@linkcode PokemonMove} being used * @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); super(battlerIndex);
this.move = move; this.move = move;
this.targetIndex = targetIndex; this.targetIndex = targetIndex;
this.useType = useType; this.useMode = useMode;
} }
public override start() { public override start() {
@ -65,6 +65,7 @@ export class MoveChargePhase extends PokemonPhase {
/** Checks the move's instant charge conditions, then ends this phase. */ /** Checks the move's instant charge conditions, then ends this phase. */
public override end() { public override end() {
const user = this.getUserPokemon(); const user = this.getUserPokemon();
// Checked for `ChargingMove` in `this.start()`
const move = this.move.getMove() as ChargingMove; const move = this.move.getMove() as ChargingMove;
const instantCharge = new BooleanHolder(false); 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. // Otherwise, add the attack portion to the user's move queue to execute next turn.
if (instantCharge.value) { if (instantCharge.value) {
globalScene.tryRemovePhase(phase => phase instanceof MoveEndPhase && phase.getPokemon() === user); 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 { } 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 // 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, move: this.move.moveId,
targets: [this.targetIndex], targets: [this.targetIndex],
result: MoveResult.OTHER, result: MoveResult.OTHER,
useType: this.useType, useMode: this.useMode,
}); });
super.end(); super.end();

View File

@ -78,14 +78,14 @@ import type Move from "#app/data/moves/move";
import { isFieldTargeted } from "#app/data/moves/move-utils"; import { isFieldTargeted } from "#app/data/moves/move-utils";
import { FaintPhase } from "./faint-phase"; import { FaintPhase } from "./faint-phase";
import { DamageAchv } from "#app/system/achv"; 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 type HitCheckEntry = [HitCheckResult, TypeDamageMultiplier];
export class MoveEffectPhase extends PokemonPhase { export class MoveEffectPhase extends PokemonPhase {
public move: Move; public move: Move;
protected targets: BattlerIndex[]; protected targets: BattlerIndex[];
protected useType: MoveUseType; protected useMode: MoveUseMode;
/** The result of the hit check against each target */ /** The result of the hit check against each target */
private hitChecks: HitCheckEntry[]; private hitChecks: HitCheckEntry[];
@ -110,12 +110,12 @@ export class MoveEffectPhase extends PokemonPhase {
private queuedPhases: Phase[] = []; 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); super(battlerIndex);
this.move = move; 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 * 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 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, this.getFirstTarget() ?? null,
move, move,
overridden, overridden,
isVirtual(this.useType), isVirtual(this.useMode),
); );
// If other effects were overriden, stop this phase before they can be applied // 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, move: this.move.id,
targets: this.targets, targets: this.targets,
result: MoveResult.PENDING, result: MoveResult.PENDING,
useType: this.useType, useMode: this.useMode,
}; };
const fieldMove = isFieldTargeted(move); const fieldMove = isFieldTargeted(move);
@ -567,7 +567,7 @@ export class MoveEffectPhase extends PokemonPhase {
} }
// Reflected moves cannot be reflected again // 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]; return [HitCheckResult.REFLECTED, 0];
} }
@ -732,7 +732,7 @@ export class MoveEffectPhase extends PokemonPhase {
/** @returns A new `MoveEffectPhase` with the same properties as this phase */ /** @returns A new `MoveEffectPhase` with the same properties as this phase */
protected getNewHitPhase(): MoveEffectPhase { 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 */ /** Removes all substitutes that were broken by this phase's invoked move */

View File

@ -50,13 +50,13 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import i18next from "i18next"; 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 { export class MovePhase extends BattlePhase {
protected _pokemon: Pokemon; protected _pokemon: Pokemon;
protected _move: PokemonMove; protected _move: PokemonMove;
protected _targets: BattlerIndex[]; protected _targets: BattlerIndex[];
protected _useType: MoveUseType; public readonly useMode: MoveUseMode; // Made public for quash
protected forcedLast: boolean; protected forcedLast: boolean;
/** Whether the current move should fail but still use PP */ /** Whether the current move should fail but still use PP */
@ -81,14 +81,6 @@ export class MovePhase extends BattlePhase {
this._move = move; this._move = move;
} }
public get useType(): MoveUseType {
return this._useType;
}
protected set useType(useType: MoveUseType) {
this._useType = useType;
}
public get targets(): BattlerIndex[] { public get targets(): BattlerIndex[] {
return this._targets; return this._targets;
} }
@ -101,17 +93,17 @@ export class MovePhase extends BattlePhase {
* Create a new MovePhase for using moves. * Create a new MovePhase for using moves.
* @param pokemon - The {@linkcode Pokemon} using the move * @param pokemon - The {@linkcode Pokemon} using the move
* @param move - The {@linkcode PokemonMove} to use * @param move - The {@linkcode PokemonMove} to use
* @param useType - The {@linkcode MoveUseType} corresponding to this move's means of execution (usually `MoveUseType.NORMAL`). * @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 `useTypes`. * 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` * @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(); super();
this.pokemon = pokemon; this.pokemon = pokemon;
this.targets = targets; this.targets = targets;
this.move = move; this.move = move;
this.useType = useType; this.useMode = useMode;
this.forcedLast = forcedLast; this.forcedLast = forcedLast;
} }
@ -123,7 +115,7 @@ export class MovePhase extends BattlePhase {
public canMove(ignoreDisableTags = false): boolean { public canMove(ignoreDisableTags = false): boolean {
return ( return (
this.pokemon.isActive(true) && 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 this.targets.length > 0
); );
} }
@ -149,16 +141,18 @@ export class MovePhase extends BattlePhase {
public start(): void { public start(): void {
super.start(); super.start();
console.log(MoveId[this.move.moveId], MoveUseType[this.useType]); // Cover our bases - if we have no use type
if (!this.useMode) {
if (!this.useType) { console.warn(`Unexpected MoveUseMode of ${this.useMode} during move phase!`);
console.warn(`Unexpected MoveUseType of ${this.useType} during move phase!`); // @ts-expect-error - useMode is readonly and shouldn't normally be assigned to
this.useType = MoveUseType.NORMAL; 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)) { 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)) { if (this.pokemon.isActive(true)) {
this.fail(); this.fail();
this.showMoveText(); this.showMoveText();
@ -171,7 +165,7 @@ export class MovePhase extends BattlePhase {
this.pokemon.turnData.acted = true; this.pokemon.turnData.acted = true;
// Reset hit-related turn data when starting follow-up moves (e.g. Metronomed moves, Dancer repeats) // 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.hitsLeft = -1;
this.pokemon.turnData.hitCount = 0; this.pokemon.turnData.hitCount = 0;
} }
@ -181,7 +175,7 @@ export class MovePhase extends BattlePhase {
this.move.getMove().doesFlagEffectApply({ this.move.getMove().doesFlagEffectApply({
flag: MoveFlags.IGNORE_ABILITIES, flag: MoveFlags.IGNORE_ABILITIES,
user: this.pokemon, 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()); globalScene.arena.setIgnoreAbilities(true, this.pokemon.getBattlerIndex());
@ -234,12 +228,12 @@ export class MovePhase extends BattlePhase {
*/ */
protected resolvePreMoveStatusEffects(): void { protected resolvePreMoveStatusEffects(): void {
// Skip for follow ups/reflected moves, no status condition or post turn statuses (e.g. Poison/Toxic) // 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; return;
} }
if ( if (
this.useType === MoveUseType.INDIRECT && this.useMode === MoveUseMode.INDIRECT &&
[StatusEffect.SLEEP, StatusEffect.FREEZE].includes(this.pokemon.status.effect) [StatusEffect.SLEEP, StatusEffect.FREEZE].includes(this.pokemon.status.effect)
) { ) {
// Dancer thaws out or wakes up a frozen/sleeping user prior to use // 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? // 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) // (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); 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. // Clear out any two turn moves once they've been used.
// TODO: Refactor move queues and remove this assignment; // TODO: Refactor move queues and remove this assignment;
// Move queues should be handled by the calling `CommandPhase` or a manager for it // 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) { if (this.pokemon.getTag(BattlerTagType.CHARGING)?.sourceMove === this.move.moveId) {
this.pokemon.lapseTag(BattlerTagType.CHARGING); this.pokemon.lapseTag(BattlerTagType.CHARGING);
} }
if (!isIgnorePP(this.useType)) { if (!isIgnorePP(this.useMode)) {
// "commit" to using the move, deducting PP. // "commit" to using the move, deducting PP.
const ppUsed = 1 + this.getPpIncreaseFromPressure(targets); const ppUsed = 1 + this.getPpIncreaseFromPressure(targets);
@ -430,7 +425,7 @@ export class MovePhase extends BattlePhase {
if (success) { if (success) {
const move = this.move.getMove(); const move = this.move.getMove();
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, move); 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 { } else {
if ([MoveId.ROAR, MoveId.WHIRLWIND, MoveId.TRICK_OR_TREAT, MoveId.FORESTS_CURSE].includes(this.move.moveId)) { if ([MoveId.ROAR, MoveId.WHIRLWIND, MoveId.TRICK_OR_TREAT, MoveId.FORESTS_CURSE].includes(this.move.moveId)) {
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove()); applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove());
@ -440,7 +435,7 @@ export class MovePhase extends BattlePhase {
move: this.move.moveId, move: this.move.moveId,
targets: this.targets, targets: this.targets,
result: MoveResult.FAIL, result: MoveResult.FAIL,
useType: this.useType, useMode: this.useMode,
}); });
const failureMessage = move.getFailedText(this.pokemon, targets[0], move); 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()`). // 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 ( if (
this.move.getMove().hasFlag(MoveFlags.DANCE_MOVE) && 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 // TODO: Fix in dancer PR to move to MEP for hit checks
globalScene.getField(true).forEach(pokemon => { globalScene.getField(true).forEach(pokemon => {
@ -486,7 +481,7 @@ export class MovePhase extends BattlePhase {
move: this.move.moveId, move: this.move.moveId,
targets: this.targets, targets: this.targets,
result: MoveResult.FAIL, result: MoveResult.FAIL,
useType: this.useType, useMode: this.useMode,
}); });
const failureMessage = move.getFailedText(this.pokemon, targets[0], move); 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()); applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove());
globalScene.unshiftPhase( 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 { public end(): void {
globalScene.unshiftPhase( globalScene.unshiftPhase(
new MoveEndPhase(this.pokemon.getBattlerIndex(), this.getActiveTargetPokemon(), isVirtual(this.useType)), new MoveEndPhase(this.pokemon.getBattlerIndex(), this.getActiveTargetPokemon(), isVirtual(this.useMode)),
); );
super.end(); super.end();
@ -641,7 +636,7 @@ export class MovePhase extends BattlePhase {
protected handlePreMoveFailures(): void { protected handlePreMoveFailures(): void {
if (this.cancelled || this.failed) { if (this.cancelled || this.failed) {
if (this.failed) { if (this.failed) {
const ppUsed = isIgnorePP(this.useType) ? 0 : 1; const ppUsed = isIgnorePP(this.useMode) ? 0 : 1;
if (ppUsed) { if (ppUsed) {
this.move.usePp(); this.move.usePp();
@ -658,7 +653,7 @@ export class MovePhase extends BattlePhase {
move: MoveId.NONE, move: MoveId.NONE,
result: MoveResult.FAIL, result: MoveResult.FAIL,
targets: this.targets, targets: this.targets,
useType: this.useType, useMode: this.useMode,
}); });
this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT);
@ -682,7 +677,7 @@ export class MovePhase extends BattlePhase {
} }
globalScene.queueMessage( globalScene.queueMessage(
i18next.t(isReflected(this.useType) ? "battle:magicCoatActivated" : "battle:useMove", { i18next.t(isReflected(this.useMode) ? "battle:magicCoatActivated" : "battle:useMove", {
pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon),
moveName: this.move.getName(), moveName: this.move.getName(),
}), }),

View File

@ -181,11 +181,11 @@ export class TurnStartPhase extends FieldPhase {
} }
if (pokemon.isPlayer() && turnCommand.cursor === -1) { if (pokemon.isPlayer() && turnCommand.cursor === -1) {
globalScene.pushPhase( 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? ); //TODO: is the bang correct here?
} else { } else {
globalScene.pushPhase( 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? ); // TODO: is the bang correct here?
} }
break; break;

View File

@ -2,7 +2,7 @@ import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator";
import type { BattlerIndex } from "#app/battle"; import type { BattlerIndex } from "#app/battle";
import type { MoveResult, TurnMove } from "#app/field/pokemon"; import type { MoveResult, TurnMove } from "#app/field/pokemon";
import type { SessionSaveData } from "#app/system/game-data"; 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"; import type { MoveId } from "#enums/move-id";
/** Prior signature of `TurnMove`; used to ensure parity */ /** 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`. * based on the prior values of `virtual` and `ignorePP`.
* Needed to ensure Last Resort and move-calling moves still work OK. * Needed to ensure Last Resort and move-calling moves still work OK.
* @param data - {@linkcode SystemSaveData} * @param data - {@linkcode SystemSaveData}
@ -31,7 +31,7 @@ const fixMoveHistory: SessionSaveMigrator = {
turn: tm.turn, turn: tm.turn,
// NOTE: This unfortuately has to mis-classify Dancer and Magic Bounce-induced moves as `FOLLOW_UP`, // 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. // 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 => { data.party.forEach(pkmn => {
pkmn.summonData.moveHistory = (pkmn.summonData.moveHistory as OldTurnMove[]).map(mapTurnMove); pkmn.summonData.moveHistory = (pkmn.summonData.moveHistory as OldTurnMove[]).map(mapTurnMove);

View File

@ -15,7 +15,7 @@ import type Pokemon from "#app/field/pokemon";
import type { CommandPhase } from "#app/phases/command-phase"; import type { CommandPhase } from "#app/phases/command-phase";
import MoveInfoOverlay from "./move-info-overlay"; import MoveInfoOverlay from "./move-info-overlay";
import { BattleType } from "#enums/battle-type"; 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 { export default class FightUiHandler extends UiHandler implements InfoToggle {
public static readonly MOVES_CONTAINER_NAME = "moves"; 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 // Attempts to back out of the move selection pane are blocked in certain MEs
const { battleType, mysteryEncounter } = globalScene.currentBattle; 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); ui.setMode(UiMode.COMMAND, this.fieldIndex);
success = true; success = true;
} }
@ -162,7 +162,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
break; break;
case Button.ACTION: case Button.ACTION:
if ( if (
(globalScene.getCurrentPhase() as CommandPhase).handleCommand(this.fromCommand, cursor, MoveUseType.NORMAL) (globalScene.getCurrentPhase() as CommandPhase).handleCommand(this.fromCommand, cursor, MoveUseMode.NORMAL)
) { ) {
success = true; success = true;
} else { } else {

View File

@ -2,7 +2,7 @@ import { BattlerIndex } from "#app/battle";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { MoveResult } from "#app/field/pokemon"; import { MoveResult } from "#app/field/pokemon";
import { MovePhase } from "#app/phases/move-phase"; 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 { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
@ -63,7 +63,7 @@ describe("Moves - After You", () => {
}); });
// TODO: Enable once rampaging moves and move queue are fixed. // 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 // within `MovePhase`, but should be enabled once that jank is removed
it.todo("should maintain PP ignore status of rampaging moves", async () => { it.todo("should maintain PP ignore status of rampaging moves", async () => {
game.override.moveset([]); game.override.moveset([]);
@ -91,7 +91,7 @@ describe("Moves - After You", () => {
expect(rattata.getLastXMoves()[0]).toMatchObject({ expect(rattata.getLastXMoves()[0]).toMatchObject({
move: MoveId.OUTRAGE, move: MoveId.OUTRAGE,
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}); });
}); });
}); });

View File

@ -3,7 +3,7 @@ import { RandomMoveAttr } from "#app/data/moves/move";
import { Stat } from "#app/enums/stat"; import { Stat } from "#app/enums/stat";
import { MoveResult } from "#app/field/pokemon"; import { MoveResult } from "#app/field/pokemon";
import { AbilityId } from "#enums/ability-id"; 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 { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
@ -75,7 +75,7 @@ describe("Moves - Copycat", () => {
expect(enemy.getLastXMoves()[0]).toMatchObject({ expect(enemy.getLastXMoves()[0]).toMatchObject({
move: MoveId.SWORDS_DANCE, move: MoveId.SWORDS_DANCE,
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.FOLLOW_UP, useMode: MoveUseMode.FOLLOW_UP,
}); });
expect(enemy.getStatStage(Stat.ATK)).toBe(2); expect(enemy.getStatStage(Stat.ATK)).toBe(2);
}); });

View File

@ -57,7 +57,8 @@ describe("Moves - Dig", () => {
expect(playerPokemon.getMoveHistory()).toHaveLength(2); 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([]); game.override.moveset([]);
await game.classicMode.startBattle([SpeciesId.MAGIKARP]); await game.classicMode.startBattle([SpeciesId.MAGIKARP]);

View File

@ -1,12 +1,13 @@
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
import { MoveResult } from "#app/field/pokemon"; import { MoveResult } from "#app/field/pokemon";
import { AbilityId } from "#enums/ability-id"; 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 { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import GameManager from "#test/testUtils/gameManager"; 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", () => { describe("Moves - Disable", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -110,7 +111,7 @@ describe("Moves - Disable", () => {
enemyMon.pushMoveHistory({ enemyMon.pushMoveHistory({
move: MoveId.SPLASH, move: MoveId.SPLASH,
targets: [BattlerIndex.ENEMY], targets: [BattlerIndex.ENEMY],
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}); });
game.move.select(MoveId.DISABLE); game.move.select(MoveId.DISABLE);
@ -128,11 +129,11 @@ describe("Moves - Disable", () => {
{ name: "Copycat", moveId: MoveId.COPYCAT }, { name: "Copycat", moveId: MoveId.COPYCAT },
{ name: "Metronome", moveId: MoveId.METRONOME }, { name: "Metronome", moveId: MoveId.METRONOME },
])("should ignore virtual moves called by $name", async ({ moveId }) => { ])("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]); await game.classicMode.startBattle([SpeciesId.PIKACHU]);
const playerMon = game.scene.getPlayerPokemon()!; 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.scene.currentBattle.lastMove = MoveId.SPLASH;
game.move.select(MoveId.DISABLE); game.move.select(MoveId.DISABLE);
@ -150,7 +151,6 @@ describe("Moves - Disable", () => {
).toBe(false); ).toBe(false);
}); });
it("should ignore dancer copied moves, even if also in moveset", async () => { it("should ignore dancer copied moves, even if also in moveset", async () => {
game.override game.override
.enemyAbility(AbilityId.DANCER) .enemyAbility(AbilityId.DANCER)

View File

@ -4,7 +4,7 @@ import type Pokemon from "#app/field/pokemon";
import { MoveResult } from "#app/field/pokemon"; import { MoveResult } from "#app/field/pokemon";
import type { MovePhase } from "#app/phases/move-phase"; import type { MovePhase } from "#app/phases/move-phase";
import { AbilityId } from "#enums/ability-id"; 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 { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
@ -250,7 +250,7 @@ describe("Moves - Instruct", () => {
move: MoveId.SEED_BOMB, move: MoveId.SEED_BOMB,
targets: [BattlerIndex.ENEMY], targets: [BattlerIndex.ENEMY],
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}); });
game.doSwitchPokemon(1); game.doSwitchPokemon(1);
@ -316,7 +316,7 @@ describe("Moves - Instruct", () => {
move: MoveId.SONIC_BOOM, move: MoveId.SONIC_BOOM,
targets: [BattlerIndex.PLAYER], targets: [BattlerIndex.PLAYER],
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}); });
game.move.select(MoveId.INSTRUCT); game.move.select(MoveId.INSTRUCT);
@ -343,7 +343,7 @@ describe("Moves - Instruct", () => {
move: MoveId.ELECTRO_DRIFT, move: MoveId.ELECTRO_DRIFT,
targets: [BattlerIndex.PLAYER], targets: [BattlerIndex.PLAYER],
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}); });
game.move.select(MoveId.SPLASH); game.move.select(MoveId.SPLASH);
@ -361,7 +361,7 @@ describe("Moves - Instruct", () => {
move: MoveId.WHIRLWIND, move: MoveId.WHIRLWIND,
targets: [BattlerIndex.PLAYER], targets: [BattlerIndex.PLAYER],
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}); });
game.move.select(MoveId.INSTRUCT); game.move.select(MoveId.INSTRUCT);
@ -417,7 +417,7 @@ describe("Moves - Instruct", () => {
move: MoveId.VINE_WHIP, move: MoveId.VINE_WHIP,
targets: [BattlerIndex.ENEMY], targets: [BattlerIndex.ENEMY],
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}); });
// Attempt to instruct banette after having been sent airborne // Attempt to instruct banette after having been sent airborne
@ -453,7 +453,7 @@ describe("Moves - Instruct", () => {
move: MoveId.VINE_WHIP, move: MoveId.VINE_WHIP,
targets: [BattlerIndex.ENEMY], targets: [BattlerIndex.ENEMY],
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}); });
game.move.select(MoveId.VINE_WHIP, BattlerIndex.PLAYER); game.move.select(MoveId.VINE_WHIP, BattlerIndex.PLAYER);

View File

@ -1,7 +1,7 @@
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
import { MoveResult } from "#app/field/pokemon"; import { MoveResult } from "#app/field/pokemon";
import { AbilityId } from "#enums/ability-id"; 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 { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
@ -54,19 +54,19 @@ describe("Moves - Last Resort", () => {
expectLastResortFail(); expectLastResortFail();
// Splash (1/3) // 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); game.move.select(MoveId.LAST_RESORT);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expectLastResortFail(); expectLastResortFail();
// Growl (2/3) // 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); game.move.select(MoveId.LAST_RESORT);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expectLastResortFail(); // Were last resort itself counted, it would error here expectLastResortFail(); // Were last resort itself counted, it would error here
// Growth (3/3) // 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); game.move.select(MoveId.LAST_RESORT);
await game.phaseInterceptor.to("TurnEndPhase"); await game.phaseInterceptor.to("TurnEndPhase");
expect(game.scene.getPlayerPokemon()?.getLastXMoves()[0]).toEqual( expect(game.scene.getPlayerPokemon()?.getLastXMoves()[0]).toEqual(
@ -118,12 +118,12 @@ describe("Moves - Last Resort", () => {
expect.objectContaining({ expect.objectContaining({
move: MoveId.LAST_RESORT, move: MoveId.LAST_RESORT,
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.FOLLOW_UP, useMode: MoveUseMode.FOLLOW_UP,
}), }),
expect.objectContaining({ expect.objectContaining({
move: MoveId.SLEEP_TALK, move: MoveId.SLEEP_TALK,
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}), }),
]); ]);
}); });

View File

@ -7,7 +7,7 @@ import { Stat } from "#app/enums/stat";
import { MoveResult } from "#app/field/pokemon"; import { MoveResult } from "#app/field/pokemon";
import { CommandPhase } from "#app/phases/command-phase"; import { CommandPhase } from "#app/phases/command-phase";
import { BattlerTagType } from "#enums/battler-tag-type"; 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 { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
@ -113,7 +113,7 @@ describe("Moves - Metronome", () => {
expect(player.getLastXMoves()[0]).toMatchObject({ expect(player.getLastXMoves()[0]).toMatchObject({
move: MoveId.SOLAR_BEAM, move: MoveId.SOLAR_BEAM,
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.FOLLOW_UP, useMode: MoveUseMode.FOLLOW_UP,
}); });
}); });

View File

@ -7,7 +7,7 @@ import { MoveResult } from "#app/field/pokemon";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { describe, beforeAll, afterEach, beforeEach, it, expect } from "vitest"; 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", () => { describe("Moves - Quash", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -60,7 +60,7 @@ describe("Moves - Quash", () => {
}); });
// TODO: Enable once rampaging moves and move queue are fixed. // 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 // within `MovePhase`, but should be enabled once that jank is removed
it.todo("should maintain PP ignore status of rampaging moves", async () => { it.todo("should maintain PP ignore status of rampaging moves", async () => {
game.override.moveset([]); game.override.moveset([]);
@ -88,7 +88,7 @@ describe("Moves - Quash", () => {
expect(rattata.getLastXMoves()[0]).toMatchObject({ expect(rattata.getLastXMoves()[0]).toMatchObject({
move: MoveId.OUTRAGE, move: MoveId.OUTRAGE,
result: MoveResult.SUCCESS, result: MoveResult.SUCCESS,
useType: MoveUseType.IGNORE_PP, useMode: MoveUseMode.IGNORE_PP,
}); });
}); });

View File

@ -24,7 +24,7 @@ import { FunAndGamesEncounter } from "#app/data/mystery-encounters/encounters/fu
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { Command } from "#app/ui/command-ui-handler"; import { Command } from "#app/ui/command-ui-handler";
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; 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 namespace = "mysteryEncounters/funAndGames";
const defaultParty = [SpeciesId.LAPRAS, SpeciesId.GENGAR, SpeciesId.ABRA]; const defaultParty = [SpeciesId.LAPRAS, SpeciesId.GENGAR, SpeciesId.ABRA];
@ -155,15 +155,15 @@ describe("Fun And Games! - Mystery Encounter", () => {
}); });
// Turn 1 // 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); await game.phaseInterceptor.to(CommandPhase);
// Turn 2 // 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); await game.phaseInterceptor.to(CommandPhase);
// Turn 3 // 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); await game.phaseInterceptor.to(SelectModifierPhase, false);
// Rewards // Rewards
@ -182,7 +182,7 @@ describe("Fun And Games! - Mystery Encounter", () => {
// Skip minigame // Skip minigame
scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0; 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); await game.phaseInterceptor.to(SelectModifierPhase, false);
// Rewards // Rewards
@ -211,7 +211,7 @@ describe("Fun And Games! - Mystery Encounter", () => {
const wobbuffet = scene.getEnemyPokemon()!; const wobbuffet = scene.getEnemyPokemon()!;
wobbuffet.hp = Math.floor(0.2 * wobbuffet.getMaxHp()); wobbuffet.hp = Math.floor(0.2 * wobbuffet.getMaxHp());
scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0; 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); await game.phaseInterceptor.to(SelectModifierPhase, false);
// Rewards // Rewards
@ -241,7 +241,7 @@ describe("Fun And Games! - Mystery Encounter", () => {
const wobbuffet = scene.getEnemyPokemon()!; const wobbuffet = scene.getEnemyPokemon()!;
wobbuffet.hp = Math.floor(0.1 * wobbuffet.getMaxHp()); wobbuffet.hp = Math.floor(0.1 * wobbuffet.getMaxHp());
scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0; 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); await game.phaseInterceptor.to(SelectModifierPhase, false);
// Rewards // Rewards
@ -271,7 +271,7 @@ describe("Fun And Games! - Mystery Encounter", () => {
const wobbuffet = scene.getEnemyPokemon()!; const wobbuffet = scene.getEnemyPokemon()!;
wobbuffet.hp = 1; wobbuffet.hp = 1;
scene.currentBattle.mysteryEncounter!.misc.turnsRemaining = 0; 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); await game.phaseInterceptor.to(SelectModifierPhase, false);
// Rewards // Rewards

View File

@ -55,7 +55,6 @@ import TextInterceptor from "#test/testUtils/TextInterceptor";
import { AES, enc } from "crypto-js"; import { AES, enc } from "crypto-js";
import fs from "node:fs"; import fs from "node:fs";
import { expect, vi } from "vitest"; import { expect, vi } from "vitest";
import { MoveUseType } from "#enums/move-use-type";
/** /**
* Class to manage the game state and transitions between phases. * Class to manage the game state and transitions between phases.

View File

@ -12,7 +12,7 @@ import { UiMode } from "#enums/ui-mode";
import { getMovePosition } from "#test/testUtils/gameManagerUtils"; import { getMovePosition } from "#test/testUtils/gameManagerUtils";
import { GameManagerHelper } from "#test/testUtils/helpers/gameManagerHelper"; import { GameManagerHelper } from "#test/testUtils/helpers/gameManagerHelper";
import { vi } from "vitest"; 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 * Helper to handle a Pokemon's move
@ -61,7 +61,7 @@ export class MoveHelper extends GameManagerHelper {
(this.game.scene.getCurrentPhase() as CommandPhase).handleCommand( (this.game.scene.getCurrentPhase() as CommandPhase).handleCommand(
Command.FIGHT, Command.FIGHT,
movePosition, movePosition,
MoveUseType.NORMAL, MoveUseMode.NORMAL,
); );
}); });
@ -89,7 +89,7 @@ export class MoveHelper extends GameManagerHelper {
); );
}); });
this.game.onNextPrompt("CommandPhase", UiMode.FIGHT, () => { 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) { if (targetIndex !== null) {
@ -185,7 +185,7 @@ export class MoveHelper extends GameManagerHelper {
target !== undefined && !legalTargets.multiple && legalTargets.targets.includes(target) target !== undefined && !legalTargets.multiple && legalTargets.targets.includes(target)
? [target] ? [target]
: enemy.getNextTargets(moveId), : 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 !== undefined && !legalTargets.multiple && legalTargets.targets.includes(target)
? [target] ? [target]
: enemy.getNextTargets(moveId), : enemy.getNextTargets(moveId),
useType: MoveUseType.NORMAL, useMode: MoveUseMode.NORMAL,
}); });
/** /**