about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--html/tower/index.html3
-rw-r--r--html/tower/js/game.js12
-rw-r--r--html/tower/js/gameState.js42
-rw-r--r--html/tower/js/mechanics.js49
-rw-r--r--html/tower/js/renderer.js51
5 files changed, 125 insertions, 32 deletions
diff --git a/html/tower/index.html b/html/tower/index.html
index e27cf28..d9dd854 100644
--- a/html/tower/index.html
+++ b/html/tower/index.html
@@ -95,10 +95,7 @@
     </div>
     
     <!-- Core game modules -->
-    <script src="js/grid.js"></script>
     <script src="js/path.js"></script>
-    <script src="js/tower.js"></script>
-    <script src="js/enemy.js"></script>
     <script src="js/mechanics.js"></script>
     <script src="js/uiHandlers.js"></script>
     
diff --git a/html/tower/js/game.js b/html/tower/js/game.js
index 5c28f31..7d362ae 100644
--- a/html/tower/js/game.js
+++ b/html/tower/js/game.js
@@ -43,6 +43,8 @@ function handleCombatPhase(timestamp, deltaTime) {
     gameState.projectiles = gameState.projectiles.filter(p => timestamp - p.createdAt < p.lifetime);
     
     const cellSize = canvas.width / 20;
+    
+    // Process tower and enemy attacks
     processTowerAttacks(
         gameState.towers,
         gameState.enemies,
@@ -52,7 +54,17 @@ function handleCombatPhase(timestamp, deltaTime) {
         cellSize
     );
     
+    processEnemyAttacks(
+        gameState.enemies,
+        gameState.towers,
+        gameState.particles,
+        timestamp,
+        cellSize
+    );
+    
+    // Remove dead enemies and destroyed towers
     gameState.enemies = gameState.enemies.filter(enemy => enemy.currentHealth > 0);
+    gameState.towers = gameState.towers.filter(tower => tower.currentHealth > 0);
 }
 
 function spawnEnemies(timestamp) {
diff --git a/html/tower/js/gameState.js b/html/tower/js/gameState.js
index a1ab765..49708ee 100644
--- a/html/tower/js/gameState.js
+++ b/html/tower/js/gameState.js
@@ -43,21 +43,53 @@ const ParticleTypes = {
     }
 };
 
+const EnemyTypes = {
+    BASIC: {
+        color: '#ff0000',
+        baseHealth: { min: 2, max: 6 },
+        speed: { min: 1, max: 1.5 },
+        damage: 0,
+        isRanged: false
+    },
+    RANGED: {
+        color: '#8e44ad', // Purple
+        baseHealth: { min: 1, max: 4 },
+        speed: { min: 0.7, max: 1.2 },
+        damage: 0.3,
+        attackRange: 3,
+        attackSpeed: 1, // attacks per second
+        isRanged: true
+    }
+};
+
 function createTower(type, position) {
     return {
         ...TowerTypes[type],
+        type,
         position,
-        lastAttackTime: 0
+        lastAttackTime: 0,
+        currentHealth: 10,
+        maxHealth: 10
     };
 }
 
 function createEnemy(startPosition) {
+    // 20% chance for ranged enemy
+    const type = Math.random() < 0.2 ? 'RANGED' : 'BASIC';
+    const enemyType = EnemyTypes[type];
+    const health = Math.floor(Math.random() * 
+        (enemyType.baseHealth.max - enemyType.baseHealth.min + 1)) + 
+        enemyType.baseHealth.min;
+    
     return {
         position: { ...startPosition },
-        currentHealth: Math.floor(Math.random() * 5) + 2, // 2-6 health
-        maxHealth: this.currentHealth,
-        speed: 1 + Math.random() * 0.5, // 1-1.5 speed
-        pathIndex: 0
+        currentHealth: health,
+        maxHealth: health,
+        speed: enemyType.speed.min + Math.random() * (enemyType.speed.max - enemyType.speed.min),
+        pathIndex: 0,
+        type,
+        lastAttackTime: 0,
+        damage: enemyType.damage
     };
 }
 
diff --git a/html/tower/js/mechanics.js b/html/tower/js/mechanics.js
index 72b284a..4babe2a 100644
--- a/html/tower/js/mechanics.js
+++ b/html/tower/js/mechanics.js
@@ -91,4 +91,53 @@ function handleTowerAttack(tower, target, projectiles, particles, timestamp, cel
     if (target.currentHealth <= 0) {
         particles.push(...createDeathParticles(target, cellSize));
     }
+}
+
+function processEnemyAttacks(enemies, towers, particles, timestamp, cellSize) {
+    enemies.forEach(enemy => {
+        if (!EnemyTypes[enemy.type].isRanged) return;
+        
+        if (timestamp - enemy.lastAttackTime > 1000 / EnemyTypes[enemy.type].attackSpeed) {
+            const towersInRange = findTowersInRange(enemy, towers);
+            
+            if (towersInRange.length > 0) {
+                const target = towersInRange[0];
+                handleEnemyAttack(enemy, target, particles, timestamp, cellSize);
+            }
+        }
+    });
+}
+
+function findTowersInRange(enemy, towers) {
+    return towers.filter(tower => {
+        const dx = tower.position.x - enemy.position.x;
+        const dy = tower.position.y - enemy.position.y;
+        return Math.sqrt(dx * dx + dy * dy) <= EnemyTypes[enemy.type].attackRange;
+    });
+}
+
+function handleEnemyAttack(enemy, tower, particles, timestamp, cellSize) {
+    // Create enemy projectile
+    const projectileColor = '#8e44ad80'; // Semi-transparent purple
+    particles.push(createParticle(
+        {
+            ...ParticleTypes.PROJECTILE,
+            color: projectileColor,
+            lifetime: 500
+        },
+        {
+            x: (enemy.position.x + 0.5) * cellSize,
+            y: (enemy.position.y + 0.5) * cellSize
+        },
+        Math.atan2(
+            tower.position.y - enemy.position.y,
+            tower.position.x - enemy.position.x
+        )
+    ));
+    
+    tower.currentHealth -= enemy.damage;
+    enemy.lastAttackTime = timestamp;
+    
+    // Reduce tower's damage as it takes damage
+    tower.damage = TowerTypes[tower.type].damage * (tower.currentHealth / tower.maxHealth);
 } 
\ No newline at end of file
diff --git a/html/tower/js/renderer.js b/html/tower/js/renderer.js
index 10444aa..b0d1da0 100644
--- a/html/tower/js/renderer.js
+++ b/html/tower/js/renderer.js
@@ -61,29 +61,15 @@ function renderEnemies(ctx, enemies) {
     const cellSize = canvas.width / 20;
     
     enemies.forEach(enemy => {
-        // Draw enemy health bar
         const healthPercent = enemy.currentHealth / enemy.maxHealth;
-        const barWidth = cellSize * 0.8;
-        const barHeight = 4;
+        const opacity = 0.3 + (healthPercent * 0.7);
         
-        ctx.fillStyle = '#e74c3c';
-        ctx.fillRect(
-            (enemy.position.x + 0.1) * cellSize,
-            (enemy.position.y - 0.1) * cellSize - barHeight,
-            barWidth,
-            barHeight
-        );
-        
-        ctx.fillStyle = '#2ecc71';
-        ctx.fillRect(
-            (enemy.position.x + 0.1) * cellSize,
-            (enemy.position.y - 0.1) * cellSize - barHeight,
-            barWidth * healthPercent,
-            barHeight
-        );
+        // Use enemy type color
+        ctx.fillStyle = `${EnemyTypes[enemy.type].color}${Math.floor(opacity * 255).toString(16).padStart(2, '0')}`;
+        ctx.strokeStyle = 'rgba(0, 0, 0, 0.8)';
+        ctx.lineWidth = 2;
         
-        // Draw enemy
-        ctx.fillStyle = 'red';
+        // Draw enemy body
         ctx.beginPath();
         ctx.arc(
             (enemy.position.x + 0.5) * cellSize,
@@ -93,6 +79,21 @@ function renderEnemies(ctx, enemies) {
             Math.PI * 2
         );
         ctx.fill();
+        ctx.stroke();
+        
+        // Draw range indicator for ranged enemies
+        if (EnemyTypes[enemy.type].isRanged) {
+            ctx.beginPath();
+            ctx.arc(
+                (enemy.position.x + 0.5) * cellSize,
+                (enemy.position.y + 0.5) * cellSize,
+                EnemyTypes[enemy.type].attackRange * cellSize,
+                0,
+                Math.PI * 2
+            );
+            ctx.strokeStyle = `${EnemyTypes[enemy.type].color}40`;
+            ctx.stroke();
+        }
     });
 }
 
@@ -107,8 +108,10 @@ function renderTowers(ctx, towers) {
     const cellSize = canvas.width / 20;
     
     towers.forEach(tower => {
-        // Draw tower body
-        ctx.fillStyle = tower.color;
+        const healthPercent = tower.currentHealth / tower.maxHealth;
+        
+        // Draw tower body with opacity based on health
+        ctx.fillStyle = tower.color + Math.floor(healthPercent * 255).toString(16).padStart(2, '0');
         ctx.fillRect(
             tower.position.x * cellSize + cellSize * 0.1,
             tower.position.y * cellSize + cellSize * 0.1,
@@ -116,7 +119,7 @@ function renderTowers(ctx, towers) {
             cellSize * 0.8
         );
         
-        // Draw range indicator (only during placement phase)
+        // Draw range indicator
         if (gameState.phase === GamePhase.PLACEMENT) {
             ctx.beginPath();
             ctx.arc(
@@ -126,7 +129,7 @@ function renderTowers(ctx, towers) {
                 0,
                 Math.PI * 2
             );
-            ctx.strokeStyle = tower.color + '40'; // 40 is hex for 25% opacity
+            ctx.strokeStyle = tower.color + '40';
             ctx.stroke();
         }
     });