Files
wownerogue/test/multiLevel_ultra.test.js
T
jwinterm fad2a695bd Wownerogue
A browser-based roguelike synchronized with crypto block timing. A run is a race
against the next block: reach the exit before the block lands, or the house wins.
The same codebase runs the solo dungeon, the social Tavern, and operator-selected
PvP and race rulesets, with separate free and paid leaderboards.

Self-hostable under the MIT License. See README.md to run it, docs/ARCHITECTURE.md
for the design, and docs/DEPLOY.md to operate an instance.
2026-07-27 08:23:01 -04:00

87 lines
4.2 KiB
JavaScript

// Multi-level descent: a run spans `maxDepth` levels, each a fresh deterministic dungeon, treasure
// only in the vault (final level), and only the final exit escapes. Verifies the mechanic + that
// every level stays reproducible from the one committed seed (provably fair across the descent).
const Game = require('../src/game/game');
const DungeonGenerator = require('../src/game/dungeon');
const { levelSeed } = require('../src/game/provablyFair');
const SAVE = {};
const KEYS = ['DUNGEON_LEVELS', 'CRYPTO_TYPE', 'DIFFICULTY_PRESET', 'NETWORK_TUNING_DISABLED', 'PAYMENTS_ENABLED', 'GAME_MODE'];
beforeEach(() => { KEYS.forEach(k => { SAVE[k] = process.env[k]; delete process.env[k]; }); process.env.DIFFICULTY_PRESET = 'normal'; });
afterEach(() => { KEYS.forEach(k => { if (SAVE[k] === undefined) delete process.env[k]; else process.env[k] = SAVE[k]; }); });
const user = () => ({ id: 0, username: 'test', endGame() {} });
describe('multi-level descent', () => {
test('descends through levels; treasure only in the vault; stays active until the final exit', () => {
process.env.DUNGEON_LEVELS = '3';
const game = new Game('sock', user(), {});
expect(game.maxDepth).toBe(3);
expect(game.depth).toBe(1);
expect(game.gameState).toBe('active');
expect(game.dungeon.treasure).toBeNull(); // level 1/3: no treasure
game._descend();
expect(game.depth).toBe(2);
expect(game.gameState).toBe('active'); // descending is NOT winning
expect(game.dungeon.treasure).toBeNull(); // level 2/3: still no treasure
expect(game.dungeon.entrance).toBeTruthy();
expect(game.dungeon.exit).toBeTruthy();
game._descend();
expect(game.depth).toBe(3);
expect(game.dungeon.treasure).not.toBeNull(); // the vault: treasure present
});
test('every level is reproducible from the committed seed + depth (provably fair)', () => {
process.env.DUNGEON_LEVELS = '3';
process.env.CRYPTO_TYPE = 'WOW';
const game = new Game('sock', user(), {});
const seed = game.gameProof.seed;
// Level 1 == regenerate from the master seed (unchanged single-level behaviour).
const regen1 = DungeonGenerator.regenerateFromSeed(levelSeed(seed, 1), 'WOW');
expect(game.dungeon.map).toEqual(regen1.map);
game._descend(); // level 2
const regen2 = DungeonGenerator.regenerateFromSeed(levelSeed(seed, 2), 'WOW');
expect(game.dungeon.map).toEqual(regen2.map);
// Deeper levels are salted → a different layout from level 1.
expect(regen2.map).not.toEqual(regen1.map);
});
test('single-level default: an untuned network runs one level and its exit escapes', () => {
process.env.CRYPTO_TYPE = 'TESTNET'; // unknown → no level tuning → maxDepth 1
const game = new Game('sock', user(), {});
expect(game.maxDepth).toBe(1);
expect(game.dungeon.treasure).not.toBeNull(); // single level IS the vault
// Walk onto the exit → escaped (won), not descend.
const [ex, ey] = game.dungeon.exit;
game.player.moveTo(ex - 1, ey); // stand next to the exit on a floor cell if possible
// Force the player adjacent by teleporting onto an exit-adjacent floor, then step in. If the
// left neighbour isn't floor, just teleport onto the exit-1 and assert via a direct exit check.
game.player.moveTo(ex, ey); // already on exit: re-derive win via a no-op-ish move
// A fresh move INTO the exit from a neighbour: place on a known floor neighbour of the exit.
const map = game.dungeon.map;
const nbrs = [[ex - 1, ey], [ex + 1, ey], [ex, ey - 1], [ex, ey + 1]];
const floor = nbrs.find(([x, y]) => map[y] && (map[y][x] === "'1" || map[y][x] === "'2"));
if (floor) {
game.player.moveTo(floor[0], floor[1]);
const res = game.movePlayer(ex - floor[0], ey - floor[1]);
expect(res.event).toBe('escaped');
expect(game.gameState).toBe('won');
} else {
// Degenerate layout (exit fully walled): the descent path is still covered by other tests.
expect(game.maxDepth).toBe(1);
}
});
test('DUNGEON_LEVELS env override sets the run length', () => {
process.env.DUNGEON_LEVELS = '5';
const game = new Game('sock', user(), {});
expect(game.maxDepth).toBe(5);
});
});