File size: 3,040 Bytes
1390db3
 
 
 
 
 
a646668
1390db3
 
 
 
 
 
a297171
 
1390db3
fd12cd0
a297171
5cf582c
 
 
1390db3
 
 
 
 
 
 
 
 
 
 
 
 
874a51f
 
 
5cf582c
 
 
 
a646668
 
 
1390db3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1f43352
 
 
 
fd12cd0
 
a297171
 
 
fd12cd0
 
 
1390db3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import * as THREE from 'three';
import { CFG } from './config.js';
import { G } from './globals.js';
import { getTerrainHeight } from './world.js';
import { showWaveBanner } from './hud.js';
import { spawnEnemy } from './enemies.js';
import { spawnAccelerators, spawnInfiniteAmmo } from './pickups.js';

export function startNextWave() {
  const waveCount = Math.min(
    CFG.waves.baseCount + CFG.waves.perWaveAdd * (G.waves.current - 1),
    CFG.waves.maxAlive
  );
  // Add two wolves on top of base wave enemies
  G.waves.spawnQueue = waveCount + 2;
  G.waves.nextSpawnTimer = 0;
  G.waves.shamansToSpawn = 1; // exactly 1 shaman per wave
  G.waves.wolvesToSpawn = 2;  // exactly 2 wolves per wave
  // Golem spawns on wave 3 and every 3 waves thereafter (3,6,9,...)
  const wave = G.waves.current;
  G.waves.golemsToSpawn = (wave >= 3 && ((wave - 3) % 3 === 0)) ? 1 : 0;

  // Choose a single spawn anchor for this wave (not near the center)
  const half = CFG.forestSize / 2;
  const margin = 24;
  const minR = Math.max(CFG.waves.annulusMin, 40);
  const maxR = Math.min(CFG.waves.annulusMax * 2.2, half - margin);
  const angle = G.random() * Math.PI * 2;
  const r = minR + G.random() * (maxR - minR);
  const ax = Math.cos(angle) * r;
  const az = Math.sin(angle) * r;
  G.waves.spawnAnchor = new THREE.Vector3(ax, getTerrainHeight(ax, az), az);

  showWaveBanner(`Wave ${G.waves.current}`);

  // Add 2 grenades each wave start (stacking)
  G.grenadeCount = (G.grenadeCount || 0) + 2;

  // Spawn 0..2 accelerator powerups at random locations
  const accelCount = Math.floor(G.random() * 3); // 0,1,2
  if (accelCount > 0) spawnAccelerators(accelCount);
  // Spawn at least 1 infinite ammo on wave 1 for visibility, then occasionally
  const infCount = (G.waves.current === 1) ? 1 : Math.floor(G.random() * 2);
  if (infCount > 0) spawnInfiniteAmmo(infCount);
}

export function updateWaves(delta) {
  if (G.waves.inBreak) {
    G.waves.breakTimer -= delta;
    if (G.waves.breakTimer <= 0) {
      G.waves.inBreak = false;
      G.waves.current++;
      startNextWave();
    }
    return;
  }

  // Spawn enemies
  if (G.waves.spawnQueue > 0 && G.waves.aliveCount < CFG.waves.maxAlive) {
    G.waves.nextSpawnTimer -= delta;
    if (G.waves.nextSpawnTimer <= 0) {
      if (G.waves.golemsToSpawn > 0) {
        spawnEnemy('golem');
        G.waves.golemsToSpawn--;
      } else if (G.waves.shamansToSpawn > 0) {
        spawnEnemy('shaman');
        G.waves.shamansToSpawn--;
      } else if (G.waves.wolvesToSpawn > 0) {
        spawnEnemy('wolf');
        G.waves.wolvesToSpawn--;
      } else {
        spawnEnemy('orc');
      }
      G.waves.spawnQueue--;
      const spawnRate = Math.max(
        CFG.waves.spawnMin,
        CFG.waves.spawnEvery - CFG.waves.spawnDecay * (G.waves.current - 1)
      );
      G.waves.nextSpawnTimer = spawnRate;
    }
  }

  // Check wave complete
  if (G.waves.spawnQueue === 0 && G.waves.aliveCount === 0) {
    G.waves.inBreak = true;
    G.waves.breakTimer = CFG.waves.breakTime;
  }
}