feat: add 9-level tower evolution system with distinct tier abilities

Extend all 5 towers to 9 upgrade levels, divided into 3 visual and
functional evolution tiers:
- Tier 1 (L1-3, Yellow): Base stats (damage, range, rate).
- Tier 2 (L4-6, Orange): First major ability evolution with pulsing orange aura.
- Tier 3 (L7-9, Blue): Final devastating evolution with blue aura.

Evolutions per tower:
- Arrow Tower:
  * L4-6 (Orange): Multishot firing 2-3 arrows simultaneously at distinct targets.
  * L7-9 (Blue): 4-arrow multishot + Poison DoT (up to 28 dmg/s).
- Cannon:
  * L4-6 (Orange): Incendiary shells applying Burn DoT in splash radius.
  * L7-9 (Blue): Flak shells hitting flying units with full splash + burn damage.
- Frost Tower:
  * L4-6 (Orange): Permafrost - every 3rd pulse completely freezes enemies (speed = 0).
  * L7-9 (Blue): Shatter - frozen enemies receive +50% damage from all sources.
- Tesla Tower:
  * L4-6 (Orange): Chain lightning applies stun on each hit.
  * L7-9 (Blue): Lightning Storm - every 4th shot strikes and stuns ALL enemies in range.
- Laser Tower:
  * L4-6 (Orange): Prism refraction splitting the beam onto 2-3 secondary targets.
  * L7-9 (Blue): Piercing beam penetrating all enemies in a line up to 280px range.

Engine & Renderer updates:
- Added DoT tick handling (poison/burn) and freeze/stun status effects.
- Added visual indicators for frozen enemies (ice spikes) and DoT particles.
- Added 3-slot tier-colored pips on tower base plates + pulsating evolution auras.
- Updated TowerPanel with 9-star tier display (★★★ yellow, ★★★ orange, ★★★ blue)
  and dynamic special ability descriptions.

Testing & Validation:
- Added `scripts/test-evolution.mts` covering all 10 evolved mechanics (all green).
- Verified lockstep multiplayer determinism via `scripts/test-mp.mts`.
- Verified solo campaign balance preservation via `scripts/sim.mts`.
- Full TypeScript typecheck and production build passing.
This commit is contained in:
Tronax 2026-08-16 13:54:09 +02:00
parent ef75203db7
commit 4f8400c480
Signed by: Tronax
SSH key fingerprint: SHA256:2pKKXDZucWvaF/GzXNz0FY53EAO1YDLN80bqS+TTz/o
8 changed files with 518 additions and 98 deletions

View file

@ -53,14 +53,24 @@ export const TOWERS: Record<TowerKind, TowerDef> = {
icon: '🏹',
desc: 'Günstiger Standardturm mit schnellen Einzelschüssen.',
cost: 50,
upgradeCost: [60, 110],
upgradeCost: [60, 110, 260, 420, 700, 1200, 2000, 3400],
levels: [
{ damage: 12, range: 110, rate: 1.7 },
{ damage: 22, range: 120, rate: 2.0 },
{ damage: 38, range: 132, rate: 2.4 },
{ damage: 70, range: 140, rate: 2.6 },
{ damage: 95, range: 148, rate: 2.8 },
{ damage: 125, range: 155, rate: 3.0 },
{ damage: 180, range: 165, rate: 3.2 },
{ damage: 240, range: 175, rate: 3.4 },
{ damage: 320, range: 185, rate: 3.6 },
],
hitsFlying: true,
projectileSpeed: 460,
multi: [1, 1, 1, 2, 2, 3, 3, 3, 4],
dotDps: [0, 0, 0, 0, 0, 0, 12, 18, 28],
dotDuration: [0, 0, 0, 0, 0, 0, 2, 2.5, 3],
dotColor: '#7ddc4f',
color: '#9a6a33',
accent: '#e8c27a',
hotkey: '1',
@ -71,15 +81,25 @@ export const TOWERS: Record<TowerKind, TowerDef> = {
icon: '🧨',
desc: 'Flächenschaden durch Explosion trifft aber keine Flieger.',
cost: 110,
upgradeCost: [100, 180],
upgradeCost: [100, 180, 380, 600, 950, 1600, 2600, 4200],
levels: [
{ damage: 28, range: 118, rate: 0.55 },
{ damage: 50, range: 128, rate: 0.62 },
{ damage: 92, range: 140, rate: 0.7 },
{ damage: 150, range: 150, rate: 0.75 },
{ damage: 200, range: 158, rate: 0.8 },
{ damage: 260, range: 165, rate: 0.85 },
{ damage: 380, range: 175, rate: 0.9 },
{ damage: 500, range: 185, rate: 0.95 },
{ damage: 680, range: 195, rate: 1.0 },
],
hitsFlying: false,
projectileSpeed: 300,
splash: [42, 48, 56],
splash: [42, 48, 56, 64, 70, 76, 84, 92, 100],
dotDps: [0, 0, 0, 10, 14, 20, 26, 34, 45],
dotDuration: [0, 0, 0, 2, 2, 2.5, 2.5, 3, 3],
dotColor: '#ff9c40',
flak: [false, false, false, false, false, false, true, true, true],
color: '#57616e',
accent: '#ff9c40',
hotkey: '2',
@ -90,15 +110,22 @@ export const TOWERS: Record<TowerKind, TowerDef> = {
icon: '❄️',
desc: 'Frostpuls verlangsamt ALLE Gegner in Reichweite (auch Flieger).',
cost: 80,
upgradeCost: [70, 130],
upgradeCost: [70, 130, 260, 420, 700, 1100, 1800, 3000],
levels: [
{ damage: 5, range: 95, rate: 0.9 },
{ damage: 9, range: 105, rate: 1.0 },
{ damage: 15, range: 118, rate: 1.1 },
{ damage: 22, range: 128, rate: 1.15 },
{ damage: 30, range: 138, rate: 1.2 },
{ damage: 40, range: 148, rate: 1.25 },
{ damage: 60, range: 158, rate: 1.3 },
{ damage: 80, range: 170, rate: 1.35 },
{ damage: 105, range: 182, rate: 1.4 },
],
hitsFlying: true,
slowFactor: [0.55, 0.45, 0.35],
slowDuration: [1.5, 1.9, 2.3],
slowFactor: [0.55, 0.45, 0.35, 0.32, 0.3, 0.28, 0.25, 0.22, 0.2],
slowDuration: [1.5, 1.9, 2.3, 2.5, 2.7, 2.9, 3.1, 3.3, 3.5],
freezeDuration: [0, 0, 0, 0.7, 0.9, 1.1, 1.3, 1.5, 1.8],
color: '#4d8fb5',
accent: '#aef0ff',
hotkey: '3',
@ -109,15 +136,23 @@ export const TOWERS: Record<TowerKind, TowerDef> = {
icon: '⚡',
desc: 'Kettenblitz springt auf mehrere Gegner über.',
cost: 130,
upgradeCost: [120, 200],
upgradeCost: [120, 200, 400, 650, 1000, 1700, 2800, 4500],
levels: [
{ damage: 22, range: 105, rate: 1.0 },
{ damage: 38, range: 115, rate: 1.1 },
{ damage: 66, range: 128, rate: 1.2 },
{ damage: 95, range: 138, rate: 1.3 },
{ damage: 125, range: 145, rate: 1.4 },
{ damage: 160, range: 152, rate: 1.5 },
{ damage: 230, range: 160, rate: 1.6 },
{ damage: 300, range: 168, rate: 1.7 },
{ damage: 400, range: 175, rate: 1.8 },
],
hitsFlying: true,
chain: [3, 4, 5],
chainRange: 100,
chain: [3, 4, 5, 6, 6, 7, 7, 8, 9],
chainRange: [100, 100, 100, 110, 110, 115, 120, 125, 130],
stunDuration: [0, 0, 0, 0.2, 0.25, 0.3, 0.35, 0.4, 0.5],
stormEvery: [0, 0, 0, 0, 0, 0, 5, 5, 4],
color: '#6a5fb0',
accent: '#c8b4ff',
hotkey: '4',
@ -128,19 +163,38 @@ export const TOWERS: Record<TowerKind, TowerDef> = {
icon: '💫',
desc: 'Soforttreffer mit hoher Reichweite und hohem Schaden.',
cost: 160,
upgradeCost: [150, 260],
upgradeCost: [150, 260, 500, 800, 1300, 2100, 3400, 5500],
levels: [
{ damage: 60, range: 170, rate: 0.5 },
{ damage: 105, range: 185, rate: 0.55 },
{ damage: 185, range: 205, rate: 0.6 },
{ damage: 170, range: 215, rate: 0.6 },
{ damage: 230, range: 225, rate: 0.65 },
{ damage: 300, range: 235, rate: 0.7 },
{ damage: 420, range: 250, rate: 0.75 },
{ damage: 560, range: 265, rate: 0.8 },
{ damage: 750, range: 280, rate: 0.85 },
],
hitsFlying: true,
prism: [0, 0, 0, 2, 2, 3, 0, 0, 0],
pierce: [false, false, false, false, false, false, true, true, true],
color: '#b0483f',
accent: '#ff8a7a',
hotkey: '5',
},
}
/** max tower level */
export const MAX_TOWER_LEVEL = 9
/** tier of a tower level: 0 = yellow (1-3), 1 = orange (4-6), 2 = blue (7-9) */
export function towerTier(level: number): number {
return Math.min(2, Math.floor((level - 1) / 3))
}
/** tier colors for level pips, stars and auras */
export const TIER_COLORS = ['#ffd23e', '#ff9c40', '#4da3ff']
export const ENEMIES: Record<EnemyKind, EnemyDef> = {
normal: {
kind: 'normal',