Added utility functions

This commit is contained in:
Bertie690 2024-12-30 18:37:46 -05:00
parent 8dcccd8ceb
commit 268131a4f6
6 changed files with 125 additions and 13 deletions

View File

@ -1823,7 +1823,9 @@ export default class BattleScene extends SceneBase {
}
getMaxExpLevel(ignoreLevelCap?: boolean): integer {
if (ignoreLevelCap) {
if (Overrides.LEVEL_CAP_OVERRIDE > 0) {
return Overrides.LEVEL_CAP_OVERRIDE;
} else if (ignoreLevelCap || Overrides.LEVEL_CAP_OVERRIDE < 0) {
return Number.MAX_SAFE_INTEGER;
}
const waveIndex = Math.ceil((this.currentBattle?.waveIndex || 1) / 10) * 10;

View File

@ -2378,8 +2378,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.battleInfo.toggleFlyout(visible);
}
addExp(exp: integer) {
const maxExpLevel = this.scene.getMaxExpLevel();
/**
* Adds experience to this PlayerPokemon, subject to wave based level caps.
* @param exp The amount of experience to add
* @param ignoreLevelCap Whether to ignore level caps when adding experience (defaults to false)
*/
addExp(exp: integer, ignoreLevelCap?: boolean) {
const maxExpLevel = this.scene.getMaxExpLevel(ignoreLevelCap);
const initialExp = this.exp;
this.exp += exp;
while (this.level < maxExpLevel && this.exp >= getLevelTotalExp(this.level + 1, this.species.growthRate)) {

View File

@ -62,8 +62,11 @@ class DefaultOverrides {
readonly STARTING_WAVE_OVERRIDE: number = 0;
readonly STARTING_BIOME_OVERRIDE: Biome = Biome.TOWN;
readonly ARENA_TINT_OVERRIDE: TimeOfDay | null = null;
/** Multiplies XP gained by this value including 0. Set to null to ignore the override */
/** Multiplies XP gained by this value including 0. Set to null to ignore the override. */
readonly XP_MULTIPLIER_OVERRIDE: number | null = null;
/** Sets the level cap to this number during experience gain calculations. Set to null/0 to disable override & use normal wave-based level caps,
or any negative number to set it to 9 quadrillion (effectively disabling it). */
readonly LEVEL_CAP_OVERRIDE: number = 0;
readonly NEVER_CRIT_OVERRIDE: boolean = false;
/** default 1000 */
readonly STARTING_MONEY_OVERRIDE: number = 0;

View File

@ -4,6 +4,8 @@ import GameManager from "#test/utils/gameManager";
import { Species } from "#enums/species";
import { Moves } from "#enums/moves";
import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { Mode } from "#app/ui/ui";
import { Button } from "#app/enums/buttons";
describe("Learn Move Phase", () => {
let phaserGame: Phaser.Game;
@ -26,7 +28,7 @@ describe("Learn Move Phase", () => {
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 ]);
await game.classicMode.startBattle([ Species.BULBASAUR ]);
const pokemon = game.scene.getPlayerPokemon()!;
const newMovePos = pokemon?.getMoveset().length;
game.move.select(Moves.SPLASH);
@ -36,12 +38,89 @@ describe("Learn Move Phase", () => {
const levelReq = levelMove[0];
const levelMoveId = levelMove[1];
expect(pokemon.level).toBeGreaterThanOrEqual(levelReq);
expect(pokemon?.getMoveset()[newMovePos]?.moveId).toBe(levelMoveId);
expect(pokemon?.moveset[newMovePos]?.moveId).toBe(levelMoveId);
});
it("If a pokemon has 4 move slots filled, the chosen move will be deleted and replaced", async () => {
await game.classicMode.startBattle([ Species.GALAR_MR_MIME ]); // many level up moves
const mrMime = game.scene.getPlayerPokemon()!;
const prevMoveset = [ Moves.SPLASH, Moves.ABSORB, Moves.ACID, Moves.VINE_WHIP ];
const moveSlotNum = 3;
game.move.changeMoveset(mrMime, prevMoveset);
game.move.select(Moves.SPLASH);
await game.doKillOpponents();
// queue up inputs to confirm dialog boxes
game.onNextPrompt("LearnMovePhase", Mode.CONFIRM, () => {
game.scene.ui.processInput(Button.ACTION);
});
game.onNextPrompt("LearnMovePhase", Mode.SUMMARY, () => {
for (let x = 0; x < moveSlotNum; x++) {
game.scene.ui.processInput(Button.DOWN);
}
game.scene.ui.processInput(Button.ACTION);
});
await game.phaseInterceptor.to(LearnMovePhase);
const levelMove = mrMime.getLevelMoves(5)[0];
const levelReq = levelMove[0];
const levelMoveId = levelMove[1];
expect(mrMime.level).toBeGreaterThanOrEqual(levelReq);
// Check each of mr mime's moveslots to make sure the changed move (and ONLY the changed move) is different
mrMime.getMoveset().forEach((move, index) => {
const expectedMove: Moves = (index === moveSlotNum ? levelMoveId : prevMoveset[index]);
expect(move?.moveId).toBe(expectedMove);
});
});
it("selecting the newly deleted move will reject it and keep old moveset", async () => {
await game.classicMode.startBattle([ Species.GALAR_MR_MIME ]); // many level up moves
const mrMime = game.scene.getPlayerPokemon()!;
const prevMoveset = [ Moves.SPLASH, Moves.ABSORB, Moves.ACID, Moves.VINE_WHIP ];
game.move.changeMoveset(mrMime, [ Moves.SPLASH, Moves.ABSORB, Moves.ACID, Moves.VINE_WHIP ]);
game.move.select(Moves.SPLASH);
await game.doKillOpponents();
// queue up inputs to confirm dialog boxes
game.onNextPrompt("LearnMovePhase", Mode.CONFIRM, () => {
game.scene.ui.processInput(Button.ACTION);
});
game.onNextPrompt("LearnMovePhase", Mode.SUMMARY, () => {
for (let x = 0; x < 4; x++) {
game.scene.ui.processInput(Button.DOWN); // moves down 4 times to the 5th move slot
}
game.scene.ui.processInput(Button.ACTION);
});
game.onNextPrompt("LearnMovePhase", Mode.CONFIRM, () => {
game.scene.ui.processInput(Button.ACTION);
});
await game.phaseInterceptor.to(LearnMovePhase);
const levelReq = mrMime.getLevelMoves(5)[0][0];
expect(mrMime.level).toBeGreaterThanOrEqual(levelReq);
expect(mrMime.getMoveset()).toEqual(prevMoveset);
});
it("macro should work", async () => {
await game.classicMode.startBattle([ Species.GALAR_MR_MIME ]); // many level up moves
const mrMime = game.scene.getPlayerPokemon()!;
game.move.changeMoveset(mrMime, [ Moves.SPLASH, Moves.ABSORB, Moves.ACID, Moves.VINE_WHIP ]);
await game.move.learnMove(Moves.SACRED_FIRE, 0, 3);
expect(mrMime.getMoveset()).toEqual([ Moves.SPLASH, Moves.ABSORB, Moves.SACRED_FIRE, Moves.VINE_WHIP ]);
});
it("macro should work V2", async () => {
await game.classicMode.startBattle([ Species.GALAR_MR_MIME ]); // many level up moves
const mrMime = game.scene.getPlayerPokemon()!;
game.move.changeMoveset(mrMime, [ Moves.SPLASH, Moves.ABSORB, Moves.ACID, Moves.VINE_WHIP ]);
await game.move.learnMove(Moves.SACRED_FIRE, 0, 4);
expect(mrMime.getMoveset()).toEqual([ Moves.SPLASH, Moves.ABSORB, Moves.ACID, Moves.VINE_WHIP ]);
});
/**
* 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.
*/
});

View File

@ -119,8 +119,10 @@ export class MoveHelper extends GameManagerHelper {
this.game.scene.ui.processInput(Button.DOWN);
}
this.game.scene.ui.processInput(Button.ACTION);
if (slot === 4) { // confirm 1 last time to give up on learning move
this.game.scene.ui.processInput(Button.ACTION);
if (slot === 4) { // hit confirm 1 last time to give up on learning move
this.game.onNextPrompt("LearnMovePhase", Mode.CONFIRM, () => {
this.game.scene.ui.processInput(Button.ACTION);
});
}
});
}

View File

@ -69,6 +69,27 @@ export class OverridesHelper extends GameManagerHelper {
return this;
}
/**
* Override the wave level cap
* @param cap the level cap value to set; 0 uses normal level caps and negative values
* disable it completely
* @returns `this`
*/
public levelCap(cap: number): this {
vi.spyOn(Overrides, "LEVEL_CAP_OVERRIDE", "get").mockReturnValue(cap);
let capStr: string;
switch (true) {
case (cap > 0):
capStr = "Level cap set to " + cap.toString() + "!";
case (cap === 0):
capStr = "Level cap reset to default value for wave.";
case (cap < 0):
capStr = "Level cap disabled!";
}
this.log(capStr!); // cap is guaranteed to be either more, less or equal to 0; if not I will scream
return this;
}
/**
* Override the player (pokemon) starting held items
* @param items the items to hold