about summary refs log tree commit diff stats
path: root/html/plains
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2024-12-18 16:22:12 -0500
committerelioat <elioat@tilde.institute>2024-12-18 16:22:12 -0500
commit734d82c140b7dca8b3e8b9ca1f5427910558bfa0 (patch)
tree8d350266efd9e9d57e469f2ba8a0549cdfba5312 /html/plains
parent241ee7f764994f7c02b576835be91ace68feea9c (diff)
downloadtour-734d82c140b7dca8b3e8b9ca1f5427910558bfa0.tar.gz
*
Diffstat (limited to 'html/plains')
-rw-r--r--html/plains/enemies.js61
-rw-r--r--html/plains/game.js148
2 files changed, 114 insertions, 95 deletions
diff --git a/html/plains/enemies.js b/html/plains/enemies.js
index 77f5245..e3be9af 100644
--- a/html/plains/enemies.js
+++ b/html/plains/enemies.js
@@ -69,6 +69,36 @@ const generateEnemies = (villagers, collisionMap) => {
     return enemies;
 };
 
+const createDeathParticles = (enemy) => {
+    const numParticles = 15 + Math.floor(Math.random() * 10);
+    for (let i = 0; i < numParticles; i++) {
+        const particleAngle = (i / numParticles) * Math.PI * 2;
+        const speed = 2 + Math.random() * 3;
+        state.particles.push({
+            x: enemy.x,
+            y: enemy.y,
+            dx: Math.cos(particleAngle) * speed,
+            dy: Math.sin(particleAngle) * speed,
+            size: enemy.size * (0.1 + Math.random() * 0.2),
+            color: enemy.color,
+            lifetime: 1000,
+            createdAt: animationTime
+        });
+    }
+};
+
+const createDeathDiamonds = (enemy) => {
+    const diamondCount = Math.floor(Math.random() * 5);
+    for (let i = 0; i < diamondCount; i++) {
+        state.diamonds.push({
+            x: enemy.x + (Math.random() - 0.5) * 20,
+            y: enemy.y + (Math.random() - 0.5) * 20,
+            size: 6,
+            collected: false
+        });
+    }
+};
+
 const handleEnemyDamage = (enemy, damage, knockbackForce = 0, angle = 0) => {
     const gridSize = CONFIG.display.grid.size;
     enemy.hp -= damage;
@@ -79,7 +109,7 @@ const handleEnemyDamage = (enemy, damage, knockbackForce = 0, angle = 0) => {
     
     // Apply knockback if there's a force
     if (knockbackForce > 0) {
-        const knockbackDistance = gridSize * 0.5; // Half grid cell knockback
+        const knockbackDistance = gridSize * 0.5;
         enemy.knockback = {
             active: true,
             startX: enemy.x,
@@ -92,33 +122,8 @@ const handleEnemyDamage = (enemy, damage, knockbackForce = 0, angle = 0) => {
     }
     
     if (damage > 0 && enemy.hp <= 0) {
-        // Create death particles
-        const numParticles = 15 + Math.floor(Math.random() * 10);
-        for (let i = 0; i < numParticles; i++) {
-            const particleAngle = (i / numParticles) * Math.PI * 2;
-            const speed = 2 + Math.random() * 3;
-            state.particles.push({
-                x: enemy.x,
-                y: enemy.y,
-                dx: Math.cos(particleAngle) * speed,
-                dy: Math.sin(particleAngle) * speed,
-                size: enemy.size * (0.1 + Math.random() * 0.2),
-                color: enemy.color,
-                lifetime: 1000,
-                createdAt: animationTime
-            });
-        }
-
-        // Generate diamonds when enemy is defeated
-        const diamondCount = Math.floor(Math.random() * 5);
-        for (let i = 0; i < diamondCount; i++) {
-            state.diamonds.push({
-                x: enemy.x + (Math.random() - 0.5) * 20,
-                y: enemy.y + (Math.random() - 0.5) * 20,
-                size: 6,
-                collected: false
-            });
-        }
+        createDeathParticles(enemy);
+        createDeathDiamonds(enemy);
     }
     
     return damage > 0 && enemy.hp <= 0;
diff --git a/html/plains/game.js b/html/plains/game.js
index 993ba45..12742d4 100644
--- a/html/plains/game.js
+++ b/html/plains/game.js
@@ -749,6 +749,22 @@ const createBubbleAttack = (state, animationTime) => {
     };
 };
 
+// Add this helper function near other weapon-related functions
+const checkEnemyCollision = (enemy, sourceX, sourceY, range) => {
+    if (enemy.stunned) return false;
+    
+    const dx = enemy.x - sourceX;
+    const dy = enemy.y - sourceY;
+    const distance = Math.sqrt(dx * dx + dy * dy);
+    
+    if (distance < enemy.size + range) {
+        const knockbackAngle = Math.atan2(dy, dx);
+        enemySystem.handleEnemyDamage(enemy, 1, 1, knockbackAngle);
+        return true;
+    }
+    return false;
+};
+
 const weaponSystems = {
     updateBubbles: (state, animationTime) => {
         const updatedBubbles = state.player.bubbles
@@ -756,18 +772,8 @@ const weaponSystems = {
             .map(bubble => {
                 // Check for enemy collisions
                 state.enemies.forEach(enemy => {
-                    if (!enemy.stunned) {
-                        const dx = enemy.x - bubble.x;
-                        const dy = enemy.y - bubble.y;
-                        const distance = Math.sqrt(dx * dx + dy * dy);
-
-                        if (distance < enemy.size + CONFIG.bubble.size) {
-                            const knockbackAngle = Math.atan2(dy, dx);
-                            enemySystem.handleEnemyDamage(enemy, 1, 1, knockbackAngle);
-                        }
-                    }
+                    checkEnemyCollision(enemy, bubble.x, bubble.y, CONFIG.bubble.size);
                 });
-                
                 return updateBubble(bubble, animationTime);
             });
             
@@ -793,24 +799,9 @@ const weaponSystems = {
         const newAngle = state.player.swordAngle + CONFIG.sword.swingSpeed;
         const swingComplete = newAngle > Math.atan2(state.player.direction.y, state.player.direction.x) + Math.PI / 2;
         
-        // Add sword collision detection
-        const swordTip = {
-            x: state.player.x + Math.cos(state.player.swordAngle) * CONFIG.sword.length,
-            y: state.player.y + Math.sin(state.player.swordAngle) * CONFIG.sword.length
-        };
-
         // Check all enemies for sword collision
         const updatedEnemies = state.enemies.map(enemy => {
-            if (!enemy.stunned) {
-                const dx = enemy.x - state.player.x;
-                const dy = enemy.y - state.player.y;
-                const distance = Math.sqrt(dx * dx + dy * dy);
-
-                if (distance < enemy.size + CONFIG.sword.length) {
-                    const knockbackAngle = Math.atan2(dy, dx);
-                    enemySystem.handleEnemyDamage(enemy, 1, 1, knockbackAngle);
-                }
-            }
+            checkEnemyCollision(enemy, state.player.x, state.player.y, CONFIG.sword.length);
             return enemy;
         });
         
@@ -1894,63 +1885,86 @@ const getCellInfo = (x, y) => {
     };
 };
 
-const showSwordUnlockAnimation = () => {
-    // Create container for animation
+const createFloatingMessage = (messageConfig) => {
+    const {
+        text, 
+        duration = null, // null means permanent
+        backgroundColor = 'rgba(0, 0, 0, 0.8)', 
+        glowColor = null,
+        glowDuration = 2000 // 2s default for glow animation
+    } = messageConfig;
+    
+    // Create container
     const container = document.createElement('div');
     container.style.position = 'fixed';
     container.style.top = '50%';
     container.style.left = '50%';
     container.style.transform = 'translate(-50%, -50%)';
     container.style.padding = '20px';
-    container.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
+    container.style.backgroundColor = backgroundColor;
     container.style.borderRadius = '10px';
-    container.style.animation = 'glow 2s ease-in-out';
     container.style.zIndex = '1000';
-
-    // Add CSS animation
-    const style = document.createElement('style');
-    style.textContent = `
-        @keyframes glow {
-            0% { box-shadow: 0 0 0 0 ${CONFIG.player.equipment.unlockAnimation.glowColor}; opacity: 0; }
-            50% { box-shadow: 0 0 30px 10px ${CONFIG.player.equipment.unlockAnimation.glowColor}; opacity: 1; }
-            100% { box-shadow: 0 0 0 0 ${CONFIG.player.equipment.unlockAnimation.glowColor}; opacity: 0; }
-        }
-    `;
-    document.head.appendChild(style);
-
+    
     // Add message text
     const message = document.createElement('div');
-    message.textContent = CONFIG.player.equipment.unlockAnimation.messageText;
-    message.style.color = CONFIG.player.equipment.unlockAnimation.messageColor;
+    message.textContent = text;
+    message.style.color = 'white';
     message.style.fontSize = '24px';
     message.style.textAlign = 'center';
     container.appendChild(message);
-
-    // Add to document and remove after animation
+    
+    // Add glow animation if specified
+    if (glowColor) {
+        container.style.animation = `glow ${glowDuration}ms ease-in-out`;
+        
+        const style = document.createElement('style');
+        style.textContent = `
+            @keyframes glow {
+                0% { box-shadow: 0 0 0 0 ${glowColor}; opacity: 0; }
+                50% { box-shadow: 0 0 30px 10px ${glowColor}; opacity: 1; }
+                100% { box-shadow: 0 0 0 0 ${glowColor}; opacity: ${duration ? 0 : 1}; }
+            }
+        `;
+        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);
-    setTimeout(() => {
-        document.body.removeChild(container);
-        document.head.removeChild(style);
-    }, CONFIG.player.equipment.unlockAnimation.duration);
+    if (duration) {
+        setTimeout(() => {
+            document.body.removeChild(container);
+        }, duration);
+    }
+    
+    return container; // Return container for manual removal if needed
 };
 
+// Update showGameOver to be permanent
 const showGameOver = () => {
-    const gameOverDiv = document.createElement('div');
-    gameOverDiv.style.position = 'fixed';
-    gameOverDiv.style.top = '50%';
-    gameOverDiv.style.left = '50%';
-    gameOverDiv.style.transform = 'translate(-50%, -50%)';
-    gameOverDiv.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
-    gameOverDiv.style.padding = '20px';
-    gameOverDiv.style.borderRadius = '10px';
-    gameOverDiv.style.color = 'white';
-    gameOverDiv.style.textAlign = 'center';
-    gameOverDiv.style.fontSize = '24px';
-    gameOverDiv.innerHTML = `
-        <h2>Game Over</h2>
-        <p>Press Space to restart</p>
-    `;
-    document.body.appendChild(gameOverDiv);
+    createFloatingMessage({
+        text: 'Game Over\nPress Space to restart',
+        duration: null, // Permanent message
+        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
+    });
 };
 
 // Update the player's HP when collecting diamonds