mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-19 23:28:32 +02:00
The migration that makes the pack ladder pay off IN the dungeon, not just the tavern.
The SP game now draws via RK (Tiled/ASCII/Iso/3D + unlocked packs) instead of the
legacy ROT display.
- Adapter: sceneFromGameState now consumes the CLIENT state shape (sparse {y:{x:v}}
tile maps, not just server arrays) via maxDims(). Verified + unit-tested.
- Bug fix: RK.sceneFromGameState was never actually exposed (only RK.scene.*), so
matchClient + tavern spectator were silently no-op-ing. Aliased onto RK.
- Bridge (spGameRenderer.js, RK.SPGame): mounts an RK renderer in a dedicated host
inside #game-display, toggles the legacy ROT canvases, zoom-enabled. Game._draw
GameScreen prefers it and FALLS BACK to RenderEngine on any failure, so the live
game can never blank. ROT still draws the splash/win/lose text screens.
- Picker (spRenderPicker.js): homepage mode + pack selector, gated by entitlements
(free = Tiled/Original + ASCII; ladder unlocks Iso/3D/packs), rebuilds on identity.
- index.html loads the render-kit renderers + the bridge/picker.
Bundled with the catalog ladder (migration 028): free Original bare pack, ladder
1/5/10/20/40/50. Deploying makes the free tavern bare (by design) AND the dungeon
render-kit-ed. v1 renders the whole explored level + zoom (player-centered camera is
the next polish). Suite 62/435 green; adapter smoke-verified.
58 lines
2.2 KiB
JavaScript
58 lines
2.2 KiB
JavaScript
// The single-player render-kit migration hinges on sceneFromGameState consuming the CLIENT state
|
|
// shape — sparse {y:{x:v}} tile maps (vs the server's arrays). Guards that adapter + the RK alias.
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const vm = require('vm');
|
|
|
|
function loadSceneKit() {
|
|
const ctx = { console };
|
|
ctx.window = ctx;
|
|
vm.createContext(ctx);
|
|
vm.runInContext(fs.readFileSync(path.join(__dirname, '../html/js/render/sceneModel.js'), 'utf8'), ctx);
|
|
return ctx.RK;
|
|
}
|
|
|
|
const F = "'1"; // primary-floor char
|
|
|
|
describe('SP client-state → Scene adapter', () => {
|
|
const RK = loadSceneKit();
|
|
|
|
test('RK.sceneFromGameState is exposed directly (not only under RK.scene)', () => {
|
|
expect(typeof RK.sceneFromGameState).toBe('function');
|
|
expect(RK.sceneFromGameState).toBe(RK.scene.sceneFromGameState);
|
|
});
|
|
|
|
test('sparse {y:{x:v}} maps yield correct dims, kinds, and entities', () => {
|
|
const state = {
|
|
visibleTiles: { 0: { 0: '#', 1: F, 2: '>' }, 1: { 0: F, 1: F, 2: '#' } },
|
|
exploredTiles: { 0: { 0: '#', 1: F, 2: '>' }, 1: { 0: F, 1: F, 2: '#' } },
|
|
player: { x: 1, y: 1, facing: 'down' }, monster: { x: 0, y: 0 },
|
|
exit: [2, 0], treasure: [1, 1], items: {}, lighting: {}
|
|
};
|
|
const scene = RK.sceneFromGameState(state, { cryptoType: 'WOW' });
|
|
|
|
expect(scene.cols).toBe(3);
|
|
expect(scene.rows).toBe(2);
|
|
expect(scene.isDungeon).toBe(true);
|
|
expect(scene.grid[0]).toEqual(['wall', 'floor', 'exit']);
|
|
expect(scene.grid[1]).toEqual(['floor', 'floor', 'wall']);
|
|
|
|
const kinds = scene.entities.map(e => e.kind);
|
|
expect(kinds).toContain('player');
|
|
expect(kinds).toContain('monster');
|
|
expect(kinds).toContain('feature'); // exit + treasure
|
|
const player = scene.entities.find(e => e.kind === 'player');
|
|
expect(player).toMatchObject({ x: 1, y: 1 });
|
|
});
|
|
|
|
test('unexplored cells render as dark, not floor', () => {
|
|
const state = {
|
|
visibleTiles: { 0: { 0: F } }, // only (0,0) seen
|
|
exploredTiles: { 0: { 0: F } },
|
|
player: { x: 0, y: 0 }, items: {}, lighting: {}
|
|
};
|
|
const scene = RK.sceneFromGameState(state, {});
|
|
expect(scene.grid[0][0]).toBe('floor');
|
|
});
|
|
});
|