diff --git a/html/index.html b/html/index.html
index 56ccef6..7920db3 100644
--- a/html/index.html
+++ b/html/index.html
@@ -21,6 +21,7 @@
+
diff --git a/html/js/options.js b/html/js/options.js
index d51b640..97aec42 100644
--- a/html/js/options.js
+++ b/html/js/options.js
@@ -26,7 +26,7 @@ var options = {
gameConfig: {
playerType: "@", // Options: "@", "@2"
treasureType: "$W", // Options: "$W" (Wownero), "$M" (Monero), "$B" (Bitcoin), "$" (Regular)
- monsterType: "~", // Options: "~", "~2"
+ monsterType: "~2", // Options: "~", "~2"
// Floor tile configuration
primaryFloor: "'1", // Main floor tile (99% of floors)
diff --git a/html/js/screenManager.js b/html/js/screenManager.js
index 9e34dcf..9ea60f0 100644
--- a/html/js/screenManager.js
+++ b/html/js/screenManager.js
@@ -5,19 +5,6 @@ var ScreenManager = {
_blockTimer: null,
_updateInterval: null, // Track the update interval separately
_waitingForBlock: false,
- _animationEnabled: true,
- _waitingAnimation: {
- frame: 0,
- playerX: 8,
- playerY: 12,
- monsterX: 5,
- monsterY: 12,
- treasureX: 35,
- treasureY: 12,
- phase: 'enter',
- frameCount: 0,
- direction: 1
- },
init: function(screenWidth, screenHeight) {
this._screenWidth = screenWidth;
@@ -25,6 +12,11 @@ var ScreenManager = {
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) {
@@ -134,354 +126,10 @@ var ScreenManager = {
- drawStaticWaitingScreen: function() {
- if (!DisplayManager.ensureDisplay()) return;
- const display = DisplayManager.getDisplay();
-
- // Draw border
- this.drawBorder();
-
- let y = Math.floor(this._screenHeight / 2) - 2;
- this.drawCenteredText(y, "Waiting for next block...");
- this.drawCenteredText(y + 1, "Your game will start soon");
-
- // Draw a simple but elegant static dungeon scene
- const centerX = Math.floor(this._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() {
- if (!DisplayManager.ensureDisplay()) return;
- const display = DisplayManager.getDisplay();
-
- // Draw border
- this.drawBorder();
-
- // Fixed-position animated text
- let y = Math.floor(this._screenHeight / 2) - 8;
- const baseText = "Waiting for next block";
- const dots = ".".repeat((Math.floor(Date.now() / 500) % 4));
- const paddedDots = dots.padEnd(3, " ");
- this.drawCenteredText(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 < this._screenWidth && dy >= 0 && dy < this._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 - 1; x <= roomEndX + 1; x++) {
- if (x >= 0 && x < this._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 < this._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 < this._screenWidth && torch.y >= 0 && torch.y < this._screenHeight) {
- // Main torch flame - animated intensity with tile stack
- const flameIntensity = 0.7 + Math.sin(time / 120 + i * 1.2) * 0.3;
- const flameColor = `rgba(255, ${100 + flameIntensity * 100}, 20, ${flameIntensity})`;
-
- // Use tile stack: wall + torch for proper layering
- const wallGlow = 0.2 + Math.sin(time * 0.001 + torch.x * 0.1) * 0.1;
- const ch = ["#", "torch"];
- const fg = [`rgba(80, 70, 50, ${wallGlow})`, flameColor];
- const bg = ["transparent", "transparent"];
- display.draw(torch.x, torch.y, ch, fg, bg);
-
- // Heat distortion around torch
- const heatPositions = [
- {x: torch.x, y: torch.y - 1}, {x: torch.x, y: torch.y + 1},
- {x: torch.x - 1, y: torch.y}, {x: torch.x + 1, y: torch.y}
- ];
-
- for (let heat of heatPositions) {
- if (heat.x >= roomStartX && heat.x <= roomEndX && heat.y >= roomStartY && heat.y <= roomEndY) {
- const shimmer = 0.1 + Math.sin(time / 80 + heat.x + heat.y) * 0.05;
- const floorTile = GameTiles.getFloorTile();
- display.draw(heat.x, heat.y, floorTile, `rgba(255, 150, 50, ${shimmer})`, "transparent");
- }
- }
-
- // Torch light radius - 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.updateWaitingAnimation();
- const anim = this._waitingAnimation;
-
- // 💎 LEGENDARY TREASURE - Pulsating with magical energy
- if (anim.treasureX >= 0 && anim.treasureX < this._screenWidth) {
- 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 < this._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 < this._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");
- },
-
- updateWaitingAnimation: 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.resetWaitingAnimation();
- } else {
- // Monster exits
- if (anim.monsterX < 48) {
- anim.monsterX++;
- }
- }
- break;
- }
- },
-
- resetWaitingAnimation: 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("Animation toggled:", this._animationEnabled ? "enabled" : "disabled");
-
- if (!this._animationEnabled) {
- this.resetWaitingAnimation();
+ if (typeof WaitingScreenAnimator !== 'undefined') {
+ WaitingScreenAnimator.toggleAnimation();
}
},
@@ -587,20 +235,39 @@ var ScreenManager = {
if (!DisplayManager.ensureDisplay()) return;
DisplayManager.clearDisplay();
- console.log("🎬 Drawing waiting screen, animation enabled:", this._animationEnabled);
+ const animationEnabled = (typeof WaitingScreenAnimator !== 'undefined') ?
+ WaitingScreenAnimator.isAnimationEnabled() : false;
- if (this._animationEnabled) {
- this.drawAnimatedWaitingScreen();
+ console.log("🎬 Drawing waiting screen, animation enabled:", animationEnabled);
+
+ // 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 {
- this.drawStaticWaitingScreen();
+ // Fallback if WaitingScreenAnimator is not available
+ this.drawFallbackWaitingScreen();
}
// Show the animation toggle button
this.showAnimationButton();
// Start animation loop if not already running
- if (this._animationEnabled && !this._waitingAnimationInterval) {
- this.startWaitingAnimation();
+ if (animationEnabled && typeof WaitingScreenAnimator !== 'undefined') {
+ WaitingScreenAnimator.startAnimation();
}
},
@@ -615,7 +282,10 @@ var ScreenManager = {
if (animButton) {
animButton.style.display = 'inline-block';
animButton.style.visibility = 'visible';
- animButton.textContent = this._animationEnabled ? '🎬 DISABLE ANIMATION' : '🎬 ENABLE ANIMATION';
+
+ const animationEnabled = (typeof WaitingScreenAnimator !== 'undefined') ?
+ WaitingScreenAnimator.isAnimationEnabled() : false;
+ animButton.textContent = animationEnabled ? '🎬 DISABLE ANIMATION' : '🎬 ENABLE ANIMATION';
console.log("✅ Animation button shown:", animButton.textContent);
} else {
console.warn("❌ Animation button element not found!");
@@ -649,35 +319,20 @@ var ScreenManager = {
return true;
},
- startWaitingAnimation: function() {
- // Clear any existing interval
- if (this._waitingAnimationInterval) {
- clearInterval(this._waitingAnimationInterval);
- }
-
- // Start new animation loop
- this._waitingAnimationInterval = setInterval(() => {
- if (this._animationEnabled && !GameState.isGameActive()) {
- this.drawWaitingScreen();
- } else {
- this.stopWaitingAnimation();
- }
- }, 100); // 10 FPS animation
- },
-
- stopWaitingAnimation: function() {
- if (this._waitingAnimationInterval) {
- clearInterval(this._waitingAnimationInterval);
- this._waitingAnimationInterval = null;
- }
- this.resetWaitingAnimation();
- },
-
stopWaitingScreen: function() {
- this.stopWaitingAnimation();
+ 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...");
}
};
diff --git a/html/js/waitingScreenAnimator.js b/html/js/waitingScreenAnimator.js
new file mode 100644
index 0000000..8eabba8
--- /dev/null
+++ b/html/js/waitingScreenAnimator.js
@@ -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;
+}
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/game/dungeon.js b/src/game/dungeon.js
index b48a9e0..8874033 100644
--- a/src/game/dungeon.js
+++ b/src/game/dungeon.js
@@ -6,8 +6,8 @@ const ROT = require('./rot.js');
// Edit these values to customize dungeon generation
const DUNGEON_CONFIGS = {
// Default dungeon dimensions
- DEFAULT_WIDTH: 80,
- DEFAULT_HEIGHT: 40,
+ DEFAULT_WIDTH: 40,
+ DEFAULT_HEIGHT: 20,
// Legacy smaller dungeon size (for compatibility)
LEGACY_WIDTH: 25,
@@ -20,7 +20,7 @@ const DUNGEON_CONFIGS = {
DUG_PERCENTAGE: 0.2,
// Lighting and appearance
- TORCH_DENSITY: 0.2, // 20% chance for torches on wall tiles adjacent to floors
+ TORCH_DENSITY: 0.1, // 20% chance for torches on wall tiles adjacent to floors
TORCH_ENABLED: true, // Set to false to disable torches completely
FLOOR_VARIATION: 0.01, // Chance for secondary floor tiles (visual variety)