diff options
Diffstat (limited to 'html')
-rw-r--r-- | html/tower/js/game.js | 10 | ||||
-rw-r--r-- | html/tower/js/gameState.js | 6 | ||||
-rw-r--r-- | html/tower/js/mechanics.js | 80 | ||||
-rw-r--r-- | html/tower/js/renderer.js | 40 |
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; |