test: cover testRaid

This commit is contained in:
dualfroz committed 2026-09-12 19:02:13 +02:00
1 parent def342977d
commit 817e000542
1 file changed
+159
+159
View File
@@ -160,3 +160,162 @@ VF_TEST(everySpawnedRaiderStartsOnTheOutskirtsAndWalksTowardsTheBell) {
startDistances.push_back(distance);
}
raid.tick(world, villagers, pois, omen, schedule, clock, 200);
for (std::size_t i = 0; i < raid.raiders().size(); ++i) {
if (!raid.raiders()[i].alive) continue;
CHECK(distanceToCentre(raid.raiders()[i].position) < startDistances[i]);
}
}
VF_TEST(theRaidRunsThroughEveryWaveAndEndsInVictory) {
World world = makeRaidWorld();
PoiRegistry pois;
pois.scan(world, villageCenter, 12, 4);
std::vector<Villager> villagers = makeVillagers(4);
VillagerSchedule schedule;
TimeOfDay clock(static_cast<WorldTick>(0.35 * 24000.0));
OmenState omen = omenAt(2);
RaidManager raid(villageCenter, 555u, raidDifficultyNormal);
CHECK(raid.tryStart(omen, {0.5f, static_cast<float>(walkY), 0.5f}, 32.0f));
int expectedSpawns = 0;
for (int index = 0; index < raid.waveCount(); ++index)
expectedSpawns += planRaidWave(index, 2, raidDifficultyNormal).total();
int guard = 0;
std::vector<int> wavesSeen;
while (raid.active() && guard++ < 20000) {
raid.tick(world, villagers, pois, omen, schedule, clock, 1);
if (wavesSeen.empty() || wavesSeen.back() != raid.waveIndex())
wavesSeen.push_back(raid.waveIndex());
for (int i = 0; i < static_cast<int>(raid.raiders().size()); ++i)
raid.damageRaider(i, 1000.0f);
}
CHECK(raid.state() == RaidState::Victory);
CHECK_EQ(static_cast<int>(wavesSeen.size()), raid.waveCount());
CHECK_EQ(raid.waveIndex(), raid.waveCount() - 1);
CHECK_EQ(raid.totalSpawned(), expectedSpawns);
CHECK_EQ(raid.livingRaiders(), 0);
CHECK_EQ(raid.villagersLost(), 0);
CHECK_EQ(livingVillagerCount(villagers), 4);
CHECK(!raid.active());
CHECK(raid.elapsedTicks() > raidWaveDelayTicks * (raid.waveCount() - 1));
}
VF_TEST(victoryLeavesMajorPositiveGossipAndHeroOfTheVillageWithEverySurvivor) {
World world = makeRaidWorld();
PoiRegistry pois;
pois.scan(world, villageCenter, 12, 4);
std::vector<Villager> villagers = makeVillagers(4);
VillagerSchedule schedule;
TimeOfDay clock(static_cast<WorldTick>(0.35 * 24000.0));
OmenState omen = omenAt(3);
RaidManager raid(villageCenter, 909u, raidDifficultyEasy);
CHECK(raid.tryStart(omen, {0.5f, static_cast<float>(walkY), 0.5f}, 32.0f));
int guard = 0;
while (raid.active() && guard++ < 20000) {
raid.tick(world, villagers, pois, omen, schedule, clock, 1);
for (int i = 0; i < static_cast<int>(raid.raiders().size()); ++i)
raid.damageRaider(i, 1000.0f);
}
CHECK(raid.state() == RaidState::Victory);
for (const Villager& villager : villagers) {
CHECK_EQ(villager.gossip.valueOf(GossipKind::MajorPositive), gossipMajorPositiveGain);
CHECK(villager.gossip.reputation() > 0);
}
CHECK(omen.isHero());
CHECK_EQ(omen.heroLevel, 3);
CHECK_EQ(omen.heroTicksRemaining, heroDurationTicks);
CHECK(!omen.hasBadOmen());
tickOmen(omen, heroDurationTicks);
CHECK(!omen.isHero());
CHECK_EQ(omen.heroLevel, 0);
}
VF_TEST(aRaidThatKillsEveryVillagerEndsInDefeat) {
World world = makeRaidWorld();
PoiRegistry pois;
pois.scan(world, villageCenter, 12, 4);
std::vector<Villager> villagers = makeVillagers(2);
VillagerSchedule schedule;
TimeOfDay clock(static_cast<WorldTick>(0.35 * 24000.0));
OmenState omen = omenAt(1);
RaidManager raid(villageCenter, 31u, raidDifficultyEasy);
CHECK(raid.tryStart(omen, {0.5f, static_cast<float>(walkY), 0.5f}, 32.0f));
CHECK_EQ(golemCapFor(2), 0);
int guard = 0;
while (raid.active() && guard++ < 20000)
raid.tick(world, villagers, pois, omen, schedule, clock, 1);
CHECK(raid.state() == RaidState::Defeat);
CHECK_EQ(livingVillagerCount(villagers), 0);
CHECK_EQ(raid.villagersLost(), 2);
CHECK_EQ(raid.golems().spawnedTotal, 0);
CHECK(!omen.isHero());
for (const Villager& villager : villagers) {
CHECK_EQ(villager.gossip.valueOf(GossipKind::MajorPositive), 0);
CHECK_EQ(villager.workstationIndex, -1);
CHECK_EQ(villager.bedIndex, -1);
}
CHECK_EQ(pois.freeBedCount(), pois.bedCount());
}
VF_TEST(golemsSpawnInProportionToThePopulationAndStopAtTheCap) {
CHECK_EQ(golemCapFor(0), 0);
CHECK_EQ(golemCapFor(golemMinimumVillagers - 1), 0);
CHECK_EQ(golemCapFor(golemMinimumVillagers), 1);
CHECK_EQ(golemCapFor(8), 2);
CHECK_EQ(golemCapFor(12), 3);
GolemSpawner spawner;
int spawns = 0;
for (int tick = 0; tick < 2000; ++tick)
if (tickGolemSpawner(spawner, 12, 1)) ++spawns;
CHECK_EQ(spawns, 3);
CHECK_EQ(spawner.golemsAlive, 3);
CHECK_EQ(spawner.spawnedTotal, 3);
spawner.golemsAlive = 0;
CHECK(tickGolemSpawner(spawner, 12, spawner.intervalTicks + 1));
CHECK_EQ(spawner.spawnedTotal, 4);
GolemSpawner hamlet;
for (int tick = 0; tick < 2000; ++tick) tickGolemSpawner(hamlet, 2, 1);
CHECK_EQ(hamlet.spawnedTotal, 0);
CHECK(!tickGolemSpawner(hamlet, 12, 0));
}
VF_TEST(aDefendedVillageFieldsGolemsWhileTheRaidIsRunning) {
World world = makeRaidWorld();
PoiRegistry pois;
pois.scan(world, villageCenter, 12, 4);
std::vector<Villager> villagers = makeVillagers(4);
VillagerSchedule schedule;
TimeOfDay clock(static_cast<WorldTick>(0.35 * 24000.0));
OmenState omen = omenAt(1);
RaidManager raid(villageCenter, 77u, raidDifficultyEasy);
CHECK(raid.tryStart(omen, {0.5f, static_cast<float>(walkY), 0.5f}, 32.0f));
raid.tick(world, villagers, pois, omen, schedule, clock, 400);
CHECK(raid.golems().spawnedTotal >= 1);
CHECK(raid.golems().golemsAlive >= 1);
CHECK(raid.golems().golemsAlive <= golemCapFor(4));
CHECK(raid.livingRaiders() < raid.wave().total());
}
VF_TEST(golemsTurnOnThePlayerOnceTheVillageReputationCollapses) {
GolemSpawner spawner;
GossipLedger calm;
calm.add(GossipKind::Trading, gossipTradingGain * 4);
updateGolemHostility(spawner, buildReputation(calm, {}));
CHECK(!spawner.hostileToPlayer);