boss waves

This commit is contained in:
2026-06-03 21:30:38 +02:00
parent 457fc47c75
commit b5185b0906
10 changed files with 214 additions and 162 deletions

View File

@@ -19,18 +19,20 @@ class WaveSystem
public:
WaveSystem(const GameConfig& config, std::mt19937& rng);
// Tick step 1: start a new wave when the current gap has expired; spawn
// any ships in the pending list whose scheduled tick has arrived.
// Tick step 1: advance the boss countdown and normal wave gap; trigger
// normal or boss waves when their timers expire; spawn any ships in the
// pending queues whose scheduled tick has arrived.
void tickWaveScheduler(Tick currentTick, ShipSystem& ships,
int worldHeightTiles);
// Tick step 2: accumulate threat from the rate formula, scaled by the
// current push multiplier (REQ-WAV-THREAT-RATE, REQ-PSH-ACCUMULATION).
void tickThreatAccumulation(Tick currentTick);
// Tick step 2: accumulate threat from the rate formula evaluated at the
// current boss wave counter (REQ-WAV-THREAT-RATE).
void tickThreatAccumulation();
// Called by Simulation (tick step 9) when the current enemy-station set
// is fully destroyed: multiplies the push scaling and increments generation.
void applyPush();
// is fully destroyed: advances the boss countdown and increments generation
// (REQ-WAV-BOSS-ADVANCE, REQ-PSH-STATION-STATS).
void onEnemyStationsDestroyed();
double threatLevel() const;
@@ -41,17 +43,23 @@ public:
private:
struct SpawnEntry
{
std::string schematicId;
int level;
Tick spawnAt;
QVector2D position;
ShipLayoutConfig layout;
std::string schematicId;
int level;
Tick spawnAt;
QVector2D position;
ShipLayoutConfig layout;
};
// Compose the next wave from the current threat budget, returning timed
// spawn entries spread across spawnDurationSeconds. Leaves any unspent
// budget in m_threatLevel (carry-over, REQ-WAV-TRIGGER).
std::vector<SpawnEntry> composeWave(Tick currentTick, int worldHeightTiles);
// Select ships from the given threat budget until no eligible ship fits.
// Reduces budget in-place to the remaining (carry-over) amount.
std::vector<SpawnEntry> selectWaveShips(double& budget, Tick currentTick,
int worldHeightTiles);
void triggerNormalWave(Tick currentTick, int worldHeightTiles);
void triggerBossWave(Tick currentTick, int worldHeightTiles);
// Returns true while normal-wave spawning should be suppressed (REQ-WAV-QUIET).
bool isInQuietWindow() const;
// Draw a random gap duration in ticks from [gapMin, gapMax].
Tick drawGapTicks();
@@ -59,11 +67,19 @@ private:
const GameConfig& m_config;
std::mt19937& m_rng;
double m_threatLevel = 0.0;
double m_pushScalingMultiplier = 1.0;
int m_generation = 0;
double m_threatLevel = 0.0;
int m_generation = 0;
bool m_waveActive = false;
Tick m_nextEventTick = 0; // absolute tick when the current gap expires
std::vector<SpawnEntry> m_pendingSpawns;
// Boss wave cycle (REQ-WAV-BOSS-COUNTER, REQ-WAV-BOSS-COUNTDOWN).
int m_bossWaveCounter = 1;
Tick m_bossCountdownTicks; // counts down each tick; reset after boss fires
Tick m_postBossQuietRemainingTicks = 0;
// Normal wave gap — frozen during quiet windows (REQ-WAV-GAP).
bool m_normalWaveActive = false;
Tick m_normalGapRemainingTicks; // replaces old m_nextEventTick
// Spawn queues — kept separate so normal-wave completion is trackable.
std::vector<SpawnEntry> m_normalPendingSpawns;
std::vector<SpawnEntry> m_bossPendingSpawns;
};