Skip to content

Commit

Permalink
[Feature] Stop random trainers from spawning near fixed battles (page…
Browse files Browse the repository at this point in the history
…faultgames#2610)

* Stop trainer spawns on evil team and E4 floors

* Thanks Xavion

* change "floors" to "wave" in coment

* at test for not spawning 3 waves within fixed trainer battle

* remove out-commented code

* apply code formatting

* Updated test and make sure isWaveTrainer returns a boolean

* Update comment

---------

Co-authored-by: Felix Staud <[email protected]>
  • Loading branch information
Tempo-anon and flx-sta authored Jul 8, 2024
1 parent 0d9dd1d commit f932768
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/field/arena.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,10 @@ export class Arena {
return weatherMultiplier * terrainMultiplier;
}

/**
* Gets the denominator for the chance for a trainer spawn
* @returns n where 1/n is the chance of a trainer battle
*/
getTrainerChance(): integer {
switch (this.biomeType) {
case Biome.METROPOLIS:
Expand Down
19 changes: 17 additions & 2 deletions src/game-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,22 +107,37 @@ export class GameMode implements GameModeConfig {
}
}

/**
* Determines whether or not to generate a trainer
* @param waveIndex the current floor the player is on (trainer sprites fail to generate on X1 floors)
* @param arena the arena that contains the scene and functions
* @returns true if a trainer should be generated, false otherwise
*/
isWaveTrainer(waveIndex: integer, arena: Arena): boolean {
/**
* Daily spawns trainers on floors 5, 15, 20, 25, 30, 35, 40, and 45
*/
if (this.isDaily) {
return waveIndex % 10 === 5 || (!(waveIndex % 10) && waveIndex > 10 && !this.isWaveFinal(waveIndex));
}
if ((waveIndex % 30) === (arena.scene.offsetGym ? 0 : 20) && !this.isWaveFinal(waveIndex)) {
return true;
} else if (waveIndex % 10 !== 1 && waveIndex % 10) {
/**
* Do not check X1 floors since there's a bug that stops trainer sprites from appearing
* after a X0 full party heal
*/

const trainerChance = arena.getTrainerChance();
let allowTrainerBattle = true;
if (trainerChance) {
const waveBase = Math.floor(waveIndex / 10) * 10;
// Stop generic trainers from spawning in within 3 waves of a trainer battle
for (let w = Math.max(waveIndex - 3, waveBase + 2); w <= Math.min(waveIndex + 3, waveBase + 9); w++) {
if (w === waveIndex) {
continue;
}
if ((w % 30) === (arena.scene.offsetGym ? 0 : 20) || this.isFixedBattle(waveIndex)) {
if ((w % 30) === (arena.scene.offsetGym ? 0 : 20) || this.isFixedBattle(w)) {
allowTrainerBattle = false;
break;
} else if (w < waveIndex) {
Expand All @@ -138,7 +153,7 @@ export class GameMode implements GameModeConfig {
}
}
}
return allowTrainerBattle && trainerChance && !Utils.randSeedInt(trainerChance);
return Boolean(allowTrainerBattle && trainerChance && !Utils.randSeedInt(trainerChance));
}
return false;
}
Expand Down
52 changes: 52 additions & 0 deletions src/test/game-mode.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { GameMode, GameModes, getGameMode } from "#app/game-mode.js";
import {
afterEach,
beforeAll,
beforeEach,
describe,
expect,
it,
vi,
} from "vitest";
import GameManager from "./utils/gameManager";
import * as Utils from "../utils";
describe("game-mode", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
vi.resetAllMocks();
});
beforeEach(() => {
game = new GameManager(phaserGame);
});
describe("classic", () => {
let classicGameMode: GameMode;
beforeEach(() => {
classicGameMode = getGameMode(GameModes.CLASSIC);
});
it("does NOT spawn trainers within 3 waves of fixed battle", () => {
const { arena } = game.scene;
/** set wave 16 to be a fixed trainer fight meaning wave 13-19 don't allow trainer spawns */
vi.spyOn(classicGameMode, "isFixedBattle").mockImplementation(
(n: number) => (n === 16 ? true : false)
);
vi.spyOn(arena, "getTrainerChance").mockReturnValue(1);
vi.spyOn(Utils, "randSeedInt").mockReturnValue(0);
expect(classicGameMode.isWaveTrainer(11, arena)).toBeFalsy();
expect(classicGameMode.isWaveTrainer(12, arena)).toBeTruthy();
expect(classicGameMode.isWaveTrainer(13, arena)).toBeFalsy();
expect(classicGameMode.isWaveTrainer(14, arena)).toBeFalsy();
expect(classicGameMode.isWaveTrainer(15, arena)).toBeFalsy();
// Wave 16 is a fixed trainer battle
expect(classicGameMode.isWaveTrainer(17, arena)).toBeFalsy();
expect(classicGameMode.isWaveTrainer(18, arena)).toBeFalsy();
expect(classicGameMode.isWaveTrainer(19, arena)).toBeFalsy();
});
});
});

0 comments on commit f932768

Please sign in to comment.