feat: preserve solo runs across production restarts

This commit is contained in:
jwinterm
2026-07-22 15:05:49 -04:00
parent b2772ff73b
commit 80d7f35e1f
37 changed files with 1816 additions and 160 deletions
+32
View File
@@ -8,6 +8,7 @@
*/
const Game = require('../src/game/game');
const DungeonGenerator = require('../src/game/dungeon');
function openGame() {
// Default-size dungeon so the digger generates validly; we then override the map and
@@ -23,6 +24,37 @@ function openGame() {
}
describe('Monster collision with multi-step movement', () => {
test('two-room fallback spawns the monster deterministically on a distant passable tile', () => {
const FL = "'1";
const map = Array.from({ length: 7 }, (_, y) => Array.from({ length: 7 }, (_, x) =>
(x === 0 || y === 0 || x === 6 || y === 6) ? '#' : FL));
const dungeon = {
map,
rooms: [],
entrance: [1, 1],
exit: [5, 5],
treasure: [4, 4],
torches: []
};
const generatedFingerprint = DungeonGenerator.layoutFingerprint(dungeon);
const generate = jest.spyOn(DungeonGenerator, 'generate').mockReturnValue(dungeon);
const previousLevels = process.env.DUNGEON_LEVELS;
process.env.DUNGEON_LEVELS = '1';
try {
const game = new Game('fallback-spawn', { id: 1 }, { width: 7, height: 7, cryptoType: 'XMR' });
expect(game.monster.getState()).toMatchObject({ x: 5, y: 4 });
expect(game.dungeon.map[game.monster.y][game.monster.x]).toBe(FL);
expect(game.monster.isAt(game.player.x, game.player.y)).toBe(false);
expect(game.monster.isAt(game.dungeon.exit[0], game.dungeon.exit[1])).toBe(false);
expect(game.monster.isAt(game.dungeon.treasure[0], game.dungeon.treasure[1])).toBe(false);
expect(DungeonGenerator.layoutFingerprint(game.dungeon)).toBe(generatedFingerprint);
} finally {
generate.mockRestore();
if (previousLevels === undefined) delete process.env.DUNGEON_LEVELS;
else process.env.DUNGEON_LEVELS = previousLevels;
}
});
test('2-step monster adjacent to the player catches it (no phasing through)', () => {
const game = openGame();
game.difficultyConfig.monster.movesPerPlayerMove = 2;