test: extend coverage of testRaid

This commit is contained in:
dualfroz committed 2026-09-12 19:16:56 +02:00
1 parent 817e000542
commit 67a5f3ff27
1 file changed
+137
+137
View File
@@ -319,3 +319,140 @@ VF_TEST(golemsTurnOnThePlayerOnceTheVillageReputationCollapses) {
updateGolemHostility(spawner, buildReputation(calm, {}));
CHECK(!spawner.hostileToPlayer);
GossipLedger angry;
angry.add(GossipKind::MajorNegative, gossipMajorNegativeGain);
std::vector<const GossipLedger*> village{&angry, &angry};
updateGolemHostility(spawner, buildReputation(calm, village));
CHECK(spawner.hostileToPlayer);
std::vector<const GossipLedger*> mixed{&angry, &calm, &calm, &calm, &calm, &calm};
updateGolemHostility(spawner, buildReputation(calm, mixed));
CHECK(!spawner.hostileToPlayer);
}
VF_TEST(twoRaidManagersOnTheSameSeedProduceTheSameRaid) {
World world = makeRaidWorld();
VillagerSchedule schedule;
TimeOfDay clock(static_cast<WorldTick>(0.35 * 24000.0));
PoiRegistry firstPois;
firstPois.scan(world, villageCenter, 12, 4);
std::vector<Villager> firstVillagers = makeVillagers(4);
OmenState firstOmen = omenAt(2);
RaidManager first(villageCenter, 4242u, raidDifficultyHard);
CHECK(first.tryStart(firstOmen, {0.5f, static_cast<float>(walkY), 0.5f}, 32.0f));
first.tick(world, firstVillagers, firstPois, firstOmen, schedule, clock, 300);
PoiRegistry secondPois;
secondPois.scan(world, villageCenter, 12, 4);
std::vector<Villager> secondVillagers = makeVillagers(4);
OmenState secondOmen = omenAt(2);
RaidManager second(villageCenter, 4242u, raidDifficultyHard);
CHECK(second.tryStart(secondOmen, {0.5f, static_cast<float>(walkY), 0.5f}, 32.0f));
second.tick(world, secondVillagers, secondPois, secondOmen, schedule, clock, 300);
CHECK_EQ(first.totalSpawned(), second.totalSpawned());
CHECK_EQ(first.livingRaiders(), second.livingRaiders());
CHECK_EQ(first.golems().spawnedTotal, second.golems().spawnedTotal);
CHECK(first.state() == second.state());
bool identical = first.raiders().size() == second.raiders().size();
for (std::size_t i = 0; i < first.raiders().size() && identical; ++i) {
const Raider& a = first.raiders()[i];
const Raider& b = second.raiders()[i];
if (a.kind != b.kind || a.alive != b.alive) identical = false;
if (std::fabs(a.position.x - b.position.x) > 1e-5f) identical = false;
if (std::fabs(a.position.z - b.position.z) > 1e-5f) identical = false;
if (std::fabs(a.health - b.health) > 1e-5f) identical = false;
}
CHECK(identical);
RaidManager other(villageCenter, 99u, raidDifficultyHard);
OmenState otherOmen = omenAt(2);
std::vector<Villager> otherVillagers = makeVillagers(4);
PoiRegistry otherPois;
otherPois.scan(world, villageCenter, 12, 4);
CHECK(other.tryStart(otherOmen, {0.5f, static_cast<float>(walkY), 0.5f}, 32.0f));
other.tick(world, otherVillagers, otherPois, otherOmen, schedule, clock, 1);
CHECK_EQ(other.wave().total(), first.wave().total());
}
VF_TEST(villagersPanicHomeInsteadOfWorkingWhileTheRaidIsRunning) {
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));
for (int tick = 0; tick < 400; ++tick)
for (Villager& villager : villagers)
tickVillager(world, villager, pois, clock, schedule, villageCenter, false, 0.05f);
CHECK(villagers[0].activity == VillagerActivity::Work);
CHECK(villagers[0].employed());
int workBefore = villagers[0].workTicks;
OmenState omen = omenAt(1);
RaidManager raid(villageCenter, 8u, raidDifficultyEasy);
CHECK(raid.tryStart(omen, {0.5f, static_cast<float>(walkY), 0.5f}, 32.0f));
raid.tick(world, villagers, pois, omen, schedule, clock, 120);
CHECK(villagers[0].activity == VillagerActivity::Panic);
CHECK_EQ(villagers[0].workTicks, workBefore);
CHECK(villagers[0].bedIndex >= 0);
CHECK(villagers[0].alive);
CHECK(pois.at(villagers[0].bedIndex).ownerId == villagers[0].id);
}
VF_TEST(aWaveAdvancesOnTimeoutWhenTheRaidersRefuseToDie) {
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, 606u, raidDifficultyNormal);
CHECK(raid.tryStart(omen, {0.5f, static_cast<float>(walkY), 0.5f}, 32.0f));
int firstWaveSize = 0;
for (int tick = 0; tick < raidWaveTimeoutTicks - 5; ++tick) {
raid.tick(world, villagers, pois, omen, schedule, clock, 1);
for (Villager& villager : villagers)
if (villager.alive) villager.health = 20.0f;
if (firstWaveSize == 0) firstWaveSize = raid.totalSpawned();
}
CHECK_EQ(raid.waveIndex(), 0);
CHECK_EQ(raid.totalSpawned(), firstWaveSize);
CHECK(raid.livingRaiders() > 0);
for (int tick = 0; tick < 20; ++tick) {
raid.tick(world, villagers, pois, omen, schedule, clock, 1);
for (Villager& villager : villagers)
if (villager.alive) villager.health = 20.0f;
}
CHECK_EQ(raid.waveIndex(), 1);
CHECK(raid.totalSpawned() > firstWaveSize);
CHECK(raid.state() == RaidState::Fighting);
CHECK_EQ(livingVillagerCount(villagers), 2);
}
VF_TEST(raiderKindsCarryDistinctStatsAndReadableNames) {
const Raider::Stats& footSoldier = raiderStats(RaiderKind::Raider);
const Raider::Stats& brute = raiderStats(RaiderKind::Ravager);
CHECK(brute.maxHealth > footSoldier.maxHealth);
CHECK(brute.damage > footSoldier.damage);
CHECK(brute.speed > footSoldier.speed);
CHECK(raiderStats(RaiderKind::Witch).attackRange > footSoldier.attackRange);
CHECK_EQ(std::string(raiderKindName(RaiderKind::Vindicator)), std::string("vindicator"));
CHECK_EQ(std::string(raidStateName(RaidState::Victory)), std::string("victory"));
CHECK_EQ(std::string(raidStateName(RaidState::Defeat)), std::string("defeat"));
RaidManager raid(villageCenter, 1u);
CHECK(raid.center() == villageCenter);
CHECK_EQ(raid.livingRaiders(), 0);
CHECK(!raid.damageRaider(0, 5.0f));
CHECK(raid.state() == RaidState::Inactive);
}