diff --git a/create-test-boilerplate.js b/create-test-boilerplate.js
index 3c53eb1125b..d9cdbd4e7cf 100644
--- a/create-test-boilerplate.js
+++ b/create-test-boilerplate.js
@@ -20,54 +20,58 @@ const type = args[0]; // "move" or "ability"
let fileName = args[1]; // The file name
if (!type || !fileName) {
- console.error('Please provide both a type ("move", "ability", or "item") and a file name.');
- process.exit(1);
+ console.error('Please provide a type ("move", "ability", or "item") and a file name.');
+ process.exit(1);
}
-// Convert fileName from to snake_case if camelCase is given
-fileName = fileName.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
+// Convert fileName from kebab-case or camelCase to snake_case
+fileName = fileName
+ .replace(/-+/g, '_') // Convert kebab-case (dashes) to underscores
+ .replace(/([a-z])([A-Z])/g, '$1_$2') // Convert camelCase to snake_case
+ .toLowerCase(); // Ensure all lowercase
// Format the description for the test case
const formattedName = fileName
- .replace(/_/g, ' ')
- .replace(/\b\w/g, char => char.toUpperCase());
+ .replace(/_/g, ' ')
+ .replace(/\b\w/g, char => char.toUpperCase());
// Determine the directory based on the type
let dir;
let description;
if (type === 'move') {
- dir = path.join(__dirname, 'src', 'test', 'moves');
- description = `Moves - ${formattedName}`;
+ dir = path.join(__dirname, 'src', 'test', 'moves');
+ description = `Moves - ${formattedName}`;
} else if (type === 'ability') {
- dir = path.join(__dirname, 'src', 'test', 'abilities');
- description = `Abilities - ${formattedName}`;
+ dir = path.join(__dirname, 'src', 'test', 'abilities');
+ description = `Abilities - ${formattedName}`;
} else if (type === "item") {
- dir = path.join(__dirname, 'src', 'test', 'items');
- description = `Items - ${formattedName}`;
+ dir = path.join(__dirname, 'src', 'test', 'items');
+ description = `Items - ${formattedName}`;
} else {
- console.error('Invalid type. Please use "move", "ability", or "item".');
- process.exit(1);
+ console.error('Invalid type. Please use "move", "ability", or "item".');
+ process.exit(1);
}
// Ensure the directory exists
if (!fs.existsSync(dir)) {
- fs.mkdirSync(dir, { recursive: true });
+ fs.mkdirSync(dir, { recursive: true });
}
// Create the file with the given name
const filePath = path.join(dir, `${fileName}.test.ts`);
if (fs.existsSync(filePath)) {
- console.error(`File "${fileName}.test.ts" already exists.`);
- process.exit(1);
+ console.error(`File "${fileName}.test.ts" already exists.`);
+ process.exit(1);
}
// Define the content template
const content = `import { Abilities } from "#enums/abilities";
+import { Moves } from "#enums/moves";
+import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
-import { afterEach, beforeAll, beforeEach, describe, it } from "vitest";
+import { afterEach, beforeAll, beforeEach, describe, it, expect } from "vitest";
describe("${description}", () => {
let phaserGame: Phaser.Game;
@@ -87,14 +91,15 @@ describe("${description}", () => {
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
+ .moveset([Moves.SPLASH])
.battleType("single")
.enemyAbility(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
it("test case", async () => {
- // await game.classicMode.startBattle();
- // game.move.select();
+ // await game.classicMode.startBattle([Species.MAGIKARP]);
+ // game.move.select(Moves.SPLASH);
}, TIMEOUT);
});
`;
diff --git a/public/images/ui/legacy/summary_moves_effect_de.png b/public/images/ui/legacy/summary_moves_effect_de.png
deleted file mode 100644
index 8d6ef024cf3..00000000000
Binary files a/public/images/ui/legacy/summary_moves_effect_de.png and /dev/null differ
diff --git a/public/images/ui/legacy/summary_moves_effect_es.png b/public/images/ui/legacy/summary_moves_effect_es.png
deleted file mode 100644
index a48f90cc8f6..00000000000
Binary files a/public/images/ui/legacy/summary_moves_effect_es.png and /dev/null differ
diff --git a/public/images/ui/legacy/summary_moves_effect_fr.png b/public/images/ui/legacy/summary_moves_effect_fr.png
deleted file mode 100644
index 9d65c920176..00000000000
Binary files a/public/images/ui/legacy/summary_moves_effect_fr.png and /dev/null differ
diff --git a/public/images/ui/legacy/summary_moves_effect_it.png b/public/images/ui/legacy/summary_moves_effect_it.png
deleted file mode 100644
index 8d6ef024cf3..00000000000
Binary files a/public/images/ui/legacy/summary_moves_effect_it.png and /dev/null differ
diff --git a/public/images/ui/legacy/summary_moves_effect_pt-BR.png b/public/images/ui/legacy/summary_moves_effect_pt-BR.png
deleted file mode 100644
index f5a0c2ea736..00000000000
Binary files a/public/images/ui/legacy/summary_moves_effect_pt-BR.png and /dev/null differ
diff --git a/public/images/ui/legacy/summary_moves_effect_zh-CN.png b/public/images/ui/legacy/summary_moves_effect_zh-CN.png
deleted file mode 100644
index 8d6ef024cf3..00000000000
Binary files a/public/images/ui/legacy/summary_moves_effect_zh-CN.png and /dev/null differ
diff --git a/src/battle-scene.ts b/src/battle-scene.ts
index ff4258a13f5..72778fa8589 100644
--- a/src/battle-scene.ts
+++ b/src/battle-scene.ts
@@ -2193,8 +2193,14 @@ export default class BattleScene extends SceneBase {
return true;
}
- findPhase(phaseFilter: (phase: Phase) => boolean): Phase | undefined {
- return this.phaseQueue.find(phaseFilter);
+ /**
+ * Find a specific {@linkcode Phase} in the phase queue.
+ *
+ * @param phaseFilter filter function to use to find the wanted phase
+ * @returns the found phase or undefined if none found
+ */
+ findPhase
(phaseFilter: (phase: P) => boolean): P | undefined {
+ return this.phaseQueue.find(phaseFilter) as P;
}
tryReplacePhase(phaseFilter: (phase: Phase) => boolean, phase: Phase): boolean {
diff --git a/src/data/ability.ts b/src/data/ability.ts
index 10aba1f030e..6acf77cfca5 100755
--- a/src/data/ability.ts
+++ b/src/data/ability.ts
@@ -1595,8 +1595,8 @@ export class PostAttackAbAttr extends AbAttr {
private attackCondition: PokemonAttackCondition;
/** The default attackCondition requires that the selected move is a damaging move */
- constructor(attackCondition: PokemonAttackCondition = (user, target, move) => (move.category !== MoveCategory.STATUS)) {
- super();
+ constructor(attackCondition: PokemonAttackCondition = (user, target, move) => (move.category !== MoveCategory.STATUS), showAbility: boolean = true) {
+ super(showAbility);
this.attackCondition = attackCondition;
}
@@ -1624,6 +1624,40 @@ export class PostAttackAbAttr extends AbAttr {
}
}
+/**
+ * Ability attribute for Gorilla Tactics
+ * @extends PostAttackAbAttr
+ */
+export class GorillaTacticsAbAttr extends PostAttackAbAttr {
+ constructor() {
+ super((user, target, move) => true, false);
+ }
+
+ /**
+ *
+ * @param {Pokemon} pokemon the {@linkcode Pokemon} with this ability
+ * @param passive n/a
+ * @param simulated whether the ability is being simulated
+ * @param defender n/a
+ * @param move n/a
+ * @param hitResult n/a
+ * @param args n/a
+ * @returns `true` if the ability is applied
+ */
+ applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise {
+ if (simulated) {
+ return simulated;
+ }
+
+ if (pokemon.getTag(BattlerTagType.GORILLA_TACTICS)) {
+ return false;
+ }
+
+ pokemon.addTag(BattlerTagType.GORILLA_TACTICS);
+ return true;
+ }
+}
+
export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
private stealCondition: PokemonAttackCondition | null;
@@ -3923,7 +3957,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr {
}
export class PostFaintAbAttr extends AbAttr {
- applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
+ applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
return false;
}
}
@@ -3974,7 +4008,7 @@ export class PostFaintClearWeatherAbAttr extends PostFaintAbAttr {
* @param args N/A
* @returns {boolean} Returns true if the weather clears, otherwise false.
*/
- applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
+ applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
const weatherType = pokemon.scene.arena.weather?.weatherType;
let turnOffWeather = false;
@@ -4022,8 +4056,8 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
this.damageRatio = damageRatio;
}
- applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
- if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) {
+ applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
+ if (move !== undefined && attacker !== undefined && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) { //If the mon didn't die to indirect damage
const cancelled = new Utils.BooleanHolder(false);
pokemon.scene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated));
if (cancelled.value || attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
@@ -4052,8 +4086,8 @@ export class PostFaintHPDamageAbAttr extends PostFaintAbAttr {
super ();
}
- applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
- if (!simulated) {
+ applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
+ if (move !== undefined && attacker !== undefined && !simulated) { //If the mon didn't die to indirect damage
const damage = pokemon.turnData.attacksReceived[0].damage;
attacker.damageAndUpdate((damage), HitResult.OTHER);
attacker.turnData.damageTaken += damage;
@@ -4711,7 +4745,7 @@ export function applyPostBattleAbAttrs(attrType: Constructor,
}
export function applyPostFaintAbAttrs(attrType: Constructor,
- pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, simulated: boolean = false, ...args: any[]): Promise {
+ pokemon: Pokemon, attacker?: Pokemon, move?: Move, hitResult?: HitResult, simulated: boolean = false, ...args: any[]): Promise {
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, simulated, attacker, move, hitResult, args), args, false, simulated);
}
@@ -5597,7 +5631,7 @@ export function initAbilities() {
.bypassFaint()
.partial(),
new Ability(Abilities.GORILLA_TACTICS, 8)
- .unimplemented(),
+ .attr(GorillaTacticsAbAttr),
new Ability(Abilities.NEUTRALIZING_GAS, 8)
.attr(SuppressFieldAbilitiesAbAttr)
.attr(UncopiableAbilityAbAttr)
diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts
index c26412c776f..52e039ed874 100644
--- a/src/data/battler-tags.ts
+++ b/src/data/battler-tags.ts
@@ -107,8 +107,8 @@ export interface TerrainBattlerTag {
* to select restricted moves.
*/
export abstract class MoveRestrictionBattlerTag extends BattlerTag {
- constructor(tagType: BattlerTagType, turnCount: integer, sourceMove?: Moves, sourceId?: integer) {
- super(tagType, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END ], turnCount, sourceMove, sourceId);
+ constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType | BattlerTagLapseType[], turnCount: integer, sourceMove?: Moves, sourceId?: integer) {
+ super(tagType, lapseType, turnCount, sourceMove, sourceId);
}
/** @override */
@@ -119,7 +119,9 @@ export abstract class MoveRestrictionBattlerTag extends BattlerTag {
const move = phase.move;
if (this.isMoveRestricted(move.moveId)) {
- pokemon.scene.queueMessage(this.interruptedText(pokemon, move.moveId));
+ if (this.interruptedText(pokemon, move.moveId)) {
+ pokemon.scene.queueMessage(this.interruptedText(pokemon, move.moveId));
+ }
phase.cancel();
}
@@ -155,7 +157,52 @@ export abstract class MoveRestrictionBattlerTag extends BattlerTag {
* @param {Moves} move {@linkcode Moves} ID of the move being interrupted
* @returns {string} text to display when the move is interrupted
*/
- abstract interruptedText(pokemon: Pokemon, move: Moves): string;
+ interruptedText(pokemon: Pokemon, move: Moves): string {
+ return "";
+ }
+}
+
+/**
+ * Tag representing the "Throat Chop" effect. Pokemon with this tag cannot use sound-based moves.
+ * @see {@link https://bulbapedia.bulbagarden.net/wiki/Throat_Chop_(move) | Throat Chop}
+ * @extends MoveRestrictionBattlerTag
+ */
+export class ThroatChoppedTag extends MoveRestrictionBattlerTag {
+ constructor() {
+ super(BattlerTagType.THROAT_CHOPPED, [ BattlerTagLapseType.TURN_END, BattlerTagLapseType.PRE_MOVE ], 2, Moves.THROAT_CHOP);
+ }
+
+ /**
+ * Checks if a {@linkcode Moves | move} is restricted by Throat Chop.
+ * @override
+ * @param {Moves} move the {@linkcode Moves | move} to check for sound-based restriction
+ * @returns true if the move is sound-based
+ */
+ override isMoveRestricted(move: Moves): boolean {
+ return allMoves[move].hasFlag(MoveFlags.SOUND_BASED);
+ }
+
+ /**
+ * Shows a message when the player attempts to select a move that is restricted by Throat Chop.
+ * @override
+ * @param {Pokemon} pokemon the {@linkcode Pokemon} that is attempting to select the restricted move
+ * @param {Moves} move the {@linkcode Moves | move} that is being restricted
+ * @returns the message to display when the player attempts to select the restricted move
+ */
+ override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
+ return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name });
+ }
+
+ /**
+ * Shows a message when a move is interrupted by Throat Chop.
+ * @override
+ * @param {Pokemon} pokemon the interrupted {@linkcode Pokemon}
+ * @param {Moves} move the {@linkcode Moves | move} that was interrupted
+ * @returns the message to display when the move is interrupted
+ */
+ override interruptedText(pokemon: Pokemon, move: Moves): string {
+ return i18next.t("battle:throatChopInterruptedMove", { pokemonName: getPokemonNameWithAffix(pokemon) });
+ }
}
/**
@@ -167,7 +214,7 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
private moveId: Moves = Moves.NONE;
constructor(sourceId: number) {
- super(BattlerTagType.DISABLED, 4, Moves.DISABLE, sourceId);
+ super(BattlerTagType.DISABLED, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END ], 4, Moves.DISABLE, sourceId);
}
/** @override */
@@ -178,7 +225,7 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
/**
* @override
*
- * Ensures that move history exists on `pokemon` and has a valid move. If so, sets the {@link moveId} and shows a message.
+ * Ensures that move history exists on `pokemon` and has a valid move. If so, sets the {@linkcode moveId} and shows a message.
* Otherwise the move ID will not get assigned and this tag will get removed next turn.
*/
override onAdd(pokemon: Pokemon): void {
@@ -207,7 +254,12 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
return i18next.t("battle:moveDisabled", { moveName: allMoves[move].name });
}
- /** @override */
+ /**
+ * @override
+ * @param {Pokemon} pokemon {@linkcode Pokemon} attempting to use the restricted move
+ * @param {Moves} move {@linkcode Moves} ID of the move being interrupted
+ * @returns {string} text to display when the move is interrupted
+ */
override interruptedText(pokemon: Pokemon, move: Moves): string {
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
}
@@ -219,6 +271,72 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
}
}
+/**
+ * Tag used by Gorilla Tactics to restrict the user to using only one move.
+ * @extends MoveRestrictionBattlerTag
+ */
+export class GorillaTacticsTag extends MoveRestrictionBattlerTag {
+ private moveId = Moves.NONE;
+
+ constructor() {
+ super(BattlerTagType.GORILLA_TACTICS, BattlerTagLapseType.CUSTOM, 0);
+ }
+
+ /** @override */
+ override isMoveRestricted(move: Moves): boolean {
+ return move !== this.moveId;
+ }
+
+ /**
+ * @override
+ * @param {Pokemon} pokemon the {@linkcode Pokemon} to check if the tag can be added
+ * @returns `true` if the pokemon has a valid move and no existing {@linkcode GorillaTacticsTag}; `false` otherwise
+ */
+ override canAdd(pokemon: Pokemon): boolean {
+ return (this.getLastValidMove(pokemon) !== undefined) && !pokemon.getTag(GorillaTacticsTag);
+ }
+
+ /**
+ * Ensures that move history exists on {@linkcode Pokemon} and has a valid move.
+ * If so, sets the {@linkcode moveId} and increases the user's Attack by 50%.
+ * @override
+ * @param {Pokemon} pokemon the {@linkcode Pokemon} to add the tag to
+ */
+ override onAdd(pokemon: Pokemon): void {
+ const lastValidMove = this.getLastValidMove(pokemon);
+
+ if (!lastValidMove) {
+ return;
+ }
+
+ this.moveId = lastValidMove;
+ pokemon.setStat(Stat.ATK, pokemon.getStat(Stat.ATK, false) * 1.5, false);
+ }
+
+ /**
+ *
+ * @override
+ * @param {Pokemon} pokemon n/a
+ * @param {Moves} move {@linkcode Moves} ID of the move being denied
+ * @returns {string} text to display when the move is denied
+ */
+ override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
+ return i18next.t("battle:canOnlyUseMove", { moveName: allMoves[this.moveId].name, pokemonName: getPokemonNameWithAffix(pokemon) });
+ }
+
+ /**
+ * Gets the last valid move from the pokemon's move history.
+ * @param {Pokemon} pokemon {@linkcode Pokemon} to get the last valid move from
+ * @returns {Moves | undefined} the last valid move from the pokemon's move history
+ */
+ getLastValidMove(pokemon: Pokemon): Moves | undefined {
+ const move = pokemon.getLastXMoves()
+ .find(m => m.move !== Moves.NONE && m.move !== Moves.STRUGGLE && !m.virtual);
+
+ return move?.move;
+ }
+}
+
/**
* BattlerTag that represents the "recharge" effects of moves like Hyper Beam.
*/
@@ -2158,6 +2276,10 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
return new GulpMissileTag(tagType, sourceMove);
case BattlerTagType.TAR_SHOT:
return new TarShotTag();
+ case BattlerTagType.THROAT_CHOPPED:
+ return new ThroatChoppedTag();
+ case BattlerTagType.GORILLA_TACTICS:
+ return new GorillaTacticsTag();
case BattlerTagType.NONE:
default:
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
diff --git a/src/data/move.ts b/src/data/move.ts
index 21b859b22ac..7800d6df12a 100644
--- a/src/data/move.ts
+++ b/src/data/move.ts
@@ -5987,9 +5987,8 @@ export class SwapStatAttr extends MoveEffectAttr {
}
/**
- * Takes the average of the user's and target's corresponding current
- * {@linkcode stat} values and sets that stat to the average for both
- * temporarily.
+ * Swaps the user's and target's corresponding current
+ * {@linkcode EffectiveStat | stat} values
* @param user the {@linkcode Pokemon} that used the move
* @param target the {@linkcode Pokemon} that the move was used on
* @param move N/A
@@ -6013,6 +6012,62 @@ export class SwapStatAttr extends MoveEffectAttr {
}
}
+/**
+ * Attribute used to switch the user's own stats.
+ * Used by Power Shift.
+ * @extends MoveEffectAttr
+ */
+export class ShiftStatAttr extends MoveEffectAttr {
+ private statToSwitch: EffectiveStat;
+ private statToSwitchWith: EffectiveStat;
+
+ constructor(statToSwitch: EffectiveStat, statToSwitchWith: EffectiveStat) {
+ super();
+
+ this.statToSwitch = statToSwitch;
+ this.statToSwitchWith = statToSwitchWith;
+ }
+
+ /**
+ * Switches the user's stats based on the {@linkcode statToSwitch} and {@linkcode statToSwitchWith} attributes.
+ * @param {Pokemon} user the {@linkcode Pokemon} that used the move
+ * @param target n/a
+ * @param move n/a
+ * @param args n/a
+ * @returns whether the effect was applied
+ */
+ override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
+ if (!super.apply(user, target, move, args)) {
+ return false;
+ }
+
+ const firstStat = user.getStat(this.statToSwitch, false);
+ const secondStat = user.getStat(this.statToSwitchWith, false);
+
+ user.setStat(this.statToSwitch, secondStat, false);
+ user.setStat(this.statToSwitchWith, firstStat, false);
+
+ user.scene.queueMessage(i18next.t("moveTriggers:shiftedStats", {
+ pokemonName: getPokemonNameWithAffix(user),
+ statToSwitch: i18next.t(getStatKey(this.statToSwitch)),
+ statToSwitchWith: i18next.t(getStatKey(this.statToSwitchWith))
+ }));
+
+ return true;
+ }
+
+ /**
+ * Encourages the user to use the move if the stat to switch with is greater than the stat to switch.
+ * @param {Pokemon} user the {@linkcode Pokemon} that used the move
+ * @param target n/a
+ * @param move n/a
+ * @returns number of points to add to the user's benefit score
+ */
+ override getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
+ return user.getStat(this.statToSwitchWith, false) > user.getStat(this.statToSwitch, false) ? 10 : 0;
+ }
+}
+
/**
* Attribute used for status moves, namely Power Split and Guard Split,
* that take the average of a user's and target's corresponding
@@ -6217,12 +6272,42 @@ export class VariableTargetAttr extends MoveAttr {
}
}
+/**
+ * Attribute for {@linkcode Moves.AFTER_YOU}
+ *
+ * [After You - Move | Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/After_You_(move))
+ */
+export class AfterYouAttr extends MoveEffectAttr {
+ /**
+ * Allows the target of this move to act right after the user.
+ *
+ * @param user {@linkcode Pokemon} that is using the move.
+ * @param target {@linkcode Pokemon} that will move right after this move is used.
+ * @param move {@linkcode Move} {@linkcode Moves.AFTER_YOU}
+ * @param _args N/A
+ * @returns true
+ */
+ override apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
+ user.scene.queueMessage(i18next.t("moveTriggers:afterYou", {targetName: getPokemonNameWithAffix(target)}));
+
+ //Will find next acting phase of the targeted pokémon, delete it and queue it next on successful delete.
+ const nextAttackPhase = target.scene.findPhase((phase) => phase.pokemon === target);
+ if (nextAttackPhase && target.scene.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) {
+ target.scene.prependToPhase(new MovePhase(target.scene, target, [...nextAttackPhase.targets], nextAttackPhase.move), MovePhase);
+ }
+
+ return true;
+ }
+}
+
const failOnGravityCondition: MoveConditionFunc = (user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY);
const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune();
const failOnMaxCondition: MoveConditionFunc = (user, target, move) => !target.isMax();
+const failIfSingleBattle: MoveConditionFunc = (user, target, move) => user.scene.currentBattle.double;
+
const failIfDampCondition: MoveConditionFunc = (user, target, move) => {
const cancelled = new Utils.BooleanHolder(false);
user.scene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled));
@@ -7870,7 +7955,10 @@ export function initMoves() {
.attr(AbilityGiveAttr),
new StatusMove(Moves.AFTER_YOU, Type.NORMAL, -1, 15, -1, 0, 5)
.ignoresProtect()
- .unimplemented(),
+ .target(MoveTarget.NEAR_OTHER)
+ .condition(failIfSingleBattle)
+ .condition((user, target, move) => !target.turnData.acted)
+ .attr(AfterYouAttr),
new AttackMove(Moves.ROUND, Type.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 5)
.soundBased()
.partial(),
@@ -8404,7 +8492,7 @@ export function initMoves() {
.target(MoveTarget.USER_AND_ALLIES)
.condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => p.hasAbility(a, false)))),
new AttackMove(Moves.THROAT_CHOP, Type.DARK, MoveCategory.PHYSICAL, 80, 100, 15, 100, 0, 7)
- .partial(),
+ .attr(AddBattlerTagAttr, BattlerTagType.THROAT_CHOPPED),
new AttackMove(Moves.POLLEN_PUFF, Type.BUG, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 7)
.attr(StatusCategoryOnAllyAttr)
.attr(HealOnAllyAttr, 0.5, true, false)
@@ -8894,7 +8982,8 @@ export function initMoves() {
new AttackMove(Moves.PSYSHIELD_BASH, Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8)
.attr(StatStageChangeAttr, [ Stat.DEF ], 1, true),
new SelfStatusMove(Moves.POWER_SHIFT, Type.NORMAL, -1, 10, -1, 0, 8)
- .unimplemented(),
+ .target(MoveTarget.USER)
+ .attr(ShiftStatAttr, Stat.ATK, Stat.DEF),
new AttackMove(Moves.STONE_AXE, Type.ROCK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8)
.attr(AddArenaTrapTagHitAttr, ArenaTagType.STEALTH_ROCK)
.slicingMove(),
diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts
index 0878bd00cd5..cb83ebf4882 100644
--- a/src/enums/battler-tag-type.ts
+++ b/src/enums/battler-tag-type.ts
@@ -73,5 +73,7 @@ export enum BattlerTagType {
SHELL_TRAP = "SHELL_TRAP",
DRAGON_CHEER = "DRAGON_CHEER",
NO_RETREAT = "NO_RETREAT",
+ GORILLA_TACTICS = "GORILLA_TACTICS",
+ THROAT_CHOPPED = "THROAT_CHOPPED",
TAR_SHOT = "TAR_SHOT",
}
diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts
index 01d728d6de0..4bc4aca448c 100644
--- a/src/field/pokemon.ts
+++ b/src/field/pokemon.ts
@@ -984,10 +984,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
: this.moveset;
// Overrides moveset based on arrays specified in overrides.ts
- const overrideArray: Array = this.isPlayer() ? Overrides.MOVESET_OVERRIDE : Overrides.OPP_MOVESET_OVERRIDE;
+ let overrideArray: Moves | Array = this.isPlayer() ? Overrides.MOVESET_OVERRIDE : Overrides.OPP_MOVESET_OVERRIDE;
+ if (!Array.isArray(overrideArray)) {
+ overrideArray = [overrideArray];
+ }
if (overrideArray.length > 0) {
+ if (!this.isPlayer()) {
+ this.moveset = [];
+ }
overrideArray.forEach((move: Moves, index: number) => {
- const ppUsed = this.moveset[index]?.ppUsed || 0;
+ const ppUsed = this.moveset[index]?.ppUsed ?? 0;
this.moveset[index] = new PokemonMove(move, Math.min(ppUsed, allMoves[move].pp));
});
}
diff --git a/src/locales/de/fight-ui-handler.json b/src/locales/de/fight-ui-handler.json
index 6965540c703..f803375e8de 100644
--- a/src/locales/de/fight-ui-handler.json
+++ b/src/locales/de/fight-ui-handler.json
@@ -3,5 +3,6 @@
"power": "Stärke",
"accuracy": "Genauigkeit",
"abilityFlyInText": "{{passive}}{{abilityName}} von {{pokemonName}} wirkt!",
- "passive": "Passive Fähigkeit "
+ "passive": "Passive Fähigkeit ",
+ "teraHover": "Tera-Typ {{type}}"
}
\ No newline at end of file
diff --git a/src/locales/de/move-trigger.json b/src/locales/de/move-trigger.json
index 61283c9e62e..01b22429fb3 100644
--- a/src/locales/de/move-trigger.json
+++ b/src/locales/de/move-trigger.json
@@ -66,5 +66,6 @@
"revivalBlessing": "{{pokemonName}} ist wieder fit und kampfbereit!",
"swapArenaTags": "{{pokemonName}} hat die Effekte, die auf den beiden Seiten des Kampffeldes wirken, miteinander getauscht!",
"exposedMove": "{{pokemonName}} erkennt {{targetPokemonName}}!",
- "safeguard": "{{targetName}} wird durch Bodyguard geschützt!"
+ "safeguard": "{{targetName}} wird durch Bodyguard geschützt!",
+ "afterYou": "{{targetName}} lässt sich auf Galanterie ein!"
}
diff --git a/src/locales/en/battle.json b/src/locales/en/battle.json
index 120ac749acb..217c77422d1 100644
--- a/src/locales/en/battle.json
+++ b/src/locales/en/battle.json
@@ -44,7 +44,10 @@
"moveNotImplemented": "{{moveName}} is not yet implemented and cannot be selected.",
"moveNoPP": "There's no PP left for\nthis move!",
"moveDisabled": "{{moveName}} is disabled!",
+ "canOnlyUseMove": "{{pokemonName}} can only use {{moveName}}!",
+ "moveCannotBeSelected": "{{moveName}} cannot be selected!",
"disableInterruptedMove": "{{pokemonNameWithAffix}}'s {{moveName}}\nis disabled!",
+ "throatChopInterruptedMove": "The effects of Throat Chop prevent\n{{pokemonName}} from using certain moves!",
"noPokeballForce": "An unseen force\nprevents using Poké Balls.",
"noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!",
"noPokeballMulti": "You can only throw a Poké Ball\nwhen there is one Pokémon remaining!",
diff --git a/src/locales/en/fight-ui-handler.json b/src/locales/en/fight-ui-handler.json
index 35b7f42772a..1b8bd1f5c71 100644
--- a/src/locales/en/fight-ui-handler.json
+++ b/src/locales/en/fight-ui-handler.json
@@ -3,5 +3,6 @@
"power": "Power",
"accuracy": "Accuracy",
"abilityFlyInText": " {{pokemonName}}'s {{passive}}{{abilityName}}",
- "passive": "Passive "
+ "passive": "Passive ",
+ "teraHover": "{{type}} Terastallized"
}
\ No newline at end of file
diff --git a/src/locales/en/move-trigger.json b/src/locales/en/move-trigger.json
index e70fb9dcfb7..375ea354d33 100644
--- a/src/locales/en/move-trigger.json
+++ b/src/locales/en/move-trigger.json
@@ -7,6 +7,7 @@
"switchedStat": "{{pokemonName}} switched {{stat}} with its target!",
"sharedGuard": "{{pokemonName}} shared its guard with the target!",
"sharedPower": "{{pokemonName}} shared its power with the target!",
+ "shiftedStats": "{{pokemonName}} switched its {{statToSwitch}} and {{statToSwitchWith}}!",
"goingAllOutForAttack": "{{pokemonName}} is going all out for this attack!",
"regainedHealth": "{{pokemonName}} regained\nhealth!",
"keptGoingAndCrashed": "{{pokemonName}} kept going\nand crashed!",
@@ -66,5 +67,6 @@
"revivalBlessing": "{{pokemonName}} was revived!",
"swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!",
"exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!",
- "safeguard": "{{targetName}} is protected by Safeguard!"
-}
\ No newline at end of file
+ "safeguard": "{{targetName}} is protected by Safeguard!",
+ "afterYou": "{{pokemonName}} took the kind offer!"
+}
diff --git a/src/locales/pt_BR/ability-trigger.json b/src/locales/pt_BR/ability-trigger.json
index f6a11267f9d..cd47fd8e3dc 100644
--- a/src/locales/pt_BR/ability-trigger.json
+++ b/src/locales/pt_BR/ability-trigger.json
@@ -12,6 +12,7 @@
"blockItemTheft": "{{abilityName}} de {{pokemonNameWithAffix}}\nprevine o roubo de itens!",
"typeImmunityHeal": "{{abilityName}} de {{pokemonNameWithAffix}}\nrestaurou um pouco de PS!",
"nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}} evitou dano\ncom {{abilityName}}!",
+ "fullHpResistType": "{{pokemonNameWithAffix}} fez seu casco brilhar!\nEstá distorcendo o confronte de tipos!",
"moveImmunity": "Isso não afeta {{pokemonNameWithAffix}}!",
"reverseDrain": "{{pokemonNameWithAffix}} absorveu a gosma líquida!",
"postDefendTypeChange": "{{abilityName}} de {{pokemonNameWithAffix}}\ntransformou-o no tipo {{typeName}}!",
diff --git a/src/locales/pt_BR/battle.json b/src/locales/pt_BR/battle.json
index 2b20e0062ea..08eeb99e0cd 100644
--- a/src/locales/pt_BR/battle.json
+++ b/src/locales/pt_BR/battle.json
@@ -44,6 +44,7 @@
"moveNotImplemented": "{{moveName}} ainda não foi implementado e não pode ser usado.",
"moveNoPP": "Não há mais PP\npara esse movimento!",
"moveDisabled": "Não se pode usar {{moveName}} porque foi desabilitado!",
+ "disableInterruptedMove": "{{moveName}} de {{pokemonNameWithAffix}}\nestá desabilitado!",
"noPokeballForce": "Uma força misteriosa\nte impede de usar Poké Bolas.",
"noPokeballTrainer": "Não se pode capturar\nPokémon dos outros!",
"noPokeballMulti": "Não se pode lançar Poké Bolas\nquando há mais de um Pokémon!",
@@ -61,6 +62,7 @@
"skipItemQuestion": "Tem certeza de que não quer escolher um item?",
"itemStackFull": "O estoque de {{fullItemName}} está cheio.\nVocê receberá {{itemName}} no lugar.",
"eggHatching": "Opa?",
+ "eggSkipPrompt": "Pular para súmario de ovos?",
"ivScannerUseQuestion": "Quer usar o Scanner de IVs em {{pokemonName}}?",
"wildPokemonWithAffix": "{{pokemonName}} selvagem",
"foePokemonWithAffix": "{{pokemonName}} adversário",
@@ -89,7 +91,7 @@
"statSeverelyFell_other": "{{stats}} de {{pokemonNameWithAffix}} diminuíram severamente!",
"statWontGoAnyLower_one": "{{stats}} de {{pokemonNameWithAffix}} não vai mais diminuir!",
"statWontGoAnyLower_other": "{{stats}} de {{pokemonNameWithAffix}} não vão mais diminuir!",
- "transformedIntoType": "{{pokemonName}} transformed\ninto the {{type}} type!",
+ "transformedIntoType": "{{pokemonName}} se transformou\nno tipo {{type}}!",
"ppReduced": "O PP do movimento {{moveName}} de\n{{targetName}} foi reduzido em {{reduction}}!",
"retryBattle": "Você gostaria de tentar novamente desde o início da batalha?",
"unlockedSomething": "{{unlockedThing}}\nfoi desbloqueado.",
diff --git a/src/locales/pt_BR/battler-tags.json b/src/locales/pt_BR/battler-tags.json
index e0f6538404b..9c0f4732013 100644
--- a/src/locales/pt_BR/battler-tags.json
+++ b/src/locales/pt_BR/battler-tags.json
@@ -67,5 +67,7 @@
"saltCuredLapse": "{{pokemonNameWithAffix}} foi ferido pelo {{moveName}}!",
"cursedOnAdd": "{{pokemonNameWithAffix}} cortou seus PS pela metade e amaldiçoou {{pokemonName}}!",
"cursedLapse": "{{pokemonNameWithAffix}} foi ferido pelo Curse!",
- "stockpilingOnAdd": "{{pokemonNameWithAffix}} estocou {{stockpiledCount}}!"
+ "stockpilingOnAdd": "{{pokemonNameWithAffix}} estocou {{stockpiledCount}}!",
+ "disabledOnAdd": "{{moveName}} de {{pokemonNameWithAffix}}\nfoi desabilitado!",
+ "disabledLapse": "{{moveName}} de {{pokemonNameWithAffix}}\nnão está mais desabilitado."
}
diff --git a/src/locales/pt_BR/challenges.json b/src/locales/pt_BR/challenges.json
index 8402ad106b6..9dc613651a6 100644
--- a/src/locales/pt_BR/challenges.json
+++ b/src/locales/pt_BR/challenges.json
@@ -1,6 +1,7 @@
{
"title": "Desafios",
"illegalEvolution": "{{pokemon}} não pode ser escolhido\nnesse desafio!",
+ "noneSelected": "Nada Selecionado",
"singleGeneration": {
"name": "Geração Única",
"desc": "Você só pode user Pokémon da {{gen}} geração.",
@@ -33,4 +34,4 @@
"value.0": "Desligado",
"value.1": "Ligado"
}
-}
+}
\ No newline at end of file
diff --git a/src/overrides.ts b/src/overrides.ts
index 48c118b55bc..d1597dfdee8 100644
--- a/src/overrides.ts
+++ b/src/overrides.ts
@@ -98,7 +98,7 @@ class DefaultOverrides {
readonly PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE;
readonly STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
readonly GENDER_OVERRIDE: Gender | null = null;
- readonly MOVESET_OVERRIDE: Array = [];
+ readonly MOVESET_OVERRIDE: Moves | Array = [];
readonly SHINY_OVERRIDE: boolean = false;
readonly VARIANT_OVERRIDE: Variant = 0;
@@ -111,7 +111,7 @@ class DefaultOverrides {
readonly OPP_PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE;
readonly OPP_STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
readonly OPP_GENDER_OVERRIDE: Gender | null = null;
- readonly OPP_MOVESET_OVERRIDE: Array = [];
+ readonly OPP_MOVESET_OVERRIDE: Moves | Array = [];
readonly OPP_SHINY_OVERRIDE: boolean = false;
readonly OPP_VARIANT_OVERRIDE: Variant = 0;
readonly OPP_IVS_OVERRIDE: number | number[] = [];
diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts
index 48366afaad4..c30003b79aa 100644
--- a/src/phases/faint-phase.ts
+++ b/src/phases/faint-phase.ts
@@ -65,6 +65,8 @@ export class FaintPhase extends PokemonPhase {
if (pokemon.turnData?.attacksReceived?.length) {
const lastAttack = pokemon.turnData.attacksReceived[0];
applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, this.scene.getPokemonById(lastAttack.sourceId)!, new PokemonMove(lastAttack.move).getMove(), lastAttack.result); // TODO: is this bang correct?
+ } else { //If killed by indirect damage, apply post-faint abilities without providing a last move
+ applyPostFaintAbAttrs(PostFaintAbAttr, pokemon);
}
const alivePlayField = this.scene.getField(true);
diff --git a/src/phases/learn-move-phase.ts b/src/phases/learn-move-phase.ts
index 049fc6951b6..fad7eac9b68 100644
--- a/src/phases/learn-move-phase.ts
+++ b/src/phases/learn-move-phase.ts
@@ -1,6 +1,6 @@
import BattleScene from "#app/battle-scene";
import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
-import { allMoves } from "#app/data/move";
+import Move, { allMoves } from "#app/data/move";
import { SpeciesFormChangeMoveLearnedTrigger } from "#app/data/pokemon-forms";
import { Moves } from "#app/enums/moves";
import { getPokemonNameWithAffix } from "#app/messages";
@@ -9,14 +9,15 @@ import { SummaryUiMode } from "#app/ui/summary-ui-handler";
import { Mode } from "#app/ui/ui";
import i18next from "i18next";
import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase";
+import Pokemon from "#app/field/pokemon";
export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
private moveId: Moves;
+ private messageMode: Mode;
private fromTM: boolean;
constructor(scene: BattleScene, partyMemberIndex: integer, moveId: Moves, fromTM?: boolean) {
super(scene, partyMemberIndex);
-
this.moveId = moveId;
this.fromTM = fromTM ?? false;
}
@@ -26,87 +27,128 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
const pokemon = this.getPokemon();
const move = allMoves[this.moveId];
+ const currentMoveset = pokemon.getMoveset();
- const existingMoveIndex = pokemon.getMoveset().findIndex(m => m?.moveId === move.id);
-
- if (existingMoveIndex > -1) {
+ // The game first checks if the Pokemon already has the move and ends the phase if it does.
+ const hasMoveAlready = currentMoveset.some(m => m?.moveId === move.id) && this.moveId !== Moves.SKETCH;
+ if (hasMoveAlready) {
return this.end();
}
- const emptyMoveIndex = pokemon.getMoveset().length < 4
- ? pokemon.getMoveset().length
- : pokemon.getMoveset().findIndex(m => m === null);
-
- const messageMode = this.scene.ui.getHandler() instanceof EvolutionSceneHandler
- ? Mode.EVOLUTION_SCENE
- : Mode.MESSAGE;
-
- if (emptyMoveIndex > -1) {
- pokemon.setMove(emptyMoveIndex, this.moveId);
- if (this.fromTM) {
- pokemon.usedTMs.push(this.moveId);
- }
- initMoveAnim(this.scene, this.moveId).then(() => {
- loadMoveAnimAssets(this.scene, [this.moveId], true)
- .then(() => {
- this.scene.ui.setMode(messageMode).then(() => {
- // Sound loaded into game as is
- this.scene.playSound("level_up_fanfare");
- this.scene.ui.showText(i18next.t("battle:learnMove", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => {
- this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true);
- this.end();
- }, messageMode === Mode.EVOLUTION_SCENE ? 1000 : null, true);
- });
- });
- });
+ this.messageMode = this.scene.ui.getHandler() instanceof EvolutionSceneHandler ? Mode.EVOLUTION_SCENE : Mode.MESSAGE;
+ this.scene.ui.setMode(this.messageMode);
+ // If the Pokemon has less than 4 moves, the new move is added to the largest empty moveset index
+ // If it has 4 moves, the phase then checks if the player wants to replace the move itself.
+ if (currentMoveset.length < 4) {
+ this.learnMove(currentMoveset.length, move, pokemon);
} else {
- this.scene.ui.setMode(messageMode).then(() => {
- this.scene.ui.showText(i18next.t("battle:learnMovePrompt", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => {
- this.scene.ui.showText(i18next.t("battle:learnMoveLimitReached", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => {
- this.scene.ui.showText(i18next.t("battle:learnMoveReplaceQuestion", { moveName: move.name }), null, () => {
- const noHandler = () => {
- this.scene.ui.setMode(messageMode).then(() => {
- this.scene.ui.showText(i18next.t("battle:learnMoveStopTeaching", { moveName: move.name }), null, () => {
- this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => {
- this.scene.ui.setMode(messageMode);
- this.scene.ui.showText(i18next.t("battle:learnMoveNotLearned", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => this.end(), null, true);
- }, () => {
- this.scene.ui.setMode(messageMode);
- this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId));
- this.end();
- });
- });
- });
- };
- this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => {
- this.scene.ui.setMode(messageMode);
- this.scene.ui.showText(i18next.t("battle:learnMoveForgetQuestion"), null, () => {
- this.scene.ui.setModeWithoutClear(Mode.SUMMARY, this.getPokemon(), SummaryUiMode.LEARN_MOVE, move, (moveIndex: integer) => {
- if (moveIndex === 4) {
- noHandler();
- return;
- }
- this.scene.ui.setMode(messageMode).then(() => {
- this.scene.ui.showText(i18next.t("battle:countdownPoof"), null, () => {
- this.scene.ui.showText(i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() }), null, () => { // TODO: is the bang correct?
- this.scene.ui.showText(i18next.t("battle:learnMoveAnd"), null, () => {
- if (this.fromTM) {
- pokemon.usedTMs.push(this.moveId);
- }
- pokemon.setMove(moveIndex, Moves.NONE);
- this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId));
- this.end();
- }, null, true);
- }, null, true);
- }, null, true);
- });
- });
- }, null, true);
- }, noHandler);
- });
- }, null, true);
- }, null, true);
- });
+ this.replaceMoveCheck(move, pokemon);
}
}
+
+ /**
+ * This displays a chain of messages (listed below) and asks if the user wishes to forget a move.
+ *
+ * > [Pokemon] wants to learn the move [MoveName]
+ * > However, [Pokemon] already knows four moves.
+ * > Should a move be forgotten and replaced with [MoveName]? --> `Mode.CONFIRM` -> Yes: Go to `this.forgetMoveProcess()`, No: Go to `this.rejectMoveAndEnd()`
+ * @param move The Move to be learned
+ * @param Pokemon The Pokemon learning the move
+ */
+ async replaceMoveCheck(move: Move, pokemon: Pokemon) {
+ const learnMovePrompt = i18next.t("battle:learnMovePrompt", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name });
+ const moveLimitReached = i18next.t("battle:learnMoveLimitReached", { pokemonName: getPokemonNameWithAffix(pokemon) });
+ const shouldReplaceQ = i18next.t("battle:learnMoveReplaceQuestion", { moveName: move.name });
+ const preQText = [learnMovePrompt, moveLimitReached].join("$");
+ await this.scene.ui.showTextPromise(preQText);
+ await this.scene.ui.showTextPromise(shouldReplaceQ, undefined, false);
+ await this.scene.ui.setModeWithoutClear(Mode.CONFIRM,
+ () => this.forgetMoveProcess(move, pokemon), // Yes
+ () => { // No
+ this.scene.ui.setMode(this.messageMode);
+ this.rejectMoveAndEnd(move, pokemon);
+ }
+ );
+ }
+
+ /**
+ * This facilitates the process in which an old move is chosen to be forgotten.
+ *
+ * > Which move should be forgotten?
+ *
+ * The game then goes `Mode.SUMMARY` to select a move to be forgotten.
+ * If a player does not select a move or chooses the new move (`moveIndex === 4`), the game goes to `this.rejectMoveAndEnd()`.
+ * If an old move is selected, the function then passes the `moveIndex` to `this.learnMove()`
+ * @param move The Move to be learned
+ * @param Pokemon The Pokemon learning the move
+ */
+ async forgetMoveProcess(move: Move, pokemon: Pokemon) {
+ this.scene.ui.setMode(this.messageMode);
+ await this.scene.ui.showTextPromise(i18next.t("battle:learnMoveForgetQuestion"), undefined, true);
+ await this.scene.ui.setModeWithoutClear(Mode.SUMMARY, pokemon, SummaryUiMode.LEARN_MOVE, move, (moveIndex: integer) => {
+ if (moveIndex === 4) {
+ this.scene.ui.setMode(this.messageMode).then(() => this.rejectMoveAndEnd(move, pokemon));
+ return;
+ }
+ const forgetSuccessText = i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() });
+ const fullText = [i18next.t("battle:countdownPoof"), forgetSuccessText, i18next.t("battle:learnMoveAnd")].join("$");
+ this.scene.ui.setMode(this.messageMode).then(() => this.learnMove(moveIndex, move, pokemon, fullText));
+ });
+ }
+
+ /**
+ * This asks the player if they wish to end the current move learning process.
+ *
+ * > Stop trying to teach [MoveName]? --> `Mode.CONFIRM` --> Yes: > [Pokemon] did not learn the move [MoveName], No: `this.replaceMoveCheck()`
+ *
+ * If the player wishes to not teach the Pokemon the move, it displays a message and ends the phase.
+ * If the player reconsiders, it repeats the process for a Pokemon with a full moveset once again.
+ * @param move The Move to be learned
+ * @param Pokemon The Pokemon learning the move
+ */
+ async rejectMoveAndEnd(move: Move, pokemon: Pokemon) {
+ await this.scene.ui.showTextPromise(i18next.t("battle:learnMoveStopTeaching", { moveName: move.name }), undefined, false);
+ this.scene.ui.setModeWithoutClear(Mode.CONFIRM,
+ () => {
+ this.scene.ui.setMode(this.messageMode);
+ this.scene.ui.showTextPromise(i18next.t("battle:learnMoveNotLearned", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), undefined, true).then(() => this.end());
+ },
+ () => {
+ this.scene.ui.setMode(this.messageMode);
+ this.replaceMoveCheck(move, pokemon);
+ }
+ );
+ }
+
+ /**
+ * This teaches the Pokemon the new move and ends the phase.
+ * When a Pokemon forgets a move and learns a new one, its 'Learn Move' message is significantly longer.
+ *
+ * Pokemon with a `moveset.length < 4`
+ * > [Pokemon] learned [MoveName]
+ *
+ * Pokemon with a `moveset.length > 4`
+ * > 1... 2... and 3... and Poof!
+ * > [Pokemon] forgot how to use [MoveName]
+ * > And...
+ * > [Pokemon] learned [MoveName]!
+ * @param move The Move to be learned
+ * @param Pokemon The Pokemon learning the move
+ */
+ async learnMove(index: number, move: Move, pokemon: Pokemon, textMessage?: string) {
+ if (this.fromTM) {
+ pokemon.usedTMs.push(this.moveId);
+ }
+ pokemon.setMove(index, this.moveId);
+ initMoveAnim(this.scene, this.moveId).then(() => {
+ loadMoveAnimAssets(this.scene, [this.moveId], true);
+ this.scene.playSound("level_up_fanfare"); // Sound loaded into game as is
+ });
+ this.scene.ui.setMode(this.messageMode);
+ const learnMoveText = i18next.t("battle:learnMove", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name });
+ textMessage = textMessage ? textMessage+"$"+learnMoveText : learnMoveText;
+ await this.scene.ui.showTextPromise(textMessage, this.messageMode === Mode.EVOLUTION_SCENE ? 1000 : undefined, true);
+ this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true);
+ this.end();
+ }
}
diff --git a/src/test/abilities/aura_break.test.ts b/src/test/abilities/aura_break.test.ts
index 0fb2212d817..422ac5178c1 100644
--- a/src/test/abilities/aura_break.test.ts
+++ b/src/test/abilities/aura_break.test.ts
@@ -3,7 +3,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -27,7 +26,7 @@ describe("Abilities - Aura Break", () => {
game = new GameManager(phaserGame);
game.override.battleType("single");
game.override.moveset([Moves.MOONBLAST, Moves.DARK_PULSE, Moves.MOONBLAST, Moves.DARK_PULSE]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyAbility(Abilities.AURA_BREAK);
game.override.enemySpecies(Species.SHUCKLE);
});
diff --git a/src/test/abilities/battery.test.ts b/src/test/abilities/battery.test.ts
index 020866509d6..cd02ed0c4eb 100644
--- a/src/test/abilities/battery.test.ts
+++ b/src/test/abilities/battery.test.ts
@@ -5,7 +5,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -31,7 +30,7 @@ describe("Abilities - Battery", () => {
game.override.enemySpecies(Species.SHUCKLE);
game.override.enemyAbility(Abilities.BALL_FETCH);
game.override.moveset([Moves.TACKLE, Moves.BREAKING_SWIPE, Moves.SPLASH, Moves.DAZZLING_GLEAM]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
it("raises the power of allies' special moves by 30%", async () => {
diff --git a/src/test/abilities/beast_boost.test.ts b/src/test/abilities/beast_boost.test.ts
index 05645a1231d..26bae7b8838 100644
--- a/src/test/abilities/beast_boost.test.ts
+++ b/src/test/abilities/beast_boost.test.ts
@@ -4,7 +4,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { Stat } from "#enums/stat";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -31,7 +30,7 @@ describe("Abilities - Beast Boost", () => {
.ability(Abilities.BEAST_BOOST)
.startingLevel(2000)
.moveset([ Moves.FLAMETHROWER ])
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
it("should prefer highest stat to boost its corresponding stat stage by 1 when winning a battle", async() => {
@@ -51,7 +50,7 @@ describe("Abilities - Beast Boost", () => {
}, 20000);
it("should use in-battle overriden stats when determining the stat stage to raise by 1", async() => {
- game.override.enemyMoveset(new Array(4).fill(Moves.GUARD_SPLIT));
+ game.override.enemyMoveset([Moves.GUARD_SPLIT]);
await game.classicMode.startBattle([Species.SLOWBRO]);
diff --git a/src/test/abilities/contrary.test.ts b/src/test/abilities/contrary.test.ts
index 19ecc7e0240..95a209395dc 100644
--- a/src/test/abilities/contrary.test.ts
+++ b/src/test/abilities/contrary.test.ts
@@ -1,10 +1,10 @@
-import { Stat } from "#enums/stat";
-import GameManager from "#test/utils/gameManager";
+import { Moves } from "#app/enums/moves";
import { Abilities } from "#enums/abilities";
import { Species } from "#enums/species";
+import { Stat } from "#enums/stat";
+import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Abilities - Contrary", () => {
let phaserGame: Phaser.Game;
@@ -27,7 +27,7 @@ describe("Abilities - Contrary", () => {
.enemySpecies(Species.BULBASAUR)
.enemyAbility(Abilities.CONTRARY)
.ability(Abilities.INTIMIDATE)
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
it("should invert stat changes when applied", async() => {
diff --git a/src/test/abilities/costar.test.ts b/src/test/abilities/costar.test.ts
index 96ec775f2a0..794bed0d3cf 100644
--- a/src/test/abilities/costar.test.ts
+++ b/src/test/abilities/costar.test.ts
@@ -5,7 +5,6 @@ import { Species } from "#app/enums/species";
import { CommandPhase } from "#app/phases/command-phase";
import { MessagePhase } from "#app/phases/message-phase";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
@@ -30,7 +29,7 @@ describe("Abilities - COSTAR", () => {
game.override.battleType("double");
game.override.ability(Abilities.COSTAR);
game.override.moveset([Moves.SPLASH, Moves.NASTY_PLOT]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
diff --git a/src/test/abilities/dancer.test.ts b/src/test/abilities/dancer.test.ts
index d80f497f8b2..ec5ce53f4c3 100644
--- a/src/test/abilities/dancer.test.ts
+++ b/src/test/abilities/dancer.test.ts
@@ -30,7 +30,7 @@ describe("Abilities - Dancer", () => {
.moveset([Moves.SWORDS_DANCE, Moves.SPLASH])
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.DANCER)
- .enemyMoveset(Array(4).fill(Moves.VICTORY_DANCE));
+ .enemyMoveset([Moves.VICTORY_DANCE]);
});
// Reference Link: https://bulbapedia.bulbagarden.net/wiki/Dancer_(Ability)
diff --git a/src/test/abilities/disguise.test.ts b/src/test/abilities/disguise.test.ts
index ef145262954..fa7f26d2716 100644
--- a/src/test/abilities/disguise.test.ts
+++ b/src/test/abilities/disguise.test.ts
@@ -6,7 +6,6 @@ import { StatusEffect } from "#app/data/status-effect";
import { Stat } from "#enums/stat";
import GameManager from "#test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@@ -31,7 +30,7 @@ describe("Abilities - Disguise", () => {
game.override
.battleType("single")
.enemySpecies(Species.MIMIKYU)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.starterSpecies(Species.REGIELEKI)
.moveset([Moves.SHADOW_SNEAK, Moves.VACUUM_WAVE, Moves.TOXIC_THREAD, Moves.SPLASH]);
}, TIMEOUT);
@@ -108,7 +107,7 @@ describe("Abilities - Disguise", () => {
}, TIMEOUT);
it("persists form change when switched out", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK));
+ game.override.enemyMoveset([Moves.SHADOW_SNEAK]);
game.override.starterSpecies(0);
await game.classicMode.startBattle([ Species.MIMIKYU, Species.FURRET ]);
@@ -194,7 +193,7 @@ describe("Abilities - Disguise", () => {
}, TIMEOUT);
it("doesn't faint twice when fainting due to Disguise break damage, nor prevent faint from Disguise break damage if using Endure", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.ENDURE));
+ game.override.enemyMoveset([Moves.ENDURE]);
await game.classicMode.startBattle();
const mimikyu = game.scene.getEnemyPokemon()!;
diff --git a/src/test/abilities/dry_skin.test.ts b/src/test/abilities/dry_skin.test.ts
index b337e4d96f7..1af8831f25b 100644
--- a/src/test/abilities/dry_skin.test.ts
+++ b/src/test/abilities/dry_skin.test.ts
@@ -1,9 +1,7 @@
import { Species } from "#app/enums/species";
-import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -23,63 +21,56 @@ describe("Abilities - Dry Skin", () => {
beforeEach(() => {
game = new GameManager(phaserGame);
- game.override.battleType("single");
- game.override.disableCrits();
- game.override.enemyAbility(Abilities.DRY_SKIN);
- game.override.enemyMoveset(SPLASH_ONLY);
- game.override.enemySpecies(Species.CHARMANDER);
- game.override.ability(Abilities.UNNERVE);
- game.override.starterSpecies(Species.CHANDELURE);
+ game.override
+ .battleType("single")
+ .disableCrits()
+ .enemyAbility(Abilities.DRY_SKIN)
+ .enemyMoveset(Moves.SPLASH)
+ .enemySpecies(Species.CHARMANDER)
+ .ability(Abilities.BALL_FETCH)
+ .moveset([Moves.SUNNY_DAY, Moves.RAIN_DANCE, Moves.SPLASH, Moves.WATER_GUN])
+ .starterSpecies(Species.CHANDELURE);
});
it("during sunlight, lose 1/8 of maximum health at the end of each turn", async () => {
- game.override.moveset([Moves.SUNNY_DAY, Moves.SPLASH]);
-
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!;
- expect(enemy).not.toBe(undefined);
// first turn
- let previousEnemyHp = enemy.hp;
game.move.select(Moves.SUNNY_DAY);
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(enemy.hp).toBeLessThan(previousEnemyHp);
+ await game.phaseInterceptor.to("TurnEndPhase");
+ expect(enemy.hp).toBeLessThan(enemy.getMaxHp());
// second turn
- previousEnemyHp = enemy.hp;
+ enemy.hp = enemy.getMaxHp();
game.move.select(Moves.SPLASH);
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(enemy.hp).toBeLessThan(previousEnemyHp);
+ await game.phaseInterceptor.to("TurnEndPhase");
+ expect(enemy.hp).toBeLessThan(enemy.getMaxHp());
});
it("during rain, gain 1/8 of maximum health at the end of each turn", async () => {
- game.override.moveset([Moves.RAIN_DANCE, Moves.SPLASH]);
-
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!;
- expect(enemy).not.toBe(undefined);
enemy.hp = 1;
// first turn
- let previousEnemyHp = enemy.hp;
game.move.select(Moves.RAIN_DANCE);
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(enemy.hp).toBeGreaterThan(previousEnemyHp);
+ await game.phaseInterceptor.to("TurnEndPhase");
+ expect(enemy.hp).toBeGreaterThan(1);
// second turn
- previousEnemyHp = enemy.hp;
+ enemy.hp = 1;
game.move.select(Moves.SPLASH);
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(enemy.hp).toBeGreaterThan(previousEnemyHp);
+ await game.phaseInterceptor.to("TurnEndPhase");
+ expect(enemy.hp).toBeGreaterThan(1);
});
it("opposing fire attacks do 25% more damage", async () => {
game.override.moveset([Moves.FLAMETHROWER]);
-
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!;
const initialHP = 1000;
@@ -87,72 +78,65 @@ describe("Abilities - Dry Skin", () => {
// first turn
game.move.select(Moves.FLAMETHROWER);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to("TurnEndPhase");
const fireDamageTakenWithDrySkin = initialHP - enemy.hp;
- expect(enemy.hp > 0);
enemy.hp = initialHP;
game.override.enemyAbility(Abilities.NONE);
// second turn
game.move.select(Moves.FLAMETHROWER);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to("TurnEndPhase");
const fireDamageTakenWithoutDrySkin = initialHP - enemy.hp;
expect(fireDamageTakenWithDrySkin).toBeGreaterThan(fireDamageTakenWithoutDrySkin);
});
it("opposing water attacks heal 1/4 of maximum health and deal no damage", async () => {
- game.override.moveset([Moves.WATER_GUN]);
-
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!;
- expect(enemy).not.toBe(undefined);
enemy.hp = 1;
game.move.select(Moves.WATER_GUN);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to("TurnEndPhase");
expect(enemy.hp).toBeGreaterThan(1);
});
it("opposing water attacks do not heal if they were protected from", async () => {
- game.override.moveset([Moves.WATER_GUN]);
+ game.override.enemyMoveset([Moves.PROTECT]);
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!;
- expect(enemy).not.toBe(undefined);
enemy.hp = 1;
- game.override.enemyMoveset([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]);
game.move.select(Moves.WATER_GUN);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to("TurnEndPhase");
expect(enemy.hp).toBe(1);
});
it("multi-strike water attacks only heal once", async () => {
game.override.moveset([Moves.WATER_GUN, Moves.WATER_SHURIKEN]);
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!;
- expect(enemy).not.toBe(undefined);
enemy.hp = 1;
// first turn
game.move.select(Moves.WATER_SHURIKEN);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to("TurnEndPhase");
const healthGainedFromWaterShuriken = enemy.hp - 1;
enemy.hp = 1;
// second turn
game.move.select(Moves.WATER_GUN);
- await game.phaseInterceptor.to(TurnEndPhase);
+ await game.phaseInterceptor.to("TurnEndPhase");
const healthGainedFromWaterGun = enemy.hp - 1;
expect(healthGainedFromWaterShuriken).toBe(healthGainedFromWaterGun);
diff --git a/src/test/abilities/flash_fire.test.ts b/src/test/abilities/flash_fire.test.ts
index de40873998f..c3cf31496ea 100644
--- a/src/test/abilities/flash_fire.test.ts
+++ b/src/test/abilities/flash_fire.test.ts
@@ -7,7 +7,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -38,7 +37,7 @@ describe("Abilities - Flash Fire", () => {
it("immune to Fire-type moves", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset(SPLASH_ONLY);
+ game.override.enemyMoveset([Moves.EMBER]).moveset(Moves.SPLASH);
await game.startBattle([Species.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!;
@@ -49,7 +48,7 @@ describe("Abilities - Flash Fire", () => {
}, 20000);
it("not activate if the Pokémon is protected from the Fire-type move", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset([Moves.PROTECT]);
+ game.override.enemyMoveset([Moves.EMBER]).moveset([Moves.PROTECT]);
await game.startBattle([Species.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!;
@@ -60,7 +59,7 @@ describe("Abilities - Flash Fire", () => {
}, 20000);
it("activated by Will-O-Wisp", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.WILL_O_WISP)).moveset(SPLASH_ONLY);
+ game.override.enemyMoveset([Moves.WILL_O_WISP]).moveset(Moves.SPLASH);
await game.startBattle([Species.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!;
@@ -75,7 +74,7 @@ describe("Abilities - Flash Fire", () => {
}, 20000);
it("activated after being frozen", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset(SPLASH_ONLY);
+ game.override.enemyMoveset([Moves.EMBER]).moveset(Moves.SPLASH);
game.override.statusEffect(StatusEffect.FREEZE);
await game.startBattle([Species.BLISSEY]);
@@ -88,7 +87,7 @@ describe("Abilities - Flash Fire", () => {
}, 20000);
it("not passing with baton pass", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset([Moves.BATON_PASS]);
+ game.override.enemyMoveset([Moves.EMBER]).moveset([Moves.BATON_PASS]);
await game.startBattle([Species.BLISSEY, Species.CHANSEY]);
// ensure use baton pass after enemy moved
@@ -104,7 +103,7 @@ describe("Abilities - Flash Fire", () => {
}, 20000);
it("boosts Fire-type move when the ability is activated", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.FIRE_PLEDGE)).moveset([Moves.EMBER, Moves.SPLASH]);
+ game.override.enemyMoveset([Moves.FIRE_PLEDGE]).moveset([Moves.EMBER, Moves.SPLASH]);
game.override.enemyAbility(Abilities.FLASH_FIRE).ability(Abilities.NONE);
await game.startBattle([Species.BLISSEY]);
const blissey = game.scene.getPlayerPokemon()!;
diff --git a/src/test/abilities/flower_gift.test.ts b/src/test/abilities/flower_gift.test.ts
index de07bd29478..256b61c6fea 100644
--- a/src/test/abilities/flower_gift.test.ts
+++ b/src/test/abilities/flower_gift.test.ts
@@ -5,7 +5,6 @@ import { WeatherType } from "#app/enums/weather-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -44,7 +43,7 @@ describe("Abilities - Flower Gift", () => {
game.override
.moveset([Moves.SPLASH, Moves.RAIN_DANCE, Moves.SUNNY_DAY, Moves.SKILL_SWAP])
.enemySpecies(Species.MAGIKARP)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyAbility(Abilities.BALL_FETCH);
});
@@ -92,7 +91,7 @@ describe("Abilities - Flower Gift", () => {
});
it("reverts to Overcast Form when the Pokémon loses Flower Gift, changes form under Harsh Sunlight/Sunny when it regains it", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.SKILL_SWAP)).weather(WeatherType.HARSH_SUN);
+ game.override.enemyMoveset([Moves.SKILL_SWAP]).weather(WeatherType.HARSH_SUN);
await game.classicMode.startBattle([Species.CHERRIM]);
@@ -111,7 +110,7 @@ describe("Abilities - Flower Gift", () => {
});
it("reverts to Overcast Form when the Flower Gift is suppressed, changes form under Harsh Sunlight/Sunny when it regains it", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.GASTRO_ACID)).weather(WeatherType.HARSH_SUN);
+ game.override.enemyMoveset([Moves.GASTRO_ACID]).weather(WeatherType.HARSH_SUN);
await game.classicMode.startBattle([Species.CHERRIM, Species.MAGIKARP]);
diff --git a/src/test/abilities/forecast.test.ts b/src/test/abilities/forecast.test.ts
index 78453c5f4d2..c1eb3600b8b 100644
--- a/src/test/abilities/forecast.test.ts
+++ b/src/test/abilities/forecast.test.ts
@@ -10,7 +10,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -67,7 +66,7 @@ describe("Abilities - Forecast", () => {
game.override
.moveset([Moves.SPLASH, Moves.RAIN_DANCE, Moves.SUNNY_DAY, Moves.TACKLE])
.enemySpecies(Species.MAGIKARP)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyAbility(Abilities.BALL_FETCH);
});
@@ -229,7 +228,7 @@ describe("Abilities - Forecast", () => {
});
it("reverts to Normal Form when Forecast is suppressed, changes form to match the weather when it regains it", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.GASTRO_ACID)).weather(WeatherType.RAIN);
+ game.override.enemyMoveset([Moves.GASTRO_ACID]).weather(WeatherType.RAIN);
await game.startBattle([Species.CASTFORM, Species.PIKACHU]);
const castform = game.scene.getPlayerPokemon()!;
@@ -260,7 +259,7 @@ describe("Abilities - Forecast", () => {
});
it("does not change Castform's form until after Stealth Rock deals damage", async () => {
- game.override.weather(WeatherType.RAIN).enemyMoveset(Array(4).fill(Moves.STEALTH_ROCK));
+ game.override.weather(WeatherType.RAIN).enemyMoveset([Moves.STEALTH_ROCK]);
await game.startBattle([Species.PIKACHU, Species.CASTFORM]);
// First turn - set up stealth rock
diff --git a/src/test/abilities/galvanize.test.ts b/src/test/abilities/galvanize.test.ts
index 4b0ddc14d7c..f81b854180a 100644
--- a/src/test/abilities/galvanize.test.ts
+++ b/src/test/abilities/galvanize.test.ts
@@ -6,7 +6,6 @@ import { Moves } from "#app/enums/moves";
import { Species } from "#app/enums/species";
import { HitResult } from "#app/field/pokemon";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -36,7 +35,7 @@ describe("Abilities - Galvanize", () => {
.moveset([Moves.TACKLE, Moves.REVELATION_DANCE, Moves.FURY_SWIPES])
.enemySpecies(Species.DUSCLOPS)
.enemyAbility(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyLevel(100);
});
diff --git a/src/test/abilities/gorilla_tactics.test.ts b/src/test/abilities/gorilla_tactics.test.ts
new file mode 100644
index 00000000000..df698194323
--- /dev/null
+++ b/src/test/abilities/gorilla_tactics.test.ts
@@ -0,0 +1,83 @@
+import { BattlerIndex } from "#app/battle";
+import { Moves } from "#app/enums/moves";
+import { Species } from "#app/enums/species";
+import { Stat } from "#app/enums/stat";
+import { Abilities } from "#enums/abilities";
+import GameManager from "#test/utils/gameManager";
+import Phaser from "phaser";
+import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
+
+describe("Abilities - Gorilla Tactics", () => {
+ let phaserGame: Phaser.Game;
+ let game: GameManager;
+ const TIMEOUT = 20 * 1000;
+
+ beforeAll(() => {
+ phaserGame = new Phaser.Game({
+ type: Phaser.HEADLESS,
+ });
+ });
+
+ afterEach(() => {
+ game.phaseInterceptor.restoreOg();
+ });
+
+ beforeEach(() => {
+ game = new GameManager(phaserGame);
+ game.override
+ .battleType("single")
+ .enemyAbility(Abilities.BALL_FETCH)
+ .enemyMoveset([Moves.SPLASH, Moves.DISABLE])
+ .enemySpecies(Species.MAGIKARP)
+ .enemyLevel(30)
+ .moveset([Moves.SPLASH, Moves.TACKLE, Moves.GROWL])
+ .ability(Abilities.GORILLA_TACTICS);
+ });
+
+ it("boosts the Pokémon's Attack by 50%, but limits the Pokémon to using only one move", async () => {
+ await game.classicMode.startBattle([Species.GALAR_DARMANITAN]);
+
+ const darmanitan = game.scene.getPlayerPokemon()!;
+ const initialAtkStat = darmanitan.getStat(Stat.ATK);
+
+ game.move.select(Moves.SPLASH);
+ await game.forceEnemyMove(Moves.SPLASH);
+
+ await game.phaseInterceptor.to("TurnEndPhase");
+
+ expect(darmanitan.getStat(Stat.ATK, false)).toBeCloseTo(initialAtkStat * 1.5);
+ // Other moves should be restricted
+ expect(darmanitan.isMoveRestricted(Moves.TACKLE)).toBe(true);
+ expect(darmanitan.isMoveRestricted(Moves.SPLASH)).toBe(false);
+ }, TIMEOUT);
+
+ it("should struggle if the only usable move is disabled", async () => {
+ await game.classicMode.startBattle([Species.GALAR_DARMANITAN]);
+
+ const darmanitan = game.scene.getPlayerPokemon()!;
+ const enemy = game.scene.getEnemyPokemon()!;
+
+ // First turn, lock move to Growl
+ game.move.select(Moves.GROWL);
+ await game.forceEnemyMove(Moves.SPLASH);
+
+ // Second turn, Growl is interrupted by Disable
+ await game.toNextTurn();
+
+ game.move.select(Moves.GROWL);
+ await game.forceEnemyMove(Moves.DISABLE);
+ await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
+
+ await game.phaseInterceptor.to("TurnEndPhase");
+ expect(enemy.getStatStage(Stat.ATK)).toBe(-1); // Only the effect of the first Growl should be applied
+
+ // Third turn, Struggle is used
+ await game.toNextTurn();
+
+ game.move.select(Moves.TACKLE);
+ await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
+
+ await game.phaseInterceptor.to("MoveEndPhase");
+ expect(darmanitan.hp).toBeLessThan(darmanitan.getMaxHp());
+ }, TIMEOUT);
+});
diff --git a/src/test/abilities/gulp_missile.test.ts b/src/test/abilities/gulp_missile.test.ts
index 286c3af1c56..ac0efd8e8d1 100644
--- a/src/test/abilities/gulp_missile.test.ts
+++ b/src/test/abilities/gulp_missile.test.ts
@@ -11,7 +11,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
import { Stat } from "#enums/stat";
describe("Abilities - Gulp Missile", () => {
@@ -49,7 +48,7 @@ describe("Abilities - Gulp Missile", () => {
.moveset([Moves.SURF, Moves.DIVE, Moves.SPLASH])
.enemySpecies(Species.SNORLAX)
.enemyAbility(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyLevel(5);
});
@@ -108,7 +107,7 @@ describe("Abilities - Gulp Missile", () => {
});
it("deals 1/4 of the attacker's maximum HP when hit by a damaging attack", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
await game.startBattle([Species.CRAMORANT]);
const enemy = game.scene.getEnemyPokemon()!;
@@ -121,7 +120,7 @@ describe("Abilities - Gulp Missile", () => {
});
it("does not have any effect when hit by non-damaging attack", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TAIL_WHIP));
+ game.override.enemyMoveset([Moves.TAIL_WHIP]);
await game.startBattle([Species.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!;
@@ -140,7 +139,7 @@ describe("Abilities - Gulp Missile", () => {
});
it("lowers attacker's DEF stat stage by 1 when hit in Gulping form", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
await game.startBattle([Species.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!;
@@ -164,7 +163,7 @@ describe("Abilities - Gulp Missile", () => {
});
it("paralyzes the enemy when hit in Gorging form", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
await game.startBattle([Species.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!;
@@ -188,7 +187,7 @@ describe("Abilities - Gulp Missile", () => {
});
it("does not activate the ability when underwater", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.SURF));
+ game.override.enemyMoveset([Moves.SURF]);
await game.startBattle([Species.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!;
@@ -201,7 +200,7 @@ describe("Abilities - Gulp Missile", () => {
});
it("prevents effect damage but inflicts secondary effect on attacker with Magic Guard", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)).enemyAbility(Abilities.MAGIC_GUARD);
+ game.override.enemyMoveset([Moves.TACKLE]).enemyAbility(Abilities.MAGIC_GUARD);
await game.startBattle([Species.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!;
@@ -225,7 +224,7 @@ describe("Abilities - Gulp Missile", () => {
});
it("cannot be suppressed", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.GASTRO_ACID));
+ game.override.enemyMoveset([Moves.GASTRO_ACID]);
await game.startBattle([Species.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!;
@@ -245,7 +244,7 @@ describe("Abilities - Gulp Missile", () => {
});
it("cannot be swapped with another ability", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.SKILL_SWAP));
+ game.override.enemyMoveset([Moves.SKILL_SWAP]);
await game.startBattle([Species.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!;
diff --git a/src/test/abilities/heatproof.test.ts b/src/test/abilities/heatproof.test.ts
index e2a558e6d99..61c406201bd 100644
--- a/src/test/abilities/heatproof.test.ts
+++ b/src/test/abilities/heatproof.test.ts
@@ -5,7 +5,6 @@ import { toDmgValue } from "#app/utils";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -30,7 +29,7 @@ describe("Abilities - Heatproof", () => {
.disableCrits()
.enemySpecies(Species.CHARMANDER)
.enemyAbility(Abilities.HEATPROOF)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyLevel(100)
.starterSpecies(Species.CHANDELURE)
.ability(Abilities.BALL_FETCH)
diff --git a/src/test/abilities/hustle.test.ts b/src/test/abilities/hustle.test.ts
index ff96b98c7ac..29cbfdc1a5d 100644
--- a/src/test/abilities/hustle.test.ts
+++ b/src/test/abilities/hustle.test.ts
@@ -4,7 +4,6 @@ import { Stat } from "#app/enums/stat";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -29,7 +28,7 @@ describe("Abilities - Hustle", () => {
.moveset([ Moves.TACKLE, Moves.GIGA_DRAIN, Moves.FISSURE ])
.disableCrits()
.battleType("single")
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemySpecies(Species.SHUCKLE)
.enemyAbility(Abilities.BALL_FETCH);
});
diff --git a/src/test/abilities/hyper_cutter.test.ts b/src/test/abilities/hyper_cutter.test.ts
index 64e04ac2fd3..ec947add939 100644
--- a/src/test/abilities/hyper_cutter.test.ts
+++ b/src/test/abilities/hyper_cutter.test.ts
@@ -3,7 +3,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -29,7 +28,7 @@ describe("Abilities - Hyper Cutter", () => {
.ability(Abilities.BALL_FETCH)
.enemySpecies(Species.SHUCKLE)
.enemyAbility(Abilities.HYPER_CUTTER)
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
// Reference Link: https://bulbapedia.bulbagarden.net/wiki/Hyper_Cutter_(Ability)
diff --git a/src/test/abilities/imposter.test.ts b/src/test/abilities/imposter.test.ts
index 2857f80632a..27673564aaa 100644
--- a/src/test/abilities/imposter.test.ts
+++ b/src/test/abilities/imposter.test.ts
@@ -6,7 +6,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Stat, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat";
import { Abilities } from "#enums/abilities";
-import { SPLASH_ONLY } from "../utils/testUtils";
// TODO: Add more tests once Imposter is fully implemented
describe("Abilities - Imposter", () => {
@@ -31,9 +30,9 @@ describe("Abilities - Imposter", () => {
.enemyLevel(200)
.enemyAbility(Abilities.BEAST_BOOST)
.enemyPassiveAbility(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.ability(Abilities.IMPOSTER)
- .moveset(SPLASH_ONLY);
+ .moveset(Moves.SPLASH);
});
it("should copy species, ability, gender, all stats except HP, all stat stages, moveset, and types of target", async () => {
@@ -77,7 +76,7 @@ describe("Abilities - Imposter", () => {
}, 20000);
it("should copy in-battle overridden stats", async () => {
- game.override.enemyMoveset(new Array(4).fill(Moves.POWER_SPLIT));
+ game.override.enemyMoveset([Moves.POWER_SPLIT]);
await game.startBattle([
Species.DITTO
diff --git a/src/test/abilities/intimidate.test.ts b/src/test/abilities/intimidate.test.ts
index f90ba6c0e1e..d4c097022df 100644
--- a/src/test/abilities/intimidate.test.ts
+++ b/src/test/abilities/intimidate.test.ts
@@ -7,7 +7,6 @@ import { getMovePosition } from "#test/utils/gameManagerUtils";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
describe("Abilities - Intimidate", () => {
let phaserGame: Phaser.Game;
@@ -31,7 +30,7 @@ describe("Abilities - Intimidate", () => {
.enemyPassiveAbility(Abilities.HYDRATION)
.ability(Abilities.INTIMIDATE)
.startingWave(3)
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
it("should lower ATK stat stage by 1 of enemy Pokemon on entry and player switch", async () => {
@@ -108,7 +107,7 @@ describe("Abilities - Intimidate", () => {
it("should lower ATK stat stage by 1 for every switch", async () => {
game.override.moveset([Moves.SPLASH])
- .enemyMoveset(new Array(4).fill(Moves.VOLT_SWITCH))
+ .enemyMoveset([Moves.VOLT_SWITCH])
.startingWave(5);
await game.classicMode.startBattle([ Species.MIGHTYENA, Species.POOCHYENA ]);
diff --git a/src/test/abilities/libero.test.ts b/src/test/abilities/libero.test.ts
index 7895e7de6bf..51f182d5401 100644
--- a/src/test/abilities/libero.test.ts
+++ b/src/test/abilities/libero.test.ts
@@ -9,7 +9,6 @@ import { Biome } from "#enums/biome";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
@@ -183,7 +182,7 @@ describe("Abilities - Libero", () => {
"ability applies correctly even if the pokemon's move misses",
async () => {
game.override.moveset([Moves.TACKLE]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
await game.startBattle([Species.MAGIKARP]);
diff --git a/src/test/abilities/magic_guard.test.ts b/src/test/abilities/magic_guard.test.ts
index 64c1746c7d9..4b3fb0ba985 100644
--- a/src/test/abilities/magic_guard.test.ts
+++ b/src/test/abilities/magic_guard.test.ts
@@ -8,7 +8,6 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -39,7 +38,7 @@ describe("Abilities - Magic Guard", () => {
/** Enemy Pokemon overrides */
game.override.enemySpecies(Species.SNORLAX);
game.override.enemyAbility(Abilities.INSOMNIA);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyLevel(100);
});
diff --git a/src/test/abilities/moody.test.ts b/src/test/abilities/moody.test.ts
index 5c46ea68ec5..166f69b0fe3 100644
--- a/src/test/abilities/moody.test.ts
+++ b/src/test/abilities/moody.test.ts
@@ -3,7 +3,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -29,8 +28,8 @@ describe("Abilities - Moody", () => {
.enemySpecies(Species.RATTATA)
.enemyAbility(Abilities.BALL_FETCH)
.ability(Abilities.MOODY)
- .enemyMoveset(SPLASH_ONLY)
- .moveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH)
+ .moveset(Moves.SPLASH);
});
it("should increase one stat stage by 2 and decrease a different stat stage by 1",
diff --git a/src/test/abilities/moxie.test.ts b/src/test/abilities/moxie.test.ts
index e713d78f39e..5f337fedabb 100644
--- a/src/test/abilities/moxie.test.ts
+++ b/src/test/abilities/moxie.test.ts
@@ -5,7 +5,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
import { BattlerIndex } from "#app/battle";
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
import { VictoryPhase } from "#app/phases/victory-phase";
@@ -34,7 +33,7 @@ describe("Abilities - Moxie", () => {
game.override.ability(Abilities.MOXIE);
game.override.startingLevel(2000);
game.override.moveset([ moveToUse ]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
it("should raise ATK stat stage by 1 when winning a battle", async() => {
diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts
index 81a30524a5e..2ad3f9e3f5c 100644
--- a/src/test/abilities/parental_bond.test.ts
+++ b/src/test/abilities/parental_bond.test.ts
@@ -7,7 +7,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -34,7 +33,7 @@ describe("Abilities - Parental Bond", () => {
game.override.ability(Abilities.PARENTAL_BOND);
game.override.enemySpecies(Species.SNORLAX);
game.override.enemyAbility(Abilities.FUR_COAT);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.startingLevel(100);
game.override.enemyLevel(100);
});
@@ -175,7 +174,7 @@ describe("Abilities - Parental Bond", () => {
"should not apply multiplier to counter moves",
async () => {
game.override.moveset([Moves.COUNTER]);
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
await game.classicMode.startBattle([Species.SHUCKLE]);
@@ -465,7 +464,7 @@ describe("Abilities - Parental Bond", () => {
"should not cause user to hit into King's Shield more than once",
async () => {
game.override.moveset([Moves.TACKLE]);
- game.override.enemyMoveset(Array(4).fill(Moves.KINGS_SHIELD));
+ game.override.enemyMoveset([Moves.KINGS_SHIELD]);
await game.classicMode.startBattle([Species.MAGIKARP]);
diff --git a/src/test/abilities/pastel_veil.test.ts b/src/test/abilities/pastel_veil.test.ts
index ba90c7e3b3f..31490aab143 100644
--- a/src/test/abilities/pastel_veil.test.ts
+++ b/src/test/abilities/pastel_veil.test.ts
@@ -8,7 +8,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Abilities - Pastel Veil", () => {
let phaserGame: Phaser.Game;
@@ -31,7 +30,7 @@ describe("Abilities - Pastel Veil", () => {
.moveset([Moves.TOXIC_THREAD, Moves.SPLASH])
.enemyAbility(Abilities.BALL_FETCH)
.enemySpecies(Species.SUNKERN)
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
it("prevents the user and its allies from being afflicted by poison", async () => {
diff --git a/src/test/abilities/power_spot.test.ts b/src/test/abilities/power_spot.test.ts
index b83284c0bac..6d349a1a3f9 100644
--- a/src/test/abilities/power_spot.test.ts
+++ b/src/test/abilities/power_spot.test.ts
@@ -5,7 +5,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -29,7 +28,7 @@ describe("Abilities - Power Spot", () => {
game = new GameManager(phaserGame);
game.override.battleType("double");
game.override.moveset([Moves.TACKLE, Moves.BREAKING_SWIPE, Moves.SPLASH, Moves.DAZZLING_GLEAM]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemySpecies(Species.SHUCKLE);
game.override.enemyAbility(Abilities.BALL_FETCH);
});
diff --git a/src/test/abilities/protean.test.ts b/src/test/abilities/protean.test.ts
index 6ecabbfade0..4be58a677a6 100644
--- a/src/test/abilities/protean.test.ts
+++ b/src/test/abilities/protean.test.ts
@@ -9,7 +9,6 @@ import { Biome } from "#enums/biome";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
@@ -183,7 +182,7 @@ describe("Abilities - Protean", () => {
"ability applies correctly even if the pokemon's move misses",
async () => {
game.override.moveset([Moves.TACKLE]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
await game.startBattle([Species.MAGIKARP]);
diff --git a/src/test/abilities/quick_draw.test.ts b/src/test/abilities/quick_draw.test.ts
index 00d344ed333..a02ee5cf56a 100644
--- a/src/test/abilities/quick_draw.test.ts
+++ b/src/test/abilities/quick_draw.test.ts
@@ -32,7 +32,7 @@ describe("Abilities - Quick Draw", () => {
game.override.enemyLevel(100);
game.override.enemySpecies(Species.MAGIKARP);
game.override.enemyAbility(Abilities.BALL_FETCH);
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
vi.spyOn(allAbilities[Abilities.QUICK_DRAW].getAttrs(BypassSpeedChanceAbAttr)[0], "chance", "get").mockReturnValue(100);
});
@@ -76,7 +76,7 @@ describe("Abilities - Quick Draw", () => {
);
test("does not increase priority", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.EXTREME_SPEED));
+ game.override.enemyMoveset([Moves.EXTREME_SPEED]);
await game.startBattle();
diff --git a/src/test/abilities/sand_spit.test.ts b/src/test/abilities/sand_spit.test.ts
index 041e20faf7f..add13ede296 100644
--- a/src/test/abilities/sand_spit.test.ts
+++ b/src/test/abilities/sand_spit.test.ts
@@ -35,7 +35,7 @@ describe("Abilities - Sand Spit", () => {
});
it("should trigger when hit with damaging move", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
await game.startBattle();
game.move.select(Moves.SPLASH);
@@ -45,7 +45,7 @@ describe("Abilities - Sand Spit", () => {
}, 20000);
it("should not trigger when targetted with status moves", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.GROWL));
+ game.override.enemyMoveset([Moves.GROWL]);
await game.startBattle();
game.move.select(Moves.COIL);
diff --git a/src/test/abilities/sap_sipper.test.ts b/src/test/abilities/sap_sipper.test.ts
index 2d70ede3530..5e8cac74c95 100644
--- a/src/test/abilities/sap_sipper.test.ts
+++ b/src/test/abilities/sap_sipper.test.ts
@@ -9,7 +9,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
// See also: TypeImmunityAbAttr
describe("Abilities - Sap Sipper", () => {
@@ -37,7 +36,7 @@ describe("Abilities - Sap Sipper", () => {
const enemyAbility = Abilities.SAP_SIPPER;
game.override.moveset([ moveToUse ]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemySpecies(Species.DUSKULL);
game.override.enemyAbility(enemyAbility);
@@ -59,7 +58,7 @@ describe("Abilities - Sap Sipper", () => {
const enemyAbility = Abilities.SAP_SIPPER;
game.override.moveset([ moveToUse ]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemySpecies(Species.RATTATA);
game.override.enemyAbility(enemyAbility);
@@ -80,7 +79,7 @@ describe("Abilities - Sap Sipper", () => {
const enemyAbility = Abilities.SAP_SIPPER;
game.override.moveset([ moveToUse ]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemySpecies(Species.RATTATA);
game.override.enemyAbility(enemyAbility);
@@ -100,7 +99,7 @@ describe("Abilities - Sap Sipper", () => {
const enemyAbility = Abilities.SAP_SIPPER;
game.override.moveset([ moveToUse ]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemySpecies(Species.RATTATA);
game.override.enemyAbility(enemyAbility);
@@ -123,7 +122,7 @@ describe("Abilities - Sap Sipper", () => {
game.override.moveset([ moveToUse ]);
game.override.ability(ability);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemySpecies(Species.RATTATA);
game.override.enemyAbility(Abilities.NONE);
diff --git a/src/test/abilities/simple.test.ts b/src/test/abilities/simple.test.ts
index 4310c5d45d1..e5ca474d7c3 100644
--- a/src/test/abilities/simple.test.ts
+++ b/src/test/abilities/simple.test.ts
@@ -1,10 +1,10 @@
-import { Stat } from "#enums/stat";
-import GameManager from "#test/utils/gameManager";
+import { Moves } from "#app/enums/moves";
import { Abilities } from "#enums/abilities";
import { Species } from "#enums/species";
+import { Stat } from "#enums/stat";
+import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Abilities - Simple", () => {
let phaserGame: Phaser.Game;
@@ -27,7 +27,7 @@ describe("Abilities - Simple", () => {
.enemySpecies(Species.BULBASAUR)
.enemyAbility(Abilities.SIMPLE)
.ability(Abilities.INTIMIDATE)
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
it("should double stat changes when applied", async() => {
diff --git a/src/test/abilities/steely_spirit.test.ts b/src/test/abilities/steely_spirit.test.ts
index 7aaa0a42ae3..7b5879555be 100644
--- a/src/test/abilities/steely_spirit.test.ts
+++ b/src/test/abilities/steely_spirit.test.ts
@@ -4,7 +4,6 @@ import { Abilities } from "#app/enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -31,7 +30,7 @@ describe("Abilities - Steely Spirit", () => {
game.override.enemySpecies(Species.SHUCKLE);
game.override.enemyAbility(Abilities.BALL_FETCH);
game.override.moveset([Moves.IRON_HEAD, Moves.SPLASH]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
vi.spyOn(allMoves[moveToCheck], "calculateBattlePower");
});
diff --git a/src/test/abilities/sweet_veil.test.ts b/src/test/abilities/sweet_veil.test.ts
index 5de3c7285a9..c2946443245 100644
--- a/src/test/abilities/sweet_veil.test.ts
+++ b/src/test/abilities/sweet_veil.test.ts
@@ -6,7 +6,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -45,7 +44,7 @@ describe("Abilities - Sweet Veil", () => {
});
it("causes Rest to fail when used by the user or its allies", async () => {
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]);
game.move.select(Moves.SPLASH);
@@ -72,7 +71,7 @@ describe("Abilities - Sweet Veil", () => {
game.override.enemySpecies(Species.PIKACHU);
game.override.enemyLevel(5);
game.override.startingLevel(5);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
await game.startBattle([Species.SHUCKLE, Species.SHUCKLE, Species.SWIRLIX]);
diff --git a/src/test/abilities/tera_shell.test.ts b/src/test/abilities/tera_shell.test.ts
index 6a6b7bb252b..2826469f3bf 100644
--- a/src/test/abilities/tera_shell.test.ts
+++ b/src/test/abilities/tera_shell.test.ts
@@ -30,7 +30,7 @@ describe("Abilities - Tera Shell", () => {
.moveset([Moves.SPLASH])
.enemySpecies(Species.SNORLAX)
.enemyAbility(Abilities.INSOMNIA)
- .enemyMoveset(Array(4).fill(Moves.MACH_PUNCH))
+ .enemyMoveset([Moves.MACH_PUNCH])
.startingLevel(100)
.enemyLevel(100);
});
@@ -60,7 +60,7 @@ describe("Abilities - Tera Shell", () => {
it(
"should not override type immunities",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK));
+ game.override.enemyMoveset([Moves.SHADOW_SNEAK]);
await game.classicMode.startBattle([Species.SNORLAX]);
@@ -77,7 +77,7 @@ describe("Abilities - Tera Shell", () => {
it(
"should not override type multipliers less than 0.5x",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.QUICK_ATTACK));
+ game.override.enemyMoveset([Moves.QUICK_ATTACK]);
await game.classicMode.startBattle([Species.AGGRON]);
@@ -94,7 +94,7 @@ describe("Abilities - Tera Shell", () => {
it(
"should not affect the effectiveness of fixed-damage moves",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.DRAGON_RAGE));
+ game.override.enemyMoveset([Moves.DRAGON_RAGE]);
await game.classicMode.startBattle([Species.CHARIZARD]);
diff --git a/src/test/abilities/wind_power.test.ts b/src/test/abilities/wind_power.test.ts
index c944e01b43a..12b8d2f2299 100644
--- a/src/test/abilities/wind_power.test.ts
+++ b/src/test/abilities/wind_power.test.ts
@@ -4,7 +4,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -28,7 +27,7 @@ describe("Abilities - Wind Power", () => {
game.override.enemySpecies(Species.SHIFTRY);
game.override.enemyAbility(Abilities.WIND_POWER);
game.override.moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
it("it becomes charged when hit by wind moves", async () => {
diff --git a/src/test/abilities/wind_rider.test.ts b/src/test/abilities/wind_rider.test.ts
index 7a1fee6794a..c917f56e101 100644
--- a/src/test/abilities/wind_rider.test.ts
+++ b/src/test/abilities/wind_rider.test.ts
@@ -3,7 +3,6 @@ import GameManager from "#test/utils/gameManager";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -28,7 +27,7 @@ describe("Abilities - Wind Rider", () => {
.enemySpecies(Species.SHIFTRY)
.enemyAbility(Abilities.WIND_RIDER)
.moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM])
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
it("takes no damage from wind moves and its ATK stat stage is raised by 1 when hit by one", async () => {
diff --git a/src/test/abilities/wonder_skin.test.ts b/src/test/abilities/wonder_skin.test.ts
index 0c2aedc8ce8..6ef985fbd42 100644
--- a/src/test/abilities/wonder_skin.test.ts
+++ b/src/test/abilities/wonder_skin.test.ts
@@ -5,7 +5,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -30,7 +29,7 @@ describe("Abilities - Wonder Skin", () => {
game.override.ability(Abilities.BALL_FETCH);
game.override.enemySpecies(Species.SHUCKLE);
game.override.enemyAbility(Abilities.WONDER_SKIN);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
it("lowers accuracy of status moves to 50%", async () => {
diff --git a/src/test/abilities/zero_to_hero.test.ts b/src/test/abilities/zero_to_hero.test.ts
index 1a9697f974e..eafc32b4c79 100644
--- a/src/test/abilities/zero_to_hero.test.ts
+++ b/src/test/abilities/zero_to_hero.test.ts
@@ -6,7 +6,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@@ -30,8 +29,8 @@ describe("Abilities - ZERO TO HERO", () => {
game = new GameManager(phaserGame);
game.override
.battleType("single")
- .moveset(SPLASH_ONLY)
- .enemyMoveset(SPLASH_ONLY)
+ .moveset(Moves.SPLASH)
+ .enemyMoveset(Moves.SPLASH)
.enemyAbility(Abilities.BALL_FETCH);
});
diff --git a/src/test/arena/arena_gravity.test.ts b/src/test/arena/arena_gravity.test.ts
index eda8c687ba1..47b8bf4cf70 100644
--- a/src/test/arena/arena_gravity.test.ts
+++ b/src/test/arena/arena_gravity.test.ts
@@ -8,7 +8,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Arena - Gravity", () => {
let phaserGame: Phaser.Game;
@@ -32,7 +31,7 @@ describe("Arena - Gravity", () => {
.ability(Abilities.UNNERVE)
.enemyAbility(Abilities.BALL_FETCH)
.enemySpecies(Species.SHUCKLE)
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
// Reference: https://bulbapedia.bulbagarden.net/wiki/Gravity_(move)
diff --git a/src/test/arena/weather_fog.test.ts b/src/test/arena/weather_fog.test.ts
index b36b0de2e06..b47145e8dd0 100644
--- a/src/test/arena/weather_fog.test.ts
+++ b/src/test/arena/weather_fog.test.ts
@@ -31,7 +31,7 @@ describe("Weather - Fog", () => {
game.override.ability(Abilities.BALL_FETCH);
game.override.enemyAbility(Abilities.BALL_FETCH);
game.override.enemySpecies(Species.MAGIKARP);
- game.override.enemyMoveset(new Array(4).fill(Moves.SPLASH));
+ game.override.enemyMoveset([Moves.SPLASH]);
});
it("move accuracy is multiplied by 90%", async () => {
diff --git a/src/test/arena/weather_hail.test.ts b/src/test/arena/weather_hail.test.ts
index 75125b3448c..31d20be2ded 100644
--- a/src/test/arena/weather_hail.test.ts
+++ b/src/test/arena/weather_hail.test.ts
@@ -4,7 +4,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
import { BattlerIndex } from "#app/battle";
describe("Weather - Hail", () => {
@@ -26,8 +25,8 @@ describe("Weather - Hail", () => {
game.override
.weather(WeatherType.HAIL)
.battleType("single")
- .moveset(SPLASH_ONLY)
- .enemyMoveset(SPLASH_ONLY)
+ .moveset(Moves.SPLASH)
+ .enemyMoveset(Moves.SPLASH)
.enemySpecies(Species.MAGIKARP);
});
diff --git a/src/test/arena/weather_sandstorm.test.ts b/src/test/arena/weather_sandstorm.test.ts
index 978774ba4c1..91188de6985 100644
--- a/src/test/arena/weather_sandstorm.test.ts
+++ b/src/test/arena/weather_sandstorm.test.ts
@@ -4,7 +4,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Weather - Sandstorm", () => {
let phaserGame: Phaser.Game;
@@ -25,8 +24,8 @@ describe("Weather - Sandstorm", () => {
game.override
.weather(WeatherType.SANDSTORM)
.battleType("single")
- .moveset(SPLASH_ONLY)
- .enemyMoveset(SPLASH_ONLY)
+ .moveset(Moves.SPLASH)
+ .enemyMoveset(Moves.SPLASH)
.enemySpecies(Species.MAGIKARP);
});
diff --git a/src/test/arena/weather_strong_winds.test.ts b/src/test/arena/weather_strong_winds.test.ts
index 8b2d3e2547e..5ce0e61e647 100644
--- a/src/test/arena/weather_strong_winds.test.ts
+++ b/src/test/arena/weather_strong_winds.test.ts
@@ -1,4 +1,5 @@
import { allMoves } from "#app/data/move";
+import { StatusEffect } from "#app/enums/status-effect";
import { TurnStartPhase } from "#app/phases/turn-start-phase";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
@@ -33,7 +34,7 @@ describe("Weather - Strong Winds", () => {
it("electric type move is not very effective on Rayquaza", async () => {
game.override.enemySpecies(Species.RAYQUAZA);
- await game.startBattle([Species.PIKACHU]);
+ await game.classicMode.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!;
@@ -44,7 +45,7 @@ describe("Weather - Strong Winds", () => {
});
it("electric type move is neutral for flying type pokemon", async () => {
- await game.startBattle([Species.PIKACHU]);
+ await game.classicMode.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!;
@@ -55,7 +56,7 @@ describe("Weather - Strong Winds", () => {
});
it("ice type move is neutral for flying type pokemon", async () => {
- await game.startBattle([Species.PIKACHU]);
+ await game.classicMode.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!;
@@ -66,7 +67,7 @@ describe("Weather - Strong Winds", () => {
});
it("rock type move is neutral for flying type pokemon", async () => {
- await game.startBattle([Species.PIKACHU]);
+ await game.classicMode.startBattle([Species.PIKACHU]);
const pikachu = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!;
@@ -75,4 +76,18 @@ describe("Weather - Strong Winds", () => {
await game.phaseInterceptor.to(TurnStartPhase);
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ROCK_SLIDE].type, pikachu)).toBe(1);
});
+
+ it("weather goes away when last trainer pokemon dies to indirect damage", async () => {
+ game.override.enemyStatusEffect(StatusEffect.POISON);
+
+ await game.classicMode.startBattle([Species.MAGIKARP]);
+
+ const enemy = game.scene.getEnemyPokemon()!;
+ enemy.hp = 1;
+
+ game.move.select(Moves.SPLASH);
+ await game.phaseInterceptor.to("TurnEndPhase");
+
+ expect(game.scene.arena.weather?.weatherType).toBeUndefined();
+ });
});
diff --git a/src/test/battle/battle.test.ts b/src/test/battle/battle.test.ts
index 25dfbc765bd..6e15bbd99d9 100644
--- a/src/test/battle/battle.test.ts
+++ b/src/test/battle/battle.test.ts
@@ -25,7 +25,6 @@ import { PlayerGender } from "#enums/player-gender";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Test Battle Phase", () => {
let phaserGame: Phaser.Game;
@@ -319,7 +318,7 @@ describe("Test Battle Phase", () => {
.startingWave(1)
.startingLevel(100)
.moveset([moveToUse])
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.startingHeldItems([{ name: "TEMP_STAT_STAGE_BOOSTER", type: Stat.ACC }]);
await game.startBattle();
diff --git a/src/test/battle/damage_calculation.test.ts b/src/test/battle/damage_calculation.test.ts
index 9c7c9dc9d3e..89f2bb4c269 100644
--- a/src/test/battle/damage_calculation.test.ts
+++ b/src/test/battle/damage_calculation.test.ts
@@ -5,7 +5,6 @@ import { ArenaTagType } from "#enums/arena-tag-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -31,7 +30,7 @@ describe("Round Down and Minimun 1 test in Damage Calculation", () => {
it("When the user fails to use Jump Kick with Wonder Guard ability, the damage should be 1.", async () => {
game.override.enemySpecies(Species.GASTLY);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.starterSpecies(Species.SHEDINJA);
game.override.moveset([Moves.JUMP_KICK]);
game.override.ability(Abilities.WONDER_GUARD);
diff --git a/src/test/battle/double_battle.test.ts b/src/test/battle/double_battle.test.ts
index d264a29ef9b..b7a5616d642 100644
--- a/src/test/battle/double_battle.test.ts
+++ b/src/test/battle/double_battle.test.ts
@@ -4,7 +4,6 @@ import { TurnInitPhase } from "#app/phases/turn-init-phase";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -29,7 +28,7 @@ describe("Double Battles", () => {
// double-battle player's pokemon both fainted in same round, then revive one, and next double battle summons two player's pokemon successfully.
// (There were bugs that either only summon one when can summon two, player stuck in switchPhase etc)
it("3v2 edge case: player summons 2 pokemon on the next battle after being fainted and revived", async () => {
- game.override.battleType("double").enemyMoveset(SPLASH_ONLY).moveset(SPLASH_ONLY);
+ game.override.battleType("double").enemyMoveset(Moves.SPLASH).moveset(Moves.SPLASH);
await game.startBattle([
Species.BULBASAUR,
Species.CHARIZARD,
diff --git a/src/test/battle/inverse_battle.test.ts b/src/test/battle/inverse_battle.test.ts
index 2a561a09e5e..d808f71addb 100644
--- a/src/test/battle/inverse_battle.test.ts
+++ b/src/test/battle/inverse_battle.test.ts
@@ -8,7 +8,6 @@ import { Species } from "#enums/species";
import { StatusEffect } from "#enums/status-effect";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const TIMEOUT = 20 * 1000;
@@ -38,7 +37,7 @@ describe("Inverse Battle", () => {
.ability(Abilities.BALL_FETCH)
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
it("Immune types are 2x effective - Thunderbolt against Ground Type", async () => {
diff --git a/src/test/boss-pokemon.test.ts b/src/test/boss-pokemon.test.ts
index c6fc276551f..8a0a0e01617 100644
--- a/src/test/boss-pokemon.test.ts
+++ b/src/test/boss-pokemon.test.ts
@@ -2,7 +2,6 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import GameManager from "./utils/gameManager";
import { Species } from "#app/enums/species";
import { getPokemonSpecies } from "#app/data/pokemon-species";
-import { SPLASH_ONLY } from "./utils/testUtils";
import { Abilities } from "#app/enums/abilities";
import { Moves } from "#app/enums/moves";
import { EFFECTIVE_STATS } from "#app/enums/stat";
@@ -33,7 +32,7 @@ describe("Boss Pokemon / Shields", () => {
.disableTrainerWaves()
.disableCrits()
.enemySpecies(Species.RATTATA)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyHeldItems([])
.startingLevel(1000)
.moveset([Moves.FALSE_SWIPE, Moves.SUPER_FANG, Moves.SPLASH])
diff --git a/src/test/evolution.test.ts b/src/test/evolution.test.ts
index 9f0806b8e24..16922babd7c 100644
--- a/src/test/evolution.test.ts
+++ b/src/test/evolution.test.ts
@@ -6,7 +6,6 @@ import * as Utils from "#app/utils";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "./utils/testUtils";
describe("Evolution", () => {
let phaserGame: Phaser.Game;
@@ -99,7 +98,7 @@ describe("Evolution", () => {
it("should increase both HP and max HP when evolving", async () => {
game.override.moveset([Moves.SURF])
.enemySpecies(Species.GOLEM)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.startingWave(21)
.startingLevel(16)
.enemyLevel(50);
@@ -126,7 +125,7 @@ describe("Evolution", () => {
it("should not fully heal HP when evolving", async () => {
game.override.moveset([Moves.SURF])
.enemySpecies(Species.GOLEM)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.startingWave(21)
.startingLevel(13)
.enemyLevel(30);
diff --git a/src/test/final_boss.test.ts b/src/test/final_boss.test.ts
index 5d006998a0b..fee4dc6c8f6 100644
--- a/src/test/final_boss.test.ts
+++ b/src/test/final_boss.test.ts
@@ -7,7 +7,6 @@ import { GameModes } from "#app/game-mode";
import { TurnHeldItemTransferModifier } from "#app/modifier/modifier";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import GameManager from "./utils/gameManager";
-import { SPLASH_ONLY } from "./utils/testUtils";
const FinalWave = {
Classic: 200,
@@ -29,7 +28,7 @@ describe("Final Boss", () => {
.startingWave(FinalWave.Classic)
.startingBiome(Biome.END)
.disableCrits()
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.moveset([ Moves.SPLASH, Moves.WILL_O_WISP, Moves.DRAGON_PULSE ])
.startingLevel(10000);
});
diff --git a/src/test/items/dire_hit.test.ts b/src/test/items/dire_hit.test.ts
index 4b5988294f3..601552de7f1 100644
--- a/src/test/items/dire_hit.test.ts
+++ b/src/test/items/dire_hit.test.ts
@@ -4,7 +4,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phase from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
import { BattleEndPhase } from "#app/phases/battle-end-phase";
import { TempCritBoosterModifier } from "#app/modifier/modifier";
import { Mode } from "#app/ui/ui";
@@ -34,7 +33,7 @@ describe("Items - Dire Hit", () => {
game.override
.enemySpecies(Species.MAGIKARP)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.moveset([ Moves.POUND ])
.startingHeldItems([{ name: "DIRE_HIT" }])
.battleType("single")
diff --git a/src/test/items/double_battle_chance_booster.test.ts b/src/test/items/double_battle_chance_booster.test.ts
index 808d4c7ca51..f581af7afc5 100644
--- a/src/test/items/double_battle_chance_booster.test.ts
+++ b/src/test/items/double_battle_chance_booster.test.ts
@@ -4,7 +4,6 @@ import { DoubleBattleChanceBoosterModifier } from "#app/modifier/modifier";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
import { ShopCursorTarget } from "#app/enums/shop-cursor-target.js";
import { Mode } from "#app/ui/ui.js";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler.js";
@@ -64,7 +63,7 @@ describe("Items - Double Battle Chance Boosters", () => {
game.override
.startingModifier([{ name: "LURE" }])
.itemRewards([{ name: "LURE" }])
- .moveset(SPLASH_ONLY)
+ .moveset(Moves.SPLASH)
.startingLevel(200);
await game.classicMode.startBattle([
diff --git a/src/test/items/grip_claw.test.ts b/src/test/items/grip_claw.test.ts
index 09afa9aea0b..d9871616449 100644
--- a/src/test/items/grip_claw.test.ts
+++ b/src/test/items/grip_claw.test.ts
@@ -8,7 +8,6 @@ import { MoveEndPhase } from "#app/phases/move-end-phase";
import GameManager from "#test/utils/gameManager";
import Phase from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
const TIMEOUT = 20 * 1000; // 20 seconds
@@ -38,7 +37,7 @@ describe("Items - Grip Claw", () => {
])
.enemySpecies(Species.SNORLAX)
.ability(Abilities.KLUTZ)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyHeldItems([
{ name: "BERRY", type: BerryType.SITRUS, count: 2 },
{ name: "BERRY", type: BerryType.LUM, count: 2 },
diff --git a/src/test/items/scope_lens.test.ts b/src/test/items/scope_lens.test.ts
index c8629093ab5..e39517ceae9 100644
--- a/src/test/items/scope_lens.test.ts
+++ b/src/test/items/scope_lens.test.ts
@@ -4,7 +4,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phase from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Items - Scope Lens", () => {
let phaserGame: Phaser.Game;
@@ -25,7 +24,7 @@ describe("Items - Scope Lens", () => {
game.override
.enemySpecies(Species.MAGIKARP)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.moveset([ Moves.POUND ])
.startingHeldItems([{ name: "SCOPE_LENS" }])
.battleType("single")
diff --git a/src/test/items/temp_stat_stage_booster.test.ts b/src/test/items/temp_stat_stage_booster.test.ts
index 3e32fa13a04..6186799623a 100644
--- a/src/test/items/temp_stat_stage_booster.test.ts
+++ b/src/test/items/temp_stat_stage_booster.test.ts
@@ -5,7 +5,6 @@ import Phase from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { Moves } from "#app/enums/moves";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
-import { SPLASH_ONLY } from "../utils/testUtils";
import { Abilities } from "#app/enums/abilities";
import { TempStatStageBoosterModifier } from "#app/modifier/modifier";
import { Mode } from "#app/ui/ui";
@@ -34,7 +33,7 @@ describe("Items - Temporary Stat Stage Boosters", () => {
game.override
.battleType("single")
.enemySpecies(Species.SHUCKLE)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyAbility(Abilities.BALL_FETCH)
.moveset([ Moves.TACKLE, Moves.SPLASH, Moves.HONE_CLAWS, Moves.BELLY_DRUM ])
.startingModifier([{ name: "TEMP_STAT_STAGE_BOOSTER", type: Stat.ATK }]);
diff --git a/src/test/moves/after_you.test.ts b/src/test/moves/after_you.test.ts
new file mode 100644
index 00000000000..efce1b28a17
--- /dev/null
+++ b/src/test/moves/after_you.test.ts
@@ -0,0 +1,65 @@
+import { BattlerIndex } from "#app/battle";
+import { Abilities } from "#app/enums/abilities";
+import { MoveResult } from "#app/field/pokemon";
+import { MovePhase } from "#app/phases/move-phase";
+import { Moves } from "#enums/moves";
+import { Species } from "#enums/species";
+import GameManager from "#test/utils/gameManager";
+import Phaser from "phaser";
+import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
+
+const TIMEOUT = 20 * 1000;
+
+describe("Moves - After You", () => {
+ let phaserGame: Phaser.Game;
+ let game: GameManager;
+
+ beforeAll(() => {
+ phaserGame = new Phaser.Game({
+ type: Phaser.HEADLESS,
+ });
+ });
+
+ afterEach(() => {
+ game.phaseInterceptor.restoreOg();
+ });
+
+ beforeEach(() => {
+ game = new GameManager(phaserGame);
+ game.override
+ .battleType("double")
+ .enemyLevel(5)
+ .enemySpecies(Species.PIKACHU)
+ .enemyAbility(Abilities.BALL_FETCH)
+ .enemyMoveset(Moves.SPLASH)
+ .ability(Abilities.BALL_FETCH)
+ .moveset([Moves.AFTER_YOU, Moves.SPLASH]);
+ });
+
+ it("makes the target move immediately after the user", async () => {
+ await game.classicMode.startBattle([Species.REGIELEKI, Species.SHUCKLE]);
+
+ game.move.select(Moves.AFTER_YOU, 0, BattlerIndex.PLAYER_2);
+ game.move.select(Moves.SPLASH, 1);
+
+ await game.phaseInterceptor.to("MoveEffectPhase");
+ await game.phaseInterceptor.to(MovePhase, false);
+ const phase = game.scene.getCurrentPhase() as MovePhase;
+ expect(phase.pokemon).toBe(game.scene.getPlayerField()[1]);
+ await game.phaseInterceptor.to("MoveEndPhase");
+ }, TIMEOUT);
+
+ it("fails if target already moved", async () => {
+ game.override.enemySpecies(Species.SHUCKLE);
+ await game.classicMode.startBattle([Species.REGIELEKI, Species.PIKACHU]);
+
+ game.move.select(Moves.SPLASH);
+ game.move.select(Moves.AFTER_YOU, 1, BattlerIndex.PLAYER);
+
+ await game.phaseInterceptor.to("MoveEndPhase");
+ await game.phaseInterceptor.to("MoveEndPhase");
+ await game.phaseInterceptor.to(MovePhase);
+
+ expect(game.scene.getPlayerField()[1].getLastXMoves(1)[0].result).toBe(MoveResult.FAIL);
+ }, TIMEOUT);
+});
diff --git a/src/test/moves/alluring_voice.test.ts b/src/test/moves/alluring_voice.test.ts
index 9807d1bce85..b438d0f736a 100644
--- a/src/test/moves/alluring_voice.test.ts
+++ b/src/test/moves/alluring_voice.test.ts
@@ -31,7 +31,7 @@ describe("Moves - Alluring Voice", () => {
.disableCrits()
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.ICE_SCALES)
- .enemyMoveset(Array(4).fill(Moves.HOWL))
+ .enemyMoveset([Moves.HOWL])
.startingLevel(10)
.enemyLevel(10)
.starterSpecies(Species.FEEBAS)
diff --git a/src/test/moves/baton_pass.test.ts b/src/test/moves/baton_pass.test.ts
index 1a4edafdd36..5643efceae2 100644
--- a/src/test/moves/baton_pass.test.ts
+++ b/src/test/moves/baton_pass.test.ts
@@ -5,7 +5,6 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { Stat } from "#enums/stat";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -31,7 +30,7 @@ describe("Moves - Baton Pass", () => {
.enemyAbility(Abilities.BALL_FETCH)
.moveset([Moves.BATON_PASS, Moves.NASTY_PLOT, Moves.SPLASH])
.ability(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.disableCrits();
});
@@ -71,7 +70,10 @@ describe("Moves - Baton Pass", () => {
// round 2 - baton pass
game.scene.getEnemyPokemon()!.hp = 100;
- game.override.enemyMoveset(new Array(4).fill(Moves.BATON_PASS));
+ game.override.enemyMoveset([Moves.BATON_PASS]);
+ // Force moveset to update mid-battle
+ // TODO: replace with enemy ai control function when it's added
+ game.scene.getEnemyParty()[0].getMoveset();
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to("PostSummonPhase", false);
@@ -90,7 +92,7 @@ describe("Moves - Baton Pass", () => {
}, 20000);
it("doesn't transfer effects that aren't transferrable", async() => {
- game.override.enemyMoveset(Array(4).fill(Moves.SALT_CURE));
+ game.override.enemyMoveset([Moves.SALT_CURE]);
await game.classicMode.startBattle([Species.PIKACHU, Species.FEEBAS]);
const [player1, player2] = game.scene.getParty();
diff --git a/src/test/moves/beak_blast.test.ts b/src/test/moves/beak_blast.test.ts
index 2a93dc00a54..fe748c87826 100644
--- a/src/test/moves/beak_blast.test.ts
+++ b/src/test/moves/beak_blast.test.ts
@@ -34,7 +34,7 @@ describe("Moves - Beak Blast", () => {
.moveset([Moves.BEAK_BLAST])
.enemySpecies(Species.SNORLAX)
.enemyAbility(Abilities.INSOMNIA)
- .enemyMoveset(Array(4).fill(Moves.TACKLE))
+ .enemyMoveset([Moves.TACKLE])
.startingLevel(100)
.enemyLevel(100);
});
@@ -80,7 +80,7 @@ describe("Moves - Beak Blast", () => {
it(
"should not burn attackers that don't make contact",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.WATER_GUN));
+ game.override.enemyMoveset([Moves.WATER_GUN]);
await game.startBattle([Species.BLASTOISE]);
@@ -116,7 +116,7 @@ describe("Moves - Beak Blast", () => {
it(
"should be blocked by Protect",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.PROTECT));
+ game.override.enemyMoveset([Moves.PROTECT]);
await game.startBattle([Species.BLASTOISE]);
diff --git a/src/test/moves/beat_up.test.ts b/src/test/moves/beat_up.test.ts
index ce1598a49b4..70b33f56583 100644
--- a/src/test/moves/beat_up.test.ts
+++ b/src/test/moves/beat_up.test.ts
@@ -29,7 +29,7 @@ describe("Moves - Beat Up", () => {
game.override.enemySpecies(Species.SNORLAX);
game.override.enemyLevel(100);
- game.override.enemyMoveset(Array(4).fill(Moves.SPLASH));
+ game.override.enemyMoveset([Moves.SPLASH]);
game.override.enemyAbility(Abilities.INSOMNIA);
game.override.startingLevel(100);
diff --git a/src/test/moves/belly_drum.test.ts b/src/test/moves/belly_drum.test.ts
index 7024deb3f18..3d85c59a2a5 100644
--- a/src/test/moves/belly_drum.test.ts
+++ b/src/test/moves/belly_drum.test.ts
@@ -6,7 +6,6 @@ import { Stat } from "#enums/stat";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
import { Abilities } from "#app/enums/abilities";
const TIMEOUT = 20 * 1000;
@@ -37,7 +36,7 @@ describe("Moves - BELLY DRUM", () => {
.startingLevel(100)
.enemyLevel(100)
.moveset([Moves.BELLY_DRUM])
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyAbility(Abilities.BALL_FETCH);
});
diff --git a/src/test/moves/burning_jealousy.test.ts b/src/test/moves/burning_jealousy.test.ts
index 2cb6a0bc52a..3f2bf453684 100644
--- a/src/test/moves/burning_jealousy.test.ts
+++ b/src/test/moves/burning_jealousy.test.ts
@@ -7,7 +7,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@@ -32,7 +31,7 @@ describe("Moves - Burning Jealousy", () => {
.disableCrits()
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.ICE_SCALES)
- .enemyMoveset(Array(4).fill(Moves.HOWL))
+ .enemyMoveset([Moves.HOWL])
.startingLevel(10)
.enemyLevel(10)
.starterSpecies(Species.FEEBAS)
@@ -73,7 +72,7 @@ describe("Moves - Burning Jealousy", () => {
game.override
.enemySpecies(Species.DITTO)
.enemyAbility(Abilities.IMPOSTER)
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!;
@@ -91,7 +90,7 @@ describe("Moves - Burning Jealousy", () => {
it("should be boosted by Sheer Force even if opponent didn't raise stat stages", async () => {
game.override
.ability(Abilities.SHEER_FORCE)
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
vi.spyOn(allMoves[Moves.BURNING_JEALOUSY], "calculateBattlePower");
await game.classicMode.startBattle();
diff --git a/src/test/moves/clangorous_soul.test.ts b/src/test/moves/clangorous_soul.test.ts
index 9bd3bc2379e..015b73b4dab 100644
--- a/src/test/moves/clangorous_soul.test.ts
+++ b/src/test/moves/clangorous_soul.test.ts
@@ -5,7 +5,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { Stat } from "#enums/stat";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
const TIMEOUT = 20 * 1000;
/** HP Cost of Move */
@@ -34,7 +33,7 @@ describe("Moves - Clangorous Soul", () => {
game.override.startingLevel(100);
game.override.enemyLevel(100);
game.override.moveset([Moves.CLANGOROUS_SOUL]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
//Bulbapedia Reference: https://bulbapedia.bulbagarden.net/wiki/Clangorous_Soul_(move)
diff --git a/src/test/moves/crafty_shield.test.ts b/src/test/moves/crafty_shield.test.ts
index e73a1fd256d..7b962518944 100644
--- a/src/test/moves/crafty_shield.test.ts
+++ b/src/test/moves/crafty_shield.test.ts
@@ -33,7 +33,7 @@ describe("Moves - Crafty Shield", () => {
game.override.moveset([Moves.CRAFTY_SHIELD, Moves.SPLASH, Moves.SWORDS_DANCE]);
game.override.enemySpecies(Species.SNORLAX);
- game.override.enemyMoveset(Array(4).fill(Moves.GROWL));
+ game.override.enemyMoveset([Moves.GROWL]);
game.override.enemyAbility(Abilities.INSOMNIA);
game.override.startingLevel(100);
@@ -62,7 +62,7 @@ describe("Moves - Crafty Shield", () => {
test(
"should not protect the user and allies from attack moves",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
@@ -84,7 +84,7 @@ describe("Moves - Crafty Shield", () => {
"should protect the user and allies from moves that ignore other protection",
async () => {
game.override.enemySpecies(Species.DUSCLOPS);
- game.override.enemyMoveset(Array(4).fill(Moves.CURSE));
+ game.override.enemyMoveset([Moves.CURSE]);
await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
diff --git a/src/test/moves/disable.test.ts b/src/test/moves/disable.test.ts
index 3d207035ce3..a35d294e91f 100644
--- a/src/test/moves/disable.test.ts
+++ b/src/test/moves/disable.test.ts
@@ -4,7 +4,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Moves - Disable", () => {
@@ -28,7 +27,7 @@ describe("Moves - Disable", () => {
.ability(Abilities.BALL_FETCH)
.enemyAbility(Abilities.BALL_FETCH)
.moveset([Moves.DISABLE, Moves.SPLASH])
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.starterSpecies(Species.PIKACHU)
.enemySpecies(Species.SHUCKLE);
});
@@ -79,7 +78,7 @@ describe("Moves - Disable", () => {
}, 20000);
it("cannot disable STRUGGLE", async() => {
- game.override.enemyMoveset(Array(4).fill(Moves.STRUGGLE));
+ game.override.enemyMoveset([Moves.STRUGGLE]);
await game.classicMode.startBattle();
const playerMon = game.scene.getPlayerPokemon()!;
@@ -114,7 +113,7 @@ describe("Moves - Disable", () => {
}, 20000);
it("disables NATURE POWER, not the move invoked by it", async() => {
- game.override.enemyMoveset(Array(4).fill(Moves.NATURE_POWER));
+ game.override.enemyMoveset([Moves.NATURE_POWER]);
await game.classicMode.startBattle();
const enemyMon = game.scene.getEnemyPokemon()!;
diff --git a/src/test/moves/dragon_cheer.test.ts b/src/test/moves/dragon_cheer.test.ts
index 747d71bd000..0fc389ccfb6 100644
--- a/src/test/moves/dragon_cheer.test.ts
+++ b/src/test/moves/dragon_cheer.test.ts
@@ -4,7 +4,6 @@ import { Moves } from "#app/enums/moves";
import { Species } from "#app/enums/species";
import { Abilities } from "#enums/abilities";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -28,7 +27,7 @@ describe("Moves - Dragon Cheer", () => {
game.override
.battleType("double")
.enemyAbility(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyLevel(20)
.moveset([Moves.DRAGON_CHEER, Moves.TACKLE, Moves.SPLASH]);
});
diff --git a/src/test/moves/dragon_rage.test.ts b/src/test/moves/dragon_rage.test.ts
index 5da6e082ce5..cab8c3f808b 100644
--- a/src/test/moves/dragon_rage.test.ts
+++ b/src/test/moves/dragon_rage.test.ts
@@ -8,7 +8,6 @@ import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -42,7 +41,7 @@ describe("Moves - Dragon Rage", () => {
game.override.startingLevel(100);
game.override.enemySpecies(Species.SNORLAX);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyAbility(Abilities.BALL_FETCH);
game.override.enemyPassiveAbility(Abilities.BALL_FETCH);
game.override.enemyLevel(100);
diff --git a/src/test/moves/dragon_tail.test.ts b/src/test/moves/dragon_tail.test.ts
index 362383e2fe3..e1af29b2db1 100644
--- a/src/test/moves/dragon_tail.test.ts
+++ b/src/test/moves/dragon_tail.test.ts
@@ -9,7 +9,6 @@ import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import GameManager from "../utils/gameManager";
-import { SPLASH_ONLY } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@@ -32,7 +31,7 @@ describe("Moves - Dragon Tail", () => {
game.override.battleType("single")
.moveset([Moves.DRAGON_TAIL, Moves.SPLASH])
.enemySpecies(Species.WAILORD)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.startingLevel(5)
.enemyLevel(5);
@@ -82,7 +81,7 @@ describe("Moves - Dragon Tail", () => {
test(
"Double battles should proceed without crashing",
async () => {
- game.override.battleType("double").enemyMoveset(SPLASH_ONLY);
+ game.override.battleType("double").enemyMoveset(Moves.SPLASH);
game.override.moveset([Moves.DRAGON_TAIL, Moves.SPLASH, Moves.FLAMETHROWER])
.enemyAbility(Abilities.ROUGH_SKIN);
await game.startBattle([Species.DRATINI, Species.DRATINI, Species.WAILORD, Species.WAILORD]);
@@ -116,7 +115,7 @@ describe("Moves - Dragon Tail", () => {
test(
"Flee move redirection works",
async () => {
- game.override.battleType("double").enemyMoveset(SPLASH_ONLY);
+ game.override.battleType("double").enemyMoveset(Moves.SPLASH);
game.override.moveset([Moves.DRAGON_TAIL, Moves.SPLASH, Moves.FLAMETHROWER]);
game.override.enemyAbility(Abilities.ROUGH_SKIN);
await game.startBattle([Species.DRATINI, Species.DRATINI, Species.WAILORD, Species.WAILORD]);
diff --git a/src/test/moves/fake_out.test.ts b/src/test/moves/fake_out.test.ts
index ac09917daea..04d6216b952 100644
--- a/src/test/moves/fake_out.test.ts
+++ b/src/test/moves/fake_out.test.ts
@@ -3,7 +3,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - Fake Out", () => {
let phaserGame: Phaser.Game;
@@ -26,7 +25,7 @@ describe("Moves - Fake Out", () => {
.enemySpecies(Species.CORVIKNIGHT)
.starterSpecies(Species.FEEBAS)
.moveset([Moves.FAKE_OUT, Moves.SPLASH])
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.disableCrits();
});
diff --git a/src/test/moves/fillet_away.test.ts b/src/test/moves/fillet_away.test.ts
index a639a86c5c1..68ace42c2ec 100644
--- a/src/test/moves/fillet_away.test.ts
+++ b/src/test/moves/fillet_away.test.ts
@@ -4,7 +4,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import { Stat } from "#enums/stat";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
@@ -35,7 +34,7 @@ describe("Moves - FILLET AWAY", () => {
game.override.startingLevel(100);
game.override.enemyLevel(100);
game.override.moveset([Moves.FILLET_AWAY]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
//Bulbapedia Reference: https://bulbapedia.bulbagarden.net/wiki/fillet_away_(move)
diff --git a/src/test/moves/fissure.test.ts b/src/test/moves/fissure.test.ts
index 34612d1fb18..8689ce4079e 100644
--- a/src/test/moves/fissure.test.ts
+++ b/src/test/moves/fissure.test.ts
@@ -6,7 +6,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -38,7 +37,7 @@ describe("Moves - Fissure", () => {
game.override.startingLevel(100);
game.override.enemySpecies(Species.SNORLAX);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyPassiveAbility(Abilities.BALL_FETCH);
game.override.enemyLevel(100);
diff --git a/src/test/moves/flame_burst.test.ts b/src/test/moves/flame_burst.test.ts
index 2777b8178b8..b2858af2b24 100644
--- a/src/test/moves/flame_burst.test.ts
+++ b/src/test/moves/flame_burst.test.ts
@@ -42,7 +42,7 @@ describe("Moves - Flame Burst", () => {
game.override.startingWave(4);
game.override.enemySpecies(Species.SHUCKLE);
game.override.enemyAbility(Abilities.BALL_FETCH);
- game.override.enemyMoveset(new Array(4).fill(Moves.SPLASH));
+ game.override.enemyMoveset([Moves.SPLASH]);
});
it("inflicts damage to the target's ally equal to 1/16 of its max HP", async () => {
diff --git a/src/test/moves/flower_shield.test.ts b/src/test/moves/flower_shield.test.ts
index ffe8ae995d3..f5fe8d532cc 100644
--- a/src/test/moves/flower_shield.test.ts
+++ b/src/test/moves/flower_shield.test.ts
@@ -7,7 +7,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -31,7 +30,7 @@ describe("Moves - Flower Shield", () => {
game.override.enemyAbility(Abilities.NONE);
game.override.battleType("single");
game.override.moveset([Moves.FLOWER_SHIELD, Moves.SPLASH]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
it("raises DEF stat stage by 1 for all Grass-type Pokemon on the field by one stage - single battle", async () => {
diff --git a/src/test/moves/focus_punch.test.ts b/src/test/moves/focus_punch.test.ts
index 249647f0294..ca80c688169 100644
--- a/src/test/moves/focus_punch.test.ts
+++ b/src/test/moves/focus_punch.test.ts
@@ -7,7 +7,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -35,7 +34,7 @@ describe("Moves - Focus Punch", () => {
.moveset([Moves.FOCUS_PUNCH])
.enemySpecies(Species.GROUDON)
.enemyAbility(Abilities.INSOMNIA)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.startingLevel(100)
.enemyLevel(100);
});
@@ -68,7 +67,7 @@ describe("Moves - Focus Punch", () => {
it(
"should fail if the user is hit",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
await game.startBattle([Species.CHARIZARD]);
@@ -95,7 +94,7 @@ describe("Moves - Focus Punch", () => {
it(
"should be cancelled if the user falls asleep mid-turn",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.SPORE));
+ game.override.enemyMoveset([Moves.SPORE]);
await game.startBattle([Species.CHARIZARD]);
diff --git a/src/test/moves/foresight.test.ts b/src/test/moves/foresight.test.ts
index b856ec0f852..d58097691fd 100644
--- a/src/test/moves/foresight.test.ts
+++ b/src/test/moves/foresight.test.ts
@@ -4,7 +4,6 @@ import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - Foresight", () => {
let phaserGame: Phaser.Game;
@@ -25,7 +24,7 @@ describe("Moves - Foresight", () => {
game.override
.disableCrits()
.enemySpecies(Species.GASTLY)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyLevel(5)
.starterSpecies(Species.MAGIKARP)
.moveset([Moves.FORESIGHT, Moves.QUICK_ATTACK, Moves.MACH_PUNCH]);
@@ -55,7 +54,7 @@ describe("Moves - Foresight", () => {
});
it("should ignore target's evasiveness boosts", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.MINIMIZE));
+ game.override.enemyMoveset([Moves.MINIMIZE]);
await game.startBattle();
const pokemon = game.scene.getPlayerPokemon()!;
diff --git a/src/test/moves/freeze_dry.test.ts b/src/test/moves/freeze_dry.test.ts
index 445a432a812..ff9e2f07162 100644
--- a/src/test/moves/freeze_dry.test.ts
+++ b/src/test/moves/freeze_dry.test.ts
@@ -3,7 +3,6 @@ import { Abilities } from "#app/enums/abilities";
import { Moves } from "#app/enums/moves";
import { Species } from "#app/enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -28,7 +27,7 @@ describe("Moves - Freeze-Dry", () => {
.battleType("single")
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.starterSpecies(Species.FEEBAS)
.ability(Abilities.BALL_FETCH)
.moveset([Moves.FREEZE_DRY]);
@@ -92,7 +91,7 @@ describe("Moves - Freeze-Dry", () => {
// enable once Electrify is implemented (and the interaction is fixed, as above)
it.todo("should deal 2x damage to water types under Electrify", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.ELECTRIFY));
+ game.override.enemyMoveset([Moves.ELECTRIFY]);
await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!;
diff --git a/src/test/moves/freezy_frost.test.ts b/src/test/moves/freezy_frost.test.ts
index ae42d5b6dc6..05c61aab49a 100644
--- a/src/test/moves/freezy_frost.test.ts
+++ b/src/test/moves/freezy_frost.test.ts
@@ -5,7 +5,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import { allMoves } from "#app/data/move";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
@@ -28,7 +27,7 @@ describe("Moves - Freezy Frost", () => {
game.override.enemySpecies(Species.RATTATA);
game.override.enemyLevel(100);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyAbility(Abilities.NONE);
game.override.startingLevel(100);
diff --git a/src/test/moves/gastro_acid.test.ts b/src/test/moves/gastro_acid.test.ts
index 67fd3464cf9..cfc458a908f 100644
--- a/src/test/moves/gastro_acid.test.ts
+++ b/src/test/moves/gastro_acid.test.ts
@@ -4,7 +4,6 @@ import { Moves } from "#app/enums/moves";
import { Species } from "#app/enums/species";
import { MoveResult } from "#app/field/pokemon";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
const TIMEOUT = 20 * 1000;
@@ -31,7 +30,7 @@ describe("Moves - Gastro Acid", () => {
game.override.ability(Abilities.NONE);
game.override.moveset([Moves.GASTRO_ACID, Moves.WATER_GUN, Moves.SPLASH, Moves.CORE_ENFORCER]);
game.override.enemySpecies(Species.BIDOOF);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyAbility(Abilities.WATER_ABSORB);
});
diff --git a/src/test/moves/gigaton_hammer.test.ts b/src/test/moves/gigaton_hammer.test.ts
index 0162375cdb2..b0ab06fdeb5 100644
--- a/src/test/moves/gigaton_hammer.test.ts
+++ b/src/test/moves/gigaton_hammer.test.ts
@@ -4,7 +4,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - Gigaton Hammer", () => {
let phaserGame: Phaser.Game;
@@ -29,7 +28,7 @@ describe("Moves - Gigaton Hammer", () => {
.moveset([Moves.GIGATON_HAMMER])
.startingLevel(10)
.enemyLevel(100)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.disableCrits();
});
diff --git a/src/test/moves/glaive_rush.test.ts b/src/test/moves/glaive_rush.test.ts
index 5867ef751b8..9eed6868432 100644
--- a/src/test/moves/glaive_rush.test.ts
+++ b/src/test/moves/glaive_rush.test.ts
@@ -29,7 +29,7 @@ describe("Moves - Glaive Rush", () => {
.disableCrits()
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.BALL_FETCH)
- .enemyMoveset(Array(4).fill(Moves.GLAIVE_RUSH))
+ .enemyMoveset([Moves.GLAIVE_RUSH])
.starterSpecies(Species.KLINK)
.ability(Abilities.BALL_FETCH)
.moveset([Moves.SHADOW_SNEAK, Moves.AVALANCHE, Moves.SPLASH, Moves.GLAIVE_RUSH]);
@@ -67,7 +67,7 @@ describe("Moves - Glaive Rush", () => {
it("interacts properly with multi-lens", async () => {
game.override
.startingHeldItems([{ name: "MULTI_LENS", count: 2 }])
- .enemyMoveset(Array(4).fill(Moves.AVALANCHE));
+ .enemyMoveset([Moves.AVALANCHE]);
await game.classicMode.startBattle();
const player = game.scene.getPlayerPokemon()!;
@@ -88,7 +88,7 @@ describe("Moves - Glaive Rush", () => {
}, TIMEOUT);
it("secondary effects only last until next move", async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK));
+ game.override.enemyMoveset([Moves.SHADOW_SNEAK]);
await game.classicMode.startBattle();
const player = game.scene.getPlayerPokemon()!;
@@ -115,7 +115,7 @@ describe("Moves - Glaive Rush", () => {
it("secondary effects are removed upon switching", async () => {
game.override
- .enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK))
+ .enemyMoveset([Moves.SHADOW_SNEAK])
.starterSpecies(0);
await game.classicMode.startBattle([Species.KLINK, Species.FEEBAS]);
@@ -152,7 +152,7 @@ describe("Moves - Glaive Rush", () => {
game.move.select(Moves.SHADOW_SNEAK);
await game.phaseInterceptor.to("TurnEndPhase");
- game.override.enemyMoveset(Array(4).fill(Moves.SPLASH));
+ game.override.enemyMoveset([Moves.SPLASH]);
const damagedHP1 = 1000 - enemy.hp;
enemy.hp = 1000;
diff --git a/src/test/moves/growth.test.ts b/src/test/moves/growth.test.ts
index defe5e26f41..a66e4ec6719 100644
--- a/src/test/moves/growth.test.ts
+++ b/src/test/moves/growth.test.ts
@@ -5,7 +5,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
@@ -29,7 +28,7 @@ describe("Moves - Growth", () => {
game.override.enemyAbility(Abilities.MOXIE);
game.override.ability(Abilities.INSOMNIA);
game.override.moveset([ Moves.GROWTH ]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
it("should raise SPATK stat stage by 1", async() => {
diff --git a/src/test/moves/guard_split.test.ts b/src/test/moves/guard_split.test.ts
index f95d09f726c..36be82ba5e4 100644
--- a/src/test/moves/guard_split.test.ts
+++ b/src/test/moves/guard_split.test.ts
@@ -6,7 +6,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Stat } from "#enums/stat";
import { Abilities } from "#enums/abilities";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - Guard Split", () => {
let phaserGame: Phaser.Game;
@@ -34,7 +33,7 @@ describe("Moves - Guard Split", () => {
});
it("should average the user's DEF and SPDEF stats with those of the target", async () => {
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
await game.startBattle([
Species.INDEEDEE
]);
@@ -56,7 +55,7 @@ describe("Moves - Guard Split", () => {
}, 20000);
it("should be idempotent", async () => {
- game.override.enemyMoveset(new Array(4).fill(Moves.GUARD_SPLIT));
+ game.override.enemyMoveset([Moves.GUARD_SPLIT]);
await game.startBattle([
Species.INDEEDEE
]);
diff --git a/src/test/moves/guard_swap.test.ts b/src/test/moves/guard_swap.test.ts
index 407d475de09..a27afaaa7ba 100644
--- a/src/test/moves/guard_swap.test.ts
+++ b/src/test/moves/guard_swap.test.ts
@@ -27,7 +27,7 @@ describe("Moves - Guard Swap", () => {
game.override
.battleType("single")
.enemyAbility(Abilities.BALL_FETCH)
- .enemyMoveset(new Array(4).fill(Moves.SHELL_SMASH))
+ .enemyMoveset([Moves.SHELL_SMASH])
.enemySpecies(Species.MEW)
.enemyLevel(200)
.moveset([ Moves.GUARD_SWAP ])
diff --git a/src/test/moves/hard_press.test.ts b/src/test/moves/hard_press.test.ts
index 70c78490269..5d2e4e5b145 100644
--- a/src/test/moves/hard_press.test.ts
+++ b/src/test/moves/hard_press.test.ts
@@ -4,7 +4,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -30,7 +29,7 @@ describe("Moves - Hard Press", () => {
game.override.ability(Abilities.BALL_FETCH);
game.override.enemySpecies(Species.MUNCHLAX);
game.override.enemyAbility(Abilities.BALL_FETCH);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.moveset([Moves.HARD_PRESS]);
vi.spyOn(moveToCheck, "calculateBattlePower");
});
diff --git a/src/test/moves/haze.test.ts b/src/test/moves/haze.test.ts
index 42081ce74e8..211c1a41409 100644
--- a/src/test/moves/haze.test.ts
+++ b/src/test/moves/haze.test.ts
@@ -5,7 +5,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
describe("Moves - Haze", () => {
@@ -28,7 +27,7 @@ describe("Moves - Haze", () => {
game.override.enemySpecies(Species.RATTATA);
game.override.enemyLevel(100);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyAbility(Abilities.NONE);
game.override.startingLevel(100);
diff --git a/src/test/moves/hyper_beam.test.ts b/src/test/moves/hyper_beam.test.ts
index 1280d8b429a..7aa2dbfec2b 100644
--- a/src/test/moves/hyper_beam.test.ts
+++ b/src/test/moves/hyper_beam.test.ts
@@ -32,7 +32,7 @@ describe("Moves - Hyper Beam", () => {
game.override.ability(Abilities.BALL_FETCH);
game.override.enemySpecies(Species.SNORLAX);
game.override.enemyAbility(Abilities.BALL_FETCH);
- game.override.enemyMoveset(Array(4).fill(Moves.SPLASH));
+ game.override.enemyMoveset([Moves.SPLASH]);
game.override.enemyLevel(100);
game.override.moveset([Moves.HYPER_BEAM, Moves.TACKLE]);
diff --git a/src/test/moves/jaw_lock.test.ts b/src/test/moves/jaw_lock.test.ts
index 42f7a244977..75fd6f0ff32 100644
--- a/src/test/moves/jaw_lock.test.ts
+++ b/src/test/moves/jaw_lock.test.ts
@@ -6,7 +6,6 @@ import { FaintPhase } from "#app/phases/faint-phase";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import GameManager from "#app/test/utils/gameManager";
-import { SPLASH_ONLY } from "#app/test/utils/testUtils";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
@@ -35,7 +34,7 @@ describe("Moves - Jaw Lock", () => {
.battleType("single")
.enemySpecies(Species.SNORLAX)
.enemyAbility(Abilities.INSOMNIA)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.moveset([Moves.JAW_LOCK, Moves.SPLASH])
.startingLevel(100)
.enemyLevel(100)
@@ -153,7 +152,7 @@ describe("Moves - Jaw Lock", () => {
it(
"should not trap either pokemon if the target is protected",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.PROTECT));
+ game.override.enemyMoveset([Moves.PROTECT]);
await game.startBattle([Species.BULBASAUR]);
diff --git a/src/test/moves/lash_out.test.ts b/src/test/moves/lash_out.test.ts
index 74d9fcd66c0..8c414832f36 100644
--- a/src/test/moves/lash_out.test.ts
+++ b/src/test/moves/lash_out.test.ts
@@ -30,7 +30,7 @@ describe("Moves - Lash Out", () => {
.disableCrits()
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.FUR_COAT)
- .enemyMoveset(Array(4).fill(Moves.GROWL))
+ .enemyMoveset([Moves.GROWL])
.startingLevel(10)
.enemyLevel(10)
.starterSpecies(Species.FEEBAS)
diff --git a/src/test/moves/lucky_chant.test.ts b/src/test/moves/lucky_chant.test.ts
index 7d5bfe02476..57e5ff80f1d 100644
--- a/src/test/moves/lucky_chant.test.ts
+++ b/src/test/moves/lucky_chant.test.ts
@@ -31,7 +31,7 @@ describe("Moves - Lucky Chant", () => {
.moveset([Moves.LUCKY_CHANT, Moves.SPLASH, Moves.FOLLOW_ME])
.enemySpecies(Species.SNORLAX)
.enemyAbility(Abilities.INSOMNIA)
- .enemyMoveset(Array(4).fill(Moves.FLOWER_TRICK))
+ .enemyMoveset([Moves.FLOWER_TRICK])
.startingLevel(100)
.enemyLevel(100);
});
@@ -87,7 +87,7 @@ describe("Moves - Lucky Chant", () => {
it(
"should prevent critical hits from field effects",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
await game.startBattle([Species.CHARIZARD]);
diff --git a/src/test/moves/lunar_blessing.test.ts b/src/test/moves/lunar_blessing.test.ts
index 92428c39029..6a104762f4d 100644
--- a/src/test/moves/lunar_blessing.test.ts
+++ b/src/test/moves/lunar_blessing.test.ts
@@ -4,7 +4,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -26,7 +25,7 @@ describe("Moves - Lunar Blessing", () => {
game.override.battleType("double");
game.override.enemySpecies(Species.SHUCKLE);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyAbility(Abilities.BALL_FETCH);
game.override.moveset([Moves.LUNAR_BLESSING, Moves.SPLASH]);
diff --git a/src/test/moves/make_it_rain.test.ts b/src/test/moves/make_it_rain.test.ts
index e41472d7561..5ac35168f92 100644
--- a/src/test/moves/make_it_rain.test.ts
+++ b/src/test/moves/make_it_rain.test.ts
@@ -5,7 +5,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
@@ -31,7 +30,7 @@ describe("Moves - Make It Rain", () => {
game.override.moveset([Moves.MAKE_IT_RAIN, Moves.SPLASH]);
game.override.enemySpecies(Species.SNORLAX);
game.override.enemyAbility(Abilities.INSOMNIA);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.startingLevel(100);
game.override.enemyLevel(100);
});
diff --git a/src/test/moves/mat_block.test.ts b/src/test/moves/mat_block.test.ts
index 4a95985eb92..b759f49bf98 100644
--- a/src/test/moves/mat_block.test.ts
+++ b/src/test/moves/mat_block.test.ts
@@ -33,7 +33,7 @@ describe("Moves - Mat Block", () => {
game.override.moveset([Moves.MAT_BLOCK, Moves.SPLASH]);
game.override.enemySpecies(Species.SNORLAX);
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
game.override.enemyAbility(Abilities.INSOMNIA);
game.override.startingLevel(100);
@@ -62,7 +62,7 @@ describe("Moves - Mat Block", () => {
test(
"should not protect the user and allies from status moves",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.GROWL));
+ game.override.enemyMoveset([Moves.GROWL]);
await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
diff --git a/src/test/moves/miracle_eye.test.ts b/src/test/moves/miracle_eye.test.ts
index d6b21a5dc2f..0528b509c82 100644
--- a/src/test/moves/miracle_eye.test.ts
+++ b/src/test/moves/miracle_eye.test.ts
@@ -5,7 +5,6 @@ import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - Miracle Eye", () => {
let phaserGame: Phaser.Game;
@@ -26,7 +25,7 @@ describe("Moves - Miracle Eye", () => {
game.override
.disableCrits()
.enemySpecies(Species.UMBREON)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyLevel(5)
.starterSpecies(Species.MAGIKARP)
.moveset([Moves.MIRACLE_EYE, Moves.CONFUSION]);
diff --git a/src/test/moves/multi_target.test.ts b/src/test/moves/multi_target.test.ts
index 16ccd5519b1..5e830f23fc7 100644
--- a/src/test/moves/multi_target.test.ts
+++ b/src/test/moves/multi_target.test.ts
@@ -4,7 +4,6 @@ import { Species } from "#app/enums/species";
import * as Utils from "#app/utils";
import { Moves } from "#enums/moves";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -32,7 +31,7 @@ describe("Multi-target damage reduction", () => {
.enemyLevel(100)
.startingLevel(100)
.enemySpecies(Species.POLIWAG)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyAbility(Abilities.BALL_FETCH)
.moveset([Moves.TACKLE, Moves.DAZZLING_GLEAM, Moves.EARTHQUAKE, Moves.SPLASH])
.ability(Abilities.BALL_FETCH);
diff --git a/src/test/moves/octolock.test.ts b/src/test/moves/octolock.test.ts
index c86906ea240..7618b08e9fc 100644
--- a/src/test/moves/octolock.test.ts
+++ b/src/test/moves/octolock.test.ts
@@ -7,7 +7,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -30,7 +29,7 @@ describe("Moves - Octolock", () => {
game.override.battleType("single")
.enemySpecies(Species.RATTATA)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyAbility(Abilities.BALL_FETCH)
.startingLevel(2000)
.moveset([ Moves.OCTOLOCK, Moves.SPLASH ])
diff --git a/src/test/moves/parting_shot.test.ts b/src/test/moves/parting_shot.test.ts
index d9535ca6482..52cfaf98111 100644
--- a/src/test/moves/parting_shot.test.ts
+++ b/src/test/moves/parting_shot.test.ts
@@ -9,7 +9,6 @@ import { BerryPhase } from "#app/phases/berry-phase";
import { FaintPhase } from "#app/phases/faint-phase";
import { MessagePhase } from "#app/phases/message-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
-import { SPLASH_ONLY } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@@ -31,7 +30,7 @@ describe("Moves - Parting Shot", () => {
game = new GameManager(phaserGame);
game.override.battleType("single");
game.override.moveset([Moves.PARTING_SHOT, Moves.SPLASH]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.startingLevel(5);
game.override.enemyLevel(5);
@@ -125,7 +124,7 @@ describe("Moves - Parting Shot", () => {
game.override
.enemySpecies(Species.ALTARIA)
.enemyAbility(Abilities.NONE)
- .enemyMoveset(Array(4).fill(Moves.MIST));
+ .enemyMoveset([Moves.MIST]);
await game.startBattle([Species.SNORLAX, Species.MEOWTH]);
const enemyPokemon = game.scene.getEnemyPokemon()!;
diff --git a/src/test/moves/power_shift.test.ts b/src/test/moves/power_shift.test.ts
new file mode 100644
index 00000000000..3fda315193e
--- /dev/null
+++ b/src/test/moves/power_shift.test.ts
@@ -0,0 +1,63 @@
+import { Moves } from "#app/enums/moves";
+import { Species } from "#app/enums/species";
+import { Stat } from "#app/enums/stat";
+import { Abilities } from "#enums/abilities";
+import GameManager from "#test/utils/gameManager";
+import Phaser from "phaser";
+import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
+
+describe("Moves - Power Shift", () => {
+ let phaserGame: Phaser.Game;
+ let game: GameManager;
+ const TIMEOUT = 20 * 1000;
+
+ beforeAll(() => {
+ phaserGame = new Phaser.Game({
+ type: Phaser.HEADLESS,
+ });
+ });
+
+ afterEach(() => {
+ game.phaseInterceptor.restoreOg();
+ });
+
+ beforeEach(() => {
+ game = new GameManager(phaserGame);
+ game.override
+ .moveset([Moves.POWER_SHIFT, Moves.BULK_UP])
+ .battleType("single")
+ .ability(Abilities.BALL_FETCH)
+ .enemyAbility(Abilities.BALL_FETCH)
+ .enemyMoveset(Moves.SPLASH);
+ });
+
+ it("switches the user's raw Attack stat with its raw Defense stat", async () => {
+ await game.classicMode.startBattle([Species.MAGIKARP]);
+
+ const playerPokemon = game.scene.getPlayerPokemon()!;
+
+ playerPokemon.setStat(Stat.ATK, 10, false);
+ playerPokemon.setStat(Stat.DEF, 20, false);
+
+ game.move.select(Moves.BULK_UP);
+
+ await game.phaseInterceptor.to("TurnEndPhase");
+
+ // Stat stages are increased by 1
+ expect(playerPokemon.getStatStageMultiplier(Stat.ATK)).toBe(1.5);
+ expect(playerPokemon.getStatStageMultiplier(Stat.DEF)).toBe(1.5);
+
+ await game.toNextTurn();
+
+ game.move.select(Moves.POWER_SHIFT);
+
+ await game.phaseInterceptor.to("TurnEndPhase");
+
+ // Effective stats are calculated correctly
+ expect(playerPokemon.getEffectiveStat(Stat.ATK)).toBe(30);
+ expect(playerPokemon.getEffectiveStat(Stat.DEF)).toBe(15);
+ // Raw stats are swapped
+ expect(playerPokemon.getStat(Stat.ATK, false)).toBe(20);
+ expect(playerPokemon.getStat(Stat.DEF, false)).toBe(10);
+ }, TIMEOUT);
+});
diff --git a/src/test/moves/power_split.test.ts b/src/test/moves/power_split.test.ts
index a532a90a54d..aaf34541567 100644
--- a/src/test/moves/power_split.test.ts
+++ b/src/test/moves/power_split.test.ts
@@ -6,7 +6,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Stat } from "#enums/stat";
import { Abilities } from "#enums/abilities";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - Power Split", () => {
let phaserGame: Phaser.Game;
@@ -34,7 +33,7 @@ describe("Moves - Power Split", () => {
});
it("should average the user's ATK and SPATK stats with those of the target", async () => {
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
await game.startBattle([
Species.INDEEDEE
]);
@@ -56,7 +55,7 @@ describe("Moves - Power Split", () => {
}, 20000);
it("should be idempotent", async () => {
- game.override.enemyMoveset(new Array(4).fill(Moves.POWER_SPLIT));
+ game.override.enemyMoveset([Moves.POWER_SPLIT]);
await game.startBattle([
Species.INDEEDEE
]);
diff --git a/src/test/moves/power_swap.test.ts b/src/test/moves/power_swap.test.ts
index f1efeaa3af3..a3d4bfca19a 100644
--- a/src/test/moves/power_swap.test.ts
+++ b/src/test/moves/power_swap.test.ts
@@ -27,7 +27,7 @@ describe("Moves - Power Swap", () => {
game.override
.battleType("single")
.enemyAbility(Abilities.BALL_FETCH)
- .enemyMoveset(new Array(4).fill(Moves.SHELL_SMASH))
+ .enemyMoveset([Moves.SHELL_SMASH])
.enemySpecies(Species.MEW)
.enemyLevel(200)
.moveset([ Moves.POWER_SWAP ])
diff --git a/src/test/moves/protect.test.ts b/src/test/moves/protect.test.ts
index 83cd088aa47..24bbcbb9d34 100644
--- a/src/test/moves/protect.test.ts
+++ b/src/test/moves/protect.test.ts
@@ -35,7 +35,7 @@ describe("Moves - Protect", () => {
game.override.enemySpecies(Species.SNORLAX);
game.override.enemyAbility(Abilities.INSOMNIA);
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
game.override.startingLevel(100);
game.override.enemyLevel(100);
@@ -59,7 +59,7 @@ describe("Moves - Protect", () => {
test(
"should prevent secondary effects from the opponent's attack",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.CEASELESS_EDGE));
+ game.override.enemyMoveset([Moves.CEASELESS_EDGE]);
vi.spyOn(allMoves[Moves.CEASELESS_EDGE], "accuracy", "get").mockReturnValue(100);
await game.classicMode.startBattle([Species.CHARIZARD]);
@@ -78,7 +78,7 @@ describe("Moves - Protect", () => {
test(
"should protect the user from status moves",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.CHARM));
+ game.override.enemyMoveset([Moves.CHARM]);
await game.classicMode.startBattle([Species.CHARIZARD]);
@@ -95,7 +95,7 @@ describe("Moves - Protect", () => {
test(
"should stop subsequent hits of a multi-hit move",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TACHYON_CUTTER));
+ game.override.enemyMoveset([Moves.TACHYON_CUTTER]);
await game.classicMode.startBattle([Species.CHARIZARD]);
@@ -114,7 +114,7 @@ describe("Moves - Protect", () => {
test(
"should fail if the user is the last to move in the turn",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.PROTECT));
+ game.override.enemyMoveset([Moves.PROTECT]);
await game.classicMode.startBattle([Species.CHARIZARD]);
diff --git a/src/test/moves/quick_guard.test.ts b/src/test/moves/quick_guard.test.ts
index 5f4af40eb71..9ab0fe1509c 100644
--- a/src/test/moves/quick_guard.test.ts
+++ b/src/test/moves/quick_guard.test.ts
@@ -32,7 +32,7 @@ describe("Moves - Quick Guard", () => {
game.override.moveset([Moves.QUICK_GUARD, Moves.SPLASH, Moves.FOLLOW_ME]);
game.override.enemySpecies(Species.SNORLAX);
- game.override.enemyMoveset(Array(4).fill(Moves.QUICK_ATTACK));
+ game.override.enemyMoveset([Moves.QUICK_ATTACK]);
game.override.enemyAbility(Abilities.INSOMNIA);
game.override.startingLevel(100);
@@ -59,7 +59,7 @@ describe("Moves - Quick Guard", () => {
"should protect the user and allies from Prankster-boosted moves",
async () => {
game.override.enemyAbility(Abilities.PRANKSTER);
- game.override.enemyMoveset(Array(4).fill(Moves.GROWL));
+ game.override.enemyMoveset([Moves.GROWL]);
await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
@@ -77,7 +77,7 @@ describe("Moves - Quick Guard", () => {
test(
"should stop subsequent hits of a multi-hit priority move",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.WATER_SHURIKEN));
+ game.override.enemyMoveset([Moves.WATER_SHURIKEN]);
await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
@@ -98,7 +98,7 @@ describe("Moves - Quick Guard", () => {
"should fail if the user is the last to move in the turn",
async () => {
game.override.battleType("single");
- game.override.enemyMoveset(Array(4).fill(Moves.QUICK_GUARD));
+ game.override.enemyMoveset([Moves.QUICK_GUARD]);
await game.classicMode.startBattle([Species.CHARIZARD]);
diff --git a/src/test/moves/rollout.test.ts b/src/test/moves/rollout.test.ts
index ddb0b22e642..c08535a61df 100644
--- a/src/test/moves/rollout.test.ts
+++ b/src/test/moves/rollout.test.ts
@@ -4,7 +4,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -32,7 +31,7 @@ describe("Moves - Rollout", () => {
game.override.enemyAbility(Abilities.BALL_FETCH);
game.override.startingLevel(100);
game.override.enemyLevel(100);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
it("should double it's dmg on sequential uses but reset after 5", async () => {
diff --git a/src/test/moves/safeguard.test.ts b/src/test/moves/safeguard.test.ts
index 94a7aa6031e..2caf698a73a 100644
--- a/src/test/moves/safeguard.test.ts
+++ b/src/test/moves/safeguard.test.ts
@@ -29,7 +29,7 @@ describe("Moves - Safeguard", () => {
game.override
.battleType("single")
.enemySpecies(Species.DRATINI)
- .enemyMoveset(Array(4).fill(Moves.SAFEGUARD))
+ .enemyMoveset([Moves.SAFEGUARD])
.enemyAbility(Abilities.BALL_FETCH)
.enemyLevel(5)
.starterSpecies(Species.DRATINI)
@@ -38,7 +38,7 @@ describe("Moves - Safeguard", () => {
});
it("protects from damaging moves with additional effects", async () => {
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemy = game.scene.getEnemyPokemon()!;
game.move.select(Moves.NUZZLE);
@@ -49,7 +49,7 @@ describe("Moves - Safeguard", () => {
}, TIMEOUT);
it("protects from status moves", async () => {
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemyPokemon = game.scene.getEnemyPokemon()!;
game.move.select(Moves.SPORE);
@@ -61,7 +61,7 @@ describe("Moves - Safeguard", () => {
it("protects from confusion", async () => {
game.override.moveset([Moves.CONFUSE_RAY]);
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemyPokemon = game.scene.getEnemyPokemon()!;
game.move.select(Moves.CONFUSE_RAY);
@@ -74,7 +74,7 @@ describe("Moves - Safeguard", () => {
it("protects ally from status", async () => {
game.override.battleType("double");
- await game.startBattle();
+ await game.classicMode.startBattle();
game.move.select(Moves.SPORE, 0, BattlerIndex.ENEMY_2);
game.move.select(Moves.NUZZLE, 1, BattlerIndex.ENEMY_2);
@@ -90,7 +90,7 @@ describe("Moves - Safeguard", () => {
}, TIMEOUT);
it("protects from Yawn", async () => {
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemyPokemon = game.scene.getEnemyPokemon()!;
game.move.select(Moves.YAWN);
@@ -101,7 +101,7 @@ describe("Moves - Safeguard", () => {
}, TIMEOUT);
it("doesn't protect from already existing Yawn", async () => {
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemyPokemon = game.scene.getEnemyPokemon()!;
game.move.select(Moves.YAWN);
@@ -116,17 +116,22 @@ describe("Moves - Safeguard", () => {
it("doesn't protect from self-inflicted via Rest or Flame Orb", async () => {
game.override.enemyHeldItems([{name: "FLAME_ORB"}]);
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemyPokemon = game.scene.getEnemyPokemon()!;
game.move.select(Moves.SPLASH);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.toNextTurn();
+ enemyPokemon.damageAndUpdate(1);
expect(enemyPokemon.status?.effect).toEqual(StatusEffect.BURN);
- game.override.enemyMoveset(Array(4).fill(Moves.REST));
+ game.override.enemyMoveset([Moves.REST]);
+ // Force the moveset to update mid-battle
+ // TODO: Remove after enemy AI rework is in
+ enemyPokemon.getMoveset();
game.move.select(Moves.SPLASH);
+ enemyPokemon.damageAndUpdate(1);
await game.toNextTurn();
expect(enemyPokemon.status?.effect).toEqual(StatusEffect.SLEEP);
@@ -135,13 +140,13 @@ describe("Moves - Safeguard", () => {
it("protects from ability-inflicted status", async () => {
game.override.ability(Abilities.STATIC);
vi.spyOn(allAbilities[Abilities.STATIC].getAttrs(PostDefendContactApplyStatusEffectAbAttr)[0], "chance", "get").mockReturnValue(100);
- await game.startBattle();
+ await game.classicMode.startBattle();
const enemyPokemon = game.scene.getEnemyPokemon()!;
game.move.select(Moves.SPLASH);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.toNextTurn();
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
game.move.select(Moves.SPLASH);
await game.toNextTurn();
diff --git a/src/test/moves/shell_trap.test.ts b/src/test/moves/shell_trap.test.ts
index 4549a8b2b73..213b9c3fd0a 100644
--- a/src/test/moves/shell_trap.test.ts
+++ b/src/test/moves/shell_trap.test.ts
@@ -9,7 +9,6 @@ import { MovePhase } from "#app/phases/move-phase";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@@ -33,7 +32,7 @@ describe("Moves - Shell Trap", () => {
.battleType("double")
.moveset([Moves.SHELL_TRAP, Moves.SPLASH, Moves.BULLDOZE])
.enemySpecies(Species.SNORLAX)
- .enemyMoveset(Array(4).fill(Moves.RAZOR_LEAF))
+ .enemyMoveset([Moves.RAZOR_LEAF])
.startingLevel(100)
.enemyLevel(100);
@@ -67,7 +66,7 @@ describe("Moves - Shell Trap", () => {
it(
"should fail if the user is only hit by special attacks",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.SWIFT));
+ game.override.enemyMoveset([Moves.SWIFT]);
await game.startBattle([Species.CHARIZARD, Species.TURTONATOR]);
@@ -93,7 +92,7 @@ describe("Moves - Shell Trap", () => {
it(
"should fail if the user isn't hit with any attack",
async () => {
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
await game.startBattle([Species.CHARIZARD, Species.TURTONATOR]);
@@ -119,7 +118,7 @@ describe("Moves - Shell Trap", () => {
it(
"should not activate from an ally's attack",
async () => {
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
await game.startBattle([Species.BLASTOISE, Species.CHARIZARD]);
diff --git a/src/test/moves/speed_swap.test.ts b/src/test/moves/speed_swap.test.ts
index 131d506792b..179f1212394 100644
--- a/src/test/moves/speed_swap.test.ts
+++ b/src/test/moves/speed_swap.test.ts
@@ -6,7 +6,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Stat } from "#enums/stat";
import { Abilities } from "#enums/abilities";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - Speed Swap", () => {
let phaserGame: Phaser.Game;
@@ -27,7 +26,7 @@ describe("Moves - Speed Swap", () => {
game.override
.battleType("single")
.enemyAbility(Abilities.NONE)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemySpecies(Species.MEW)
.enemyLevel(200)
.moveset([ Moves.SPEED_SWAP ])
diff --git a/src/test/moves/spikes.test.ts b/src/test/moves/spikes.test.ts
index fa2e7521152..aa59912d802 100644
--- a/src/test/moves/spikes.test.ts
+++ b/src/test/moves/spikes.test.ts
@@ -4,7 +4,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - Spikes", () => {
@@ -28,7 +27,7 @@ describe("Moves - Spikes", () => {
.enemySpecies(Species.MAGIKARP)
.enemyAbility(Abilities.BALL_FETCH)
.ability(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.moveset([Moves.SPIKES, Moves.SPLASH, Moves.ROAR]);
});
diff --git a/src/test/moves/spit_up.test.ts b/src/test/moves/spit_up.test.ts
index f88791efb74..acf7f01d991 100644
--- a/src/test/moves/spit_up.test.ts
+++ b/src/test/moves/spit_up.test.ts
@@ -9,7 +9,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import { MovePhase } from "#app/phases/move-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
@@ -33,7 +32,7 @@ describe("Moves - Spit Up", () => {
game.override.battleType("single");
game.override.enemySpecies(Species.RATTATA);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyAbility(Abilities.NONE);
game.override.enemyLevel(2000);
diff --git a/src/test/moves/stockpile.test.ts b/src/test/moves/stockpile.test.ts
index d57768d0ffd..8e7a44d053b 100644
--- a/src/test/moves/stockpile.test.ts
+++ b/src/test/moves/stockpile.test.ts
@@ -7,7 +7,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -30,7 +29,7 @@ describe("Moves - Stockpile", () => {
game.override.battleType("single");
game.override.enemySpecies(Species.RATTATA);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyAbility(Abilities.NONE);
game.override.startingLevel(2000);
diff --git a/src/test/moves/swallow.test.ts b/src/test/moves/swallow.test.ts
index 9cea7ae8dc9..5a0e63e6e78 100644
--- a/src/test/moves/swallow.test.ts
+++ b/src/test/moves/swallow.test.ts
@@ -8,7 +8,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -30,7 +29,7 @@ describe("Moves - Swallow", () => {
game.override.battleType("single");
game.override.enemySpecies(Species.RATTATA);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.enemyAbility(Abilities.NONE);
game.override.enemyLevel(2000);
diff --git a/src/test/moves/tail_whip.test.ts b/src/test/moves/tail_whip.test.ts
index 04730a04f7a..5c83feb8a4e 100644
--- a/src/test/moves/tail_whip.test.ts
+++ b/src/test/moves/tail_whip.test.ts
@@ -5,7 +5,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
@@ -33,7 +32,7 @@ describe("Moves - Tail whip", () => {
game.override.ability(Abilities.INSOMNIA);
game.override.startingLevel(2000);
game.override.moveset([ moveToUse ]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
it("should lower DEF stat stage by 1", async() => {
diff --git a/src/test/moves/tailwind.test.ts b/src/test/moves/tailwind.test.ts
index d158a9cce86..6a08cfe802f 100644
--- a/src/test/moves/tailwind.test.ts
+++ b/src/test/moves/tailwind.test.ts
@@ -5,7 +5,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -27,7 +26,7 @@ describe("Moves - Tailwind", () => {
game = new GameManager(phaserGame);
game.override.battleType("double");
game.override.moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
});
it("doubles the Speed stat of the Pokemons on its side", async () => {
diff --git a/src/test/moves/tar_shot.test.ts b/src/test/moves/tar_shot.test.ts
index 15667122a37..2963f061fc6 100644
--- a/src/test/moves/tar_shot.test.ts
+++ b/src/test/moves/tar_shot.test.ts
@@ -5,7 +5,6 @@ import { Species } from "#app/enums/species";
import { Stat } from "#app/enums/stat";
import { Abilities } from "#enums/abilities";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -29,7 +28,7 @@ describe("Moves - Tar Shot", () => {
game.override
.battleType("single")
.enemyAbility(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemySpecies(Species.TANGELA)
.enemyLevel(1000)
.moveset([Moves.TAR_SHOT, Moves.FIRE_PUNCH])
diff --git a/src/test/moves/tera_blast.test.ts b/src/test/moves/tera_blast.test.ts
index fa7a99adc14..55d61496297 100644
--- a/src/test/moves/tera_blast.test.ts
+++ b/src/test/moves/tera_blast.test.ts
@@ -9,7 +9,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - Tera Blast", () => {
let phaserGame: Phaser.Game;
@@ -37,7 +36,7 @@ describe("Moves - Tera Blast", () => {
.ability(Abilities.BALL_FETCH)
.startingHeldItems([{ name: "TERA_SHARD", type: Type.FIRE }])
.enemySpecies(Species.MAGIKARP)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.enemyAbility(Abilities.BALL_FETCH)
.enemyLevel(20);
diff --git a/src/test/moves/throat_chop.test.ts b/src/test/moves/throat_chop.test.ts
new file mode 100644
index 00000000000..cb34b4bafff
--- /dev/null
+++ b/src/test/moves/throat_chop.test.ts
@@ -0,0 +1,57 @@
+import { BattlerIndex } from "#app/battle";
+import { Moves } from "#app/enums/moves";
+import { Species } from "#app/enums/species";
+import { Stat } from "#app/enums/stat";
+import { Abilities } from "#enums/abilities";
+import GameManager from "#test/utils/gameManager";
+import Phaser from "phaser";
+import { afterEach, beforeAll, beforeEach, describe, it, expect } from "vitest";
+
+describe("Moves - Throat Chop", () => {
+ let phaserGame: Phaser.Game;
+ let game: GameManager;
+ const TIMEOUT = 20 * 1000;
+
+ beforeAll(() => {
+ phaserGame = new Phaser.Game({
+ type: Phaser.HEADLESS,
+ });
+ });
+
+ afterEach(() => {
+ game.phaseInterceptor.restoreOg();
+ });
+
+ beforeEach(() => {
+ game = new GameManager(phaserGame);
+ game.override
+ .moveset(Array(4).fill(Moves.GROWL))
+ .battleType("single")
+ .ability(Abilities.BALL_FETCH)
+ .enemyAbility(Abilities.BALL_FETCH)
+ .enemyMoveset(Array(4).fill(Moves.THROAT_CHOP))
+ .enemySpecies(Species.MAGIKARP);
+ });
+
+ it("prevents the target from using sound-based moves for two turns", async () => {
+ await game.classicMode.startBattle([Species.MAGIKARP]);
+
+ const enemy = game.scene.getEnemyPokemon()!;
+
+ game.move.select(Moves.GROWL);
+ await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
+
+ // First turn, move is interrupted
+ await game.phaseInterceptor.to("TurnEndPhase");
+ expect(enemy.getStatStage(Stat.ATK)).toBe(0);
+
+ // Second turn, struggle if no valid moves
+ await game.toNextTurn();
+
+ game.move.select(Moves.GROWL);
+ await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
+
+ await game.phaseInterceptor.to("MoveEndPhase");
+ expect(enemy.isFullHp()).toBe(false);
+ }, TIMEOUT);
+});
diff --git a/src/test/moves/thunder_wave.test.ts b/src/test/moves/thunder_wave.test.ts
index 0c91be29714..7ad59518013 100644
--- a/src/test/moves/thunder_wave.test.ts
+++ b/src/test/moves/thunder_wave.test.ts
@@ -6,7 +6,6 @@ import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
const TIMEOUT = 20 * 1000;
@@ -30,7 +29,7 @@ describe("Moves - Thunder Wave", () => {
.battleType("single")
.starterSpecies(Species.PIKACHU)
.moveset([Moves.THUNDER_WAVE])
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
});
// References: https://bulbapedia.bulbagarden.net/wiki/Thunder_Wave_(move)
diff --git a/src/test/moves/tidy_up.test.ts b/src/test/moves/tidy_up.test.ts
index 5204b06106b..255fe948447 100644
--- a/src/test/moves/tidy_up.test.ts
+++ b/src/test/moves/tidy_up.test.ts
@@ -6,7 +6,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
-import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
@@ -30,7 +29,7 @@ describe("Moves - Tidy Up", () => {
game.override.battleType("single");
game.override.enemySpecies(Species.MAGIKARP);
game.override.enemyAbility(Abilities.BALL_FETCH);
- game.override.enemyMoveset(SPLASH_ONLY);
+ game.override.enemyMoveset(Moves.SPLASH);
game.override.starterSpecies(Species.FEEBAS);
game.override.ability(Abilities.BALL_FETCH);
game.override.moveset([Moves.TIDY_UP]);
diff --git a/src/test/moves/transform.test.ts b/src/test/moves/transform.test.ts
index 45769447e4d..6686f1fc73b 100644
--- a/src/test/moves/transform.test.ts
+++ b/src/test/moves/transform.test.ts
@@ -6,7 +6,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { Moves } from "#enums/moves";
import { Stat, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat";
import { Abilities } from "#enums/abilities";
-import { SPLASH_ONLY } from "../utils/testUtils";
// TODO: Add more tests once Transform is fully implemented
describe("Moves - Transform", () => {
@@ -31,7 +30,7 @@ describe("Moves - Transform", () => {
.enemyLevel(200)
.enemyAbility(Abilities.BEAST_BOOST)
.enemyPassiveAbility(Abilities.BALL_FETCH)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.ability(Abilities.INTIMIDATE)
.moveset([ Moves.TRANSFORM ]);
});
@@ -77,7 +76,7 @@ describe("Moves - Transform", () => {
}, 20000);
it("should copy in-battle overridden stats", async () => {
- game.override.enemyMoveset(new Array(4).fill(Moves.POWER_SPLIT));
+ game.override.enemyMoveset([Moves.POWER_SPLIT]);
await game.startBattle([
Species.DITTO
diff --git a/src/test/moves/u_turn.test.ts b/src/test/moves/u_turn.test.ts
index ae55302bb42..c4b6ae2497f 100644
--- a/src/test/moves/u_turn.test.ts
+++ b/src/test/moves/u_turn.test.ts
@@ -7,7 +7,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("Moves - U-turn", () => {
let phaserGame: Phaser.Game;
@@ -31,7 +30,7 @@ describe("Moves - U-turn", () => {
.startingLevel(90)
.startingWave(97)
.moveset([Moves.U_TURN])
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.disableCrits();
});
diff --git a/src/test/moves/wide_guard.test.ts b/src/test/moves/wide_guard.test.ts
index 6feeff815b5..b4e6e305539 100644
--- a/src/test/moves/wide_guard.test.ts
+++ b/src/test/moves/wide_guard.test.ts
@@ -32,7 +32,7 @@ describe("Moves - Wide Guard", () => {
game.override.moveset([Moves.WIDE_GUARD, Moves.SPLASH, Moves.SURF]);
game.override.enemySpecies(Species.SNORLAX);
- game.override.enemyMoveset(Array(4).fill(Moves.SWIFT));
+ game.override.enemyMoveset([Moves.SWIFT]);
game.override.enemyAbility(Abilities.INSOMNIA);
game.override.startingLevel(100);
@@ -61,7 +61,7 @@ describe("Moves - Wide Guard", () => {
test(
"should protect the user and allies from multi-target status moves",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.GROWL));
+ game.override.enemyMoveset([Moves.GROWL]);
await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
@@ -82,7 +82,7 @@ describe("Moves - Wide Guard", () => {
test(
"should not protect the user and allies from single-target moves",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
+ game.override.enemyMoveset([Moves.TACKLE]);
await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
@@ -103,7 +103,7 @@ describe("Moves - Wide Guard", () => {
test(
"should protect the user from its ally's multi-target move",
async () => {
- game.override.enemyMoveset(Array(4).fill(Moves.SPLASH));
+ game.override.enemyMoveset([Moves.SPLASH]);
await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]);
diff --git a/src/test/phases/learn-move-phase.test.ts b/src/test/phases/learn-move-phase.test.ts
new file mode 100644
index 00000000000..60cdbee8570
--- /dev/null
+++ b/src/test/phases/learn-move-phase.test.ts
@@ -0,0 +1,47 @@
+import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
+import Phaser from "phaser";
+import GameManager from "#test/utils/gameManager";
+import { Species } from "#enums/species";
+import { Moves } from "#enums/moves";
+import { LearnMovePhase } from "#app/phases/learn-move-phase";
+
+describe("Learn Move Phase", () => {
+ let phaserGame: Phaser.Game;
+ let game: GameManager;
+
+ beforeAll(() => {
+ phaserGame = new Phaser.Game({
+ type: Phaser.HEADLESS,
+ });
+ });
+
+ afterEach(() => {
+ game.phaseInterceptor.restoreOg();
+ });
+
+ beforeEach(() => {
+ game = new GameManager(phaserGame);
+ game.override.xpMultiplier(50);
+ });
+
+ it("If Pokemon has less than 4 moves, its newest move will be added to the lowest empty index", async () => {
+ game.override.moveset([Moves.SPLASH]);
+ await game.startBattle([Species.BULBASAUR]);
+ const pokemon = game.scene.getPlayerPokemon()!;
+ const newMovePos = pokemon?.getMoveset().length;
+ game.move.select(Moves.SPLASH);
+ await game.doKillOpponents();
+ await game.phaseInterceptor.to(LearnMovePhase);
+ const levelMove = pokemon.getLevelMoves(5)[0];
+ const levelReq = levelMove[0];
+ const levelMoveId = levelMove[1];
+ expect(pokemon.level).toBeGreaterThanOrEqual(levelReq);
+ expect(pokemon?.getMoveset()[newMovePos]?.moveId).toBe(levelMoveId);
+ });
+
+ /**
+ * Future Tests:
+ * If a Pokemon has four moves, the user can specify an old move to be forgotten and a new move will take its place.
+ * If a Pokemon has four moves, the user can reject the new move, keeping the moveset the same.
+ */
+});
diff --git a/src/test/reload.test.ts b/src/test/reload.test.ts
index 0a712fcc7df..a96a525ca2d 100644
--- a/src/test/reload.test.ts
+++ b/src/test/reload.test.ts
@@ -2,7 +2,6 @@ import { Species } from "#app/enums/species";
import { GameModes } from "#app/game-mode";
import GameManager from "#test/utils/gameManager";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
-import { SPLASH_ONLY } from "./utils/testUtils";
import { Moves } from "#app/enums/moves";
import { Biome } from "#app/enums/biome";
@@ -45,7 +44,7 @@ describe("Reload", () => {
.enemyLevel(1000)
.disableTrainerWaves()
.moveset([Moves.KOWTOW_CLEAVE])
- .enemyMoveset(SPLASH_ONLY);
+ .enemyMoveset(Moves.SPLASH);
await game.dailyMode.startBattle();
// Transition from Daily Run Wave 10 to Wave 11 in order to trigger biome switch
diff --git a/src/test/ui/type-hints.test.ts b/src/test/ui/type-hints.test.ts
index ccab02b82bf..726094b258a 100644
--- a/src/test/ui/type-hints.test.ts
+++ b/src/test/ui/type-hints.test.ts
@@ -8,7 +8,6 @@ import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import MockText from "../utils/mocks/mocksContainer/mockText";
-import { SPLASH_ONLY } from "../utils/testUtils";
describe("UI - Type Hints", () => {
let phaserGame: Phaser.Game;
@@ -27,7 +26,7 @@ describe("UI - Type Hints", () => {
beforeEach(async () => {
game = new GameManager(phaserGame);
game.settings.typeHints(true); //activate type hints
- game.override.battleType("single").startingLevel(100).startingWave(1).enemyMoveset(SPLASH_ONLY);
+ game.override.battleType("single").startingLevel(100).startingWave(1).enemyMoveset(Moves.SPLASH);
});
it("check immunity color", async () => {
@@ -36,7 +35,7 @@ describe("UI - Type Hints", () => {
.startingLevel(100)
.startingWave(1)
.enemySpecies(Species.FLORGES)
- .enemyMoveset(SPLASH_ONLY)
+ .enemyMoveset(Moves.SPLASH)
.moveset([Moves.DRAGON_CLAW]);
game.settings.typeHints(true); //activate type hints
diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts
index a42ef84b496..a17b841b682 100644
--- a/src/test/utils/helpers/overridesHelper.ts
+++ b/src/test/utils/helpers/overridesHelper.ts
@@ -48,6 +48,17 @@ export class OverridesHelper extends GameManagerHelper {
return this;
}
+ /**
+ * Override the XP Multiplier
+ * @param value the XP multiplier to set
+ * @returns `this`
+ */
+ xpMultiplier(value: number): this {
+ vi.spyOn(Overrides, "XP_MULTIPLIER_OVERRIDE", "get").mockReturnValue(value);
+ this.log(`XP Multiplier set to ${value}!`);
+ return this;
+ }
+
/**
* Override the player (pokemon) starting held items
* @param items the items to hold
@@ -122,8 +133,11 @@ export class OverridesHelper extends GameManagerHelper {
* @param moveset the {@linkcode Moves | moves}set to set
* @returns this
*/
- moveset(moveset: Moves[]): this {
+ moveset(moveset: Moves | Moves[]): this {
vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue(moveset);
+ if (!Array.isArray(moveset)) {
+ moveset = [moveset];
+ }
const movesetStr = moveset.map((moveId) => Moves[moveId]).join(", ");
this.log(`Player Pokemon moveset set to ${movesetStr} (=[${moveset.join(", ")}])!`);
return this;
@@ -241,8 +255,11 @@ export class OverridesHelper extends GameManagerHelper {
* @param moveset the {@linkcode Moves | moves}set to set
* @returns this
*/
- enemyMoveset(moveset: Moves[]): this {
+ enemyMoveset(moveset: Moves | Moves[]): this {
vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue(moveset);
+ if (!Array.isArray(moveset)) {
+ moveset = [moveset];
+ }
const movesetStr = moveset.map((moveId) => Moves[moveId]).join(", ");
this.log(`Enemy Pokemon moveset set to ${movesetStr} (=[${moveset.join(", ")}])!`);
return this;
diff --git a/src/test/utils/mocks/mocksContainer/mockContainer.ts b/src/test/utils/mocks/mocksContainer/mockContainer.ts
index d2cdd852257..94ae61a6ce4 100644
--- a/src/test/utils/mocks/mocksContainer/mockContainer.ts
+++ b/src/test/utils/mocks/mocksContainer/mockContainer.ts
@@ -52,9 +52,8 @@ export default class MockContainer implements MockGameObject {
/// Sets the position of this Game Object to be a relative position from the source Game Object.
}
- setInteractive(hitArea?, callback?, dropZone?) {
- /// Sets the InteractiveObject to be a drop zone for a drag and drop operation.
- }
+ setInteractive = vi.fn();
+
setOrigin(x, y) {
this.x = x;
this.y = y;
diff --git a/src/test/utils/mocks/mocksContainer/mockSprite.ts b/src/test/utils/mocks/mocksContainer/mockSprite.ts
index 35cd2d5faab..ae43df46cf5 100644
--- a/src/test/utils/mocks/mocksContainer/mockSprite.ts
+++ b/src/test/utils/mocks/mocksContainer/mockSprite.ts
@@ -1,5 +1,6 @@
import Phaser from "phaser";
import { MockGameObject } from "../mockGameObject";
+import { vi } from "vitest";
import Sprite = Phaser.GameObjects.Sprite;
import Frame = Phaser.Textures.Frame;
@@ -101,9 +102,7 @@ export default class MockSprite implements MockGameObject {
return this.phaserSprite.stop();
}
- setInteractive(hitArea, hitAreaCallback, dropZone) {
- return null;
- }
+ setInteractive = vi.fn();
on(event, callback, source) {
return this.phaserSprite.on(event, callback, source);
diff --git a/src/test/utils/mocks/mocksContainer/mockText.ts b/src/test/utils/mocks/mocksContainer/mockText.ts
index 6b9ecf083fd..5a89432902b 100644
--- a/src/test/utils/mocks/mocksContainer/mockText.ts
+++ b/src/test/utils/mocks/mocksContainer/mockText.ts
@@ -197,6 +197,8 @@ export default class MockText implements MockGameObject {
this.color = color;
});
+ setInteractive = vi.fn();
+
setShadowColor(color) {
// Sets the shadow color.
// return this.phaserText.setShadowColor(color);
diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts
index 2eb5324a2aa..a89d1788be9 100644
--- a/src/test/utils/phaseInterceptor.ts
+++ b/src/test/utils/phaseInterceptor.ts
@@ -12,6 +12,7 @@ import { EndEvolutionPhase } from "#app/phases/end-evolution-phase";
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
import { EvolutionPhase } from "#app/phases/evolution-phase";
import { FaintPhase } from "#app/phases/faint-phase";
+import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { LevelCapPhase } from "#app/phases/level-cap-phase";
import { LoginPhase } from "#app/phases/login-phase";
import { MessagePhase } from "#app/phases/message-phase";
@@ -89,6 +90,7 @@ export default class PhaseInterceptor {
[NextEncounterPhase, this.startPhase],
[NewBattlePhase, this.startPhase],
[VictoryPhase, this.startPhase],
+ [LearnMovePhase, this.startPhase],
[MoveEndPhase, this.startPhase],
[StatStageChangePhase, this.startPhase],
[ShinySparklePhase, this.startPhase],
diff --git a/src/test/utils/testUtils.ts b/src/test/utils/testUtils.ts
index 2265cf8d79c..b922fc9c61c 100644
--- a/src/test/utils/testUtils.ts
+++ b/src/test/utils/testUtils.ts
@@ -1,10 +1,6 @@
-import { Moves } from "#app/enums/moves";
import i18next, { type ParseKeys } from "i18next";
import { vi } from "vitest";
-/** Ready to use array of Moves.SPLASH x4 */
-export const SPLASH_ONLY = [Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH];
-
/**
* Sets up the i18next mock.
* Includes a i18next.t mocked implementation only returning the raw key (`(key) => key`)
diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts
index 05c634609f8..c7b82dc826e 100644
--- a/src/ui/battle-info.ts
+++ b/src/ui/battle-info.ts
@@ -323,7 +323,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.teraIcon.setVisible(this.lastTeraType !== Type.UNKNOWN);
this.teraIcon.on("pointerover", () => {
if (this.lastTeraType !== Type.UNKNOWN) {
- (this.scene as BattleScene).ui.showTooltip("", `${Utils.toReadableString(Type[this.lastTeraType])} Terastallized`);
+ (this.scene as BattleScene).ui.showTooltip("", i18next.t("fightUiHandler:teraHover", {type: i18next.t(`pokemonInfo:Type.${Type[this.lastTeraType]}`) }));
}
});
this.teraIcon.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip());
diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts
index 3bea0f21433..9a694d50b29 100644
--- a/src/ui/battle-message-ui-handler.ts
+++ b/src/ui/battle-message-ui-handler.ts
@@ -97,6 +97,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
this.levelUpStatsContainer = levelUpStatsContainer;
const levelUpStatsLabelsContent = addTextObject(this.scene, (this.scene.game.canvas.width / 6) - 73, -94, "", TextStyle.WINDOW, { maxLines: 6 });
+ levelUpStatsLabelsContent.setLineSpacing(i18next.resolvedLanguage === "ja" ? 25 : 5);
let levelUpStatsLabelText = "";
for (const s of PERMANENT_STATS) {
@@ -112,11 +113,13 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
levelUpStatsContainer.add(levelUpStatsLabelsContent);
const levelUpStatsIncrContent = addTextObject(this.scene, (this.scene.game.canvas.width / 6) - 50, -94, "+\n+\n+\n+\n+\n+", TextStyle.WINDOW, { maxLines: 6 });
+ levelUpStatsIncrContent.setLineSpacing(i18next.resolvedLanguage === "ja" ? 25 : 5);
levelUpStatsContainer.add(levelUpStatsIncrContent);
this.levelUpStatsIncrContent = levelUpStatsIncrContent;
const levelUpStatsValuesContent = addBBCodeTextObject(this.scene, (this.scene.game.canvas.width / 6) - 7, -94, "", TextStyle.WINDOW, { maxLines: 6, lineSpacing: 5});
+ levelUpStatsValuesContent.setLineSpacing(i18next.resolvedLanguage === "ja" ? 25 : 5);
levelUpStatsValuesContent.setOrigin(1, 0);
levelUpStatsValuesContent.setAlign("right");
levelUpStatsContainer.add(levelUpStatsValuesContent);
diff --git a/src/ui/move-info-overlay.ts b/src/ui/move-info-overlay.ts
index 859e95a39b6..77010f84528 100644
--- a/src/ui/move-info-overlay.ts
+++ b/src/ui/move-info-overlay.ts
@@ -58,6 +58,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
// set up the description; wordWrap uses true pixels, unaffected by any scaling, while other values are affected
this.desc = addTextObject(scene, (options?.onSide && !options?.right ? EFF_WIDTH : 0) + BORDER, (options?.top ? EFF_HEIGHT : 0) + BORDER - 2, "", TextStyle.BATTLE_INFO, { wordWrap: { width: (width - (BORDER - 2) * 2 - (options?.onSide ? EFF_WIDTH : 0)) * GLOBAL_SCALE } });
+ this.desc.setLineSpacing(i18next.resolvedLanguage === "ja" ? 25 : 5);
// limit the text rendering, required for scrolling later on
const maskPointOrigin = {
diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts
index 6b75c46bd45..e1269499b10 100644
--- a/src/ui/starter-select-ui-handler.ts
+++ b/src/ui/starter-select-ui-handler.ts
@@ -266,6 +266,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private pokemonPassiveDisabledIcon: Phaser.GameObjects.Sprite;
private pokemonPassiveLockedIcon: Phaser.GameObjects.Sprite;
+ private activeTooltip: "ABILITY" | "PASSIVE" | "CANDY" | undefined;
private instructionsContainer: Phaser.GameObjects.Container;
private filterInstructionsContainer: Phaser.GameObjects.Container;
private shinyIconElement: Phaser.GameObjects.Sprite;
@@ -561,10 +562,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 127 + starterInfoYOffset, i18next.t("starterSelectUiHandler:ability"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityLabelText.setOrigin(0, 0);
this.pokemonAbilityLabelText.setVisible(false);
+
this.starterSelectContainer.add(this.pokemonAbilityLabelText);
this.pokemonAbilityText = addTextObject(this.scene, starterInfoXPos, 127 + starterInfoYOffset, "", TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityText.setOrigin(0, 0);
+ this.pokemonAbilityText.setInteractive(new Phaser.Geom.Rectangle(0, 0, 250, 55), Phaser.Geom.Rectangle.Contains);
+
this.starterSelectContainer.add(this.pokemonAbilityText);
this.pokemonPassiveLabelText = addTextObject(this.scene, 6, 136 + starterInfoYOffset, i18next.t("starterSelectUiHandler:passive"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
@@ -574,6 +578,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonPassiveText = addTextObject(this.scene, starterInfoXPos, 136 + starterInfoYOffset, "", TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonPassiveText.setOrigin(0, 0);
+ this.pokemonPassiveText.setInteractive(new Phaser.Geom.Rectangle(0, 0, 250, 55), Phaser.Geom.Rectangle.Contains);
this.starterSelectContainer.add(this.pokemonPassiveText);
this.pokemonPassiveDisabledIcon = this.scene.add.sprite(starterInfoXPos, 137 + starterInfoYOffset, "icon_stop");
@@ -1921,6 +1926,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
} while (newAbilityIndex !== this.abilityCursor);
starterAttributes.ability = newAbilityIndex; // store the selected ability
+
+ const { visible: tooltipVisible } = this.scene.ui.getTooltip();
+
+ if (tooltipVisible && this.activeTooltip === "ABILITY") {
+ const newAbility = allAbilities[this.lastSpecies.getAbility(newAbilityIndex)];
+ this.scene.ui.editTooltip(`${newAbility.name}`, `${newAbility.description}`);
+ }
+
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, newAbilityIndex, undefined);
success = true;
}
@@ -2687,12 +2700,30 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
}
+ getFriendship(speciesId: number) {
+ let currentFriendship = this.scene.gameData.starterData[speciesId].friendship;
+ if (!currentFriendship || currentFriendship === undefined) {
+ currentFriendship = 0;
+ }
+
+ const friendshipCap = getStarterValueFriendshipCap(speciesStarters[speciesId]);
+
+ return { currentFriendship, friendshipCap };
+ }
+
setSpecies(species: PokemonSpecies | null) {
this.speciesStarterDexEntry = species ? this.scene.gameData.dexData[species.speciesId] : null;
this.dexAttrCursor = species ? this.getCurrentDexProps(species.speciesId) : 0n;
this.abilityCursor = species ? this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species) : 0;
this.natureCursor = species ? this.scene.gameData.getSpeciesDefaultNature(species) : 0;
+ if (!species && this.scene.ui.getTooltip().visible) {
+ this.scene.ui.hideTooltip();
+ }
+
+ this.pokemonAbilityText.off("pointerover");
+ this.pokemonPassiveText.off("pointerover");
+
const starterAttributes : StarterAttributes | null = species ? {...this.starterPreferences[species.speciesId]} : null;
if (starterAttributes?.nature) {
@@ -2807,17 +2838,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonHatchedIcon.setVisible(true);
this.pokemonHatchedCountText.setVisible(true);
- let currentFriendship = this.scene.gameData.starterData[this.lastSpecies.speciesId].friendship;
- if (!currentFriendship || currentFriendship === undefined) {
- currentFriendship = 0;
- }
-
- const friendshipCap = getStarterValueFriendshipCap(speciesStarters[this.lastSpecies.speciesId]);
+ const { currentFriendship, friendshipCap } = this.getFriendship(this.lastSpecies.speciesId);
const candyCropY = 16 - (16 * (currentFriendship / friendshipCap));
if (this.pokemonCandyDarknessOverlay.visible) {
- this.pokemonCandyDarknessOverlay.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip("", `${currentFriendship}/${friendshipCap}`, true));
- this.pokemonCandyDarknessOverlay.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip());
+ this.pokemonCandyDarknessOverlay.on("pointerover", () => {
+ this.scene.ui.showTooltip("", `${currentFriendship}/${friendshipCap}`, true);
+ this.activeTooltip = "CANDY";
+ });
+ this.pokemonCandyDarknessOverlay.on("pointerout", () => {
+ this.scene.ui.hideTooltip();
+ this.activeTooltip = undefined;
+ });
}
this.pokemonCandyDarknessOverlay.setCrop(0, 0, 16, candyCropY);
@@ -2932,6 +2964,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.abilityCursor = -1;
this.natureCursor = -1;
+ if (this.activeTooltip === "CANDY") {
+ const { currentFriendship, friendshipCap } = this.getFriendship(this.lastSpecies.speciesId);
+ this.scene.ui.editTooltip("", `${currentFriendship}/${friendshipCap}`);
+ }
+
if (species?.forms?.find(f => f.formKey === "female")) {
if (female !== undefined) {
formIndex = female ? 1 : 0;
@@ -3081,8 +3118,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
if (dexEntry.caughtAttr) {
- const ability = this.lastSpecies.getAbility(abilityIndex!); // TODO: is this bang correct?
- this.pokemonAbilityText.setText(allAbilities[ability].name);
+ const ability = allAbilities[this.lastSpecies.getAbility(abilityIndex!)]; // TODO: is this bang correct?
+ this.pokemonAbilityText.setText(ability.name);
const isHidden = abilityIndex === (this.lastSpecies.ability2 ? 2 : 1);
this.pokemonAbilityText.setColor(this.getTextColor(!isHidden ? TextStyle.SUMMARY_ALT : TextStyle.SUMMARY_GOLD));
@@ -3091,6 +3128,21 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const passiveAttr = this.scene.gameData.starterData[species.speciesId].passiveAttr;
const passiveAbility = allAbilities[starterPassiveAbilities[this.lastSpecies.speciesId]];
+ if (this.pokemonAbilityText.visible) {
+ if (this.activeTooltip === "ABILITY") {
+ this.scene.ui.editTooltip(`${ability.name}`, `${ability.description}`);
+ }
+
+ this.pokemonAbilityText.on("pointerover", () => {
+ this.scene.ui.showTooltip(`${ability.name}`, `${ability.description}`, true);
+ this.activeTooltip = "ABILITY";
+ });
+ this.pokemonAbilityText.on("pointerout", () => {
+ this.scene.ui.hideTooltip();
+ this.activeTooltip = undefined;
+ });
+ }
+
if (passiveAbility) {
const isUnlocked = !!(passiveAttr & PassiveAttr.UNLOCKED);
const isEnabled = !!(passiveAttr & PassiveAttr.ENABLED);
@@ -3107,6 +3159,21 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonPassiveText.setAlpha(textAlpha);
this.pokemonPassiveText.setShadowColor(this.getTextColor(textStyle, true));
+ if (this.activeTooltip === "PASSIVE") {
+ this.scene.ui.editTooltip(`${passiveAbility.name}`, `${passiveAbility.description}`);
+ }
+
+ if (this.pokemonPassiveText.visible) {
+ this.pokemonPassiveText.on("pointerover", () => {
+ this.scene.ui.showTooltip(`${passiveAbility.name}`, `${passiveAbility.description}`, true);
+ this.activeTooltip = "PASSIVE";
+ });
+ this.pokemonPassiveText.on("pointerout", () => {
+ this.scene.ui.hideTooltip();
+ this.activeTooltip = undefined;
+ });
+ }
+
const iconPosition = {
x: this.pokemonPassiveText.x + this.pokemonPassiveText.displayWidth + 1,
y: this.pokemonPassiveText.y + this.pokemonPassiveText.displayHeight / 2
diff --git a/src/ui/ui.ts b/src/ui/ui.ts
index 6c988b43043..50fb240aad8 100644
--- a/src/ui/ui.ts
+++ b/src/ui/ui.ts
@@ -244,7 +244,7 @@ export default class UI extends Phaser.GameObjects.Container {
this.tooltipContent = addTextObject(this.scene, 6, 16, "", TextStyle.TOOLTIP_CONTENT);
this.tooltipContent.setName("text-tooltip-content");
- this.tooltipContent.setWordWrapWidth(696);
+ this.tooltipContent.setWordWrapWidth(850);
this.tooltipContainer.add(this.tooltipBg);
this.tooltipContainer.add(this.tooltipTitle);
@@ -289,6 +289,12 @@ export default class UI extends Phaser.GameObjects.Container {
return handler.processInput(button);
}
+ showTextPromise(text: string, callbackDelay: number = 0, prompt: boolean = true, promptDelay?: integer | null): Promise {
+ return new Promise(resolve => {
+ this.showText(text ?? "", null, () => resolve(), callbackDelay, prompt, promptDelay);
+ });
+ }
+
showText(text: string, delay?: integer | null, callback?: Function | null, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null): void {
if (prompt && text.indexOf("$") > -1) {
const messagePages = text.split(/\$/g).map(m => m.trim());
@@ -362,14 +368,13 @@ export default class UI extends Phaser.GameObjects.Container {
return false;
}
+ getTooltip(): { visible: boolean; title: string; content: string } {
+ return { visible: this.tooltipContainer.visible, title: this.tooltipTitle.text, content: this.tooltipContent.text };
+ }
+
showTooltip(title: string, content: string, overlap?: boolean): void {
this.tooltipContainer.setVisible(true);
- this.tooltipTitle.setText(title || "");
- const wrappedContent = this.tooltipContent.runWordWrap(content);
- this.tooltipContent.setText(wrappedContent);
- this.tooltipContent.y = title ? 16 : 4;
- this.tooltipBg.width = Math.min(Math.max(this.tooltipTitle.displayWidth, this.tooltipContent.displayWidth) + 12, 684);
- this.tooltipBg.height = (title ? 31 : 19) + 10.5 * (wrappedContent.split("\n").length - 1);
+ this.editTooltip(title, content);
if (overlap) {
(this.scene as BattleScene).uiContainer.moveAbove(this.tooltipContainer, this);
} else {
@@ -377,6 +382,15 @@ export default class UI extends Phaser.GameObjects.Container {
}
}
+ editTooltip(title: string, content: string): void {
+ this.tooltipTitle.setText(title || "");
+ const wrappedContent = this.tooltipContent.runWordWrap(content);
+ this.tooltipContent.setText(wrappedContent);
+ this.tooltipContent.y = title ? 16 : 4;
+ this.tooltipBg.width = Math.min(Math.max(this.tooltipTitle.displayWidth, this.tooltipContent.displayWidth) + 12, 838);
+ this.tooltipBg.height = (title ? 31 : 19) + 10.5 * (wrappedContent.split("\n").length - 1);
+ }
+
hideTooltip(): void {
this.tooltipContainer.setVisible(false);
this.tooltipTitle.clearTint();
@@ -384,8 +398,12 @@ export default class UI extends Phaser.GameObjects.Container {
update(): void {
if (this.tooltipContainer.visible) {
- const reverse = this.scene.game.input.mousePointer && this.scene.game.input.mousePointer.x >= this.scene.game.canvas.width - this.tooltipBg.width * 6 - 12;
- this.tooltipContainer.setPosition(!reverse ? this.scene.game.input.mousePointer!.x / 6 + 2 : this.scene.game.input.mousePointer!.x / 6 - this.tooltipBg.width - 2, this.scene.game.input.mousePointer!.y / 6 + 2); // TODO: are these bangs correct?
+ const xReverse = this.scene.game.input.mousePointer && this.scene.game.input.mousePointer.x >= this.scene.game.canvas.width - this.tooltipBg.width * 6 - 12;
+ const yReverse = this.scene.game.input.mousePointer && this.scene.game.input.mousePointer.y >= this.scene.game.canvas.height - this.tooltipBg.height * 6 - 12;
+ this.tooltipContainer.setPosition(
+ !xReverse ? this.scene.game.input.mousePointer!.x / 6 + 2 : this.scene.game.input.mousePointer!.x / 6 - this.tooltipBg.width - 2,
+ !yReverse ? this.scene.game.input.mousePointer!.y / 6 + 2 : this.scene.game.input.mousePointer!.y / 6 - this.tooltipBg.height - 2,
+ );
}
}