Compare commits

...

40 Commits

Author SHA1 Message Date
RedstonewolfX 2bc786503c
Merge 9062925cf8 into 605ae9e1c3 2024-09-19 09:03:33 +10:00
RedstonewolfX 9062925cf8 Almost there!! 2024-09-18 16:02:36 -04:00
RedstonewolfX 696a52fe15 Rename test 2024-09-18 14:58:39 -04:00
RedstonewolfX 4a27252231 Delete a skipped test, and skip a nonfunctional one
The test I added a skip statement to is just there as a second possible method of making these last tests
2024-09-18 14:58:24 -04:00
RedstonewolfX 752bd4f017 I might have done it
the tests didn't fail
2024-09-18 14:55:03 -04:00
RedstonewolfX c6c489b289
Merge branch 'beta' into daily-standardization 2024-09-18 14:25:45 -04:00
RedstonewolfX 21315a3664 Push progress so I can sync to beta 2024-09-18 14:25:22 -04:00
RedstonewolfX 029dfa4b3b Update reload.test.ts
Thanks to DayKev again for these fixes
2024-09-18 11:24:08 -04:00
flx-sta 6cfc6f9341
Merge branch 'beta' into daily-standardization 2024-09-17 19:14:00 -07:00
RedstonewolfX 9c391f92bd
Merge pull request #1 from pagefaultgames/main
[Bug] Fix Dire Hit & System Data Conversion Failure (#4282)
2024-09-17 20:24:09 -04:00
NightKev fa6b754dec
Merge branch 'beta' into daily-standardization 2024-09-17 05:38:18 -07:00
MokaStitcher 7ea608fb8a
[Bug] Fix Dire Hit & System Data Conversion Failure (#4282)
Co-authored-by: xsn34kzx <xsn34kzx@gmail.com>
2024-09-16 10:56:55 +01:00
Jannik Tappert 808b15bd94
Merge branch 'beta' into daily-standardization 2024-09-15 22:36:03 +02:00
RedstonewolfX a9b6359e34 Tests still broken
what else is new

god i hate tests

go away eslinter nobody likes you
2024-09-12 21:14:20 -04:00
RedstonewolfX 0114d795a5 Tests
I forgot what desc I wrote this morning but here you go

Still working on this, but will submit now to show my work
2024-09-12 19:35:04 -04:00
RedstonewolfX 8fdce2405c
Merge branch 'pagefaultgames:main' into daily-standardization 2024-09-12 10:46:23 -04:00
RedstonewolfX 64861447cb
Merge branch 'beta' into daily-standardization 2024-09-12 10:44:46 -04:00
Frederico Santos 801b0a66f7 Readded vouchers to original weights 2024-09-12 01:13:22 +01:00
Frederico Santos 103c87ec3b Undo egg skip event 2024-09-12 01:09:44 +01:00
NightKev 6373a86011 Fix tests 2024-09-01 01:13:37 -07:00
NightKev 2a2ef7d50c
Merge branch 'beta' into daily-standardization 2024-08-31 17:41:27 -07:00
RedstonewolfX b71ddda191 (Temporary) Implement startBattle fix 2024-08-27 18:52:07 -04:00
RedstonewolfX 49036f9522 More testing attempts
please help me
2024-08-27 18:28:27 -04:00
RedstonewolfX 3e65888ff1 Update overrides
Relocated the "isUnlocked" function to gameData since it requires a reference to it in order to run

Removed unnecessary override that disables unlocked items (and its associated overridesHelper statement)
2024-08-27 17:54:09 -04:00
RedstonewolfX d7263b6677
Update src/modifier/modifier-type.ts
Remove unused code I forgot to delete

Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com>
2024-08-27 14:09:48 -04:00
RedstonewolfX 3095ecebf8
Update src/system/unlockables.ts
Fixing my silly typo

Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com>
2024-08-27 14:09:26 -04:00
RedstonewolfX f5b49d812d Write shop test and add new overrides
Adds new overrides that allow you to force content to be locked or unlocked
These overrides were also added to the OverridesHelper to make them available to tests

Adds a new check function for content unlocks, which returns `true` if it is overrode to be unlocked, `false` if it is overrode to be locked, and the unlock data mapped to a Boolean otherwise

All existing checks (other than the ones that involve actually unlocking things) for unlockables have been changed to use this

Added a pair of new exporting booleans, specifically for my test, that check if Eviolite or Mini Black Hole are in the loot table

please forgive my jank
2024-08-27 10:56:26 -04:00
RedstonewolfX e9b06bdf1b Try (and fail) to write tests
Wrote a check (that might not even work) to make sure the player starts with a Map in the Daily Run

Attempted to write a check to see if Eviolite spawns in Daily Run, but can't figure out how to look for the right thing in the loot table

Attempted to write a check for shiny luck, but don't know how to manually set luck
2024-08-26 14:40:53 -04:00
RedstonewolfX 6225a020e0 Remove unused import 2024-08-26 13:13:29 -04:00
RedstonewolfX 48fbc571cd Update modifier-type.ts 2024-08-26 13:09:57 -04:00
RedstonewolfX 9baeac8d40
Update src/modifier/modifier-type.ts
Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
2024-08-26 12:05:44 -04:00
RedstonewolfX 1b558cd945
Review Suggestions: Reformatting
Small edits to formatting as requested by flx

Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
2024-08-26 12:04:53 -04:00
RedstonewolfX ae33a46945 Fix formatting
== my bebanished
2024-08-26 09:48:53 -04:00
RedstonewolfX e4c62e55cf Disable Eviolite in Daily Runs
Disables Eviolite spawning in Daily Run mode.
2024-08-26 01:52:19 -04:00
RedstonewolfX 590f1a6833 Give free map in daily
Adds a Map to the player's pool of starting items for Daily Runs.
2024-08-26 01:50:20 -04:00
RedstonewolfX 02e9273f97 Disable Luck in Daily Runs
If the Game Mode is Daily Run, the player's Luck is set to 0, and the Luck value is hidden.
2024-08-26 01:47:07 -04:00
RedstonewolfX f8478aa79b
Merge branch 'pagefaultgames:beta' into beta 2024-08-26 01:39:10 -04:00
RedstonewolfX d1e14850ef
Fix parenthases order
oops

Co-authored-by: Leo Kim <47556641+KimJeongSun@users.noreply.github.com>
2024-08-21 16:36:43 -04:00
RedstonewolfX 103ad807ee
Fix potential divide by zero error
Thank you to KimJeongSun for bringing this up

Co-authored-by: Leo Kim <47556641+KimJeongSun@users.noreply.github.com>
2024-08-21 06:57:59 -04:00
RedstonewolfX 0be82b32dd Improve scroll bar
Remaking these changes on the beta branch since you're supposed to do it for the PR checklist
2024-08-18 12:52:06 -04:00
14 changed files with 278 additions and 29 deletions

View File

@ -1674,7 +1674,12 @@ export default class BattleScene extends SceneBase {
this.scoreText.setVisible(this.gameMode.isDaily);
}
updateAndShowText(duration: integer): void {
/**
* Displays the current luck value.
* @param duration The time for this label to fade in, if it is not already visible.
* @param isDaily If true, hides the label. (This is done because Luck does not apply in Daily Mode anymore)
*/
updateAndShowText(duration: number, isDaily?: boolean): void {
const labels = [ this.luckLabelText, this.luckText ];
labels.forEach(t => t.setAlpha(0));
const luckValue = getPartyLuckValue(this.getParty());
@ -1685,12 +1690,16 @@ export default class BattleScene extends SceneBase {
this.luckText.setTint(0xffef5c, 0x47ff69, 0x6b6bff, 0xff6969);
}
this.luckLabelText.setX((this.game.canvas.width / 6) - 2 - (this.luckText.displayWidth + 2));
if (isDaily) {
// Hide luck label
labels.forEach(t => t.setVisible(false));
}
this.tweens.add({
targets: labels,
duration: duration,
alpha: 1,
onComplete: () => {
labels.forEach(t => t.setVisible(true));
labels.forEach(t => t.setVisible(!isDaily));
}
});
}

View File

@ -1699,7 +1699,8 @@ const modifierPool: ModifierPool = {
new WeightedModifierType(modifierTypes.FORM_CHANGE_ITEM, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 50), 4) * 6, 24),
new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)),
new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => {
if (!party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.unlocks[Unlockables.EVIOLITE]) {
const { gameMode, gameData } = party[0].scene;
if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) {
return party.some(p => ((p.getSpeciesForm(true).speciesId in pokemonEvolutions) || (p.isFusion() && (p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))) && !p.getHeldItems().some(i => i instanceof Modifiers.EvolutionStatBoosterModifier)) ? 10 : 0;
}
return 0;
@ -1777,7 +1778,7 @@ const modifierPool: ModifierPool = {
new WeightedModifierType(modifierTypes.MULTI_LENS, 18),
new WeightedModifierType(modifierTypes.VOUCHER_PREMIUM, (party: Pokemon[], rerollCount: integer) => !party[0].scene.gameMode.isDaily && !party[0].scene.gameMode.isEndless && !party[0].scene.gameMode.isSplicedOnly ? Math.max(5 - rerollCount * 2, 0) : 0, 5),
new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => !party[0].scene.gameMode.isSplicedOnly && party.filter(p => !p.fusionSpecies).length > 1 ? 24 : 0, 24),
new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => (!party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) ? 1 : 0, 1),
new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => (party[0].scene.gameMode.isDaily || (!party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.isUnlocked(Unlockables.MINI_BLACK_HOLE))) ? 1 : 0, 1),
].map(m => {
m.setTier(ModifierTier.MASTER); return m;
})
@ -1969,9 +1970,13 @@ export function getModifierPoolForType(poolType: ModifierPoolType): ModifierPool
}
const tierWeights = [ 768 / 1024, 195 / 1024, 48 / 1024, 12 / 1024, 1 / 1024 ];
export const itemPoolChecks: Map<ModifierTypeKeys, boolean> = new Map();
export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: ModifierPoolType, rerollCount: integer = 0) {
const pool = getModifierPoolForType(poolType);
itemPoolChecks.forEach((v, k) => {
itemPoolChecks.set(k, false);
});
const ignoredIndexes = {};
const modifierTableData = {};
@ -2008,6 +2013,9 @@ export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: Mod
ignoredIndexes[t].push(i++);
return total;
}
if (itemPoolChecks.has(modifierType.modifierType.id as ModifierTypeKeys)) {
itemPoolChecks.set(modifierType.modifierType.id as ModifierTypeKeys, true);
}
thresholds.set(total, i++);
return total;
}, 0);
@ -2410,8 +2418,16 @@ export class ModifierTypeOption {
}
}
/**
* Calculates the team's luck value.
* @param party The player's party.
* @returns A value between 0 and 14, or 0 if the player is in Daily Run mode.
*/
export function getPartyLuckValue(party: Pokemon[]): integer {
const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() : 0)
if (party[0].scene.gameMode.isDaily) {
return 0;
}
const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? (p.scene.gameMode.isDaily ? 0 : p.getLuck()) : 0)
.reduce((total: integer, value: integer) => total += value, 0), 0, 14);
return luck || 0;
}

View File

@ -12,6 +12,7 @@ import { type PokeballCounts } from "./battle-scene";
import { Gender } from "./data/gender";
import { Variant } from "./data/variant";
import { type ModifierOverride } from "./modifier/modifier-type";
import { Unlockables } from "./system/unlockables";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
@ -70,8 +71,10 @@ class DefaultOverrides {
[PokeballType.MASTER_BALL]: 0,
},
};
/** Forces an item to be UNLOCKED */
readonly ITEM_UNLOCK_OVERRIDE: Unlockables[] = [];
/** Set to `true` to show all tutorials */
readonly BYPASS_TUTORIAL_SKIP: boolean = false;
readonly BYPASS_TUTORIAL_SKIP_OVERRIDE: boolean = false;
// ----------------
// PLAYER OVERRIDES

View File

@ -76,7 +76,8 @@ export class TitlePhase extends Phase {
this.scene.ui.clearText();
this.end();
};
if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) {
const { gameData } = this.scene;
if (gameData.isUnlocked(Unlockables.ENDLESS_MODE)) {
const options: OptionSelectItem[] = [
{
label: GameMode.getModeName(GameModes.CLASSIC),
@ -100,7 +101,7 @@ export class TitlePhase extends Phase {
}
}
];
if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) {
if (gameData.isUnlocked(Unlockables.SPLICED_ENDLESS_MODE)) {
options.push({
label: GameMode.getModeName(GameModes.SPLICED_ENDLESS),
handler: () => {
@ -220,6 +221,7 @@ export class TitlePhase extends Phase {
const modifiers: Modifier[] = Array(3).fill(null).map(() => modifierTypes.EXP_SHARE().withIdFromFunc(modifierTypes.EXP_SHARE).newModifier())
.concat(Array(3).fill(null).map(() => modifierTypes.GOLDEN_EXP_CHARM().withIdFromFunc(modifierTypes.GOLDEN_EXP_CHARM).newModifier()))
.concat([modifierTypes.MAP().withIdFromFunc(modifierTypes.MAP).newModifier()])
.concat(getDailyRunStarterModifiers(party))
.filter((m) => m !== null);

View File

@ -372,6 +372,18 @@ export class GameData {
};
}
/**
* Checks if an `Unlockable` has been unlocked.
* @param unlockable The Unlockable to check
* @returns `true` if the player has unlocked this `Unlockable` or an override has enabled it
*/
public isUnlocked(unlockable: Unlockables): boolean {
if (Overrides.ITEM_UNLOCK_OVERRIDE.includes(unlockable)) {
return true;
}
return this.unlocks[unlockable];
}
public saveSystem(): Promise<boolean> {
return new Promise<boolean>(resolve => {
this.scene.ui.savingIcon.show();

View File

@ -22,15 +22,25 @@ export function applySessionDataPatches(data: SessionSaveData) {
} else if (m.className === "PokemonResetNegativeStatStageModifier") {
m.className = "ResetNegativeStatStageModifier";
} else if (m.className === "TempBattleStatBoosterModifier") {
m.className = "TempStatStageBoosterModifier";
m.typeId = "TEMP_STAT_STAGE_BOOSTER";
// Dire Hit no longer a part of the TempBattleStatBoosterModifierTypeGenerator
if (m.typeId !== "DIRE_HIT") {
m.className = "TempStatStageBoosterModifier";
m.typeId = "TEMP_STAT_STAGE_BOOSTER";
// Migration from TempBattleStat to Stat
const newStat = m.typePregenArgs[0] + 1;
m.typePregenArgs[0] = newStat;
// Migration from TempBattleStat to Stat
const newStat = m.typePregenArgs[0] + 1;
m.typePregenArgs[0] = newStat;
// From [ stat, battlesLeft ] to [ stat, maxBattles, battleCount ]
m.args = [ newStat, 5, m.args[1] ];
} else {
m.className = "TempCritBoosterModifier";
m.typePregenArgs = [];
// From [ stat, battlesLeft ] to [ maxBattles, battleCount ]
m.args = [ 5, m.args[1] ];
}
// From [ stat, battlesLeft ] to [ stat, maxBattles, battleCount ]
m.args = [ newStat, 5, m.args[1] ];
} else if (m.className === "DoubleBattleChanceBoosterModifier" && m.args.length === 1) {
let maxBattles: number;
switch (m.typeId) {
@ -73,7 +83,7 @@ export function applySystemDataPatches(data: SystemSaveData) {
case "1.0.3":
case "1.0.4":
// --- LEGACY PATCHES ---
if (data.starterData) {
if (data.starterData && data.dexData) {
// Migrate ability starter data if empty for caught species
Object.keys(data.starterData).forEach(sd => {
if (data.dexData[sd]?.caughtAttr && (data.starterData[sd] && !data.starterData[sd].abilityAttr)) {
@ -104,12 +114,14 @@ export function applySystemDataPatches(data: SystemSaveData) {
// --- PATCHES ---
// Fix Starter Data
for (const starterId of defaultStarterSpecies) {
if (data.starterData[starterId]?.abilityAttr) {
data.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1;
}
if (data.dexData[starterId]?.caughtAttr) {
data.dexData[starterId].caughtAttr |= DexAttr.FEMALE;
if (data.starterData && data.dexData) {
for (const starterId of defaultStarterSpecies) {
if (data.starterData[starterId]?.abilityAttr) {
data.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1;
}
if (data.dexData[starterId]?.caughtAttr) {
data.dexData[starterId].caughtAttr |= DexAttr.FEMALE;
}
}
}
}

View File

@ -1,5 +1,15 @@
import { MapModifier } from "#app/modifier/modifier";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import GameManager from "./utils/gameManager";
import { Moves } from "#app/enums/moves";
import { getPartyLuckValue, itemPoolChecks } from "#app/modifier/modifier-type";
import { Biome } from "#app/enums/biome";
import { BattleEndPhase } from "#app/phases/battle-end-phase";
import { Mode } from "#app/ui/ui";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
import Overrides from "#app/overrides";
//const TIMEOUT = 20 * 1000;
describe("Daily Mode", () => {
let phaserGame: Phaser.Game;
@ -28,5 +38,97 @@ describe("Daily Mode", () => {
expect(pkm.level).toBe(20);
expect(pkm.moveset.length).toBeGreaterThan(0);
});
expect(game.scene.getModifiers(MapModifier).length).toBeGreaterThan(0);
});
});
//*
// Need to figure out how to properly start a battle
// Need to fix eviolite - test keeps insisting it is not in loot table, even though Mini Black Hole (which is using the exact same condition) is
describe("Shop modifications", async () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.startingWave(9)
.startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather
.battleType("single")
.shinyLevel(true)
.startingLevel(100) // Avoid levelling up
.enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents()
.disableTrainerWaves()
.moveset([Moves.KOWTOW_CLEAVE])
.enemyMoveset(Moves.SPLASH);
itemPoolChecks.set("EVIOLITE", false);
itemPoolChecks.set("MINI_BLACK_HOLE", false);
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
itemPoolChecks.clear();
});
it("should not have Eviolite and Mini Black Hole available in Classic if not unlocked", async () => {
await game.classicMode.runToSummon();
expect(itemPoolChecks.get("EVIOLITE")).toBeDefined();
expect(itemPoolChecks.get("EVIOLITE")).toBeFalsy();
expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeDefined();
expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeFalsy();
game.move.select(Moves.KOWTOW_CLEAVE);
await game.phaseInterceptor.to("DamagePhase");
await game.doKillOpponents();
await game.phaseInterceptor.to(BattleEndPhase);
game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler);
expect(itemPoolChecks.get("EVIOLITE")).toBeDefined();
expect(itemPoolChecks.get("EVIOLITE")).toBeFalsy();
expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeDefined();
expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeFalsy();
});
});
it("should have Eviolite and Mini Black Hole available in Daily", async () => {
await game.dailyMode.runToSummon();
expect(itemPoolChecks.get("EVIOLITE")).toBeDefined();
expect(itemPoolChecks.get("EVIOLITE")).toBeFalsy();
expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeDefined();
expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeFalsy();
game.move.select(Moves.KOWTOW_CLEAVE);
await game.phaseInterceptor.to("DamagePhase");
await game.doKillOpponents();
await game.phaseInterceptor.to(BattleEndPhase);
game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler);
expect(itemPoolChecks.get("EVIOLITE")).toBeDefined();
expect(itemPoolChecks.get("EVIOLITE")).toBeTruthy();
expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeDefined();
expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeTruthy();
});
});
it("should apply luck in Classic Mode", async () => {
await game.classicMode.runToSummon();
const party = game.scene.getParty();
expect(Overrides.SHINY_OVERRIDE).toBeTruthy();
expect(party[0]).toBeDefined();
expect(party[0].getLuck()).toBeGreaterThan(0);
expect(getPartyLuckValue(party)).toBeGreaterThan(0);
});
it("should not apply luck in Daily Run", async () => {
await game.dailyMode.runToSummon();
const party = game.scene.getParty();
expect(party[0]).toBeDefined();
expect(party[0].getLuck()).toBeGreaterThan(0);
expect(getPartyLuckValue(party)).toBe(0);
});
});
//*/

View File

@ -2,6 +2,7 @@ import { GameMode, GameModes, getGameMode } from "#app/game-mode";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as Utils from "../utils";
import GameManager from "./utils/gameManager";
describe("game-mode", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
@ -12,6 +13,7 @@ describe("game-mode", () => {
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
vi.clearAllMocks();
vi.resetAllMocks();
});
beforeEach(() => {

View File

@ -1,9 +1,13 @@
import { Species } from "#app/enums/species";
import { GameModes } from "#app/game-mode";
import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler";
import { Mode } from "#app/ui/ui";
import { Biome } from "#enums/biome";
import { Button } from "#enums/buttons";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { MockClock } from "#test/utils/mocks/mockClock";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { Moves } from "#app/enums/moves";
import { Biome } from "#app/enums/biome";
describe("Reload", () => {
let phaserGame: Phaser.Game;
@ -50,6 +54,13 @@ describe("Reload", () => {
game.move.select(Moves.KOWTOW_CLEAVE);
await game.phaseInterceptor.to("DamagePhase");
await game.doKillOpponents();
game.onNextPrompt("SelectBiomePhase", Mode.OPTION_SELECT, () => {
(game.scene.time as MockClock).overrideDelay = null;
const optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler;
game.scene.time.delayedCall(1010, () => optionSelectUiHandler.processInput(Button.ACTION));
game.endPhase();
(game.scene.time as MockClock).overrideDelay = 1;
});
await game.toNextWave();
expect(game.phaseInterceptor.log).toContain("NewBiomeEncounterPhase");

View File

@ -2,6 +2,7 @@ import { BerryType } from "#app/enums/berry-type";
import { Button } from "#app/enums/buttons";
import { Moves } from "#app/enums/moves";
import { Species } from "#app/enums/species";
import { itemPoolChecks } from "#app/modifier/modifier-type";
import { BattleEndPhase } from "#app/phases/battle-end-phase";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
@ -94,3 +95,47 @@ describe("UI - Transfer Items", () => {
await game.phaseInterceptor.to(SelectModifierPhase);
}, 20000);
});
describe.skip("Backup Test", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(async () => {
game = new GameManager(phaserGame);
game.override
.battleType("single")
.startingLevel(100)
.startingWave(1)
.startingHeldItems([
{ name: "BERRY", count: 1, type: BerryType.SITRUS },
{ name: "BERRY", count: 2, type: BerryType.APICOT },
{ name: "BERRY", count: 2, type: BerryType.LUM },
])
.moveset([Moves.DRAGON_CLAW])
.enemySpecies(Species.MAGIKARP)
.enemyMoveset([Moves.SPLASH]);
itemPoolChecks.set("EVIOLITE", false);
itemPoolChecks.set("MINI_BLACK_HOLE", false);
});
it("should run", async () => {
await game.classicMode.startBattle([Species.RAYQUAZA, Species.RAYQUAZA, Species.RAYQUAZA]);
game.move.select(Moves.DRAGON_CLAW);
game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler);
});
await game.phaseInterceptor.to(BattleEndPhase);
});
});

View File

@ -10,6 +10,8 @@ import { ModifierOverride } from "#app/modifier/modifier-type";
import Overrides from "#app/overrides";
import { vi } from "vitest";
import { GameManagerHelper } from "./gameManagerHelper";
import { Unlockables } from "#app/system/unlockables";
import { Variant } from "#app/data/variant";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
@ -300,6 +302,17 @@ export class OverridesHelper extends GameManagerHelper {
return this;
}
/**
* Gives the player access to an Unlockable.
* @param unlockable The Unlockable to enable.
* @returns this
*/
enableUnlockable(unlockable: Unlockables[]) {
vi.spyOn(Overrides, "ITEM_UNLOCK_OVERRIDE", "get").mockReturnValue(unlockable);
this.log("Temporarily unlocked the following content: ", unlockable);
return this;
}
/**
* Override the items rolled at the end of a battle
* @param items the items to be rolled
@ -311,6 +324,25 @@ export class OverridesHelper extends GameManagerHelper {
return this;
}
/**
* Override player shininess
* @param shininess Whether the player's Pokemon should be shiny.
*/
shinyLevel(shininess: boolean): this {
vi.spyOn(Overrides, "SHINY_OVERRIDE", "get").mockReturnValue(shininess);
this.log(`Set player Pokemon as ${shininess ? "" : "not "}shiny!`);
return this;
}
/**
* Override player shiny variant
* @param variant The player's shiny variant.
*/
variantLevel(variant: Variant): this {
vi.spyOn(Overrides, "VARIANT_OVERRIDE", "get").mockReturnValue(variant);
this.log(`Set player Pokemon's shiny variant to ${variant}!`);
return this;
}
/**
* Override the enemy (Pokemon) to have the given amount of health segments
* @param healthSegments the number of segments to give

View File

@ -43,6 +43,7 @@ import { UnavailablePhase } from "#app/phases/unavailable-phase";
import { VictoryPhase } from "#app/phases/victory-phase";
import { PartyHealPhase } from "#app/phases/party-heal-phase";
import UI, { Mode } from "#app/ui/ui";
import { SelectBiomePhase } from "#app/phases/select-biome-phase";
import {
MysteryEncounterBattlePhase,
MysteryEncounterOptionSelectedPhase,
@ -122,6 +123,7 @@ export default class PhaseInterceptor {
[EndEvolutionPhase, this.startPhase],
[LevelCapPhase, this.startPhase],
[AttemptRunPhase, this.startPhase],
[SelectBiomePhase, this.startPhase],
[MysteryEncounterPhase, this.startPhase],
[MysteryEncounterOptionSelectedPhase, this.startPhase],
[MysteryEncounterBattlePhase, this.startPhase],
@ -346,7 +348,8 @@ export default class PhaseInterceptor {
console.log("setMode", `${Mode[mode]} (=${mode})`, args);
const ret = this.originalSetMode.apply(instance, [mode, ...args]);
if (!this.phases[currentPhase.constructor.name]) {
throw new Error(`missing ${currentPhase.constructor.name} in phaseInterceptor PHASES list`);
throw new Error(`missing ${currentPhase.constructor.name} in phaseInterceptor PHASES list --- Add it to PHASES inside of /test/utils/phaseInterceptor.ts`);
}
if (this.phases[currentPhase.constructor.name].endBySetMode) {
this.inProgress?.callback();

View File

@ -74,11 +74,11 @@ const tutorialHandlers = {
* @returns a promise with result `true` if the tutorial was run and finished, `false` otherwise
*/
export async function handleTutorial(scene: BattleScene, tutorial: Tutorial): Promise<boolean> {
if (!scene.enableTutorials && !Overrides.BYPASS_TUTORIAL_SKIP) {
if (!scene.enableTutorials && !Overrides.BYPASS_TUTORIAL_SKIP_OVERRIDE) {
return false;
}
if (scene.gameData.getTutorialFlags()[tutorial] && !Overrides.BYPASS_TUTORIAL_SKIP) {
if (scene.gameData.getTutorialFlags()[tutorial] && !Overrides.BYPASS_TUTORIAL_SKIP_OVERRIDE) {
return false;
}

View File

@ -230,7 +230,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
/* Multiplies the appearance duration by the speed parameter so that it is always constant, and avoids "flashbangs" at game speed x5 */
this.scene.showShopOverlay(750 * this.scene.gameSpeed);
this.scene.updateAndShowText(750);
this.scene.updateAndShowText(750, this.scene.gameMode.isDaily);
this.scene.updateBiomeWaveText();
this.scene.updateMoneyText();