about summary refs log tree commit diff stats
path: root/html
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2025-02-16 21:21:32 -0500
committerelioat <elioat@tilde.institute>2025-02-16 21:21:32 -0500
commit478252f03fb1b25f55430502f1ebabbbcd51d107 (patch)
tree185fe9cced0d96255f1e81073e4194d465b26f29 /html
parent8ed77a82bc74f195806ddc4c187b590c5dfcdde0 (diff)
downloadtour-478252f03fb1b25f55430502f1ebabbbcd51d107.tar.gz
*
Diffstat (limited to 'html')
-rw-r--r--html/tower/js/game.js10
-rw-r--r--html/tower/js/gameState.js6
-rw-r--r--html/tower/js/mechanics.js80
-rw-r--r--html/tower/js/renderer.js40
4 files changed, 117 insertions, 19 deletions
diff --git a/html/tower/js/game.js b/html/tower/js/game.js
index 5c39b8b..5ab2396 100644
--- a/html/tower/js/game.js
+++ b/html/tower/js/game.js
@@ -122,11 +122,11 @@ function spawnEnemies(timestamp) {
  */
 function renderGame() {
     renderGrid(ctx, gameState.grid);        // Background grid
-    renderProjectiles(ctx, gameState.projectiles); // Projectiles
-    renderEnemies(ctx, gameState.enemies);   // Enemies
-    renderTowers(ctx, gameState.towers);     // Towers
-    renderParticles(ctx, gameState.particles); // Visual effects
-    renderUI(ctx, gameState);                // User interface
+    renderParticles(ctx, gameState.particles); // Particles (including slime) go under everything
+    renderProjectiles(ctx, gameState.projectiles);
+    renderTowers(ctx, gameState.towers);
+    renderEnemies(ctx, gameState.enemies);   // Enemies on top of slime trail
+    renderUI(ctx, gameState);
 }
 
 // Start the game
diff --git a/html/tower/js/gameState.js b/html/tower/js/gameState.js
index b7dc33b..9da8474 100644
--- a/html/tower/js/gameState.js
+++ b/html/tower/js/gameState.js
@@ -67,6 +67,12 @@ const ParticleTypes = {
         finalRadius: 60,
         color: '#d35400',
         ringWidth: 3
+    },
+    SLIME_TRAIL: {
+        lifetime: 800,
+        color: '#27ae60',  // Same as Goop tower
+        size: 12,
+        fadeStart: 0.2     // When the fade should begin (percentage of lifetime)
     }
 };
 
diff --git a/html/tower/js/mechanics.js b/html/tower/js/mechanics.js
index ab9bee4..f2ec57b 100644
--- a/html/tower/js/mechanics.js
+++ b/html/tower/js/mechanics.js
@@ -1,5 +1,7 @@
 // Combat mechanics
 function updateEnemies() {
+    const cellSize = canvas.width / 20;
+    
     gameState.enemies = gameState.enemies.filter(enemy => {
         // Add progress property if it doesn't exist
         if (typeof enemy.progress === 'undefined') {
@@ -34,6 +36,19 @@ function updateEnemies() {
         enemy.position.x = pathPosition.x;
         enemy.position.y = pathPosition.y;
         
+        // Check if slow effect has expired
+        if (enemy.slowed && performance.now() > enemy.slowExpiry) {
+            enemy.slowed = false;
+            enemy.slowStacks = 0;
+            enemy.currentSlowAmount = 0;
+            enemy.speed = enemy.originalSpeed;
+        }
+        
+        // Add slime trail for slowed enemies (more particles for more stacks)
+        if (enemy.slowed && Math.random() < 0.2 + (enemy.slowStacks * 0.05)) {
+            gameState.particles.push(createSlimeTrail(enemy, cellSize));
+        }
+        
         return true;
     });
     
@@ -125,8 +140,19 @@ function createAOEExplosion(position, cellSize) {
     };
 }
 
+function createSlimeTrail(enemy, cellSize) {
+    return {
+        position: {
+            x: (enemy.position.x + 0.5) * cellSize,
+            y: (enemy.position.y + 0.5) * cellSize
+        },
+        createdAt: performance.now(),
+        type: 'SLIME_TRAIL',
+        ...ParticleTypes.SLIME_TRAIL
+    };
+}
+
 function handleTowerAttack(tower, target, projectiles, particles, timestamp, cellSize) {
-    // Create projectile
     projectiles.push({
         startPos: tower.position,
         targetPos: target.position,
@@ -135,7 +161,37 @@ function handleTowerAttack(tower, target, projectiles, particles, timestamp, cel
         towerType: tower.type
     });
     
-    if (tower.special === 'aoe') {
+    if (tower.special === 'slow') {
+        // Initialize slow effect if not present
+        if (!target.slowStacks) {
+            target.slowStacks = 0;
+        }
+        
+        // Add another stack of slow (up to a maximum)
+        const maxStacks = 5;  // Maximum 5 stacks
+        if (target.slowStacks < maxStacks) {
+            target.slowStacks++;
+            // Each stack slows by an additional 10% (multiplicative)
+            const newSlowAmount = 1 - Math.pow(0.9, target.slowStacks);  // 10%, 19%, 27%, 34%, 41%
+            
+            // Only adjust speed if this is a stronger slow
+            if (!target.slowed || newSlowAmount > target.currentSlowAmount) {
+                const originalSpeed = target.originalSpeed || target.speed;
+                target.originalSpeed = originalSpeed;  // Store original speed if not stored
+                target.speed = originalSpeed * (1 - newSlowAmount);
+                target.currentSlowAmount = newSlowAmount;
+                target.slowed = true;
+            }
+            
+            // Create slime particles for visual feedback
+            for (let i = 0; i < 4 + target.slowStacks; i++) {  // More particles for more stacks
+                particles.push(createSlimeTrail(target, cellSize));
+            }
+        }
+        
+        // Refresh slow duration
+        target.slowExpiry = timestamp + 2000;  // 2 second duration
+    } else if (tower.special === 'aoe') {
         // Find all enemies in AOE radius
         const enemiesInAOE = gameState.enemies.filter(enemy => {
             const dx = enemy.position.x - target.position.x;
@@ -153,15 +209,6 @@ function handleTowerAttack(tower, target, projectiles, particles, timestamp, cel
                 particles.push(...createDeathParticles(enemy, cellSize));
             }
         });
-    } else if (tower.special === 'slow') {
-        // Apply slow effect instead of damage
-        if (!target.slowed) {
-            target.speed *= (1 - tower.slowAmount);
-            target.slowed = true;
-            
-            // Visual indicator for slowed enemies
-            target.color = '#27ae60' + Math.floor(0.5 * 255).toString(16).padStart(2, '0');
-        }
     } else {
         // Normal damage for regular towers
         target.currentHealth -= tower.damage;
@@ -221,4 +268,15 @@ function handleEnemyAttack(enemy, tower, particles, timestamp, cellSize) {
     
     // Reduce tower's damage as it takes damage
     tower.damage = TowerTypes[tower.type].damage * (tower.currentHealth / tower.maxHealth);
+}
+
+// Update createEnemy to track original speed
+function createEnemy(startPosition) {
+    const enemy = {
+        // ... existing enemy properties ...
+        slowStacks: 0,
+        currentSlowAmount: 0
+    };
+    enemy.originalSpeed = enemy.speed;  // Store original speed
+    return enemy;
 } 
\ No newline at end of file
diff --git a/html/tower/js/renderer.js b/html/tower/js/renderer.js
index ddae51d..cd2d11d 100644
--- a/html/tower/js/renderer.js
+++ b/html/tower/js/renderer.js
@@ -146,9 +146,43 @@ function renderParticles(ctx, particles) {
         const lifePercent = age / particle.lifetime;
         
         if (lifePercent <= 1) {
-            ctx.globalAlpha = 1 - lifePercent;
-            
-            if (particle.type === 'AOE_EXPLOSION') {
+            if (particle.type === 'SLIME_TRAIL') {
+                // Calculate opacity based on lifetime and fade start
+                let opacity = 1;
+                if (lifePercent > particle.fadeStart) {
+                    opacity = 1 - ((lifePercent - particle.fadeStart) / (1 - particle.fadeStart));
+                }
+                opacity *= 0.3; // Make it translucent
+                
+                ctx.globalAlpha = opacity;
+                ctx.fillStyle = particle.color;
+                
+                // Draw a circular slime splat
+                ctx.beginPath();
+                ctx.arc(
+                    particle.position.x,
+                    particle.position.y,
+                    particle.size * (1 - lifePercent * 0.3), // Slightly shrink over time
+                    0,
+                    Math.PI * 2
+                );
+                ctx.fill();
+                
+                // Add some variation to the splat
+                for (let i = 0; i < 3; i++) {
+                    const angle = (Math.PI * 2 * i) / 3;
+                    const distance = particle.size * 0.4;
+                    ctx.beginPath();
+                    ctx.arc(
+                        particle.position.x + Math.cos(angle) * distance,
+                        particle.position.y + Math.sin(angle) * distance,
+                        particle.size * 0.4 * (1 - lifePercent * 0.3),
+                        0,
+                        Math.PI * 2
+                    );
+                    ctx.fill();
+                }
+            } else if (particle.type === 'AOE_EXPLOSION') {
                 // Draw expanding circle
                 const radius = particle.initialRadius + 
                     (particle.finalRadius - particle.initialRadius) * lifePercent;