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

@@ -29,73 +29,33 @@ static GameConfig loadConfig()
// Threat accumulation
// ---------------------------------------------------------------------------
TEST_CASE("WaveSystem: threat stays 0 for first 30 game-seconds", "[wave]")
TEST_CASE("WaveSystem: threat accumulates at boss wave counter rate", "[wave]")
{
const GameConfig cfg = loadConfig();
std::mt19937 rng(42);
WaveSystem ws(cfg, rng);
// threat_rate_formula = "1*x - 30", which is <= 0 for x <= 30.
const int ticks30s = static_cast<int>(secondsToTicks(30.0));
for (int i = 0; i < ticks30s; ++i)
// threat_rate_formula = "x", boss wave counter starts at 1 → rate = 1 threat/s.
// After 1 second: threat ≈ 1.0.
const int ticks1s = static_cast<int>(secondsToTicks(1.0));
for (int i = 0; i < ticks1s; ++i)
{
ws.tickThreatAccumulation(static_cast<Tick>(i));
ws.tickThreatAccumulation();
}
REQUIRE(ws.threatLevel() == Approx(0.0));
REQUIRE(ws.threatLevel() == Approx(1.0));
}
TEST_CASE("WaveSystem: threat accumulates after 30 game-seconds", "[wave]")
{
const GameConfig cfg = loadConfig();
std::mt19937 rng(42);
WaveSystem ws(cfg, rng);
// Run 31 seconds worth of ticks.
const int ticks31s = static_cast<int>(secondsToTicks(31.0));
for (int i = 0; i < ticks31s; ++i)
{
ws.tickThreatAccumulation(static_cast<Tick>(i));
}
REQUIRE(ws.threatLevel() > 0.0);
}
TEST_CASE("WaveSystem: applyPush increases threat accumulation rate", "[wave]")
{
const GameConfig cfg = loadConfig();
std::mt19937 rng(42);
WaveSystem ws(cfg, rng);
// Accumulate for 1 tick past the 30s mark to get a baseline rate.
const Tick baseTick = secondsToTicks(31.0);
ws.tickThreatAccumulation(baseTick);
const double levelBefore = ws.threatLevel();
// Apply push: multiplier should increase.
ws.applyPush();
WaveSystem ws2(cfg, rng);
ws2.tickThreatAccumulation(baseTick);
// After the push the same tick adds more threat.
ws.tickThreatAccumulation(baseTick + 1);
ws2.tickThreatAccumulation(baseTick + 1);
// ws has the push multiplier applied; ws2 does not.
REQUIRE(ws.threatLevel() > ws2.threatLevel());
}
TEST_CASE("WaveSystem: generation starts at 0 and increments on push", "[wave]")
TEST_CASE("WaveSystem: generation starts at 0 and increments on station destruction", "[wave]")
{
const GameConfig cfg = loadConfig();
std::mt19937 rng(42);
WaveSystem ws(cfg, rng);
REQUIRE(ws.generation() == 0);
ws.applyPush();
ws.onEnemyStationsDestroyed();
REQUIRE(ws.generation() == 1);
ws.applyPush();
ws.onEnemyStationsDestroyed();
REQUIRE(ws.generation() == 2);
}
@@ -217,18 +177,23 @@ TEST_CASE("WaveSystem: enemy ships spawn after the initial gap elapses", "[wave]
// The maximum gap is gapMaxSeconds = 45s → 1350 ticks.
// Run 1500 ticks to guarantee at least one wave has triggered.
// Check each tick: enemy ships may be killed quickly by player stations,
// so we must detect them while they are alive, not only after the loop.
const int limit = static_cast<int>(secondsToTicks(50.0));
bool foundEnemyShip = false;
for (int i = 0; i < limit; ++i)
{
sim.tick();
}
bool foundEnemyShip = false;
sim.admin().forEach<ShipIdentityComponent, FactionComponent>(
[&](entt::entity /*e*/, const ShipIdentityComponent& /*si*/, const FactionComponent& f)
if (!foundEnemyShip)
{
if (f.isEnemy) { foundEnemyShip = true; }
});
sim.admin().forEach<ShipIdentityComponent, FactionComponent>(
[&](entt::entity /*e*/, const ShipIdentityComponent& /*si*/,
const FactionComponent& f)
{
if (f.isEnemy) { foundEnemyShip = true; }
});
}
}
REQUIRE(foundEnemyShip);
}