refactor frontend and fix debug mode

This commit is contained in:
jwinterm
2025-05-29 13:40:44 -04:00
parent de3eed792b
commit f02e16272e
28 changed files with 422 additions and 376 deletions
+287
View File
@@ -0,0 +1,287 @@
// Refactored Game Object - Main game controller using modular architecture
// This provides a mock socket when the real one isn't available
if (typeof window !== 'undefined' && !window.socket) {
window.socket = {
emit: function(event, data) {
// Mock socket emit - removed debug logging
}
};
}
var Game = {
_screenWidth: 25, // Default values, will be updated from options
_screenHeight: 19,
_inputEnabled: true,
_messageLog: [],
_maxLogMessages: 5,
init: function() {
// Update screen dimensions from options
if (typeof options !== 'undefined') {
this._screenWidth = options.width || 25;
this._screenHeight = options.height || 19;
}
// Initialize all modules
if (!DisplayManager.init(this._screenWidth, this._screenHeight)) {
return false;
}
ScreenManager.init(this._screenWidth, this._screenHeight);
RenderEngine.init(this._screenWidth, this._screenHeight);
GameState.init();
// Draw welcome screen
ScreenManager.drawWelcomeScreen();
return true;
},
_ensureDisplay: function() {
return DisplayManager.ensureDisplay();
},
_isFirefox: function() {
return navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
},
startGame: function(playerData, mapData, monsterData, itemData, initialVisibleTiles, lightingData, torchData) {
if (!this._ensureDisplay()) {
console.error("Game: Cannot start game, display not ready.");
return false;
}
DisplayManager.clearDisplay();
// Force clear all display caches and artifacts
if (typeof DisplayManager !== 'undefined' && DisplayManager.forceClearToBlack) {
DisplayManager.forceClearToBlack();
}
// Stop the block simulation to prevent welcome screen from interfering
if (typeof ScreenManager !== 'undefined' && ScreenManager.stopBlockSimulation) {
ScreenManager.stopBlockSimulation();
}
try {
GameState.setGameActive(true);
// Clear any previous game state but preserve what we need for initialization
GameState._exploredTiles = {};
// Don't clear _visibleTiles yet - let initializeMap handle it properly
GameState._map = {};
GameState._items = {};
GameState._monster = null;
GameState._entrance = null;
GameState._exit = null;
GameState._treasure = null;
// Initialize player
GameState.initializePlayer(playerData);
// Initialize other game objects
GameState._monster = monsterData;
GameState._items = itemData;
GameState._entrance = null;
GameState._exit = null;
GameState._treasure = null;
// Initialize lighting and torch data
if (lightingData) {
GameState._lighting = lightingData;
}
if (torchData) {
GameState._torches = torchData;
}
// Initialize map and validate player position
GameState.initializeMap(mapData, initialVisibleTiles, this._screenWidth, this._screenHeight);
if (!GameState.validatePlayerPosition(this._screenWidth, this._screenHeight)) {
ScreenManager.drawCenteredText(10, "Error: Map invalid / No player start!");
return false;
}
// Compute field of view
GameState.computeFieldOfView();
// Setup scheduler and engine
if (!GameState._scheduler) GameState._scheduler = new ROT.Scheduler.Simple();
else GameState._scheduler.clear();
if (!GameState._engine) GameState._engine = new ROT.Engine(GameState._scheduler);
GameState._scheduler.add(GameState._player, true);
if (!GameState._map[GameState._player.y] || GameState._map[GameState._player.y][GameState._player.x] === undefined) {
console.error(`Player position (${GameState._player.x}, ${GameState._player.y}) is STILL invalid before drawing. Map issue?`);
ScreenManager.drawCenteredText(10, "Error: Player invalid for draw!");
return false;
}
this._drawGameScreen();
return true;
} catch (err) {
console.error("Error during Game.startGame:", err);
console.error("Error name:", err.name, "Error message:", err.message, "Stack:", err.stack);
if (err.message && (err.message.includes("_map") || err.message.includes("Cannot read properties of undefined"))) {
console.error("Detailed error info: Player:", GameState._player, "Map keys:", Object.keys(GameState._map || {}).length);
}
try {
ScreenManager.drawCenteredText(10, "Error starting game!");
ScreenManager.drawCenteredText(12, "Check console (F12) for details.");
} catch (drawError) {
console.error("Failed to draw error message on screen:", drawError);
}
return false;
}
},
// Update game state with new data from server
updateGameState: function(data) {
const needsRedraw = GameState.updateGameState(data);
// Redraw the game screen if any relevant data changed
if (needsRedraw) {
this._drawGameScreen();
}
},
clearDisplay: function() {
DisplayManager.clearDisplay();
},
_drawGameScreen: function() {
if (!this._ensureDisplay()) return;
const gameState = GameState.getGameStateForRender();
RenderEngine.drawGameScreen(gameState);
},
// Screen drawing methods - delegate to ScreenManager
_drawWelcomeScreen: function() {
ScreenManager.drawWelcomeScreen();
},
drawWinScreen: function(hasTreasure) {
ScreenManager.drawWinScreen(hasTreasure);
},
drawLoseScreen: function(reason) {
ScreenManager.drawLoseScreen(reason);
},
drawWaitingScreen: function() {
ScreenManager.drawWaitingScreen();
},
stopWaitingScreen: function() {
ScreenManager.stopWaitingScreen();
},
// Display mode switching - delegate to DisplayManager
switchToAsciiMode: function() {
DisplayManager.switchToAsciiMode();
},
switchToTileMode: function() {
DisplayManager.switchToTileMode();
},
// Player movement - delegate to GameState
movePlayer: function(dx, dy) {
const moved = GameState.movePlayer(dx, dy, this._screenWidth, this._screenHeight);
if (moved) {
this._drawGameScreen();
}
},
// Debug functions - delegate to GameState
debugPrintMap: function() {
GameState.debugPrintMap(this._screenWidth, this._screenHeight);
},
debugTileMapping: function() {
GameState.debugTileMapping();
},
// Properties for backward compatibility
get _gameActive() {
return GameState.isGameActive();
},
set _gameActive(value) {
GameState.setGameActive(value);
},
get _player() {
return GameState._player;
},
get _monster() {
return GameState._monster;
},
get _map() {
return GameState._map;
},
get _items() {
return GameState._items;
},
get _visibleTiles() {
return GameState._visibleTiles;
},
get _exploredTiles() {
return GameState._exploredTiles;
}
};
// Debug utility functions (keep as-is for compatibility)
const GameDebug = {
log: function(message) {
console.log(message);
this.updateDebugDisplay(message);
this.sendToServer(message);
},
updateDebugDisplay: function(message) {
const debugContent = document.getElementById('debug-content');
if (debugContent) {
const timestamp = new Date().toLocaleTimeString();
debugContent.innerHTML += `<div>[${timestamp}] ${message}</div>`;
// Keep only last 10 debug messages
const lines = debugContent.children;
if (lines.length > 10) {
debugContent.removeChild(lines[0]);
}
// Auto-scroll to bottom
const debugDisplay = document.getElementById('debug-display');
debugDisplay.scrollTop = debugDisplay.scrollHeight;
}
},
sendToServer: function(message) {
try {
fetch('/debug', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message: message })
}).catch(err => {
// Silently fail if server unavailable
});
} catch (err) {
// Silently fail
}
}
};
// Make them available globally
if (typeof window !== 'undefined') {
window.Game = Game;
window.GameDebug = GameDebug;
}
+417
View File
@@ -0,0 +1,417 @@
// GameState - Handles game state management and updates
var GameState = {
_player: null,
_monster: null,
_map: {},
_items: {},
_gameActive: false,
_visibleTiles: {},
_exploredTiles: {},
_entrance: null,
_exit: null,
_treasure: null,
_message: null,
_scheduler: null,
_engine: null,
_lighting: {},
_torches: [],
init: function() {
this.reset();
},
reset: function() {
this._player = null;
this._monster = null;
this._map = {};
this._items = {};
this._gameActive = false;
this._visibleTiles = {};
this._exploredTiles = {};
this._entrance = null;
this._exit = null;
this._treasure = null;
this._message = null;
this._lighting = {};
this._torches = [];
if (this._scheduler) this._scheduler.clear();
if (!this._scheduler) this._scheduler = new ROT.Scheduler.Simple();
if (!this._engine) this._engine = new ROT.Engine(this._scheduler);
},
setGameActive: function(active) {
this._gameActive = active;
},
isGameActive: function() {
return this._gameActive;
},
initializePlayer: function(playerData) {
if (playerData && typeof playerData.x === 'number' && typeof playerData.y === 'number') {
this._player = { x: playerData.x, y: playerData.y };
} else {
console.warn("Invalid or missing playerData.x/y, using default player position.", playerData);
this._player = { x: 12, y: 12 }; // Default position
}
// console.log("Player initialized to:", this._player);
return this._player;
},
initializeMap: function(mapData, initialVisibleTiles, screenWidth, screenHeight) {
this._map = {};
this._visibleTiles = {};
this._exploredTiles = this._exploredTiles || {};
let mapInitialized = false;
// Try to initialize from mapData.tiles
if (mapData && mapData.tiles && typeof mapData.tiles === 'object' && Object.keys(mapData.tiles).length > 0) {
for (var yKey in mapData.tiles) {
const y = parseInt(yKey);
this._map[y] = {};
for (var xKey in mapData.tiles[y]) {
const x = parseInt(xKey);
this._map[y][x] = mapData.tiles[y][x];
}
}
mapInitialized = true;
}
// Try array-based mapData
else if (mapData && Array.isArray(mapData) && mapData.length > 0) {
for (let y = 0; y < mapData.length; y++) {
this._map[y] = {};
if (mapData[y] && Array.isArray(mapData[y])) {
for (let x = 0; x < mapData[y].length; x++) {
this._map[y][x] = mapData[y][x];
}
}
}
mapInitialized = true;
}
// Try initialVisibleTiles
else if (initialVisibleTiles && typeof initialVisibleTiles === 'object' && Object.keys(initialVisibleTiles).length > 0) {
this._visibleTiles = JSON.parse(JSON.stringify(initialVisibleTiles)); // Deep copy
for (const yKey in this._visibleTiles) {
const y = parseInt(yKey);
this._map[y] = this._map[y] || {};
for (const xKey in this._visibleTiles[y]) {
const x = parseInt(xKey);
this._map[y][x] = this._visibleTiles[y][x];
}
}
mapInitialized = true;
}
// Create default map if nothing worked
if (!mapInitialized) {
console.warn("No valid mapData or initialVisibleTiles provided. Creating default map for testing.");
const defaultMapWidth = screenWidth;
const defaultMapHeight = screenHeight;
for (let y = 0; y < defaultMapHeight; y++) {
this._map[y] = {};
for (let x = 0; x < defaultMapWidth; x++) {
this._map[y][x] = (x === 0 || x === defaultMapWidth - 1 || y === 0 || y === defaultMapHeight - 1) ? 1 : 0;
}
}
// Adjust player position if it's in a wall of the default map
if (this._map[this._player.y] && this._map[this._player.y][this._player.x] === 1) {
this._player.x = Math.floor(defaultMapWidth / 2);
this._player.y = Math.floor(defaultMapHeight / 2);
if (this._map[this._player.y][this._player.x] === 1) {
this._map[this._player.y][this._player.x] = 0; // Force floor
}
}
}
return mapInitialized;
},
validatePlayerPosition: function(screenWidth, screenHeight) {
// Validate player position against the map
if (!this._map[this._player.y] || this._map[this._player.y][this._player.x] === undefined) {
console.error(`Player position (${this._player.x}, ${this._player.y}) is invalid or outside map boundaries. Attempting to find fallback.`);
let foundFallback = false;
for (let y_scan = 0; y_scan < screenHeight; y_scan++) {
if (this._map[y_scan]) {
for (let x_scan = 0; x_scan < screenWidth; x_scan++) {
const tile = this._map[y_scan][x_scan];
// Check for both legacy (0) and new ("'1", "'2") floor tiles
if (tile === 0 || tile === "'1" || tile === "'2") {
this._player.x = x_scan;
this._player.y = y_scan;
foundFallback = true;
break;
}
}
}
if (foundFallback) break;
}
if (!foundFallback) {
console.error("Could not find a valid fallback starting position for the player on the map.");
return false;
}
}
return true;
},
computeFieldOfView: function() {
// Initialize FOV with corrected wall detection callback
var fov = new ROT.FOV.PreciseShadowcasting(function(x, y) {
// Return true if the tile is transparent (walkable), false if it blocks light
if (!this._map[y] || this._map[y][x] === undefined) {
return false; // Unknown tiles block light
}
const tile = this._map[y][x];
// Check for both legacy (0) and new ("'1", "'2") floor tiles
return tile === 0 || tile === "'1" || tile === "'2";
}.bind(this));
// If map was NOT built from initialVisibleTiles, compute FOV now
if (!this._visibleTiles || Object.keys(this._visibleTiles).length === 0) {
this._visibleTiles = {};
fov.compute(this._player.x, this._player.y, 10, function(x, y, r, visibility) {
if (!this._visibleTiles[y]) this._visibleTiles[y] = {};
if (this._map[y] && this._map[y][x] !== undefined) {
this._visibleTiles[y][x] = this._map[y][x];
}
}.bind(this));
}
// NOTE: Don't call updateExploredTiles() here on initial game load
// Explored tiles should only be updated when player moves, not on first FOV computation
},
updateExploredTiles: function() {
// Add all currently visible tiles to explored tiles
for (var yKey in this._visibleTiles) {
const y = parseInt(yKey);
if (!this._exploredTiles[y]) this._exploredTiles[y] = {};
for (var xKey in this._visibleTiles[y]) {
const x = parseInt(xKey);
this._exploredTiles[y][x] = this._visibleTiles[y][x];
}
}
},
updateGameState: function(data) {
if (!this._gameActive) {
console.warn("GameState.updateGameState called, but game is not active. Ignoring update.");
return false;
}
if (!data) {
console.error("GameState.updateGameState: No update data received!");
return false;
}
try {
let needsRedraw = false;
// Update player state
if (data.player) {
this._player = data.player;
needsRedraw = true;
}
// Update monster state
if (data.monster !== undefined) {
this._monster = data.monster;
needsRedraw = true;
}
// Update items
if (data.items !== undefined) {
this._items = data.items;
needsRedraw = true;
}
// Update entrance, exit, treasure
if (data.entrance !== undefined) {
this._entrance = data.entrance;
needsRedraw = true;
}
if (data.exit !== undefined) {
this._exit = data.exit;
needsRedraw = true;
}
if (data.treasure !== undefined) {
this._treasure = data.treasure;
needsRedraw = true;
}
// Update lighting and torch data
if (data.lighting !== undefined) {
this._lighting = data.lighting;
needsRedraw = true;
}
if (data.torches !== undefined) {
this._torches = data.torches;
needsRedraw = true;
}
// Update visible tiles (most critical for movement feedback)
if (data.visibleTiles && typeof data.visibleTiles === 'object' && Object.keys(data.visibleTiles).length > 0) {
this._visibleTiles = data.visibleTiles;
// Debug log for specific problematic coordinates
if (this._visibleTiles[18] && (this._visibleTiles[18][36] !== undefined || this._visibleTiles[18][35] !== undefined)) {
const clientDebug = `🔍 CLIENT y=18: x=35: ${this._visibleTiles[18][35]}, x=36: ${this._visibleTiles[18][36]}`;
if (window.GameDebug) window.GameDebug.updateDebugDisplay(clientDebug);
}
if (this._visibleTiles[16] && (this._visibleTiles[16][36] !== undefined || this._visibleTiles[16][35] !== undefined)) {
const clientDebug = `🔍 CLIENT y=16: x=35: ${this._visibleTiles[16][35]}, x=36: ${this._visibleTiles[16][36]}`;
if (window.GameDebug) window.GameDebug.updateDebugDisplay(clientDebug);
}
this.updateExploredTiles();
needsRedraw = true;
}
return needsRedraw;
} catch (err) {
console.error("Error in GameState.updateGameState:", err);
return false;
}
},
movePlayer: function(dx, dy, screenWidth, screenHeight) {
if (!DisplayManager.ensureDisplay()) return;
const newX = this._player.x + dx;
const newY = this._player.y + dy;
// Basic bounds checking
if (newX < 0 || newY < 0 || newX >= screenWidth || newY >= screenHeight) {
console.warn("Attempted to move player outside of bounds:", newX, newY);
return;
}
// Check if the new position is a wall (1) or out of map bounds
if (this._map[newY] && this._map[newY][newX] !== undefined && this._map[newY][newX] !== 1) {
// Move the player
this._player.x = newX;
this._player.y = newY;
// Update visibility and redraw
this.updateExploredTiles();
return true;
} else {
return false;
}
},
// Debug functions
debugPrintMap: function(screenWidth, screenHeight) {
// Map debugging - preserve console.log for debug function
console.log("Current game map:");
for (let y = 0; y < screenHeight; y++) {
let row = "";
for (let x = 0; x < screenWidth; x++) {
if (this._map[y] && this._map[y][x] !== undefined) {
row += this._map[y][x] + " ";
} else {
row += "? "; // Unknown/undefined area
}
}
console.log(row);
}
},
debugTileMapping: function() {
// Tile mapping debugging - preserve console.log for debug function
const testValues = [0, 1, undefined, null];
for (const val of testValues) {
const char = (val === 1) ? '#' : "\'";
const debugMsg = `Test mapping: value=${val} -> char='${char}'`;
console.log(debugMsg);
if (window.GameDebug) window.GameDebug.updateDebugDisplay(debugMsg);
}
},
// Compute field of view for the player (LOCAL TESTING ONLY - server handles FOV)
computeFieldOfView: function() {
if (!this._player) {
console.warn("Cannot compute FOV: player not initialized");
return;
}
// Warning for local FOV computation (keep for debugging)
// console.log("⚠️ LOCAL FOV COMPUTATION (should only be used for testing without server)");
const oldVisibleTiles = JSON.parse(JSON.stringify(this._visibleTiles));
this._visibleTiles = {};
const fov = new ROT.FOV.PreciseShadowcasting(function(x, y) {
const tile = this._map[y] && this._map[y][x];
// Check for both legacy (0) and new ("'1", "'2") floor tiles
return tile === 0 || tile === "'1" || tile === "'2";
}.bind(this));
fov.compute(this._player.x, this._player.y, 6, function(x, y, r, visibility) {
if (!this._visibleTiles[y]) this._visibleTiles[y] = {};
this._visibleTiles[y][x] = this._map[y] && this._map[y][x] !== undefined ? this._map[y][x] : 0;
// Mark as explored
if (!this._exploredTiles[y]) this._exploredTiles[y] = {};
this._exploredTiles[y][x] = this._map[y] && this._map[y][x] !== undefined ? this._map[y][x] : 0;
}.bind(this));
},
// Get game state data for rendering
getGameStateForRender: function() {
const renderState = {
map: this._map,
player: this._player,
monster: this._monster,
items: this._items,
entrance: this._entrance,
exit: this._exit,
treasure: this._treasure,
visibleTiles: this._visibleTiles,
exploredTiles: this._exploredTiles,
message: this._message,
gameActive: this._gameActive,
lighting: this._lighting,
torches: this._torches
};
return renderState;
},
// Move player and update game state
movePlayer: function(dx, dy, screenWidth, screenHeight) {
if (!this._player) {
console.warn("Cannot move player: player not initialized");
return false;
}
const newX = this._player.x + dx;
const newY = this._player.y + dy;
// Check bounds
if (newX < 0 || newX >= screenWidth || newY < 0 || newY >= screenHeight) {
// console.log("Player move blocked: out of bounds");
return false;
}
// Check if the new position is passable
if (this._map[newY] && this._map[newY][newX] === 1) {
// console.log("Player move blocked: wall at", newX, newY);
return false;
}
// Update player position
this._player.x = newX;
this._player.y = newY;
// console.log("Player moved to:", this._player.x, this._player.y);
return true;
}
};
// Make it available globally
if (typeof window !== 'undefined') {
window.GameState = GameState;
}
+179
View File
@@ -0,0 +1,179 @@
var tileSet = document.createElement("img");
var tileSetLoaded = false;
tileSet.onload = function() {
tileSetLoaded = true;
};
tileSet.onerror = function() {
console.error("Failed to load tileset image!");
};
tileSet.src = "tiles.png";
var options = {
layout: "tile",
bg: "transparent",
// Adjusted dimensions for ~800x600 display
width: 25, // 25 tiles * 32px/tile = 800px
height: 19, // 19 tiles * 32px/tile = 608px
tileWidth: 32, // Width of a single tile in pixels
tileHeight: 32, // Height of a single tile in pixels
tileColorize: true, // Enable colorization for tile stacks
tileSet: tileSet,
// GAME CONFIGURATION - Change these to select different assets
gameConfig: {
playerType: "@", // Options: "@", "@2"
treasureType: "$W", // Options: "$W" (Wownero), "$M" (Monero), "$B" (Bitcoin), "$" (Regular)
monsterType: "~2", // Options: "~", "~2"
// Floor tile configuration
primaryFloor: "'1", // Main floor tile (99% of floors)
secondaryFloor: "'2", // Alt floor tile (1% of floors)
floorVariation: 0.01, // Percentage of secondary floor tiles (0.01 = 1%)
// Torch configuration
torchEnabled: true, // Enable/disable torch placement
torchDensity: 0.15, // Percentage of wall tiles that get torches (0.15 = 15%)
torchTile: "torch" // Torch tile identifier
},
tileMap: {
// Keep your existing tile mappings
"'1": [0, 0], // Floor
">": [32, 0], // Exit
"@": [64, 0], // Player
"~": [96, 0], // Monster
"$W": [960, 0], // Wownero Treasure
"$M": [992, 0], // Monero Treasure
"'2": [1024, 0], // Alt floor
"<": [0, 32], // Entrance
"=": [32, 32], // Monster Entrance
"#": [64, 32], // Wall
"$B": [96, 32], // Bitcoin Treasure
"@2": [960, 32], // Player Alt
"~2": [992, 32], // Monster Alt
"torch": [1024, 32], // Torch
// ... include all other necessary character mappings ...
"a": [128, 0],
"b": [160, 0],
"c": [192, 0],
"d": [224, 0],
"e": [256, 0],
"f": [288, 0],
"g": [320, 0],
"h": [352, 0],
"i": [384, 0],
"j": [416, 0],
"k": [448, 0],
"l": [480, 0],
"m": [512, 0], // Duplicate M? Ensure one is correct
"n": [544, 0],
"o": [576, 0],
"p": [608, 0],
"q": [640, 0],
"r": [672, 0],
"s": [704, 0],
"t": [736, 0],
"u": [768, 0],
"v": [800, 0],
"w": [832, 0],
"x": [864, 0],
"y": [896, 0],
"z": [928, 0],
"A": [128, 32],
"B": [160, 32],
"C": [192, 32],
"D": [224, 32],
"E": [256, 32],
"F": [288, 32],
"G": [320, 32],
"H": [352, 32],
"I": [384, 32],
"J": [416, 32],
"K": [448, 32],
"L": [480, 32],
"M": [512, 32], // Already mapped M
"N": [544, 32],
"O": [576, 32],
"P": [608, 32],
"Q": [640, 32],
"R": [672, 32],
"S": [704, 32],
"T": [736, 32],
"U": [768, 32],
"V": [800, 32],
"W": [832, 32],
"X": [864, 32],
"Y": [896, 32],
"Z": [928, 32],
"&": [0, 64],
"-": [32, 64],
"+": [64, 64],
"`": [96, 64],
"0": [128, 64],
"1": [160, 64],
"2": [192, 64],
"3": [224, 64],
"4": [256, 64],
"5": [288, 64],
"6": [320, 64],
"7": [352, 64],
"8": [384, 64],
"9": [416, 64],
".": [448, 64],
":": [480, 64],
",": [512, 64],
";": [544, 64],
"(": [576, 64],
"*": [608, 64],
"!": [640, 64],
"?": [672, 64],
"}": [704, 64],
"^": [736, 64],
")": [768, 64],
"[": [800, 64],
"$": [832, 64], // remap to regular dollar sign
"{": [864, 64],
"%": [896, 64],
"^": [928, 64],
"\'": [960, 64], // New quotes mapping
"\"": [992, 64],
" ": [1024, 64]
}
};
// Make options globally available
window.tileSet = tileSet;
window.tileMap = options.tileMap;
window.options = options;
// Helper functions to get configured tile types
window.GameTiles = {
getPlayerTile: function() {
return options.gameConfig.playerType;
},
getTreasureTile: function() {
return options.gameConfig.treasureType;
},
getMonsterTile: function() {
return options.gameConfig.monsterType;
},
getFloorTile: function(useVariation = false) {
if (useVariation && Math.random() < options.gameConfig.floorVariation) {
return options.gameConfig.secondaryFloor;
}
return options.gameConfig.primaryFloor;
},
getTorchTile: function() {
return options.gameConfig.torchTile;
},
shouldPlaceTorch: function() {
return options.gameConfig.torchEnabled && Math.random() < options.gameConfig.torchDensity;
}
};