mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-28 02:28:34 +01:00
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.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
const scene = require('../html/js/render/sceneModel');
|
||||
|
||||
describe('sceneFromTavern (render kit adapter)', () => {
|
||||
test('maps layout chars to tile kinds and occupants to entities', () => {
|
||||
const appearance = {
|
||||
avatar: 'char-ranger',
|
||||
tint: 'teal',
|
||||
equipment: { body: 'mail', head: 'hood', shield: 'round', weapon: 'bow' }
|
||||
};
|
||||
const state = {
|
||||
cols: 3, rows: 2,
|
||||
layout: ['#=@', 'T..'],
|
||||
occupants: [{ id: 'a', x: 2, y: 0, avatar: 'green', appearance, facing: 'left', name: 'Al' }]
|
||||
};
|
||||
const s = scene.sceneFromTavern(state, 'a');
|
||||
expect(s.cols).toBe(3);
|
||||
expect(s.rows).toBe(2);
|
||||
expect(s.grid[0]).toEqual(['wall', 'bar', 'floor']); // '@' is walkable floor
|
||||
expect(s.grid[1]).toEqual(['table', 'floor', 'floor']);
|
||||
expect(s.entities).toHaveLength(1);
|
||||
expect(s.entities[0]).toMatchObject({ id: 'a', x: 2, y: 0, kind: 'avatar', avatar: 'char-ranger', appearance, facing: 'left', label: 'Al', you: true });
|
||||
expect(s.entities[0].color).toBe(scene.AVATAR_COLORS.default);
|
||||
});
|
||||
|
||||
test('you-flag is false for other occupants and unknown avatars fall back to default', () => {
|
||||
const s = scene.sceneFromTavern(
|
||||
{ cols: 1, rows: 1, layout: ['.'], occupants: [{ id: 'b', x: 0, y: 0, avatar: 'zzz' }] },
|
||||
'a'
|
||||
);
|
||||
expect(s.entities[0].you).toBe(false);
|
||||
expect(s.entities[0].color).toBe(scene.AVATAR_COLORS.default);
|
||||
});
|
||||
|
||||
test('unknown / out-of-legend characters are treated as walls (solid)', () => {
|
||||
const s = scene.sceneFromTavern({ cols: 2, rows: 1, layout: ['?~'], occupants: [] });
|
||||
expect(s.grid[0]).toEqual(['wall', 'wall']);
|
||||
});
|
||||
|
||||
test('uses walkability when a designed room has no ASCII layout', () => {
|
||||
const s = scene.sceneFromTavern({
|
||||
cols: 3,
|
||||
rows: 2,
|
||||
layout: null,
|
||||
walkable: [
|
||||
[true, false, true],
|
||||
[false, true, true]
|
||||
],
|
||||
occupants: []
|
||||
});
|
||||
expect(s.grid).toEqual([
|
||||
['floor', 'wall', 'floor'],
|
||||
['wall', 'floor', 'floor']
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sceneFromGameState (dungeon adapter)', () => {
|
||||
const api = require('../html/js/render/sceneModel.js');
|
||||
|
||||
test('converts visible tiles, entities, and lighting into a dungeon Scene', () => {
|
||||
const scene = api.sceneFromGameState({
|
||||
visibleTiles: [['#', "'1", '>'], ["'1", "'1", "'1"]],
|
||||
exploredTiles: [['#', "'1", '>'], ["'1", "'1", "'1"]],
|
||||
lighting: [[0, 0.5, 0], [0, 0, 0]],
|
||||
entrance: [0, 1],
|
||||
exit: [2, 0],
|
||||
treasure: null,
|
||||
player: { x: 1, y: 1, facing: 'down' },
|
||||
monster: { x: 2, y: 1 },
|
||||
items: {},
|
||||
isSpectating: true
|
||||
});
|
||||
|
||||
expect(scene.isDungeon).toBe(true);
|
||||
expect(scene.cols).toBe(3);
|
||||
expect(scene.rows).toBe(2);
|
||||
expect(scene.grid[0]).toEqual(['wall', 'floor', 'exit']);
|
||||
expect(scene.grid[1]).toEqual(['floor', 'floor', 'floor']);
|
||||
expect(scene.lightGrid[0][1]).toBeCloseTo(0.5, 1);
|
||||
// Entities: entrance, exit, monster, player (no treasure)
|
||||
const kinds = scene.entities.map(e => e.kind);
|
||||
expect(kinds).toContain('feature');
|
||||
expect(kinds).toContain('monster');
|
||||
expect(kinds).toContain('player');
|
||||
// Player entity should be marked as not-you for spectators
|
||||
const player = scene.entities.find(e => e.kind === 'player');
|
||||
expect(player.you).toBe(false);
|
||||
});
|
||||
|
||||
test('treasure entity appears when treasure position is set', () => {
|
||||
const scene = api.sceneFromGameState({
|
||||
visibleTiles: [["'1", '$']],
|
||||
entrance: [0, 0],
|
||||
exit: [1, 0],
|
||||
treasure: [1, 0],
|
||||
player: { x: 0, y: 0 },
|
||||
monster: null,
|
||||
items: {},
|
||||
isSpectating: false
|
||||
});
|
||||
const treasure = scene.entities.find(e => e.id === 'treasure');
|
||||
expect(treasure).toBeTruthy();
|
||||
expect(treasure.char).toContain('$');
|
||||
});
|
||||
|
||||
test('unexplored tiles become dark', () => {
|
||||
const scene = api.sceneFromGameState({
|
||||
visibleTiles: [["'1", undefined]],
|
||||
exploredTiles: [["'1", undefined]],
|
||||
lighting: [[0, 0]],
|
||||
player: { x: 0, y: 0 },
|
||||
monster: null,
|
||||
items: {},
|
||||
isSpectating: true
|
||||
});
|
||||
expect(scene.grid[0][1]).toBe('dark');
|
||||
expect(scene.lightGrid[0][1]).toBe(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user