about summary refs log tree commit diff stats
path: root/html/plains/game.js
diff options
context:
space:
mode:
authorelioat <{ID}+{username}@users.noreply.github.com>2024-12-19 17:07:34 -0500
committerelioat <{ID}+{username}@users.noreply.github.com>2024-12-19 17:07:34 -0500
commit8a8ad9ab33524769b5327be78cfaadb426cf859d (patch)
treec58d1559f79dce24a80bbe47ba382be2c9525669 /html/plains/game.js
parent293df8c03c9307156f98b285674148e65ad896fa (diff)
downloadtour-8a8ad9ab33524769b5327be78cfaadb426cf859d.tar.gz
*
Diffstat (limited to 'html/plains/game.js')
-rw-r--r--html/plains/game.js252
1 files changed, 73 insertions, 179 deletions
diff --git a/html/plains/game.js b/html/plains/game.js
index 2b4f342..5b23e5b 100644
--- a/html/plains/game.js
+++ b/html/plains/game.js
@@ -1,4 +1,3 @@
-// ============= Utility Functions =============
 const lerp = (start, end, t) => {
     return start * (1 - t) + end * t;
 };
@@ -13,7 +12,6 @@ const worldToGrid = (x, y) => ({
     y: Math.floor(y / CONFIG.display.grid.size)
 });
 
-// Add the villager-related functions here
 const generateVillagers = () => {
     const villagers = [];
     const occupiedCells = new Set();
@@ -21,7 +19,7 @@ const generateVillagers = () => {
     const villageSize = CONFIG.world.village.size;
     const worldSize = CONFIG.display.grid.worldSize;
     
-    // First, place one villager near the village
+    // place one villager near the village, so that hopefully the player can find them easily
     const nearVillageX = villageSize + Math.floor(Math.random() * 2);
     const nearVillageY = villageSize + Math.floor(Math.random() * 2);
     
@@ -33,24 +31,24 @@ const generateVillagers = () => {
         status: 'lost',
         cellX: nearVillageX,
         cellY: nearVillageY,
-        bobSpeed: 0.005 + Math.random() * 0.005, // Random speed for rescued villagers
-        bobAmplitude: 2 + Math.random() * 2, // Random amplitude for rescued villagers
-        lostBobSpeed: 0.005 + Math.random() * 0.005, // Random speed for lost villagers
-        lostBobAmplitude: 2 + Math.random() * 2 // Random amplitude for lost villagers
+        bobSpeed: 0.005 + Math.random() * 0.005,
+        bobAmplitude: 2 + Math.random() * 2,
+        lostBobSpeed: 0.005 + Math.random() * 0.005,
+        lostBobAmplitude: 2 + Math.random() * 2
     });
     occupiedCells.add(`${nearVillageX},${nearVillageY}`);
 
-    // Place remaining villagers
     while (villagers.length < CONFIG.world.villagers.total) {
         const cellX = villageSize + Math.floor(Math.random() * (worldSize - villageSize));
         const cellY = villageSize + Math.floor(Math.random() * (worldSize - villageSize));
         const cellKey = `${cellX},${cellY}`;
 
-        // Skip if cell is occupied or has a tree
+        // try not to put villagers into trees...but this doesn't always work
         if (occupiedCells.has(cellKey) || state.collisionMap.has(cellKey)) {
             continue;
         }
 
+        // look...sometimes copy and paste is easy and good
         villagers.push({
             x: (cellX * gridSize) + (gridSize / 2),
             y: (cellY * gridSize) + (gridSize / 2),
@@ -59,10 +57,10 @@ const generateVillagers = () => {
             status: 'lost',
             cellX,
             cellY,
-            bobSpeed: 0.005 + Math.random() * 0.005, // Random speed for rescued villagers
-            bobAmplitude: 2 + Math.random() * 2, // Random amplitude for rescued villagers
-            lostBobSpeed: 0.005 + Math.random() * 0.005, // Random speed for lost villagers
-            lostBobAmplitude: 2 + Math.random() * 2 // Random amplitude for lost villagers
+            bobSpeed: 0.005 + Math.random() * 0.005,
+            bobAmplitude: 2 + Math.random() * 2,
+            lostBobSpeed: 0.005 + Math.random() * 0.005,
+            lostBobAmplitude: 2 + Math.random() * 2
         });
         occupiedCells.add(cellKey);
     }
@@ -108,7 +106,7 @@ const drawVillagerShape = (ctx, x, y, shape, size) => {
     ctx.closePath();
 };
 
-// ============= Configuration =============
+
 const CONFIG = {
     display: {
         fps: 60,
@@ -145,21 +143,21 @@ const CONFIG = {
         },
         dash: {
             duration: 3000,    // 3 seconds of use
-            cooldown: 1000,    // 1 second cooldown
-            exhaustedAt: 0     // Track when dash was exhausted
+            cooldown: 3000,    // 3 second cooldown
+            exhaustedAt: 0
         },
         idle: {
-            startDelay: 1500,    // Start idle animation after 1.5 seconds
-            lookSpeed: 0.001,    // Speed of the looking animation
-            lookRadius: 0.4      // How far to look around (in radians)
+            startDelay: 1500,    // Get board after 1.5 seconds
+            lookSpeed: 0.001,
+            lookRadius: 0.4
         },
         equipment: {
-            swordUnlockCount: 5,  // Number of rescues needed to unlock sword
+            swordUnlockCount: 5,  // The number of villagers you need to rescue to unlock the sword
             unlockAnimation: {
-                duration: 1500,    // Duration of unlock animation in ms
-                glowColor: 'rgba(255, 215, 0, 0.6)',  // Golden glow
+                duration: 1500,
+                glowColor: 'rgba(255, 215, 0, 0.6)',
                 messageText: 'Sword Unlocked!',
-                messageColor: '#FFD700'  // Gold color for text
+                messageColor: '#FFD700'
             }
         }
     },
@@ -202,7 +200,7 @@ const CONFIG = {
             groundColor: '#f2f2f2'
         },
         villagers: {
-            total: 25,  // Total number of villagers to spawn
+            total: 25,
             colors: [
                 '#4B0082',  // Indigo
                 '#483D8B',  // DarkSlateBlue
@@ -212,15 +210,15 @@ const CONFIG = {
                 '#4682B4'   // SteelBlue
             ],
             shapes: ['square', 'triangle', 'pentagon', 'hexagon'],
-            size: 30,  // Same as player size
+            size: 30,
             rescueMessage: 'Congratulations! You rescued all the villagers!',
-            messageDisplayTime: 5000  // How long to show the completion message (ms)
+            messageDisplayTime: 5000
         },
         wilderness: {
             groundColor: '#e6ffe6',
             vegetation: {
                 tree: {
-                    frequency: 0.1,  // Chance per grid cell
+                    frequency: 0.1, // Chance per grid cell
                     colors: [
                         'rgba(100, 144, 79, 1)',
                         'rgba(85, 128, 64, 1)',
@@ -245,7 +243,7 @@ const CONFIG = {
                         margin: 10,
                         variation: 0.5,
                         offset: 0.5,
-                        singleColor: 0.7  // % chance that all dots in a cell will be the same color
+                        singleColor: 0.7 // % chance that all dots in a cell will be the same color
                     }
                 },
                 flower: {
@@ -258,7 +256,7 @@ const CONFIG = {
                     pattern: {
                         size: 12,
                         spacing: 16,
-                        rotation: Math.PI / 6,  // Base rotation of pattern
+                        rotation: Math.PI / 6, // rotation of pattern
                         margin: 10,
                         variation: 0.2
                     }
@@ -270,10 +268,10 @@ const CONFIG = {
                         spacing: 8,
                         length: 6,
                         angle: Math.PI / 4,
-                        variation: 0.4,   // Slight randomness in angle
+                        variation: 0.4, // we can have some randomness, as a treat
                         margin: 4
                     },
-                    spreadFactor: 0.6  // Add this for grass spreading
+                    spreadFactor: 0.6
                 }
             }
         }
@@ -313,15 +311,15 @@ const CONFIG = {
                 max: 200
             },
             speed: {
-                base: 100  // pixels per second
+                base: 100 // PPS, pixels per second
             }
         },
         chase: {
             range: 2,
-            speedMultiplier: 1.5  // 50% faster than base speed
+            speedMultiplier: 1.5
         },
         return: {
-            speedMultiplier: 1.25  // 25% faster than base speed
+            speedMultiplier: 1.25
         }
     }
 };
@@ -331,7 +329,6 @@ CONFIG.sword.colors = CONFIG.effects.colors;
 CONFIG.bubble.colors = CONFIG.effects.colors;
 
 
-// ============= Global State =============
 let GAME_WIDTH = window.innerWidth;
 let GAME_HEIGHT = window.innerHeight;
 let lastFrameTime = 0;
@@ -341,7 +338,6 @@ const CAMERA_DEADZONE_X = GAME_WIDTH * CONFIG.display.camera.deadzoneMultiplierX
 const CAMERA_DEADZONE_Y = GAME_HEIGHT * CONFIG.display.camera.deadzoneMultiplierY;
 
 
-// ============= State Management =============
 const createInitialState = () => ({
     player: {
         x: CONFIG.player.size,
@@ -367,8 +363,8 @@ const createInitialState = () => ({
         isInvulnerable: false,
         invulnerableUntil: 0,
         isDead: false,
-        diamonds: 0, // Track number of collected diamonds
-        lastRenderedCircles: 4, // Add this line
+        diamonds: 0,
+        lastRenderedCircles: 4
     },
     particles: [],
     footprints: [],
@@ -384,17 +380,15 @@ const createInitialState = () => ({
     gameComplete: false,
     gameCompleteMessageShown: false,
     enemies: [],
-    diamonds: [] // Array to hold diamond objects
+    diamonds: []
 });
 
 let state = createInitialState();
 
 
-// ============= Input Handling =============
 const keys = new Set();
 
 const handleKeyDown = (e) => {
-    // If player is dead, only handle restart
     if (state.player.isDead) {
         if (e.code === 'Space') {
             window.location.reload();
@@ -461,7 +455,7 @@ const inputHandlers = {
         if (state.player.isDefending) return state;
         
         if (state.player.equipment === 'sword') {
-            if (!state.player.swordUnlocked) return state; // Prevent sword usage if not unlocked
+            if (!state.player.swordUnlocked) return state; // can't swing a sword you haven't earned yet!
             if (!state.player.isSwinging) {
                 return {
                     ...state,
@@ -479,7 +473,7 @@ const inputHandlers = {
     },
 
     handleEquipmentSwitch: (state) => {
-        if (!state.player.swordUnlocked) return state; // Can't switch if sword isn't unlocked
+        if (!state.player.swordUnlocked) return state; // can't switch to a sword you haven't earned yet!
         
         const equipment = ['sword', 'unarmed'];
         const currentIndex = equipment.indexOf(state.player.equipment);
@@ -494,7 +488,6 @@ const inputHandlers = {
 };
 
 
-// ============= Movement System =============
 const calculateMovement = (keys) => {
     let dx = 0;
     let dy = 0;
@@ -508,7 +501,6 @@ const calculateMovement = (keys) => {
         return { moving: false };
     }
     
-    // Update last input time when moving
     state.player.lastInputTime = animationTime;
     
     const length = Math.sqrt(dx * dx + dy * dy);
@@ -519,9 +511,8 @@ const calculateMovement = (keys) => {
     
     const newDirection = isStrafing ? 
         { ...state.player.direction } : // strafe
-        { x: normalizedDx, y: normalizedDy }; // normal movement
+        { x: normalizedDx, y: normalizedDy }; // normal
     
-    // Update base direction when not strafing
     if (!isStrafing) {
         state.player.baseDirection = { ...newDirection };
     }
@@ -540,9 +531,9 @@ const isPositionBlocked = (x, y) => {
     if (!state.collisionMap.has(key)) return false;
 
     const obstacle = state.collisionMap.get(key);
-    const obstacleRadius = CONFIG.player.size / 2;  // Use player size for all collision
+    const obstacleRadius = CONFIG.player.size / 2;
 
-    // Distance check from center of grid cell
+    // check distance from the center of a grid cell
     const dx = x - obstacle.x;
     const dy = y - obstacle.y;
     const distanceSquared = dx * dx + dy * dy;
@@ -565,7 +556,6 @@ const movementSystem = {
         
         const movement = calculateMovement(keys);
         if (!movement.moving) {
-            // Reset dash when not moving
             return {
                 ...state,
                 player: {
@@ -591,7 +581,7 @@ const movementSystem = {
             }
             isDashing = true;
             
-            // Check if dash duration is exhausted
+            // Are you tired of dashing?
             if (animationTime - dashStartTime >= CONFIG.player.dash.duration) {
                 isDashing = false;
                 dashExhausted = true;
@@ -629,25 +619,22 @@ const movementSystem = {
             max: CONFIG.display.grid.size * CONFIG.display.grid.worldSize
         };
 
-        // After calculating new position, clamp it to world bounds
         const newX = state.player.x + movement.dx * speed;
         const newY = state.player.y + movement.dy * speed;
 
         const clampedX = Math.max(worldBounds.min, Math.min(worldBounds.max, newX));
         const clampedY = Math.max(worldBounds.min, Math.min(worldBounds.max, newY));
 
-        // Check for collisions at the new position
         const playerRadius = CONFIG.player.size / 2;
-        const checkPoints = [
-            { x: newX - playerRadius, y: newY - playerRadius }, // Top-left
-            { x: newX + playerRadius, y: newY - playerRadius }, // Top-right
-            { x: newX - playerRadius, y: newY + playerRadius }, // Bottom-left
-            { x: newX + playerRadius, y: newY + playerRadius }  // Bottom-right
-        ];
+        // const checkPoints = [
+        //     { x: newX - playerRadius, y: newY - playerRadius }, // Top-left
+        //     { x: newX + playerRadius, y: newY - playerRadius }, // Top-right
+        //     { x: newX - playerRadius, y: newY + playerRadius }, // Bottom-left
+        //     { x: newX + playerRadius, y: newY + playerRadius }  // Bottom-right
+        // ];
 
-        const wouldCollide = checkCollision(newX, newY, playerRadius * 0.8); // Use 80% of player radius for better feel
+        const wouldCollide = checkCollision(newX, newY, playerRadius * 0.8);
 
-        // Only update position if there's no collision
         const finalX = wouldCollide ? state.player.x : clampedX;
         const finalY = wouldCollide ? state.player.y : clampedY;
 
@@ -671,7 +658,6 @@ const movementSystem = {
 };
 
 
-// ============= Weapon Systems =============
 const updateBubble = (bubble, animationTime) => {
     const age = animationTime - bubble.createdAt;
     const ageRatio = age / CONFIG.bubble.lifetime;
@@ -749,7 +735,6 @@ const createBubbleAttack = (state, animationTime) => {
     };
 };
 
-// Update the collision helper to handle different damage amounts
 const checkEnemyCollision = (enemy, sourceX, sourceY, range, damage = 0) => {
     if (enemy.stunned) return false;
     
@@ -770,7 +755,6 @@ const weaponSystems = {
         const updatedBubbles = state.player.bubbles
             .filter(bubble => animationTime - bubble.createdAt < CONFIG.bubble.lifetime)
             .map(bubble => {
-                // Check for enemy collisions with 0 damage
                 state.enemies.forEach(enemy => {
                     checkEnemyCollision(enemy, bubble.x, bubble.y, CONFIG.bubble.size, 0);
                 });
@@ -793,13 +777,12 @@ const weaponSystems = {
         };
     },
 
-    updateSwordSwing: (state, animationTime) => {
+    updateSwordSwing: (state) => {
         if (!state.player.isSwinging) return state;
         
         const newAngle = state.player.swordAngle + CONFIG.sword.swingSpeed;
         const swingComplete = newAngle > Math.atan2(state.player.direction.y, state.player.direction.x) + Math.PI / 2;
         
-        // Check all enemies for sword collision with 1 damage
         const updatedEnemies = state.enemies.map(enemy => {
             checkEnemyCollision(enemy, state.player.x, state.player.y, CONFIG.sword.length, 1);
             return enemy;
@@ -818,7 +801,6 @@ const weaponSystems = {
 };
 
 
-// ============= Particle Systems =============
 const createParticle = (x, y, angle) => ({
     x,
     y,
@@ -839,7 +821,6 @@ const createFootprint = (x, y, direction) => ({
 });
 
 
-// ============= Rendering System =============
 const renderPlayer = () => {
     ctx.save();
     
@@ -1049,11 +1030,9 @@ const renderPlayer = () => {
         // Draw the eyeball...square
         const dotSize = CONFIG.player.directionIndicator.size;
         
-        // Calculate cooldown progress
-        const timeSinceLastBubble = animationTime - state.player.lastBubbleTime;
+        // const timeSinceLastBubble = animationTime - state.player.lastBubbleTime;
         // const cooldownProgress = Math.min(timeSinceLastBubble / CONFIG.bubble.cooldown, 1);
         
-        // Set opacity based on cooldown's progress
         const dotOpacity = getDotOpacity(state, animationTime);
         
         ctx.fillStyle = CONFIG.player.directionIndicator.color.replace(
@@ -1068,7 +1047,6 @@ const renderPlayer = () => {
             dotSize
         );
     } else {
-        // Draw player square
         ctx.fillStyle = CONFIG.player.color;
         ctx.fillRect(
             state.player.x - CONFIG.player.size / 2,
@@ -1077,7 +1055,7 @@ const renderPlayer = () => {
             CONFIG.player.size
         );
         
-        // Draw direction indicator square with cooldown opacity
+        // direction indicator square with cooldown opacity
         const dotSize = CONFIG.player.directionIndicator.size;
         const dotDistance = CONFIG.player.size / 3;
         const dotX = state.player.x + state.player.direction.x * dotDistance;
@@ -1086,13 +1064,9 @@ const renderPlayer = () => {
         const timeSinceLastBubble = animationTime - state.player.lastBubbleTime;
         // const cooldownProgress = Math.min(timeSinceLastBubble / CONFIG.bubble.cooldown, 1);
         
-        // Set opacity based on cooldown's progress
         const dotOpacity = getDotOpacity(state, animationTime);
         
-        ctx.fillStyle = CONFIG.player.directionIndicator.color.replace(
-            '1)',  // Replace the full opacity with our calculated opacity
-            `${dotOpacity})`
-        );
+        ctx.fillStyle = CONFIG.player.directionIndicator.color.replace('1)', `${dotOpacity})`);
         
         ctx.fillRect(
             dotX - dotSize/2,
@@ -1106,10 +1080,8 @@ const renderPlayer = () => {
 };
 
 const renderPlayerHUD = (ctx) => {
-    // Save the current context state
     ctx.save();
     
-    // Switch to screen coordinates
     ctx.setTransform(1, 0, 0, 1, 0, 0);
     
     const circleRadius = 15;
@@ -1119,22 +1091,17 @@ const renderPlayerHUD = (ctx) => {
     const totalCircles = 5;
     const hpPerCircle = state.player.maxHp / totalCircles;
     
-    // Track if we need to create explosion particles
     const currentFilledCircles = Math.ceil(state.player.hp / hpPerCircle);
     if (currentFilledCircles < state.player.lastRenderedCircles) {
-        // Create explosion particles for the depleted circle
         const circleIndex = currentFilledCircles;
         const particleX = startX + circleIndex * circleSpacing;
         createHealthCircleExplosion(particleX, startY);
     }
     state.player.lastRenderedCircles = currentFilledCircles;
     
-    // Draw circles
     for (let i = 0; i < totalCircles; i++) {
         const circleX = startX + i * circleSpacing;
-        const circleY = startY;
-        
-        // Calculate how full this circle should be
+        const circleY = startY;        
         const circleStartHp = i * hpPerCircle;
         const circleEndHp = (i + 1) * hpPerCircle;
         let fillAmount = 1;
@@ -1145,16 +1112,13 @@ const renderPlayerHUD = (ctx) => {
             fillAmount = (state.player.hp - circleStartHp) / hpPerCircle;
         }
         
-        // Draw outer circle (border)
         ctx.beginPath();
         ctx.arc(circleX, circleY, circleRadius, 0, Math.PI * 2);
         ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
         ctx.lineWidth = 2;
         ctx.stroke();
         
-        // Draw fill
         if (fillAmount > 0) {
-            // Create gradient for filled portion
             const gradient = ctx.createRadialGradient(
                 circleX, circleY, 0,
                 circleX, circleY, circleRadius
@@ -1171,11 +1135,9 @@ const renderPlayerHUD = (ctx) => {
         }
     }
     
-    // Restore the context state
     ctx.restore();
 };
 
-// Add this new function to create the explosion effect
 const createHealthCircleExplosion = (screenX, screenY) => {
     const numParticles = 20;
     const colors = [
@@ -1184,7 +1146,6 @@ const createHealthCircleExplosion = (screenX, screenY) => {
         'rgba(150, 0, 0, 0.4)'
     ];
     
-    // Convert screen coordinates to world coordinates
     const worldX = screenX - state.camera.x;
     const worldY = screenY - state.camera.y;
     
@@ -1237,13 +1198,11 @@ const render = () => {
     const worldSize = gridSize * CONFIG.display.grid.worldSize;
     const villageSize = CONFIG.world.village.size * gridSize;
     
-    // Calculate visible area
     const startX = Math.floor((-state.camera.x) / gridSize) * gridSize;
     const startY = Math.floor((-state.camera.y) / gridSize) * gridSize;
     const endX = startX + GAME_WIDTH + gridSize;
     const endY = startY + GAME_HEIGHT + gridSize;
     
-    // Draw void background
     ctx.fillStyle = CONFIG.display.grid.voidColor;
     ctx.fillRect(
         startX, startY,
@@ -1254,13 +1213,10 @@ const render = () => {
     ctx.fillStyle = CONFIG.world.wilderness.groundColor;
     ctx.fillRect(0, 0, worldSize, worldSize);
     
-    // Then draw the village ground in the top-left
+    // Then draw the village
     ctx.fillStyle = CONFIG.world.village.groundColor;
     ctx.fillRect(0, 0, villageSize, villageSize);
     
-    // After drawing village and wilderness grounds, but before grid:
-    
-    // The shore gradient
     const shoreWidth = 60;
     const shoreColor = 'rgba(179, 220, 255, 0.3)';
     
@@ -1294,19 +1250,15 @@ const render = () => {
     ctx.fillStyle = rightShore;
     ctx.fillRect(worldSize - shoreWidth, 0, shoreWidth, worldSize);
 
-    // Draw grid inside of the world
+
     ctx.strokeStyle = CONFIG.display.grid.color;
     ctx.lineWidth = 1;
-
-    // Draw vertical lines
     for (let x = 0; x < worldSize; x += gridSize) {
         ctx.beginPath();
         ctx.moveTo(x, 0);
         ctx.lineTo(x, worldSize);
         ctx.stroke();
     }
-
-    // Draw horizontal lines
     for (let y = 0; y < worldSize; y += gridSize) {
         ctx.beginPath();
         ctx.moveTo(0, y);
@@ -1314,7 +1266,7 @@ const render = () => {
         ctx.stroke();
     }
 
-    // Draw vegetation in the wilderness 
+    // Now add vegetation
     for (let x = startX; x < endX; x += gridSize) {
         for (let y = startY; y < endY; y += gridSize) {
             if (x >= worldSize || y >= worldSize) continue;
@@ -1337,13 +1289,9 @@ const render = () => {
                     addToCollisionMap(cellX, cellY, 'tree');
                 }
                 
-                // Generate number of sides for this tree
                 const sides = Math.floor(10 + seededRandom(cellX * 3, cellY * 3) * 13); // 10 to 22 sides
-                
-                // Choose color for this tree
                 const colorIndex = Math.floor(seededRandom(cellX * 4, cellY * 4) * CONFIG.world.wilderness.vegetation.tree.colors.length);
                 ctx.fillStyle = CONFIG.world.wilderness.vegetation.tree.colors[colorIndex];
-                
                 ctx.beginPath();
                 
                 for (let i = 0; i < sides; i++) {
@@ -1371,26 +1319,20 @@ const render = () => {
                      CONFIG.world.wilderness.vegetation.mushroom.frequency) {
                 const config = CONFIG.world.wilderness.vegetation.mushroom;
                 
-                // Determine if cell uses single color
                 const useSingleColor = seededRandom(cellX * 31, cellY * 31) < config.pattern.singleColor;
                 const cellColorIndex = Math.floor(seededRandom(cellX * 13, cellY * 13) * config.colors.length);
                 
-                // Create regular grid of circles with slight variation
                 for (let i = config.pattern.margin; i < gridSize - config.pattern.margin; i += config.pattern.spacing) {
                     for (let j = config.pattern.margin; j < gridSize - config.pattern.margin; j += config.pattern.spacing) {
-                        // Offset every other row for more natural pattern
                         const offsetX = (Math.floor(j / config.pattern.spacing) % 2) * 
                             (config.pattern.spacing * config.pattern.offset);
                         const px = x + i + offsetX;
-                        const py = y + j;
-                        
-                        // Add variation to position
+                        const py = y + j;                        
                         const variation = {
                             x: (seededRandom(cellX * i, cellY * j) - 0.5) * config.pattern.variation * config.pattern.spacing,
                             y: (seededRandom(cellX * j, cellY * i) - 0.5) * config.pattern.variation * config.pattern.spacing
                         };
                         
-                        // Choose color for this dot
                         const colorIndex = useSingleColor ? cellColorIndex :
                             Math.floor(seededRandom(cellX * i, cellY * j) * config.colors.length);
                         ctx.fillStyle = config.colors[colorIndex];
@@ -1412,29 +1354,23 @@ const render = () => {
                      CONFIG.world.wilderness.vegetation.flower.frequency) {
                 const config = CONFIG.world.wilderness.vegetation.flower;
                 
-                // Determine base color for this cell
                 const colorIndex = Math.floor(seededRandom(cellX * 13, cellY * 13) * config.colors.length);
                 ctx.fillStyle = config.colors[colorIndex];
                 
-                // Calculate base rotation for this cell
                 const baseRotation = config.pattern.rotation + 
                     (seededRandom(cellX * 14, cellY * 14) - 0.5) * config.pattern.variation;
                 
-                // Draw tessellating triangle pattern
                 for (let i = config.pattern.margin; i < gridSize - config.pattern.margin; i += config.pattern.spacing) {
                     for (let j = config.pattern.margin; j < gridSize - config.pattern.margin; j += config.pattern.spacing) {
-                        // Offset every other row
                         const offsetX = (Math.floor(j / config.pattern.spacing) % 2) * (config.pattern.spacing / 2);
                         const px = x + i + offsetX;
                         const py = y + j;
                         
-                        // Add slight position variation
                         const variation = {
                             x: (seededRandom(cellX * i, cellY * j) - 0.5) * 4,
                             y: (seededRandom(cellX * j, cellY * i) - 0.5) * 4
                         };
                         
-                        // Draw triangle
                         ctx.beginPath();
                         ctx.save();
                         ctx.translate(px + variation.x, py + variation.y);
@@ -1451,6 +1387,7 @@ const render = () => {
                     }
                 }
             }
+
             // Grass
             else if (random < CONFIG.world.wilderness.vegetation.tree.frequency + 
                      CONFIG.world.wilderness.vegetation.mushroom.frequency +
@@ -1462,21 +1399,17 @@ const render = () => {
                 
                 const config = CONFIG.world.wilderness.vegetation.grass;
                 
-                // Draw hatching pattern
                 ctx.strokeStyle = config.colors[0];
                 ctx.lineWidth = 1;
 
-                // Calculate base angle with slight variation
                 const baseAngle = config.hatch.angle + 
                     (seededRandom(cellX * 20, cellY * 20) - 0.5) * config.hatch.variation;
 
-                // Create hatching pattern
                 for (let i = config.hatch.margin; i < gridSize - config.hatch.margin; i += config.hatch.spacing) {
                     for (let j = config.hatch.margin; j < gridSize - config.hatch.margin; j += config.hatch.spacing) {
                         const hatchX = x + i;
                         const hatchY = y + j;
                         
-                        // Add slight position variation
                         const offsetX = (seededRandom(cellX * i, cellY * j) - 0.5) * 2;
                         const offsetY = (seededRandom(cellX * j, cellY * i) - 0.5) * 2;
                         
@@ -1496,17 +1429,16 @@ const render = () => {
         }
     }
 
-    // After drawing vegetation but before drawing the player, add:
+    // After drawing vegetation but before drawing the player
     state.villagers.forEach(villager => {
         ctx.save();
         ctx.fillStyle = villager.color;
         
-        // Add slight bobbing motion for rescued villagers
+        // Bobbing
         if (villager.status === 'rescued') {
             const bobOffset = Math.sin(animationTime * villager.bobSpeed) * villager.bobAmplitude;
             drawVillagerShape(ctx, villager.x, villager.y + bobOffset, villager.shape, CONFIG.world.villagers.size);
         } else if (villager.status === 'lost') {
-            // Horizontal bobbing for lost villagers
             const lostBobOffset = Math.sin(animationTime * villager.lostBobSpeed) * villager.lostBobAmplitude;
             drawVillagerShape(ctx, villager.x + lostBobOffset, villager.y, villager.shape, CONFIG.world.villagers.size);
         } else {
@@ -1517,10 +1449,7 @@ const render = () => {
         ctx.restore();
     });
 
-    // Render enemies
     enemySystem.renderEnemies(ctx, state.enemies);
-
-    // Draw player
     renderPlayer();
 
     state.footprints.forEach(footprint => {
@@ -1549,7 +1478,6 @@ const render = () => {
         ctx.restore();
     });
     
-    // Render particles
     state.particles = state.particles.filter(particle => {
         const age = animationTime - particle.createdAt;
         if (age >= particle.lifetime) return false;
@@ -1568,22 +1496,18 @@ const render = () => {
         return true;
     });
     
-    // Render HUD elements
     renderPlayerHUD(ctx);
     
-    // Update player invulnerability
     if (state.player.isInvulnerable && animationTime >= state.player.invulnerableUntil) {
         state.player.isInvulnerable = false;
     }
     
-    // Render diamonds
     renderDiamonds();
     
     ctx.restore();
 };
 
 
-// ============= Game Loop =============
 const updatePlayer = () => {
     Object.assign(state, weaponSystems.updateBubbles(state, animationTime));
     Object.assign(state, weaponSystems.updateSwordSwing(state, animationTime));
@@ -1593,7 +1517,6 @@ const updatePlayer = () => {
         return (animationTime - footprint.createdAt) < CONFIG.footprints.lifetime;
     });
     
-    // Update player direction for idle animation
     if (!keys.size && !state.player.isSwinging && !state.player.isDefending) {
         const idleTime = animationTime - state.player.lastInputTime;
         
@@ -1607,17 +1530,14 @@ const updatePlayer = () => {
                 y: Math.sin(newAngle)
             };
         } else {
-            // Reset direction to base direction when not idle
             state.player.direction = { ...state.player.baseDirection };
         }
     } else {
-        // Update last input time when other actions occur
         if (state.player.isSwinging || state.player.isDefending) {
             state.player.lastInputTime = animationTime;
         }
     }
 
-    // Check for villager collisions
     state.villagers.forEach(villager => {
         if (villager.status === 'rescued') return;
         
@@ -1629,25 +1549,21 @@ const updatePlayer = () => {
             villager.status = 'rescued';
             state.player.rescuedCount++;
             
-            // Check for sword unlock
             if (state.player.rescuedCount >= CONFIG.player.equipment.swordUnlockCount && !state.player.swordUnlocked) {
                 state.player.swordUnlocked = true;
                 state.player.equipment = 'sword';  // Auto-equip sword
                 showSwordUnlockAnimation();
             }
             
-            // Assign new position in village when rescued
             const villageSize = CONFIG.world.village.size * CONFIG.display.grid.size;
             const margin = CONFIG.world.villagers.size;
             
             villager.x = margin + Math.random() * (villageSize - margin * 2);
             villager.y = margin + Math.random() * (villageSize - margin * 2);
             
-            // Check if all villagers are rescued
             const allRescued = state.villagers.every(v => v.status === 'rescued');
             if (allRescued && !state.gameComplete) {
                 state.gameComplete = true;
-                // Show completion message
                 const message = document.createElement('div');
                 message.textContent = CONFIG.world.villagers.rescueMessage;
                 message.style.position = 'fixed';
@@ -1680,7 +1596,6 @@ const gameLoop = (currentTime) => {
     if (deltaTime >= FRAME_TIME) {
         animationTime += FRAME_TIME;
         
-        // Check for player death
         if (state.player.hp <= 0 && !state.player.isDead) {
             state.player.isDead = true;
             showGameOver();
@@ -1688,7 +1603,7 @@ const gameLoop = (currentTime) => {
         
         updatePlayer();
         state.enemies = enemySystem.updateEnemies(state.enemies, deltaTime);
-        collectDiamonds(); // Add this line to check for diamond collection
+        collectDiamonds();
         render();
         
         lastFrameTime = currentTime;
@@ -1698,7 +1613,9 @@ const gameLoop = (currentTime) => {
 };
 
 
-// ============= Setup & Initialization =============
+
+
+
 const canvas = document.getElementById('gameCanvas');
 const ctx = canvas.getContext('2d');
 
@@ -1723,16 +1640,13 @@ resizeCanvas();
 state.villagers = generateVillagers();
 state.enemies = enemySystem.generateEnemies(state.villagers, state.collisionMap);
 
-// Start the game loop
 requestAnimationFrame(gameLoop);
 
 const getDotOpacity = (state, animationTime) => {
-    // Get bubble cooldown opacity
     const timeSinceLastBubble = animationTime - state.player.lastBubbleTime;
     const bubbleCooldownProgress = Math.min(timeSinceLastBubble / CONFIG.bubble.cooldown, 1);
     const bubbleOpacity = 0.1 + (bubbleCooldownProgress * 0.9);
     
-    // Get dash cooldown opacity
     let dashOpacity = 1;
     if (state.player.dashExhausted) {
         const timeSinceExhaustion = animationTime - state.player.lastDashEnd;
@@ -1740,7 +1654,7 @@ const getDotOpacity = (state, animationTime) => {
         dashOpacity = 0.1 + (Math.min(dashCooldownProgress, 1) * 0.9);
     } else if (state.player.isDashing) {
         const dashProgress = (animationTime - state.player.dashStartTime) / CONFIG.player.dash.duration;
-        dashOpacity = 1 - (dashProgress * 0.7);  // Fade to 0.3 during dash
+        dashOpacity = 1 - (dashProgress * 0.7);
     }
 
     let blinkOpacity = 1;
@@ -1751,12 +1665,10 @@ const getDotOpacity = (state, animationTime) => {
         }
     }
     
-    // Return the lowest opacity of all systems
     return Math.min(bubbleOpacity, dashOpacity, blinkOpacity);
 };
 
 const checkCollision = (x, y, size) => {
-    // Check corners of player square
     const halfSize = size / 2;
     const corners = [
         { x: x - halfSize, y: y - halfSize }, // Top-left
@@ -1769,15 +1681,10 @@ const checkCollision = (x, y, size) => {
 };
 
 const createNaturalCluster = (centerX, centerY, config, cellX, cellY, i) => {
-    // Base angle and distance
     const angle = seededRandom(cellX * 8 + i, cellY * 8) * Math.PI * 2;
-    
-    // Make clusters denser in the middle and sparser on edges
     const distanceFromCenter = seededRandom(cellX * 9 + i, cellY * 9);
-    // Use square root to bias towards center
     const distance = Math.sqrt(distanceFromCenter) * config.size.max;
     
-    // Add some variation
     const variation = {
         x: (seededRandom(cellX * 10 + i, cellY * 10) - 0.5) * config.size.max,
         y: (seededRandom(cellX * 11 + i, cellY * 11) - 0.5) * config.size.max
@@ -1789,7 +1696,7 @@ const createNaturalCluster = (centerX, centerY, config, cellX, cellY, i) => {
         size: config.size.min + 
             seededRandom(cellX * 3 + i, cellY * 3) * 
             (config.size.max - config.size.min) *
-            // Make items on the edge slightly smaller
+            // This makes stuff on the edge a little smaller
             (1 - (distance / config.cluster.spread) * 0.3)
     };
 };
@@ -1797,7 +1704,6 @@ const createNaturalCluster = (centerX, centerY, config, cellX, cellY, i) => {
 const renderTree = (ctx, x, y, size, isTop = false) => {
     ctx.fillStyle = CONFIG.world.wilderness.vegetation.tree.color;
     if (isTop) {
-        // Draw only the top 2/3 of the tree
         ctx.beginPath();
         ctx.arc(
             x + CONFIG.display.grid.size/2, 
@@ -1807,7 +1713,6 @@ const renderTree = (ctx, x, y, size, isTop = false) => {
         );
         ctx.fill();
     } else {
-        // Draw only the bottom 2/3 of the tree
         ctx.beginPath();
         ctx.arc(
             x + CONFIG.display.grid.size/2, 
@@ -1888,13 +1793,12 @@ const getCellInfo = (x, y) => {
 const createFloatingMessage = (messageConfig) => {
     const {
         text, 
-        duration = null, // null means permanent
+        duration = null, // null for permanent
         backgroundColor = 'rgba(0, 0, 0, 0.8)', 
         glowColor = null,
-        glowDuration = 2000 // 2s default for glow animation
+        glowDuration = 2000
     } = messageConfig;
     
-    // Create container
     const container = document.createElement('div');
     container.style.position = 'fixed';
     container.style.top = '50%';
@@ -1905,7 +1809,6 @@ const createFloatingMessage = (messageConfig) => {
     container.style.borderRadius = '10px';
     container.style.zIndex = '1000';
     
-    // Add message text
     const message = document.createElement('div');
     message.textContent = text;
     message.style.color = 'white';
@@ -1913,7 +1816,6 @@ const createFloatingMessage = (messageConfig) => {
     message.style.textAlign = 'center';
     container.appendChild(message);
     
-    // Add glow animation if specified
     if (glowColor) {
         container.style.animation = `glow ${glowDuration}ms ease-in-out`;
         
@@ -1927,17 +1829,14 @@ const createFloatingMessage = (messageConfig) => {
         `;
         document.head.appendChild(style);
         
-        // Clean up style element after animation
         setTimeout(() => {
             document.head.removeChild(style);
             if (!duration) {
-                // For permanent messages, set final glow state after animation
                 container.style.boxShadow = `0 0 30px 10px ${glowColor}`;
             }
         }, glowDuration);
     }
     
-    // Add to document and remove after duration (if specified)
     document.body.appendChild(container);
     if (duration) {
         setTimeout(() => {
@@ -1945,29 +1844,26 @@ const createFloatingMessage = (messageConfig) => {
         }, duration);
     }
     
-    return container; // Return container for manual removal if needed
+    return container;
 };
 
-// Update showGameOver to be permanent
 const showGameOver = () => {
     createFloatingMessage({
         text: 'Game Over\nPress Space to restart',
-        duration: null, // Permanent message
+        duration: null,
         glowColor: 'rgba(255, 0, 0, 0.6)'
     });
 };
 
-// Update showSwordUnlockAnimation with explicit timing
 const showSwordUnlockAnimation = () => {
     createFloatingMessage({
         text: CONFIG.player.equipment.unlockAnimation.messageText,
         duration: CONFIG.player.equipment.unlockAnimation.duration,
         glowColor: CONFIG.player.equipment.unlockAnimation.glowColor,
-        glowDuration: 2000 // Explicit glow animation duration
+        glowDuration: 2000
     });
 };
 
-// Update the player's HP when collecting diamonds
 const collectDiamonds = () => {
     state.diamonds.forEach(diamond => {
         const dx = state.player.x - diamond.x;
@@ -1975,12 +1871,11 @@ const collectDiamonds = () => {
         const distance = Math.sqrt(dx * dx + dy * dy);
         
         if (distance < (CONFIG.player.size / 2 + diamond.size / 2) && !diamond.collected) {
-            diamond.collected = true; // Mark diamond as collected
+            diamond.collected = true;
             state.player.hp = Math.min(state.player.hp + 1, state.player.maxHp); // Restore 1 HP, max out at maxHp
         }
     });
     
-    // Remove collected diamonds from the state
     state.diamonds = state.diamonds.filter(diamond => !diamond.collected);
 };
 
@@ -1988,7 +1883,6 @@ const renderDiamonds = () => {
     state.diamonds.forEach(diamond => {
         ctx.save();
         
-        // Add pulsing glow effect
         const pulseIntensity = 0.5 + Math.sin(animationTime * 0.005) * 0.3; // Pulsing between 0.2 and 0.8
         
         // Outer glow
@@ -2011,7 +1905,7 @@ const renderDiamonds = () => {
         ctx.fillStyle = `rgba(255, 223, 0, ${0.8 + pulseIntensity * 0.2})`; // Brighter gold
         ctx.fill();
         
-        // Shine effect
+        // Shiny
         ctx.beginPath();
         ctx.arc(
             diamond.x - diamond.size * 0.2,