about summary refs log tree commit diff stats
path: root/html/tower
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2025-02-16 16:27:37 -0500
committerelioat <elioat@tilde.institute>2025-02-16 16:27:37 -0500
commit651ba65917968af90b97a77d02e28648c808b672 (patch)
treee4997cf40e6c430a6b7bec2443c08be202d1f1d3 /html/tower
parentac7e975cc7a194f0b7993a1a884dd98d47b73a6c (diff)
downloadtour-651ba65917968af90b97a77d02e28648c808b672.tar.gz
*
Diffstat (limited to 'html/tower')
-rw-r--r--html/tower/index.html2
-rw-r--r--html/tower/js/game.js142
-rw-r--r--html/tower/js/mechanics.js94
-rw-r--r--html/tower/js/uiHandlers.js48
4 files changed, 177 insertions, 109 deletions
diff --git a/html/tower/index.html b/html/tower/index.html
index 23755fa..e27cf28 100644
--- a/html/tower/index.html
+++ b/html/tower/index.html
@@ -99,6 +99,8 @@
     <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>
     
     <!-- Rendering modules -->
     <script src="js/renderer.js"></script>
diff --git a/html/tower/js/game.js b/html/tower/js/game.js
index 263d25c..5c28f31 100644
--- a/html/tower/js/game.js
+++ b/html/tower/js/game.js
@@ -26,126 +26,50 @@ function gameLoop(timestamp) {
     const deltaTime = timestamp - lastTimestamp;
     lastTimestamp = timestamp;
     
-    // Clear canvas
     ctx.clearRect(0, 0, canvas.width, canvas.height);
     
     if (gameState.phase === GamePhase.COMBAT) {
-        // Spawn enemies
-        if (enemiesRemaining > 0 && timestamp - lastEnemySpawn > ENEMY_SPAWN_INTERVAL) {
-            gameState.enemies.push(createEnemy({ x: 0, y: gameState.path[0].y }));
-            lastEnemySpawn = timestamp;
-            enemiesRemaining--;
-        }
-        
-        // Update enemy positions
-        gameState.enemies.forEach(enemy => {
-            if (enemy.pathIndex < gameState.path.length - 1) {
-                const targetPos = gameState.path[enemy.pathIndex + 1];
-                const dx = targetPos.x - enemy.position.x;
-                const dy = targetPos.y - enemy.position.y;
-                const distance = Math.sqrt(dx * dx + dy * dy);
-                
-                if (distance < enemy.speed * deltaTime / 1000) {
-                    enemy.position = { ...targetPos };
-                    enemy.pathIndex++;
-                } else {
-                    enemy.position.x += (dx / distance) * enemy.speed * deltaTime / 1000;
-                    enemy.position.y += (dy / distance) * enemy.speed * deltaTime / 1000;
-                }
-            }
-        });
-        
-        // Update particles
-        gameState.particles = gameState.particles.filter(particle => {
-            const age = timestamp - particle.createdAt;
-            if (age > particle.lifetime) return false;
-            
-            particle.position.x += particle.velocity.x * deltaTime;
-            particle.position.y += particle.velocity.y * deltaTime;
-            return true;
-        });
-        
-        // Update projectiles
-        gameState.projectiles = gameState.projectiles.filter(projectile => {
-            return timestamp - projectile.createdAt < projectile.lifetime;
-        });
-        
-        // Process tower attacks
-        gameState.towers.forEach(tower => {
-            if (timestamp - tower.lastAttackTime > 1000 / tower.attackSpeed) {
-                const enemiesInRange = gameState.enemies.filter(enemy => {
-                    const dx = enemy.position.x - tower.position.x;
-                    const dy = enemy.position.y - tower.position.y;
-                    return Math.sqrt(dx * dx + dy * dy) <= tower.range;
-                });
-                
-                if (enemiesInRange.length > 0) {
-                    const target = enemiesInRange[0];
-                    
-                    // Create projectile
-                    gameState.projectiles.push({
-                        startPos: tower.position,
-                        targetPos: target.position,
-                        createdAt: timestamp,
-                        lifetime: 300 // 300ms travel time
-                    });
-                    
-                    // Apply damage
-                    target.currentHealth -= tower.damage;
-                    tower.lastAttackTime = timestamp;
-                    
-                    // Create death particles if enemy dies
-                    if (target.currentHealth <= 0) {
-                        const cellSize = canvas.width / 20;
-                        const centerX = (target.position.x + 0.5) * cellSize;
-                        const centerY = (target.position.y + 0.5) * cellSize;
-                        
-                        // Create explosion particles with random angles and speeds
-                        const particleCount = 8 + Math.floor(Math.random() * 8); // Random number of particles (8-15)
-                        for (let i = 0; i < particleCount; i++) {
-                            // Random angle with some clustering
-                            const baseAngle = (Math.PI * 2 * i) / particleCount;
-                            const randomAngle = baseAngle + (Math.random() - 0.5) * 1.5; // Add up to ±0.75 radians of randomness
-                            
-                            // Random speed multiplier
-                            const speedMultiplier = 0.7 + Math.random() * 0.6; // Speed varies from 0.7x to 1.3x
-                            
-                            // Random offset from center
-                            const startOffset = Math.random() * 5;
-                            const startX = centerX + Math.cos(randomAngle) * startOffset;
-                            const startY = centerY + Math.sin(randomAngle) * startOffset;
-                            
-                            gameState.particles.push(
-                                createParticle(
-                                    {
-                                        ...ParticleTypes.DEATH_PARTICLE,
-                                        speed: ParticleTypes.DEATH_PARTICLE.speed * speedMultiplier,
-                                        lifetime: ParticleTypes.DEATH_PARTICLE.lifetime * (0.8 + Math.random() * 0.4) // Random lifetime 80%-120%
-                                    },
-                                    { x: startX, y: startY },
-                                    randomAngle
-                                )
-                            );
-                        }
-                    }
-                }
-            }
-        });
-        
-        // Remove dead enemies
-        gameState.enemies = gameState.enemies.filter(enemy => enemy.currentHealth > 0);
+        handleCombatPhase(timestamp, deltaTime);
     }
     
-    // Render game state
+    renderGame();
+    requestAnimationFrame(gameLoop);
+}
+
+function handleCombatPhase(timestamp, deltaTime) {
+    spawnEnemies(timestamp);
+    updateEnemies(gameState.enemies, gameState.path, deltaTime);
+    gameState.particles = updateParticles(gameState.particles, timestamp, deltaTime);
+    gameState.projectiles = gameState.projectiles.filter(p => timestamp - p.createdAt < p.lifetime);
+    
+    const cellSize = canvas.width / 20;
+    processTowerAttacks(
+        gameState.towers,
+        gameState.enemies,
+        gameState.projectiles,
+        gameState.particles,
+        timestamp,
+        cellSize
+    );
+    
+    gameState.enemies = gameState.enemies.filter(enemy => enemy.currentHealth > 0);
+}
+
+function spawnEnemies(timestamp) {
+    if (enemiesRemaining > 0 && timestamp - lastEnemySpawn > ENEMY_SPAWN_INTERVAL) {
+        gameState.enemies.push(createEnemy({ x: 0, y: gameState.path[0].y }));
+        lastEnemySpawn = timestamp;
+        enemiesRemaining--;
+    }
+}
+
+function renderGame() {
     renderGrid(ctx, gameState.grid);
     renderProjectiles(ctx, gameState.projectiles);
     renderEnemies(ctx, gameState.enemies);
     renderTowers(ctx, gameState.towers);
     renderParticles(ctx, gameState.particles);
     renderUI(ctx, gameState);
-    
-    // Request next frame
-    requestAnimationFrame(gameLoop);
 }
 
 // Start the game
diff --git a/html/tower/js/mechanics.js b/html/tower/js/mechanics.js
new file mode 100644
index 0000000..72b284a
--- /dev/null
+++ b/html/tower/js/mechanics.js
@@ -0,0 +1,94 @@
+// Combat mechanics
+function updateEnemies(enemies, path, deltaTime) {
+    enemies.forEach(enemy => {
+        if (enemy.pathIndex < path.length - 1) {
+            const targetPos = path[enemy.pathIndex + 1];
+            const dx = targetPos.x - enemy.position.x;
+            const dy = targetPos.y - enemy.position.y;
+            const distance = Math.sqrt(dx * dx + dy * dy);
+            
+            if (distance < enemy.speed * deltaTime / 1000) {
+                enemy.position = { ...targetPos };
+                enemy.pathIndex++;
+            } else {
+                enemy.position.x += (dx / distance) * enemy.speed * deltaTime / 1000;
+                enemy.position.y += (dy / distance) * enemy.speed * deltaTime / 1000;
+            }
+        }
+    });
+}
+
+function updateParticles(particles, timestamp, deltaTime) {
+    return particles.filter(particle => {
+        const age = timestamp - particle.createdAt;
+        if (age > particle.lifetime) return false;
+        
+        particle.position.x += particle.velocity.x * deltaTime;
+        particle.position.y += particle.velocity.y * deltaTime;
+        return true;
+    });
+}
+
+function createDeathParticles(target, cellSize) {
+    const particles = [];
+    const centerX = (target.position.x + 0.5) * cellSize;
+    const centerY = (target.position.y + 0.5) * cellSize;
+    
+    const particleCount = 8 + Math.floor(Math.random() * 8);
+    for (let i = 0; i < particleCount; i++) {
+        const baseAngle = (Math.PI * 2 * i) / particleCount;
+        const randomAngle = baseAngle + (Math.random() - 0.5) * 1.5;
+        const speedMultiplier = 0.7 + Math.random() * 0.6;
+        const startOffset = Math.random() * 5;
+        const startX = centerX + Math.cos(randomAngle) * startOffset;
+        const startY = centerY + Math.sin(randomAngle) * startOffset;
+        
+        particles.push(createParticle(
+            {
+                ...ParticleTypes.DEATH_PARTICLE,
+                speed: ParticleTypes.DEATH_PARTICLE.speed * speedMultiplier,
+                lifetime: ParticleTypes.DEATH_PARTICLE.lifetime * (0.8 + Math.random() * 0.4)
+            },
+            { x: startX, y: startY },
+            randomAngle
+        ));
+    }
+    return particles;
+}
+
+function processTowerAttacks(towers, enemies, projectiles, particles, timestamp, cellSize) {
+    towers.forEach(tower => {
+        if (timestamp - tower.lastAttackTime > 1000 / tower.attackSpeed) {
+            const enemiesInRange = findEnemiesInRange(tower, enemies);
+            
+            if (enemiesInRange.length > 0) {
+                const target = enemiesInRange[0];
+                handleTowerAttack(tower, target, projectiles, particles, timestamp, cellSize);
+            }
+        }
+    });
+}
+
+function findEnemiesInRange(tower, enemies) {
+    return enemies.filter(enemy => {
+        const dx = enemy.position.x - tower.position.x;
+        const dy = enemy.position.y - tower.position.y;
+        return Math.sqrt(dx * dx + dy * dy) <= tower.range;
+    });
+}
+
+function handleTowerAttack(tower, target, projectiles, particles, timestamp, cellSize) {
+    projectiles.push({
+        startPos: tower.position,
+        targetPos: target.position,
+        createdAt: timestamp,
+        lifetime: 300
+    });
+    
+    target.currentHealth -= tower.damage;
+    tower.lastAttackTime = timestamp;
+    
+    if (target.currentHealth <= 0) {
+        particles.push(...createDeathParticles(target, cellSize));
+    }
+} 
\ No newline at end of file
diff --git a/html/tower/js/uiHandlers.js b/html/tower/js/uiHandlers.js
new file mode 100644
index 0000000..5dc048a
--- /dev/null
+++ b/html/tower/js/uiHandlers.js
@@ -0,0 +1,48 @@
+function initializeDragAndDrop(canvas, gameState) {
+    let draggedTowerType = null;
+    let hoverCell = null;
+
+    const dragHandlers = {
+        onDragStart: (e) => {
+            draggedTowerType = e.target.dataset.towerType;
+            e.dataTransfer.setData('text/plain', '');
+        },
+        
+        onDragEnd: () => {
+            draggedTowerType = null;
+            hoverCell = null;
+        },
+        
+        onDragOver: (e) => {
+            e.preventDefault();
+            const rect = canvas.getBoundingClientRect();
+            const x = Math.floor((e.clientX - rect.left) / (canvas.width / 20));
+            const y = Math.floor((e.clientY - rect.top) / (canvas.height / 20));
+            
+            hoverCell = (x >= 0 && x < 20 && y >= 0 && y < 20) ? { x, y } : null;
+        },
+        
+        onDrop: (e) => {
+            e.preventDefault();
+            if (!draggedTowerType || !hoverCell) return;
+            
+            placeTower(gameState, draggedTowerType, hoverCell);
+            draggedTowerType = null;
+            hoverCell = null;
+        }
+    };
+
+    return { dragHandlers, getHoverInfo: () => ({ draggedTowerType, hoverCell }) };
+}
+
+function placeTower(gameState, towerType, position) {
+    const tower = TowerTypes[towerType];
+    if (
+        gameState.grid[position.y][position.x] === 'empty' &&
+        gameState.playerCurrency >= tower.cost
+    ) {
+        gameState.grid[position.y][position.x] = 'tower';
+        gameState.towers.push(createTower(towerType, { ...position }));
+        gameState.playerCurrency -= tower.cost;
+    }
+} 
\ No newline at end of file
100 101 102 103 104 105 106 107 108 109 110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152