From d5df5dbd12d22646db7d7c0885a95aaa229a8fce Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sun, 31 May 2026 14:31:10 -0400 Subject: [PATCH] refactor: remove dead move handler + stale test scratch files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 4.2 (partial): Delete the dead handlePlayerMove socket handler and its orphaned playerMoveTimestamps map + cleanup. It was never registered (the live move path is MovementManager.handleMove) but, if ever wired, it double-stepped the monster and bypassed the escape/collision event handling — a loaded footgun. No behaviour change. 4.5: Delete 14 stale non-jest files from test/ (5 scratch .js scripts + 9 .html debug pages) — they contain no jest constructs and are referenced nowhere. test/ is now exclusively the 21 real jest suites. Full suite: 21 suites / 155 tests. --- docs/REMEDIATION_PLAN.md | 6 +- src/network/socketHandlers.js | 96 +----------- test/debug_client_lighting.html | 163 -------------------- test/debug_game_updates.html | 186 ----------------------- test/debug_lighting.html | 174 --------------------- test/dungeon.js | 92 ------------ test/game.js | 172 --------------------- test/monster.js | 86 ----------- test/player.js | 48 ------ test/test_address_detection.js | 109 -------------- test/test_fixes.html | 79 ---------- test/test_lighting.html | 132 ---------------- test/test_lighting_verification.html | 216 --------------------------- test/test_movement.html | 0 test/test_movement.js | 0 test/test_tile_system.js | 117 --------------- 16 files changed, 4 insertions(+), 1672 deletions(-) delete mode 100644 test/debug_client_lighting.html delete mode 100644 test/debug_game_updates.html delete mode 100644 test/debug_lighting.html delete mode 100644 test/dungeon.js delete mode 100644 test/game.js delete mode 100644 test/monster.js delete mode 100644 test/player.js delete mode 100644 test/test_address_detection.js delete mode 100644 test/test_fixes.html delete mode 100644 test/test_lighting.html delete mode 100644 test/test_lighting_verification.html delete mode 100644 test/test_movement.html delete mode 100644 test/test_movement.js delete mode 100644 test/test_tile_system.js diff --git a/docs/REMEDIATION_PLAN.md b/docs/REMEDIATION_PLAN.md index cfd67a7..12a60fd 100644 --- a/docs/REMEDIATION_PLAN.md +++ b/docs/REMEDIATION_PLAN.md @@ -43,11 +43,11 @@ Key: `S` ≤ half day · `M` ~1–3 days · `L` ~1 week+ · 🔴 launch-blocker - [x] **3.3 S — Multi-step monster collision fix.** ✅ Collision is now checked after **each** monster sub-step, not just after the loop. With `movesPerPlayerMove > 1` (casino's 1.5× speed) the monster could previously step onto the player's tile and off again between checks, phasing through and missing the catch (player-favorable, eroded the house edge). New `monsterCollision.test.js`. ## Phase 4 — De-spaghetti / structural cleanup (🟡) -- [ ] **4.1 L — Break up `index.js`** into `app.js`, `routes/{public,user,admin,auth}.js`, `views/verify.js`, `server.js`. -- [ ] **4.2 M — Kill duplicates.** Merge `rpcService`+`rpccalls`; delete dead `handlePlayerMove` (`socketHandlers.js:244`); unify `payout_address` widths; remove `QueryValidator` theater (`databaseManager.js:21`). +- [x] **4.1 L — Break up `index.js` (substantially).** ✅ Extracted the verify HTML → `views/verifyPage.js` (now HTML-escaped), all 15 admin endpoints → `routes/admin.js`, and the 3 smirk endpoints → `routes/auth.js`, each as DI factories with smoke tests. **index.js: 2029 → 882 lines (-57%).** _Remaining user/public routes left inline — they're interleaved with bootstrap and have no route tests, so further slicing is diminishing-return/higher-risk; the structure + pattern are established for later._ +- [~] **4.2 M — Kill duplicates (partial).** ✅ Deleted the dead `handlePlayerMove` handler (a footgun that double-stepped the monster + bypassed escape/collision detection) and its orphaned `playerMoveTimestamps` map/cleanup — the live path is `MovementManager`. _Remaining (lower-value/higher-effort): merge `rpcService`+`rpccalls`, unify `payout_address` column widths, address the `QueryValidator` false-positive — deferred._ - [ ] **4.3 M — Config as immutable snapshots;** stop mutating `process.env` (`gameModeManager.js:189`). - [ ] **4.4 M — Frontend de-spaghetti.** Shared `escapeHtml`/`dom.js`; kill double-declares + dead `_appendMessage`; explicit init ordering; upgrade/drop jQuery; gate broadcast logging (`broadcastManager.js:33`). -- [ ] **4.5 S — Delete stale `test/` scratch files.** +- [x] **4.5 S — Delete stale `test/` scratch files.** ✅ Removed 14 non-jest leftovers (5 `.js` scratch scripts + 9 `.html` debug pages) — confirmed they contained no jest constructs and were referenced nowhere. `test/` is now exclusively the 21 real jest suites. ## Phase 5 — Test & ops overhaul (🟠 — the launch gate) - [ ] **5.1 L — Real money-path tests** against Postgres (no stubbed `withTransaction`): under/overpay, double-confirm, batch dispatch, credit race, retry idempotency; property-test `money/atomic.js`. diff --git a/src/network/socketHandlers.js b/src/network/socketHandlers.js index fbf90bb..4549bf9 100644 --- a/src/network/socketHandlers.js +++ b/src/network/socketHandlers.js @@ -187,8 +187,7 @@ class SocketHandlers { cleanupTimeoutMs: 300000 // 5 minutes to reconnect before game is lost }); - // Movement manager abstraction with memory cleanup - this.playerMoveTimestamps = new Map(); + // Movement manager abstraction (owns its own move-cooldown state) this.movementManager = new MovementManager({ activeGames: this.activeGames, io: this.io, @@ -206,32 +205,6 @@ class SocketHandlers { * Register memory cleanup functions to prevent memory leaks */ _registerMemoryCleanups() { - // Cleanup player move timestamps (keep for 5 minutes) - this.memoryManager.registerCleanup( - 'playerMoveTimestamps', - () => { - const now = Date.now(); - const maxAge = 300000; // 5 minutes - let cleaned = 0; - const toDelete = []; - - for (const [socketId, timestamp] of this.playerMoveTimestamps.entries()) { - if (now - timestamp > maxAge) { - toDelete.push(socketId); - } - } - - for (const socketId of toDelete) { - if (this.playerMoveTimestamps.delete(socketId)) { - cleaned++; - } - } - - return cleaned; - }, - 300000 - ); - // (mempool-notification dedup + TTL eviction lives in PaymentHandlers, which owns // the actual dedup set; the old SocketHandlers copy here was unused and is removed.) @@ -245,69 +218,6 @@ class SocketHandlers { } } - /** - * Handle player movement input from client. - * Expects moveData: { direction: 'up'|'down'|'left'|'right' } - */ - handlePlayerMove(socket, moveData) { - try { - if (!moveData || typeof moveData.direction !== 'string') return; - const now = Date.now(); - const last = this.playerMoveTimestamps.get(socket.id) || 0; - if (now - last < this.MOVE_COOLDOWN) return; // rate limit moves - this.playerMoveTimestamps.set(socket.id, now); - - const game = this.activeGames.get(socket.id); - if (!game) return; // not in a game - - // Translate direction to delta - const dir = moveData.direction; - let dx = 0, dy = 0; - switch (dir) { - case 'up': dy = -1; break; - case 'down': dy = 1; break; - case 'left': dx = -1; break; - case 'right': dx = 1; break; - default: return; // ignore unknown - } - - // Attempt move via game API (assuming game has movePlayer(dx,dy)) - if (typeof game.movePlayer === 'function') { - game.movePlayer(dx, dy); - } else if (game.player) { - // Fallback direct mutation (legacy) with simple bounds check - const newX = game.player.x + dx; - const newY = game.player.y + dy; - if (newX >= 0 && newY >= 0) { - game.player.x = newX; - game.player.y = newY; - } - } - - if (typeof game.moveMonster === 'function') { - game.moveMonster(); - } - - // Build updated state - let state; - if (typeof game.getState === 'function') { - state = game.getState(); - } else { - state = { player: game.player }; - } - - // Add block height context - if (this.debugManager && typeof this.debugManager.getCurrentBlockHeight === 'function') { - state.blockHeight = this.debugManager.getCurrentBlockHeight(); - } - - this.io.to(socket.id).emit('game_update', state); - - } catch (err) { - console.error('handlePlayerMove error:', err); - } - } - /** * Called after a successful player move (before update is emitted) via MovementManager postMoveHook. * Handles monster chasing logic and immediate game over if monster catches player. @@ -816,9 +726,6 @@ class SocketHandlers { // addressToUser entries must persist so checkPaymentStatus() can query the wallet // RPC after session resumption. They get cleaned up when payments are confirmed or expired. - // Clean up movement timestamps - this.playerMoveTimestamps.delete(socketId); - // Preserve queue entry for users with session/payment // The queue entry's socketId will be updated on reconnection if (this.queueManager && typeof this.queueManager.removePlayer === 'function') { @@ -1211,7 +1118,6 @@ class SocketHandlers { // Clear remaining data structures this.activeGames.clear(); - this.playerMoveTimestamps.clear(); if (this.debugManager.CONSOLE_LOGGING) { console.log('✅ SocketHandlers shutdown complete'); diff --git a/test/debug_client_lighting.html b/test/debug_client_lighting.html deleted file mode 100644 index 61c2add..0000000 --- a/test/debug_client_lighting.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - Debug Client Lighting - - - -

Client-Side Lighting Debug

- -
-

Game State Lighting Data

-
No data received yet...
-
- -
-

Lighting Visualization

-
-
- -
-

Console Log

-
-
- - - - - - diff --git a/test/debug_game_updates.html b/test/debug_game_updates.html deleted file mode 100644 index edeb27c..0000000 --- a/test/debug_game_updates.html +++ /dev/null @@ -1,186 +0,0 @@ - - - - Game Update Debugging - - - -

Game Update Debugging

- -
- - - - -
- -
Not connected
-
- - - - - diff --git a/test/debug_lighting.html b/test/debug_lighting.html deleted file mode 100644 index 575ac14..0000000 --- a/test/debug_lighting.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - Lighting Debug - Wowngeon - - - -

Lighting System Debug

- -
-

Alpha Value Tests

-

Testing different alpha values to see how they render:

-
-
- -
-

Game Display

-
- - -
- -
-

Live Lighting Data

-
No data captured yet
-
- -
-

Console Log

-
-
- - - - - - - - - - - - - - - - diff --git a/test/dungeon.js b/test/dungeon.js deleted file mode 100644 index 493af29..0000000 --- a/test/dungeon.js +++ /dev/null @@ -1,92 +0,0 @@ -const ROT = require('./rot.js'); - -/** - * Dungeon generation utilities - */ -class DungeonGenerator { - static generate(width, height) { - // Create dungeon using ROT.js Map.Digger - const digger = new ROT.Map.Digger(width, height, { - roomWidth: [3, 9], - roomHeight: [3, 7], - corridorLength: [2, 6], - dugPercentage: 0.2 - }); - - // Initialize the empty map with walls (1) - const map = Array(height).fill().map(() => Array(width).fill(1)); - - // Fill in floors (0) using digger's callback - digger.create((x, y, value) => { - // value: 0 = floor, 1 = wall - map[y][x] = value; - }); - - // Get rooms that were created - const rooms = digger.getRooms(); - - // Place entrance in the first room - const entranceRoom = rooms[0]; - const entranceCenter = entranceRoom.getCenter(); - const entrance = [entranceCenter[0], entranceCenter[1]]; - - // Place exit in the last room - const exitRoom = rooms[rooms.length - 1]; - const exitCenter = exitRoom.getCenter(); - const exit = [exitCenter[0], exitCenter[1]]; - - // Place treasure in a middle room (not first or last) - let treasureRoom; - if (rooms.length > 2) { - treasureRoom = rooms[Math.floor(rooms.length / 2)]; - } else { - // Fallback if we have fewer than 3 rooms - treasureRoom = rooms[0]; - } - const treasureCenter = treasureRoom.getCenter(); - // Place treasure slightly off center to make it more interesting - const treasure = [ - treasureCenter[0] + Math.floor(Math.random() * 3) - 1, - treasureCenter[1] + Math.floor(Math.random() * 3) - 1 - ]; - - // Ensure the treasure is on a floor tile - if (map[treasure[1]][treasure[0]] !== 0) { - treasure[0] = treasureCenter[0]; - treasure[1] = treasureCenter[1]; - } - - return { - map: map, - rooms: rooms, - entrance: entrance, - exit: exit, - treasure: treasure - }; - } - - static getRandomRoomCenter(rooms, excludeFirst = false, excludeLast = false) { - if (!rooms || rooms.length === 0) return null; - - let availableRooms = [...rooms]; - if (excludeFirst && availableRooms.length > 1) { - availableRooms = availableRooms.slice(1); - } - if (excludeLast && availableRooms.length > 1) { - availableRooms = availableRooms.slice(0, -1); - } - - const randomRoom = availableRooms[Math.floor(Math.random() * availableRooms.length)]; - return randomRoom.getCenter(); - } - - static isFloorTile(map, x, y) { - return map[y] && map[y][x] === 0; - } - - static isWallTile(map, x, y) { - return map[y] && map[y][x] === 1; - } -} - -module.exports = DungeonGenerator; diff --git a/test/game.js b/test/game.js deleted file mode 100644 index 6b5ec43..0000000 --- a/test/game.js +++ /dev/null @@ -1,172 +0,0 @@ -const ROT = require('./rot.js'); -const Player = require('./player.js'); -const Monster = require('./monster.js'); -const DungeonGenerator = require('./dungeon.js'); - -class Game { - constructor(socketId, mapWidth, mapHeight) { - this.socketId = socketId; - this.width = mapWidth || 25; // Reduced default size to match client display - this.height = mapHeight || 19; // Reduced default size to match client display - this.gameState = 'waiting'; // waiting, active, won, lost - this.startBlock = null; - this.dungeon = null; - this.player = new Player(); - this.monster = new Monster(); - this.fee = 0; // Amount player paid - this.visibleTiles = {}; // Will store visible tiles - this.fov = null; // FOV calculator - this.generateDungeon(); - } - - generateDungeon() { - this.dungeon = DungeonGenerator.generate(this.width, this.height); - - if (this.dungeon.entrance) { - this.player.moveTo(this.dungeon.entrance[0], this.dungeon.entrance[1]); - } - - // Place monster far from entrance - if (this.dungeon.rooms && this.dungeon.rooms.length > 2) { - const monsterRoom = this.dungeon.rooms[Math.floor(this.dungeon.rooms.length * 0.7)]; - const center = monsterRoom.getCenter(); - this.monster.moveTo(center[0], center[1]); - } - - // Initialize FOV calculator - this.fov = new ROT.FOV.PreciseShadowcasting( - (x, y) => { - // Return true if the tile is transparent (can see through it) - return this.dungeon.map[y] && this.dungeon.map[y][x] === 0; - } - ); - - // Calculate initial FOV - this.updateFOV(); - - // Set game state to active - this.gameState = 'active'; - } - - updateFOV() { - // Reset visible tiles - this.visibleTiles = {}; - - // Calculate new visible tiles - this.fov.compute(this.player.x, this.player.y, 10, (x, y, r, visibility) => { // Added r and visibility params - if (visibility > 0) { // Only add if tile is actually visible - if (!this.visibleTiles[y]) { - this.visibleTiles[y] = {}; - } - // Store the actual tile type (0 for floor, 1 for wall) from the dungeon map - if (this.dungeon && this.dungeon.map && this.dungeon.map[y] && this.dungeon.map[y][x] !== undefined) { - this.visibleTiles[y][x] = this.dungeon.map[y][x]; - } else { - // Should not happen if FOV is within map bounds, but as a fallback: - // this.visibleTiles[y][x] = 1; // Default to wall if outside known map - } - } - }); - // console.log("FOV updated. Player:", this.player.x, this.player.y, "Visible tiles count:", Object.keys(this.visibleTiles).reduce((acc, k) => acc + Object.keys(this.visibleTiles[k]).length, 0)); - } - - movePlayer(dx, dy) { - const newX = this.player.x + dx; - const newY = this.player.y + dy; - - // Debug logging for movement validation - console.log(`[DEBUG] Move attempt: from (${this.player.x},${this.player.y}) to (${newX},${newY}) with dx=${dx},dy=${dy}`); - console.log(`[DEBUG] Map bounds: width=${this.width}, height=${this.height}`); - console.log(`[DEBUG] Dungeon exists: ${!!this.dungeon}`); - if (this.dungeon && this.dungeon.map) { - console.log(`[DEBUG] Map row ${newY} exists: ${!!this.dungeon.map[newY]}`); - if (this.dungeon.map[newY]) { - console.log(`[DEBUG] Map cell [${newY}][${newX}] value: ${this.dungeon.map[newY][newX]} (0=floor, 1=wall)`); - } - } - - // Check if the move is valid (not into a wall and within map bounds) - if (this.dungeon && - this.dungeon.map[newY] && - this.dungeon.map[newY][newX] !== undefined && - this.dungeon.map[newY][newX] === 0) { // 0 is floor - - this.player.moveTo(newX, newY); - console.log(`Player moved to ${newX},${newY} in game for socket ${this.socketId}`); - - // Update FOV after moving - this.updateFOV(); - - // Check for game events like finding treasure or exit - if (this.dungeon.exit && this.player.isAt(this.dungeon.exit[0], this.dungeon.exit[1])) { - // Handle win condition (e.g., escaped) - this.gameState = 'won'; - return { status: 'moved', event: 'escaped', player: this.player.getState(), visibleTiles: this.visibleTiles }; - } - if (this.dungeon.treasure && this.player.isAt(this.dungeon.treasure[0], this.dungeon.treasure[1]) && !this.player.hasTreasure) { - this.player.hasTreasure = true; - // Remove treasure from dungeon so it won't be sent in future updates - this.dungeon.treasure = null; - console.log(`Player ${this.socketId} collected treasure! hasTreasure: ${this.player.hasTreasure}`); - return { status: 'moved', event: 'treasure_found', player: this.player.getState(), visibleTiles: this.visibleTiles }; - } - - return { status: 'moved', player: this.player.getState(), visibleTiles: this.visibleTiles }; - } - - - console.log(`Player move to ${newX},${newY} for socket ${this.socketId} is invalid (wall or out of bounds).`); - - // Debug: Show map around player - console.log(`[DEBUG] Map around player position:`); - for (let y = this.player.y - 2; y <= this.player.y + 2; y++) { - let row = ''; - for (let x = this.player.x - 2; x <= this.player.x + 2; x++) { - if (x === this.player.x && y === this.player.y) { - row += '@'; // Player position - } else if (x === newX && y === newY) { - row += 'X'; // Attempted move position - } else if (this.dungeon && this.dungeon.map[y] && this.dungeon.map[y][x] !== undefined) { - row += this.dungeon.map[y][x] === 0 ? '.' : '#'; - } else { - row += '?'; // Out of bounds or undefined - } - } - console.log(`[DEBUG] Y=${y}: ${row}`); - } - - return { status: 'invalid' }; - } - - moveMonster() { - this.monster.moveTowardPlayer(this.player, this.dungeon); - } - - // Update the getState() method to include all entities with relative positions - getState() { - const state = { - gameState: this.gameState, - player: this.player.getState(), // Use Player's getState method - monster: this.monster ? this.monster.getState() : null, // Use Monster's getState method - visibleTiles: { ...this.visibleTiles }, // Send a copy of visible tiles - entrance: this.dungeon ? this.dungeon.entrance : null, - exit: this.dungeon ? this.dungeon.exit : null, - treasure: this.dungeon ? this.dungeon.treasure : null, - }; - - // Debug logging to verify entity data - console.log("🎮 getState() sending entities - Monster:", state.monster, "Entrance:", state.entrance, "Exit:", state.exit, "Treasure:", state.treasure); - - return state; - } -} - -// Check if monster killed player -function checkMonsterKill(player, monster) { - // Use Monster's hasCaughtPlayer method - const monsterInstance = new Monster(monster.x, monster.y); - return monsterInstance.hasCaughtPlayer(player); -} - -module.exports = Game; -module.exports.checkMonsterKill = checkMonsterKill; \ No newline at end of file diff --git a/test/monster.js b/test/monster.js deleted file mode 100644 index 9010378..0000000 --- a/test/monster.js +++ /dev/null @@ -1,86 +0,0 @@ -const ROT = require('./rot.js'); - -/** - * Monster class - Manages monster state and AI - */ -class Monster { - constructor(x = 0, y = 0) { - this.x = x; - this.y = y; - } - - // Move monster to new position - moveTo(x, y) { - this.x = x; - this.y = y; - } - - // Check if monster is at given coordinates - isAt(x, y) { - return this.x === x && this.y === y; - } - - // Simple AI to move toward player - moveTowardPlayer(player, dungeon) { - if (!player || !dungeon || !dungeon.map) return; - - const dx = Math.sign(player.x - this.x); - const dy = Math.sign(player.y - this.y); - - // Try horizontal move first - if (dx !== 0) { - const newX = this.x + dx; - if (dungeon.map[this.y] && dungeon.map[this.y][newX] === 0) { - this.x = newX; - return; - } - } - - // Try vertical move - if (dy !== 0) { - const newY = this.y + dy; - if (dungeon.map[newY] && dungeon.map[newY][this.x] === 0) { - this.y = newY; - return; - } - } - - // Try random direction if direct path is blocked - const dirs = [[0,1],[1,0],[0,-1],[-1,0]]; - const shuffledDirs = ROT.RNG.shuffle(dirs.slice()); - - for (const [dx, dy] of shuffledDirs) { - const nx = this.x + dx; - const ny = this.y + dy; - if (dungeon.map[ny] && dungeon.map[ny][nx] === 0) { - this.x = nx; - this.y = ny; - break; - } - } - } - - // Check if monster has caught the player - hasCaughtPlayer(player) { - if (!player) return false; - - // Check for direct overlap - monster on same tile as player - return this.x === player.x && this.y === player.y; - } - - // Get monster state as object - getState() { - return { - x: this.x, - y: this.y - }; - } - - // Set monster state from object - setState(state) { - if (state.x !== undefined) this.x = state.x; - if (state.y !== undefined) this.y = state.y; - } -} - -module.exports = Monster; diff --git a/test/player.js b/test/player.js deleted file mode 100644 index 73d7346..0000000 --- a/test/player.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Player class - Manages player state and actions - */ -class Player { - constructor(x = 0, y = 0) { - this.x = x; - this.y = y; - this.hasKey = false; - this.hasTreasure = false; - } - - // Move player to new position - moveTo(x, y) { - this.x = x; - this.y = y; - } - - // Check if player is at given coordinates - isAt(x, y) { - return this.x === x && this.y === y; - } - - // Reset player state - reset() { - this.hasKey = false; - this.hasTreasure = false; - } - - // Get player state as object - getState() { - return { - x: this.x, - y: this.y, - hasKey: this.hasKey, - hasTreasure: this.hasTreasure - }; - } - - // Set player state from object - setState(state) { - if (state.x !== undefined) this.x = state.x; - if (state.y !== undefined) this.y = state.y; - if (state.hasKey !== undefined) this.hasKey = state.hasKey; - if (state.hasTreasure !== undefined) this.hasTreasure = state.hasTreasure; - } -} - -module.exports = Player; diff --git a/test/test_address_detection.js b/test/test_address_detection.js deleted file mode 100644 index baa47bf..0000000 --- a/test/test_address_detection.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Test script for XMR/WOW address detection system - */ - -// Test the regex patterns used in socketHandlers.js -function testAddressDetection() { - console.log('🧪 Testing XMR/WOW Address Detection System\n'); - - // XMR mainnet addresses start with 4, 8, A, or B and are 95 characters - // WOW addresses start with W and are 97 characters - const xmrRegex = /\b[48AB][1-9A-HJ-NP-Za-km-z]{94}\b/; - const wowRegex = /\bW[1-9A-HJ-NP-Za-km-z]{96}\b/; - - function detectXMRAddress(message) { - const xmrMatch = message.match(xmrRegex); - const wowMatch = message.match(wowRegex); - - if (xmrMatch) { - return { address: xmrMatch[0], type: 'XMR' }; - } - if (wowMatch) { - return { address: wowMatch[0], type: 'WOW' }; - } - - return null; - } - - // Test cases with real address formats - const testCases = [ - { - name: 'Valid XMR Address (starts with 8)', - message: 'Here is my XMR address: 8Bqez9dvqY9bw3CgwMC9X1c8MX5KuRgKbiXRWg2F9UtYNYLevqjJXbQW4qYHUM1JF1792hhWYJLUufSUn9GvSC4G6wjMiRL', - expected: { address: '8Bqez9dvqY9bw3CgwMC9X1c8MX5KuRgKbiXRWg2F9UtYNYLevqjJXbQW4qYHUM1JF1792hhWYJLUufSUn9GvSC4G6wjMiRL', type: 'XMR' } - }, - { - name: 'Valid XMR Address (starts with 4)', - message: 'Send to: 44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A', - expected: { address: '44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A', type: 'XMR' } - }, - { - name: 'Valid WOW Address (starts with WW)', - message: 'My WOW address is: WW35SBkcZDNGRkLroGNg4tKuJtyV8JhA95CREopLPCwrj9LgRU5pSnDb4D5BHKo9oBAZSjHXWnDwCJ4mRL5F6iJ81vSmNBuRC', - expected: { address: 'WW35SBkcZDNGRkLroGNg4tKuJtyV8JhA95CREopLPCwrj9LgRU5pSnDb4D5BHKo9oBAZSjHXWnDwCJ4mRL5F6iJ81vSmNBuRC', type: 'WOW' } - }, - { - name: 'Valid WOW Address (starts with Wo)', - message: 'please send to Wo3MWeKwtA918DU4c69hVSNgejdWFCRCuWjShRY66mJkU2Hv58eygJWDJS1MNa2Ge5M1WjUkGHuLqHkweDxwZZU42d16v94mP thanks', - expected: { address: 'Wo3MWeKwtA918DU4c69hVSNgejdWFCRCuWjShRY66mJkU2Hv58eygJWDJS1MNa2Ge5M1WjUkGHuLqHkweDxwZZU42d16v94mP', type: 'WOW' } - }, - { - name: 'Invalid XMR (too short)', - message: '4AdUndXHHZ6cfufTMvppY6JwXNouMBzSkbLYfpAV5Usx3skxNgYeYTRJ5zA4NJD9QhKCciJBcH9qPq8FgZKR8U8n', - expected: null - }, - { - name: 'Invalid XMR (wrong prefix)', - message: '3AdUndXHHZ6cfufTMvppY6JwXNouMBzSkbLYfpAV5Usx3skxNgYeYTRJ5zA4NJD9QhKCciJBcH9qPq8FgZKR8U8nZZZZ', - expected: null - }, - { - name: 'Invalid WOW (wrong prefix)', - message: 'XW35SBkcZDNGRkLroGNg4tKuJtyV8JhA95CREopLPCwrj9LgRU5pSnDb4D5BHKo9oBAZSjHXWnDwCJ4mRL5F6iJ81vSmNBuRC', - expected: null - }, - { - name: 'No address in message', - message: 'hello world this is just a chat message', - expected: null - }, - { - name: 'Partial address in message', - message: 'my address starts with 4AdUnd but I wont share the full thing', - expected: null - } - ]; - - let passed = 0; - let failed = 0; - - testCases.forEach((testCase, index) => { - console.log(`Test ${index + 1}: ${testCase.name}`); - console.log(`Message: "${testCase.message}"`); - - const result = detectXMRAddress(testCase.message); - - if (JSON.stringify(result) === JSON.stringify(testCase.expected)) { - console.log(`✅ PASS - Detected: ${result ? `${result.type} ${result.address}` : 'null'}`); - passed++; - } else { - console.log(`❌ FAIL - Expected: ${JSON.stringify(testCase.expected)}`); - console.log(`❌ FAIL - Got: ${JSON.stringify(result)}`); - failed++; - } - console.log(''); - }); - - console.log(`📊 Test Results: ${passed} passed, ${failed} failed`); - - if (failed === 0) { - console.log('🎉 All tests passed! Address detection system is working correctly.'); - } else { - console.log('⚠️ Some tests failed. Please review the regex patterns.'); - } -} - -// Run the tests -testAddressDetection(); - -module.exports = { testAddressDetection }; diff --git a/test/test_fixes.html b/test/test_fixes.html deleted file mode 100644 index b02e5f8..0000000 --- a/test/test_fixes.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - Wowngeon Fixes Test - - - -

🎮 Wowngeon Fixes Verification

- -
-

🔧 Fix #1: START Button Visibility

-

Issue: START button was invisible (cut off in game display)

-

Fix: Moved to HTML status area with proper styling

-

Test: Check if START button is visible in the status area below

-
- -
-

⏱️ Fix #2: Auto-Entry Death Timing

-

Issue: Players died after 2+ blocks instead of 1 block in debug mode

-

Fix: Set currentUser.blockRec = currentBlock + 1 for consistent timing

-

Test: Use "enter" command and check death timing logs in console

-
- -

🎯 Live Game Test

- - -
-

📋 Test Instructions:

-
    -
  1. START Button Test: Look for the green "🎮 START GAME" button in the status area (should be visible)
  2. -
  3. Death Timing Test: Click START or type "enter" in chat, then check browser console for timing logs
  4. -
  5. Expected Logs: Should see "🕒 AUTO-ENTRY: Player starts on block X, will die after block X+2"
  6. -
-
- - - - diff --git a/test/test_lighting.html b/test/test_lighting.html deleted file mode 100644 index 5d6f45c..0000000 --- a/test/test_lighting.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - Torch Lighting Test - - - -

Torch Lighting System Test

-

Open browser console to see detailed lighting data flow test.

-
- - - - diff --git a/test/test_lighting_verification.html b/test/test_lighting_verification.html deleted file mode 100644 index 915ae7d..0000000 --- a/test/test_lighting_verification.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - Torch Lighting Verification Test - - - -

🔥 Torch Lighting System Verification

- -
-

Connection Test

-
Connecting...
-
- -
-

Data Reception Test

-
Waiting for lighting data...
-
Waiting for torch data...
-
Waiting for game state...
-
- -
-

Rendering Test

-
Waiting for render test...
-
Checking tileColorize setting...
-
- -
-

Live Data

-
-
- -
-
-
- - - - - - - - - - - - - - - diff --git a/test/test_movement.html b/test/test_movement.html deleted file mode 100644 index e69de29..0000000 diff --git a/test/test_movement.js b/test/test_movement.js deleted file mode 100644 index e69de29..0000000 diff --git a/test/test_tile_system.js b/test/test_tile_system.js deleted file mode 100644 index 82d924d..0000000 --- a/test/test_tile_system.js +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env node - -/** - * Test script to demonstrate the new tile system - * Shows floor variations, torch placement, and configurable assets - */ - -const DungeonGenerator = require('../src/backend/dungeon.js'); - -console.log("🏛️ WOWNGEON TILE SYSTEM TEST"); -console.log("=" * 50); - -// Test 1: Default Configuration -console.log("\n🔧 Test 1: Default Configuration"); -const defaultConfig = { - playerType: "@", - treasureType: "$W", - monsterType: "~", - primaryFloor: "'1", - secondaryFloor: "'2", - floorVariation: 0.01, - torchEnabled: true, - torchDensity: 0.15, - torchTile: "torch" -}; - -const dungeon1 = DungeonGenerator.generate(20, 15, defaultConfig); -console.log(`Generated dungeon: ${dungeon1.map.length}x${dungeon1.map[0].length}`); -console.log(`Entrance: [${dungeon1.entrance}]`); -console.log(`Exit: [${dungeon1.exit}]`); -console.log(`Treasure: [${dungeon1.treasure}]`); -console.log(`Torches: ${dungeon1.torches.length} placed`); - -// Count tile types -const tileCounts = {}; -for (let y = 0; y < dungeon1.map.length; y++) { - for (let x = 0; x < dungeon1.map[0].length; x++) { - const tile = dungeon1.map[y][x]; - tileCounts[tile] = (tileCounts[tile] || 0) + 1; - } -} - -console.log("\n📊 Tile Distribution:"); -Object.keys(tileCounts).sort().forEach(tile => { - console.log(` ${tile}: ${tileCounts[tile]} tiles`); -}); - -if (tileCounts["'1"] && tileCounts["'2"]) { - const floorTotal = tileCounts["'1"] + tileCounts["'2"]; - const variationPercent = (tileCounts["'2"] / floorTotal * 100).toFixed(2); - console.log(` Floor variation: ${variationPercent}% secondary floors`); -} - -// Test 2: Custom Configuration -console.log("\n🔧 Test 2: Custom Configuration (Bitcoin theme)"); -const customConfig = { - playerType: "@2", - treasureType: "$B", - monsterType: "~2", - primaryFloor: "'1", - secondaryFloor: "'2", - floorVariation: 0.05, // 5% variation - torchEnabled: true, - torchDensity: 0.25, // 25% more torches - torchTile: "torch" -}; - -const dungeon2 = DungeonGenerator.generate(15, 10, customConfig); -console.log(`Generated custom dungeon: ${dungeon2.map.length}x${dungeon2.map[0].length}`); -console.log(`Torches in custom dungeon: ${dungeon2.torches.length}`); - -// Test 3: Show a small visual sample -console.log("\n🗺️ Sample Dungeon (15x12):"); -const sampleDungeon = DungeonGenerator.generate(15, 12, defaultConfig); - -console.log(" 012345678901234"); -for (let y = 0; y < sampleDungeon.map.length; y++) { - let line = y.toString().padStart(2) + " "; - for (let x = 0; x < sampleDungeon.map[0].length; x++) { - let char = sampleDungeon.map[y][x]; - - // Add entities for display - if (sampleDungeon.entrance && sampleDungeon.entrance[0] === x && sampleDungeon.entrance[1] === y) { - char = '<'; - } else if (sampleDungeon.exit && sampleDungeon.exit[0] === x && sampleDungeon.exit[1] === y) { - char = '>'; - } else if (sampleDungeon.treasure && sampleDungeon.treasure[0] === x && sampleDungeon.treasure[1] === y) { - char = '$'; - } - - // Display character mapping - if (char === "'1") char = '.'; - else if (char === "'2") char = ':'; - else if (char === 'torch') char = 'T'; - else if (char === '#') char = '#'; - - line += char; - } - console.log(line); -} - -console.log("\nLegend:"); -console.log(" . = Primary floor ('1)"); -console.log(" : = Secondary floor ('2)"); -console.log(" # = Wall"); -console.log(" T = Torch"); -console.log(" < = Entrance"); -console.log(" > = Exit"); -console.log(" $ = Treasure"); - -console.log("\n✅ Tile System Test Complete!"); -console.log("\nFeatures verified:"); -console.log(" ✓ Configurable player/treasure/monster types"); -console.log(" ✓ Floor tile variations (primary/secondary)"); -console.log(" ✓ Configurable torch placement"); -console.log(" ✓ Enhanced dungeon generation"); -console.log(" ✓ Torch position tracking");