mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-27 01:58:33 +01:00
refactor frontend and fix debug mode
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
// DisplayManager - Handles ROT.Display initialization and clearing
|
||||
var DisplayManager = {
|
||||
_display: null,
|
||||
_displayReady: false,
|
||||
_screenWidth: null,
|
||||
_screenHeight: null,
|
||||
|
||||
init: function(screenWidth, screenHeight) {
|
||||
this._screenWidth = screenWidth;
|
||||
this._screenHeight = screenHeight;
|
||||
|
||||
var displayOptions = {
|
||||
width: this._screenWidth,
|
||||
height: this._screenHeight,
|
||||
forceSquareRatio: true,
|
||||
};
|
||||
|
||||
displayOptions.layout = "tile";
|
||||
displayOptions.bg = window.options.bg;
|
||||
displayOptions.fg = window.options.fg || "#FFF";
|
||||
displayOptions.tileWidth = window.options.tileWidth;
|
||||
displayOptions.tileHeight = window.options.tileHeight;
|
||||
displayOptions.tileSet = window.options.tileSet;
|
||||
displayOptions.tileMap = window.options.tileMap;
|
||||
displayOptions.tileColorize = true; // Enable colorization for tile stacks
|
||||
|
||||
try {
|
||||
var gameDisplayContainer = document.getElementById("game-display");
|
||||
if (!gameDisplayContainer) {
|
||||
console.error("Game display container #game-display not found in HTML!");
|
||||
alert("Error: Game display container #game-display not found. Cannot start game.");
|
||||
return false;
|
||||
}
|
||||
|
||||
this._display = new ROT.Display(displayOptions);
|
||||
gameDisplayContainer.innerHTML = '';
|
||||
gameDisplayContainer.appendChild(this._display.getContainer());
|
||||
this._displayReady = true;
|
||||
return true;
|
||||
|
||||
} catch (e) {
|
||||
console.error("Error initializing ROT.Display:", e);
|
||||
alert("Failed to initialize game display. Error: " + e.message + ". Check console for details.");
|
||||
this._displayReady = false;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
getDisplay: function() {
|
||||
return this._display;
|
||||
},
|
||||
|
||||
isReady: function() {
|
||||
return this._display && this._displayReady;
|
||||
},
|
||||
|
||||
ensureDisplay: function() {
|
||||
if (!this._display || !this._displayReady) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, forceClearToBlack: function() {
|
||||
if (!this.ensureDisplay()) {
|
||||
console.warn("DisplayManager.forceClearToBlack: Display not ready, aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
const display = this._display;
|
||||
|
||||
// Step 1: Clear ROT.js's internal data cache and dirty flags
|
||||
display._data = {};
|
||||
display._dirty = {};
|
||||
|
||||
// Step 2: Force redraw entire screen with blank characters
|
||||
for (let x = 0; x < this._screenWidth; x++) {
|
||||
for (let y = 0; y < this._screenHeight; y++) {
|
||||
display.draw(x, y, ' ', '#000', '#000');
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Directly clear the visual canvas to black
|
||||
var canvas = display.getContainer();
|
||||
if (canvas && typeof canvas.getContext === 'function') {
|
||||
var ctx = canvas.getContext("2d");
|
||||
if (ctx) {
|
||||
ctx.fillStyle = "#000000";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
} else {
|
||||
console.warn("DisplayManager.forceClearToBlack: Failed to get 2D context from canvas.");
|
||||
this._fallbackClear(display);
|
||||
}
|
||||
} else {
|
||||
console.warn("DisplayManager.forceClearToBlack: Display container is not a canvas or does not exist. Attempting fallback clear.");
|
||||
this._fallbackClear(display);
|
||||
}
|
||||
},
|
||||
|
||||
_fallbackClear: function(display) {
|
||||
console.warn("DisplayManager.forceClearToBlack: Using fallback clear method.");
|
||||
const originalBg = display.getOptions().bg;
|
||||
try {
|
||||
if (display._options) {
|
||||
display._options.bg = "#000000";
|
||||
}
|
||||
display.clear();
|
||||
} catch (e) {
|
||||
console.error("Error during fallback clear:", e);
|
||||
} finally {
|
||||
if (display._options) {
|
||||
display._options.bg = originalBg;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
clearDisplay: function() {
|
||||
if (!this.ensureDisplay()) return;
|
||||
this.forceClearToBlack();
|
||||
}
|
||||
};
|
||||
|
||||
// Make it available globally
|
||||
if (typeof window !== 'undefined') {
|
||||
window.DisplayManager = DisplayManager;
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
// RenderEngine - Handles game screen rendering and drawing logic
|
||||
var RenderEngine = {
|
||||
defaultFg: "#FFF",
|
||||
|
||||
init: function(screenWidth, screenHeight) {
|
||||
this._screenWidth = screenWidth;
|
||||
this._screenHeight = screenHeight;
|
||||
},
|
||||
|
||||
isVisible: function(x, y, visibleTiles) {
|
||||
return visibleTiles[y] && visibleTiles[y][x] !== undefined;
|
||||
},
|
||||
|
||||
drawGameScreen: function(gameState) {
|
||||
if (!DisplayManager.ensureDisplay()) return;
|
||||
|
||||
// Ensure we have a clean display first
|
||||
DisplayManager.clearDisplay();
|
||||
|
||||
const display = DisplayManager.getDisplay();
|
||||
const player = gameState.player;
|
||||
const monster = gameState.monster;
|
||||
const items = gameState.items;
|
||||
const entrance = gameState.entrance;
|
||||
const exit = gameState.exit;
|
||||
const treasure = gameState.treasure;
|
||||
const torches = gameState.torches || []; // New torch positions
|
||||
const visibleTiles = gameState.visibleTiles || {};
|
||||
const exploredTiles = gameState.exploredTiles || {};
|
||||
const lighting = gameState.lighting || {}; // Lighting data from server
|
||||
const message = gameState.message;
|
||||
|
||||
// Get configured tile types from options
|
||||
const playerTile = window.GameTiles ? window.GameTiles.getPlayerTile() : '@';
|
||||
const treasureTile = window.GameTiles ? window.GameTiles.getTreasureTile() : '$W';
|
||||
const monsterTile = window.GameTiles ? window.GameTiles.getMonsterTile() : '~';
|
||||
const torchTile = window.GameTiles ? window.GameTiles.getTorchTile() : 'torch';
|
||||
|
||||
const playerWX = player.x;
|
||||
const playerWY = player.y;
|
||||
const centerX = Math.floor(this._screenWidth / 2);
|
||||
const centerY = Math.floor(this._screenHeight / 2);
|
||||
|
||||
const topLeftWX = playerWX - centerX;
|
||||
const topLeftWY = playerWY - centerY;
|
||||
|
||||
for (let sy = 0; sy < this._screenHeight; sy++) {
|
||||
for (let sx = 0; sx < this._screenWidth; sx++) {
|
||||
const wx = topLeftWX + sx;
|
||||
const wy = topLeftWY + sy;
|
||||
|
||||
let charStack = [];
|
||||
let fgStack = [];
|
||||
let bgStack = [];
|
||||
|
||||
let baseChar = ' ';
|
||||
let baseFg = this.defaultFg;
|
||||
let tileType;
|
||||
|
||||
// Debug log for a specific tile if needed - replace with actual test coordinates
|
||||
// const wx_test = 10, wy_test = 10; // Example coordinates
|
||||
// if (wx === wx_test && wy === wy_test) {
|
||||
// console.log(`RenderEngine DEBUG: Tile (${wx},${wy}) raw lighting data: ${lighting[wy] ? lighting[wy][wx] : 'N/A'}`);
|
||||
// }
|
||||
|
||||
// Render base terrain
|
||||
if (this.isVisible(wx, wy, visibleTiles)) {
|
||||
tileType = visibleTiles[wy][wx];
|
||||
baseFg = this.defaultFg;
|
||||
|
||||
// Handle new string-based tile system
|
||||
if (tileType === '#') {
|
||||
baseChar = '#'; // Wall
|
||||
} else if (tileType === "'1" || tileType === "'2") {
|
||||
baseChar = tileType; // Use the specific floor tile type
|
||||
} else if (tileType === 'torch') {
|
||||
baseChar = '#'; // Torch tiles are walls with torches on top
|
||||
} else if (tileType === 1) {
|
||||
baseChar = '#'; // Legacy wall support
|
||||
} else if (tileType === 0) {
|
||||
baseChar = "'1"; // Legacy floor support - use primary floor
|
||||
} else {
|
||||
// Use the tile type directly if it's a string
|
||||
baseChar = tileType || "'1"; // Default to primary floor for safety
|
||||
}
|
||||
|
||||
} else if (exploredTiles[wy] && exploredTiles[wy][wx] !== undefined) {
|
||||
tileType = exploredTiles[wy][wx];
|
||||
baseFg = this.defaultFg;
|
||||
|
||||
// Handle new string-based tile system for explored tiles
|
||||
if (tileType === '#') {
|
||||
baseChar = '#'; // Wall
|
||||
} else if (tileType === "'1" || tileType === "'2") {
|
||||
baseChar = tileType; // Use the specific floor tile type
|
||||
} else if (tileType === 'torch') {
|
||||
baseChar = '#'; // Torch tiles are walls with torches on top
|
||||
} else if (tileType === 1) {
|
||||
baseChar = '#'; // Legacy wall support
|
||||
} else if (tileType === 0) {
|
||||
baseChar = "'1"; // Legacy floor support - use primary floor
|
||||
} else {
|
||||
// Use the tile type directly if it's a string
|
||||
baseChar = tileType || "'1"; // Default to primary floor for safety
|
||||
}
|
||||
} else {
|
||||
// No visible or explored tile - render empty space
|
||||
baseChar = ' ';
|
||||
baseFg = this.defaultFg;
|
||||
}
|
||||
|
||||
// Only add to stacks if we have a valid character
|
||||
if (baseChar && baseChar !== ' ') {
|
||||
charStack.push(baseChar);
|
||||
|
||||
// Get lighting information for this tile
|
||||
const lightingAlpha = (lighting[wy] && lighting[wy][wx]) ? lighting[wy][wx] : 0.0;
|
||||
|
||||
// Apply lighting shadows for terrain
|
||||
const isCurrentlyVisible = this.isVisible(wx, wy, visibleTiles);
|
||||
|
||||
// Added log to inspect lightingAlpha for visible, lit tiles
|
||||
// if (isCurrentlyVisible && lightingAlpha > 0.01) { // Using 0.01 to catch small, non-zero alphas
|
||||
// console.log(`RenderEngine TRACE: Tile (${wx},${wy}), Visible: ${isCurrentlyVisible}, lightingAlpha: ${lightingAlpha.toFixed(3)}, from: ${lighting[wy] ? lighting[wy][wx].toFixed(3) : 'N/A'}`);
|
||||
// }
|
||||
|
||||
if (isCurrentlyVisible) {
|
||||
if (lightingAlpha > 0) {
|
||||
// Apply torch shadow using foreground overlay
|
||||
fgStack.push(`rgba(0, 0, 0, ${Math.min(lightingAlpha, 0.8)})`);
|
||||
} else {
|
||||
// Normal tile with no shadow
|
||||
fgStack.push("transparent");
|
||||
}
|
||||
} else {
|
||||
// Explored but not currently visible - apply darker shadow
|
||||
fgStack.push(`rgba(0, 0, 0, 0.7)`);
|
||||
}
|
||||
|
||||
bgStack.push("transparent"); // Always transparent background for terrain
|
||||
}
|
||||
|
||||
// Render items
|
||||
if (items) {
|
||||
for (const itemKey in items) {
|
||||
if (items.hasOwnProperty(itemKey)) {
|
||||
const currentItem = items[itemKey];
|
||||
if (currentItem && currentItem.x === wx && currentItem.y === wy && this.isVisible(wx, wy, visibleTiles)) {
|
||||
charStack.push('$');
|
||||
// Apply torch lighting to items
|
||||
const lightingAlpha = (lighting[wy] && lighting[wy][wx]) ? lighting[wy][wx] : 0.0;
|
||||
if (lightingAlpha > 0) {
|
||||
fgStack.push(`rgba(0, 0, 0, ${Math.min(lightingAlpha, 0.8)})`);
|
||||
} else {
|
||||
fgStack.push("transparent");
|
||||
}
|
||||
bgStack.push("transparent");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render entrance
|
||||
if (entrance && entrance[0] === wx && entrance[1] === wy && this.isVisible(wx, wy, visibleTiles)) {
|
||||
charStack.push('<');
|
||||
// Apply torch lighting to entrance
|
||||
const lightingAlpha = (lighting[wy] && lighting[wy][wx]) ? lighting[wy][wx] : 0.0;
|
||||
if (lightingAlpha > 0) {
|
||||
fgStack.push(`rgba(0, 0, 0, ${Math.min(lightingAlpha, 0.8)})`);
|
||||
} else {
|
||||
fgStack.push("transparent");
|
||||
}
|
||||
bgStack.push("transparent");
|
||||
}
|
||||
|
||||
// Render exit
|
||||
if (exit && exit[0] === wx && exit[1] === wy && this.isVisible(wx, wy, visibleTiles)) {
|
||||
charStack.push('>');
|
||||
// Apply torch lighting to exit
|
||||
const lightingAlpha = (lighting[wy] && lighting[wy][wx]) ? lighting[wy][wx] : 0.0;
|
||||
if (lightingAlpha > 0) {
|
||||
fgStack.push(`rgba(0, 0, 0, ${Math.min(lightingAlpha, 0.8)})`);
|
||||
} else {
|
||||
fgStack.push("transparent");
|
||||
}
|
||||
bgStack.push("transparent");
|
||||
}
|
||||
|
||||
// Render treasure
|
||||
if (treasure && treasure[0] === wx && treasure[1] === wy && this.isVisible(wx, wy, visibleTiles)) {
|
||||
charStack.push(treasureTile);
|
||||
// Apply torch lighting to treasure
|
||||
const lightingAlpha = (lighting[wy] && lighting[wy][wx]) ? lighting[wy][wx] : 0.0;
|
||||
if (lightingAlpha > 0) {
|
||||
fgStack.push(`rgba(0, 0, 0, ${Math.min(lightingAlpha, 0.8)})`);
|
||||
} else {
|
||||
fgStack.push("transparent");
|
||||
}
|
||||
bgStack.push("transparent");
|
||||
}
|
||||
|
||||
// Render torches (check if this tile has a torch)
|
||||
if (this.isVisible(wx, wy, visibleTiles) && visibleTiles[wy][wx] === 'torch') {
|
||||
charStack.push(torchTile);
|
||||
// Don't apply shadows to torches since they're light sources
|
||||
fgStack.push("transparent");
|
||||
bgStack.push("transparent");
|
||||
}
|
||||
|
||||
// Render monster
|
||||
if (monster && monster.x === wx && monster.y === wy && this.isVisible(wx, wy, visibleTiles)) {
|
||||
charStack.push(monsterTile);
|
||||
// Apply torch lighting to monster
|
||||
const lightingAlpha = (lighting[wy] && lighting[wy][wx]) ? lighting[wy][wx] : 0.0;
|
||||
if (lightingAlpha > 0) {
|
||||
fgStack.push(`rgba(0, 0, 0, ${Math.min(lightingAlpha, 0.8)})`);
|
||||
} else {
|
||||
fgStack.push("transparent");
|
||||
}
|
||||
bgStack.push("transparent");
|
||||
}
|
||||
|
||||
// Render player (always on top)
|
||||
if (wx === playerWX && wy === playerWY) {
|
||||
charStack.push(playerTile);
|
||||
// Don't apply shadows to player - keep them clearly visible
|
||||
fgStack.push("transparent");
|
||||
bgStack.push("transparent");
|
||||
}
|
||||
|
||||
if (charStack.length > 0) {
|
||||
// Validate array lengths
|
||||
while (fgStack.length < charStack.length) fgStack.push("transparent");
|
||||
while (bgStack.length < charStack.length) bgStack.push("transparent");
|
||||
|
||||
// Validate characters are in tileMap
|
||||
for (let i = 0; i < charStack.length; i++) {
|
||||
if (!charStack[i] || (window.options?.tileMap && !window.options.tileMap.hasOwnProperty(charStack[i]))) {
|
||||
// Default to primary floor if tile not found
|
||||
charStack[i] = "'1";
|
||||
}
|
||||
if (!fgStack[i]) fgStack[i] = "transparent";
|
||||
if (!bgStack[i]) bgStack[i] = "transparent";
|
||||
}
|
||||
|
||||
try {
|
||||
display.draw(sx, sy, charStack, fgStack, bgStack);
|
||||
} catch (error) {
|
||||
display.draw(sx, sy, ["'"], ["transparent"], ["transparent"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render message at bottom if present
|
||||
if (message) {
|
||||
ScreenManager.drawCenteredText(this._screenHeight - 1, message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Make it available globally
|
||||
if (typeof window !== 'undefined') {
|
||||
window.RenderEngine = RenderEngine;
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
// ScreenManager - Handles different screen states and UI drawing
|
||||
var ScreenManager = {
|
||||
defaultFg: "#FFF",
|
||||
_currentBlockHeight: 0,
|
||||
_blockTimer: null,
|
||||
_updateInterval: null, // Track the update interval separately
|
||||
_waitingForBlock: false,
|
||||
|
||||
init: function(screenWidth, screenHeight) {
|
||||
this._screenWidth = screenWidth;
|
||||
this._screenHeight = screenHeight;
|
||||
this._currentBlockHeight = 0;
|
||||
this._waitingForBlock = false;
|
||||
this._updateInterval = null; // Initialize update interval tracker
|
||||
|
||||
// Initialize the waiting screen animator
|
||||
if (typeof WaitingScreenAnimator !== 'undefined') {
|
||||
WaitingScreenAnimator.init();
|
||||
}
|
||||
},
|
||||
|
||||
drawText: function(x, y, text) {
|
||||
if (!DisplayManager.ensureDisplay()) return;
|
||||
const display = DisplayManager.getDisplay();
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const char = text[i];
|
||||
if (window.options?.tileMap?.hasOwnProperty(char) || char === ' ') {
|
||||
display.draw(x + i, y, char, "transparent", "transparent");
|
||||
} else {
|
||||
display.draw(x + i, y, "?", "transparent", "transparent");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
drawCenteredText: function(y, text) {
|
||||
const x = Math.floor((this._screenWidth - text.length) / 2);
|
||||
this.drawText(x, y, text);
|
||||
},
|
||||
|
||||
drawBorder: function() {
|
||||
if (!DisplayManager.ensureDisplay()) return;
|
||||
const display = DisplayManager.getDisplay();
|
||||
|
||||
// Use wall tiles (#) for borders - these are guaranteed to exist in tileMap
|
||||
const borderChar = "#"; // Wall tile at [64, 32]
|
||||
|
||||
// Draw top and bottom borders
|
||||
for (var i = 0; i < this._screenWidth; i++) {
|
||||
display.draw(i, 0, borderChar, "transparent", "transparent");
|
||||
display.draw(i, this._screenHeight - 1, borderChar, "transparent", "transparent");
|
||||
}
|
||||
|
||||
// Draw left and right borders
|
||||
for (var j = 1; j < this._screenHeight - 1; j++) {
|
||||
display.draw(0, j, borderChar, "transparent", "transparent");
|
||||
display.draw(this._screenWidth - 1, j, borderChar, "transparent", "transparent");
|
||||
}
|
||||
},
|
||||
|
||||
drawWelcomeScreen: function() {
|
||||
if (!DisplayManager.ensureDisplay()) return;
|
||||
DisplayManager.clearDisplay();
|
||||
|
||||
// Draw the border
|
||||
this.drawBorder();
|
||||
|
||||
// Draw content
|
||||
let y = 3;
|
||||
this.drawCenteredText(y, "WOWGUE");
|
||||
y += 4;
|
||||
|
||||
// Draw instructions
|
||||
this.drawCenteredText(y, "Type enter to queue!");
|
||||
this.drawCenteredText(y + 1, "Or use START GAME");
|
||||
y += 3;
|
||||
|
||||
// Draw legend with special tile handling
|
||||
const display = DisplayManager.getDisplay();
|
||||
const legendItems = [
|
||||
{ tile: "@2", text: "This is you" },
|
||||
{ tile: ">", text: " Escape the dungeon" },
|
||||
{ tile: "~", text: " Avoid the monster" },
|
||||
{ tile: "$M", text: "Secure the bag" }
|
||||
];
|
||||
|
||||
const centerX = Math.floor(this._screenWidth / 2) - 10;
|
||||
for (let item of legendItems) {
|
||||
let x = centerX;
|
||||
|
||||
// Draw the special tile
|
||||
if (window.options?.tileMap?.hasOwnProperty(item.tile)) {
|
||||
display.draw(x, y, item.tile, "transparent", "transparent");
|
||||
x += item.tile.length;
|
||||
} else {
|
||||
display.draw(x, y, "?", "transparent", "transparent");
|
||||
x += 1;
|
||||
}
|
||||
|
||||
// Draw the descriptive text
|
||||
this.drawText(x, y, item.text);
|
||||
y++;
|
||||
}
|
||||
|
||||
// Draw current block info
|
||||
y += 2;
|
||||
this.drawCenteredText(y, `Current Block: ${this._currentBlockHeight}`);
|
||||
|
||||
// Control HTML button visibility
|
||||
const startButton = document.getElementById('startButton');
|
||||
if (startButton) {
|
||||
startButton.style.display = 'block';
|
||||
}
|
||||
|
||||
// Hide animation button on welcome screen
|
||||
this.hideAnimationButton();
|
||||
|
||||
// Debug mode detection (for future use)
|
||||
const isDebugMode = window.location.hostname === 'localhost' ||
|
||||
window.location.hostname === '127.0.0.1' ||
|
||||
window.location.protocol === 'file:';
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
toggleAnimation: function() {
|
||||
if (typeof WaitingScreenAnimator !== 'undefined') {
|
||||
WaitingScreenAnimator.toggleAnimation();
|
||||
}
|
||||
},
|
||||
|
||||
// Start simulated block mining (30 second intervals)
|
||||
startBlockSimulation: function() {
|
||||
this._currentBlockHeight = Math.floor(Math.random() * 1000000) + 3200000; // Realistic Wownero block height
|
||||
this._waitingForBlock = true;
|
||||
|
||||
// Update welcome screen every second during mining
|
||||
this._updateInterval = setInterval(() => {
|
||||
if (this._waitingForBlock && !GameState.isGameActive()) {
|
||||
this.drawWelcomeScreen();
|
||||
} else {
|
||||
if (this._updateInterval) {
|
||||
clearInterval(this._updateInterval);
|
||||
this._updateInterval = null;
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// Simulate new block every 30 seconds
|
||||
this._blockTimer = setInterval(() => {
|
||||
if (!GameState.isGameActive()) { // Only continue if game is not active
|
||||
this._currentBlockHeight++;
|
||||
this._waitingForBlock = false;
|
||||
this.drawWelcomeScreen();
|
||||
|
||||
// Show block found message briefly
|
||||
setTimeout(() => {
|
||||
if (!DisplayManager.ensureDisplay() || GameState.isGameActive()) return;
|
||||
let y = Math.floor(this._screenHeight / 2);
|
||||
this.drawCenteredText(y, "*** NEW BLOCK FOUND! ***");
|
||||
this.drawCenteredText(y + 1, "You may now enter the dungeon!");
|
||||
|
||||
// Allow entry for 5 seconds
|
||||
setTimeout(() => {
|
||||
if (!GameState.isGameActive()) {
|
||||
this._waitingForBlock = true;
|
||||
this.drawWelcomeScreen();
|
||||
}
|
||||
}, 5000);
|
||||
}, 500);
|
||||
}
|
||||
}, 30000); // 30 second intervals
|
||||
},
|
||||
|
||||
// Stop block simulation
|
||||
stopBlockSimulation: function() {
|
||||
if (this._blockTimer) {
|
||||
clearInterval(this._blockTimer);
|
||||
this._blockTimer = null;
|
||||
}
|
||||
if (this._updateInterval) {
|
||||
clearInterval(this._updateInterval);
|
||||
this._updateInterval = null;
|
||||
}
|
||||
this._waitingForBlock = false;
|
||||
},
|
||||
|
||||
// Check if player can enter (not waiting for block or debug mode)
|
||||
canEnterGame: function() {
|
||||
const isDebugMode = window.location.hostname === 'localhost' ||
|
||||
window.location.hostname === '127.0.0.1' ||
|
||||
window.location.protocol === 'file:';
|
||||
return !this._waitingForBlock || isDebugMode;
|
||||
},
|
||||
|
||||
drawWinScreen: function(hasTreasure) {
|
||||
if (!DisplayManager.ensureDisplay()) return;
|
||||
DisplayManager.clearDisplay();
|
||||
|
||||
let y = Math.floor(this._screenHeight / 3);
|
||||
this.drawCenteredText(y, "CONGRATULATIONS!");
|
||||
|
||||
if (hasTreasure) {
|
||||
this.drawCenteredText(y + 2, "You escaped with the treasure!");
|
||||
} else {
|
||||
this.drawCenteredText(y + 2, "You escaped the dungeon!");
|
||||
}
|
||||
this.drawCenteredText(y + 3, "A true hero of Wownero!");
|
||||
},
|
||||
|
||||
drawLoseScreen: function(reason) {
|
||||
if (!DisplayManager.ensureDisplay()) return;
|
||||
DisplayManager.clearDisplay();
|
||||
|
||||
let y = Math.floor(this._screenHeight / 3);
|
||||
this.drawCenteredText(y, "YOU HAVE PERISHED");
|
||||
|
||||
if (reason === 'monster') {
|
||||
this.drawCenteredText(y + 2, "Slain by a fearsome beast.");
|
||||
} else if (reason === 'timeout') {
|
||||
this.drawCenteredText(y + 2, "The dungeon claimed you before the next block.");
|
||||
} else {
|
||||
this.drawCenteredText(y + 2, "Your adventure ends here.");
|
||||
}
|
||||
this.drawCenteredText(y + 3, "Better luck next time.");
|
||||
},
|
||||
|
||||
drawWaitingScreen: function() {
|
||||
if (!DisplayManager.ensureDisplay()) return;
|
||||
DisplayManager.clearDisplay();
|
||||
|
||||
const animationEnabled = (typeof WaitingScreenAnimator !== 'undefined') ?
|
||||
WaitingScreenAnimator.isAnimationEnabled() : false;
|
||||
|
||||
// Delegate to WaitingScreenAnimator with proper parameters
|
||||
if (typeof WaitingScreenAnimator !== 'undefined') {
|
||||
if (animationEnabled) {
|
||||
WaitingScreenAnimator.drawAnimatedWaitingScreen(
|
||||
this._screenWidth,
|
||||
this._screenHeight,
|
||||
this.drawBorder.bind(this),
|
||||
this.drawCenteredText.bind(this)
|
||||
);
|
||||
} else {
|
||||
WaitingScreenAnimator.drawStaticWaitingScreen(
|
||||
this._screenWidth,
|
||||
this._screenHeight,
|
||||
this.drawBorder.bind(this),
|
||||
this.drawCenteredText.bind(this)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Fallback if WaitingScreenAnimator is not available
|
||||
this.drawFallbackWaitingScreen();
|
||||
}
|
||||
|
||||
// Show the animation toggle button
|
||||
this.showAnimationButton();
|
||||
|
||||
// Start animation loop if not already running
|
||||
if (animationEnabled && typeof WaitingScreenAnimator !== 'undefined') {
|
||||
WaitingScreenAnimator.startAnimation();
|
||||
}
|
||||
},
|
||||
|
||||
showAnimationButton: function() {
|
||||
// First ensure the button exists
|
||||
if (!this.ensureAnimationButton()) {
|
||||
console.error("❌ Cannot show animation button - element missing from DOM");
|
||||
return;
|
||||
}
|
||||
|
||||
const animButton = document.getElementById('animationToggleButton');
|
||||
if (animButton) {
|
||||
animButton.style.display = 'inline-block';
|
||||
animButton.style.visibility = 'visible';
|
||||
|
||||
const animationEnabled = (typeof WaitingScreenAnimator !== 'undefined') ?
|
||||
WaitingScreenAnimator.isAnimationEnabled() : false;
|
||||
animButton.textContent = animationEnabled ? '🎬 DISABLE ANIMATION' : '🎬 ENABLE ANIMATION';
|
||||
} else {
|
||||
// Animation button element not found - non-critical warning
|
||||
// console.warn("❌ Animation button element not found!");
|
||||
}
|
||||
},
|
||||
|
||||
hideAnimationButton: function() {
|
||||
const animButton = document.getElementById('animationToggleButton');
|
||||
if (animButton) {
|
||||
animButton.style.display = 'none';
|
||||
}
|
||||
},
|
||||
|
||||
ensureAnimationButton: function() {
|
||||
let animButton = document.getElementById('animationToggleButton');
|
||||
|
||||
if (!animButton) {
|
||||
// Animation button not found - create or handle missing button
|
||||
const statusDiv = document.querySelector('.status');
|
||||
if (statusDiv) {
|
||||
const existingButtons = statusDiv.querySelectorAll('button');
|
||||
// Check existing buttons for debugging
|
||||
for (let btn of existingButtons) {
|
||||
// Button discovery for debugging
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
stopWaitingScreen: function() {
|
||||
if (typeof WaitingScreenAnimator !== 'undefined') {
|
||||
WaitingScreenAnimator.stopAnimation();
|
||||
}
|
||||
this.hideAnimationButton();
|
||||
if (!DisplayManager.ensureDisplay()) return;
|
||||
DisplayManager.clearDisplay();
|
||||
},
|
||||
|
||||
drawFallbackWaitingScreen: function() {
|
||||
this.drawBorder();
|
||||
let y = Math.floor(this._screenHeight / 2) - 1;
|
||||
this.drawCenteredText(y, "Waiting for next block...");
|
||||
this.drawCenteredText(y + 1, "Loading animation module...");
|
||||
}
|
||||
};
|
||||
|
||||
// Make it available globally
|
||||
if (typeof window !== 'undefined') {
|
||||
window.ScreenManager = ScreenManager;
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
// WaitingScreenAnimator - Handles waiting screen animations and visual effects
|
||||
var WaitingScreenAnimator = {
|
||||
_animationEnabled: true,
|
||||
_waitingAnimationInterval: null,
|
||||
_waitingAnimation: {
|
||||
frame: 0,
|
||||
playerX: 8,
|
||||
playerY: 12,
|
||||
monsterX: 5,
|
||||
monsterY: 12,
|
||||
treasureX: 35,
|
||||
treasureY: 12,
|
||||
phase: 'enter',
|
||||
frameCount: 0,
|
||||
direction: 1
|
||||
},
|
||||
|
||||
init: function() {
|
||||
this._animationEnabled = true;
|
||||
this._waitingAnimationInterval = null;
|
||||
this.resetAnimation();
|
||||
},
|
||||
|
||||
drawStaticWaitingScreen: function(screenWidth, screenHeight, drawBorderFn, drawCenteredTextFn) {
|
||||
if (!DisplayManager.ensureDisplay()) return;
|
||||
const display = DisplayManager.getDisplay();
|
||||
|
||||
// Draw border
|
||||
drawBorderFn();
|
||||
|
||||
let y = Math.floor(screenHeight / 2) - 2;
|
||||
drawCenteredTextFn(y, "Waiting for next block...");
|
||||
drawCenteredTextFn(y + 1, "Your game will start soon");
|
||||
|
||||
// Draw a simple but elegant static dungeon scene
|
||||
const centerX = Math.floor(screenWidth / 2);
|
||||
const roomY = y + 3;
|
||||
|
||||
// Draw a simple room outline
|
||||
const roomWidth = 12;
|
||||
const startX = centerX - Math.floor(roomWidth / 2);
|
||||
|
||||
// Room walls
|
||||
for (let x = startX; x < startX + roomWidth; x++) {
|
||||
display.draw(x, roomY - 1, "#", "transparent", "transparent"); // Top wall
|
||||
display.draw(x, roomY + 1, "#", "transparent", "transparent"); // Bottom wall
|
||||
}
|
||||
display.draw(startX - 1, roomY, "#", "transparent", "transparent"); // Left wall
|
||||
display.draw(startX + roomWidth, roomY, "#", "transparent", "transparent"); // Right wall
|
||||
|
||||
// Floor tiles
|
||||
for (let x = startX; x < startX + roomWidth; x++) {
|
||||
display.draw(x, roomY, GameTiles.getFloorTile(), "white", "transparent");
|
||||
}
|
||||
|
||||
// Entrance and exit
|
||||
display.draw(startX - 2, roomY, "<", "transparent", "transparent"); // Entrance
|
||||
display.draw(startX + roomWidth + 1, roomY, ">", "transparent", "transparent"); // Exit
|
||||
|
||||
// Characters in static positions
|
||||
display.draw(startX + 2, roomY, GameTiles.getPlayerTile(), "white", "transparent"); // Player
|
||||
display.draw(centerX, roomY, GameTiles.getTreasureTile(), "white", "transparent"); // Treasure
|
||||
display.draw(startX + roomWidth - 2, roomY, GameTiles.getMonsterTile(), "white", "transparent"); // Monster
|
||||
|
||||
// Add some decorative floor elements
|
||||
display.draw(startX + 1, roomY, GameTiles.getFloorTile(true), "white", "transparent"); // Floor variation
|
||||
display.draw(startX + roomWidth - 1, roomY, GameTiles.getFloorTile(true), "white", "transparent"); // Floor variation
|
||||
},
|
||||
|
||||
drawAnimatedWaitingScreen: function(screenWidth, screenHeight, drawBorderFn, drawCenteredTextFn) {
|
||||
if (!DisplayManager.ensureDisplay()) return;
|
||||
const display = DisplayManager.getDisplay();
|
||||
|
||||
// Draw border
|
||||
drawBorderFn();
|
||||
|
||||
// Fixed-position animated text
|
||||
let y = Math.floor(screenHeight / 2) - 8;
|
||||
const baseText = "Awaiting next block";
|
||||
const dots = ".".repeat((Math.floor(Date.now() / 500) % 4));
|
||||
const paddedDots = dots.padEnd(3, " ");
|
||||
drawCenteredTextFn(y, `${baseText}${paddedDots}`);
|
||||
|
||||
// ✨ EPIC DUNGEON SCENE WITH PROPER TRANSPARENCY ✨
|
||||
const roomStartX = 6;
|
||||
const roomEndX = 44;
|
||||
const roomStartY = 8;
|
||||
const roomEndY = 16;
|
||||
const time = Date.now();
|
||||
|
||||
// 🏛️ BASE DUNGEON FLOOR - Dark stone with subtle variation
|
||||
for (let x = roomStartX; x <= roomEndX; x++) {
|
||||
for (let dy = roomStartY; dy <= roomEndY; dy++) {
|
||||
if (x >= 0 && x < screenWidth && dy >= 0 && dy < screenHeight) {
|
||||
const floorTile = GameTiles.getFloorTile(true);
|
||||
|
||||
// Dark atmospheric base - no white foregrounds!
|
||||
const baseAlpha = 0.1 + Math.sin(x * 0.2 + dy * 0.3) * 0.05;
|
||||
display.draw(x, dy, floorTile, `rgba(100, 80, 60, ${baseAlpha})`, "transparent");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 🧱 DUNGEON WALLS - Ancient stone with moss
|
||||
for (let x = roomStartX; x <= roomEndX; x++) {
|
||||
if (x >= 0 && x < screenWidth) {
|
||||
const wallGlow = 0.2 + Math.sin(time * 0.001 + x * 0.1) * 0.1;
|
||||
display.draw(x, roomStartY - 1, "#", `rgba(80, 70, 50, ${wallGlow})`, "transparent");
|
||||
display.draw(x, roomEndY + 1, "#", `rgba(80, 70, 50, ${wallGlow})`, "transparent");
|
||||
}
|
||||
}
|
||||
for (let dy = roomStartY; dy <= roomEndY; dy++) {
|
||||
if (dy >= 0 && dy < screenHeight) {
|
||||
const wallGlow = 0.2 + Math.sin(time * 0.001 + dy * 0.1) * 0.1;
|
||||
display.draw(roomStartX - 1, dy, "#", `rgba(80, 70, 50, ${wallGlow})`, "transparent");
|
||||
display.draw(roomEndX + 1, dy, "#", `rgba(80, 70, 50, ${wallGlow})`, "transparent");
|
||||
}
|
||||
}
|
||||
|
||||
// 🔥 MYSTICAL TORCHES - Dancing flames with heat distortion
|
||||
const torchPositions = [
|
||||
{x: roomStartX - 1, y: roomStartY + 2},
|
||||
{x: roomEndX + 1, y: roomStartY + 2},
|
||||
{x: roomStartX - 1, y: roomEndY - 2},
|
||||
{x: roomEndX + 1, y: roomEndY - 2}
|
||||
];
|
||||
|
||||
for (let i = 0; i < torchPositions.length; i++) {
|
||||
const torch = torchPositions[i];
|
||||
if (torch.x >= 0 && torch.x < screenWidth && torch.y >= 0 && torch.y < screenHeight) {
|
||||
// Main torch flame - animated intensity with tile stack
|
||||
const flameIntensity = 0.6 + Math.sin(time / 200 + i) * 0.4;
|
||||
const flameColor = `rgba(255, ${100 + flameIntensity * 100}, 20, ${flameIntensity})`;
|
||||
const wallGlow = 0.2 + Math.sin(time * 0.001 + torch.x * 0.1) * 0.1;
|
||||
const wallColor = `rgba(80, 70, 50, ${wallGlow})`;
|
||||
|
||||
// Use tile stack for proper layering: wall + torch
|
||||
const ch = ["#", "torch"];
|
||||
const fg = [wallColor, flameColor];
|
||||
const bg = ["transparent", "transparent"];
|
||||
display.draw(torch.x, torch.y, ch, fg, bg);
|
||||
|
||||
// Light pool around torch - warm orange glow
|
||||
const lightRadius = 3 + Math.sin(time / 200 + i) * 0.5;
|
||||
for (let lx = torch.x - 3; lx <= torch.x + 3; lx++) {
|
||||
for (let ly = torch.y - 3; ly <= torch.y + 3; ly++) {
|
||||
if (lx >= roomStartX && lx <= roomEndX && ly >= roomStartY && ly <= roomEndY) {
|
||||
const dist = Math.sqrt((lx - torch.x) ** 2 + (ly - torch.y) ** 2);
|
||||
if (dist <= lightRadius) {
|
||||
const lightIntensity = Math.max(0, (lightRadius - dist) / lightRadius);
|
||||
const warmth = 0.05 + lightIntensity * 0.15;
|
||||
const floorTile = GameTiles.getFloorTile();
|
||||
display.draw(lx, ly, floorTile, `rgba(255, 180, 80, ${warmth})`, "transparent");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update character positions
|
||||
this.updateAnimation();
|
||||
const anim = this._waitingAnimation;
|
||||
|
||||
// 💎 LEGENDARY TREASURE - Pulsating with magical energy
|
||||
if (anim.treasureX >= 0 && anim.treasureX < screenWidth) {
|
||||
// Treasure magical effects - golden glow with sparkles
|
||||
const treasurePulse = 0.6 + Math.sin(time / 250) * 0.4;
|
||||
const magicShimmer = Math.sin(time / 100) * 0.3 + 0.7;
|
||||
|
||||
// Main treasure glow with tile stack
|
||||
const treasureGlow = `rgba(255, 215, 0, ${treasurePulse})`;
|
||||
const floorTile = GameTiles.getFloorTile();
|
||||
const baseAlpha = 0.1 + Math.sin(anim.treasureX * 0.2 + anim.treasureY * 0.3) * 0.05;
|
||||
const ch = [floorTile, GameTiles.getTreasureTile()];
|
||||
const fg = [`rgba(100, 80, 60, ${baseAlpha})`, treasureGlow];
|
||||
const bg = ["transparent", "transparent"];
|
||||
display.draw(anim.treasureX, anim.treasureY, ch, fg, bg);
|
||||
|
||||
// Magic sparkles around treasure
|
||||
const sparklePositions = [
|
||||
{x: anim.treasureX - 1, y: anim.treasureY - 1},
|
||||
{x: anim.treasureX + 1, y: anim.treasureY + 1},
|
||||
{x: anim.treasureX - 1, y: anim.treasureY + 1},
|
||||
{x: anim.treasureX + 1, y: anim.treasureY - 1}
|
||||
];
|
||||
|
||||
for (let sparkle of sparklePositions) {
|
||||
if (sparkle.x >= roomStartX && sparkle.x <= roomEndX && sparkle.y >= roomStartY && sparkle.y <= roomEndY) {
|
||||
const sparkleIntensity = Math.max(0, Math.sin(time / 150 + sparkle.x + sparkle.y) * 0.4);
|
||||
if (sparkleIntensity > 0.2) {
|
||||
const floorTile = GameTiles.getFloorTile();
|
||||
display.draw(sparkle.x, sparkle.y, floorTile, `rgba(255, 255, 150, ${sparkleIntensity})`, "transparent");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 🧙♂️ HEROIC PLAYER - Glowing with determination
|
||||
if (anim.playerX >= 0 && anim.playerX < screenWidth) {
|
||||
// Player aura - heroic blue/white glow
|
||||
const heroGlow = 0.4 + Math.sin(time / 300) * 0.2;
|
||||
const heroColor = `rgba(100, 150, 255, ${heroGlow})`;
|
||||
|
||||
// Use tile stack: floor + player for proper layering
|
||||
const floorTile = GameTiles.getFloorTile();
|
||||
const baseAlpha = 0.1 + Math.sin(anim.playerX * 0.2 + anim.playerY * 0.3) * 0.05;
|
||||
const ch = [floorTile, "@"];
|
||||
const fg = [`rgba(100, 80, 60, ${baseAlpha})`, heroColor];
|
||||
const bg = ["transparent", "transparent"];
|
||||
display.draw(anim.playerX, anim.playerY, ch, fg, bg);
|
||||
|
||||
// Light footsteps behind player
|
||||
if (anim.phase === 'enter' || anim.phase === 'escape') {
|
||||
const footstepX = anim.playerX - 1;
|
||||
if (footstepX >= roomStartX && footstepX <= roomEndX) {
|
||||
const footstepGlow = Math.max(0, Math.sin(time / 400) * 0.2);
|
||||
const floorTile = GameTiles.getFloorTile();
|
||||
display.draw(footstepX, anim.playerY, floorTile, `rgba(150, 200, 255, ${footstepGlow})`, "transparent");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 👹 TERRIFYING MONSTER - Darkness incarnate with red menace
|
||||
if (anim.monsterX >= 0 && anim.monsterX < screenWidth) {
|
||||
// Monster's menacing red glow - more intense than before
|
||||
const menacePulse = 0.3 + Math.sin(time / 180) * 0.4;
|
||||
const fearColor = `rgba(255, 30, 30, ${menacePulse})`;
|
||||
|
||||
// Use tile stack: floor + monster for proper layering
|
||||
const floorTile = GameTiles.getFloorTile();
|
||||
const baseAlpha = 0.1 + Math.sin(anim.monsterX * 0.2 + anim.monsterY * 0.3) * 0.05;
|
||||
const ch = [floorTile, "~"];
|
||||
const fg = [`rgba(100, 80, 60, ${baseAlpha})`, fearColor];
|
||||
const bg = ["transparent", "transparent"];
|
||||
display.draw(anim.monsterX, anim.monsterY, ch, fg, bg);
|
||||
|
||||
// Spreading darkness around monster
|
||||
const shadowRadius = 2 + Math.sin(time / 220) * 0.5;
|
||||
for (let sx = anim.monsterX - 2; sx <= anim.monsterX + 2; sx++) {
|
||||
for (let sy = anim.monsterY - 2; sy <= anim.monsterY + 2; sy++) {
|
||||
if (sx >= roomStartX && sx <= roomEndX && sy >= roomStartY && sy <= roomEndY) {
|
||||
const dist = Math.sqrt((sx - anim.monsterX) ** 2 + (sy - anim.monsterY) ** 2);
|
||||
if (dist <= shadowRadius && !(sx === anim.monsterX && sy === anim.monsterY)) {
|
||||
const shadowIntensity = Math.max(0, (shadowRadius - dist) / shadowRadius * 0.3);
|
||||
const darkPulse = Math.sin(time / 300 + dist) * 0.1;
|
||||
const floorTile = GameTiles.getFloorTile();
|
||||
display.draw(sx, sy, floorTile, `rgba(100, 0, 0, ${shadowIntensity + darkPulse})`, "transparent");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 🚪 MYSTICAL PORTALS - Entrance and exit with swirling energy
|
||||
const portalPulse = 0.3 + Math.sin(time / 400) * 0.2;
|
||||
const entranceGlow = `rgba(50, 255, 50, ${portalPulse})`; // Green entrance
|
||||
const exitGlow = `rgba(255, 100, 255, ${portalPulse})`; // Purple exit
|
||||
|
||||
display.draw(roomStartX - 1, 12, '<', entranceGlow, "transparent");
|
||||
display.draw(roomEndX + 1, 12, '>', exitGlow, "transparent");
|
||||
},
|
||||
|
||||
updateAnimation: function() {
|
||||
const anim = this._waitingAnimation;
|
||||
anim.frameCount++;
|
||||
|
||||
// Smooth animation timing - update every 4 frames for fluid movement
|
||||
if (anim.frameCount % 4 !== 0) return;
|
||||
|
||||
switch(anim.phase) {
|
||||
case 'enter':
|
||||
// Player enters from left, smooth movement toward treasure
|
||||
if (anim.playerX < anim.treasureX - 2) {
|
||||
anim.playerX++;
|
||||
} else {
|
||||
anim.phase = 'monster_enter';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'monster_enter':
|
||||
// Monster enters and starts chase
|
||||
if (anim.monsterX < anim.playerX - 3) {
|
||||
anim.monsterX++;
|
||||
} else {
|
||||
anim.phase = 'chase';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'chase':
|
||||
// Dramatic chase sequence - both moving
|
||||
if (anim.playerX < anim.treasureX) {
|
||||
anim.playerX++;
|
||||
if (anim.monsterX < anim.playerX - 2) {
|
||||
anim.monsterX++;
|
||||
}
|
||||
} else {
|
||||
anim.treasureX = -1; // Player gets treasure
|
||||
anim.phase = Math.random() < 0.7 ? 'escape' : 'caught';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'escape':
|
||||
// Player successfully escapes with treasure
|
||||
if (anim.playerX < 46) {
|
||||
anim.playerX++;
|
||||
if (anim.monsterX < anim.playerX - 1) {
|
||||
anim.monsterX++;
|
||||
}
|
||||
} else {
|
||||
anim.phase = 'exit';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'caught':
|
||||
// Monster catches player - dramatic end
|
||||
if (anim.monsterX < anim.playerX) {
|
||||
anim.monsterX++;
|
||||
} else {
|
||||
anim.playerX = -1; // Player vanishes
|
||||
anim.phase = 'exit';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'exit':
|
||||
// Brief pause then reset
|
||||
if (anim.frameCount > anim.frameCount + 20) {
|
||||
this.resetAnimation();
|
||||
} else {
|
||||
// Monster exits
|
||||
if (anim.monsterX < 48) {
|
||||
anim.monsterX++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
resetAnimation: function() {
|
||||
this._waitingAnimation = {
|
||||
frame: 0,
|
||||
playerX: 8, // Start near entrance
|
||||
playerY: 12,
|
||||
monsterX: 5, // Start at entrance
|
||||
monsterY: 12,
|
||||
treasureX: 35, // Treasure near exit
|
||||
treasureY: 12,
|
||||
phase: 'enter',
|
||||
frameCount: 0,
|
||||
direction: 1
|
||||
};
|
||||
},
|
||||
|
||||
toggleAnimation: function() {
|
||||
this._animationEnabled = !this._animationEnabled;
|
||||
console.log("WaitingScreenAnimator: Animation toggled:", this._animationEnabled ? "enabled" : "disabled");
|
||||
|
||||
if (!this._animationEnabled) {
|
||||
this.resetAnimation();
|
||||
}
|
||||
|
||||
return this._animationEnabled;
|
||||
},
|
||||
|
||||
startAnimation: function() {
|
||||
// Clear any existing interval
|
||||
if (this._waitingAnimationInterval) {
|
||||
clearInterval(this._waitingAnimationInterval);
|
||||
}
|
||||
|
||||
// Start new animation loop
|
||||
this._waitingAnimationInterval = setInterval(() => {
|
||||
if (this._animationEnabled && !GameState.isGameActive()) {
|
||||
// Trigger a redraw in the main screen manager
|
||||
if (typeof ScreenManager !== 'undefined' && ScreenManager.drawWaitingScreen) {
|
||||
ScreenManager.drawWaitingScreen();
|
||||
}
|
||||
} else {
|
||||
this.stopAnimation();
|
||||
}
|
||||
}, 100); // 10 FPS animation
|
||||
},
|
||||
|
||||
stopAnimation: function() {
|
||||
if (this._waitingAnimationInterval) {
|
||||
clearInterval(this._waitingAnimationInterval);
|
||||
this._waitingAnimationInterval = null;
|
||||
}
|
||||
this.resetAnimation();
|
||||
},
|
||||
|
||||
isAnimationEnabled: function() {
|
||||
return this._animationEnabled;
|
||||
}
|
||||
};
|
||||
|
||||
// Make it available globally
|
||||
if (typeof window !== 'undefined') {
|
||||
window.WaitingScreenAnimator = WaitingScreenAnimator;
|
||||
}
|
||||
Reference in New Issue
Block a user