test: cover testVillager

This commit is contained in:
dualfroz committed 2026-09-14 02:17:58 +02:00
1 parent 33b25a7185
commit a816d26b88
1 file changed
+159
+159
View File
@@ -156,3 +156,162 @@ VF_TEST(villagerWalksTheWholeDayFromBedToWorkToTheBellAndBackToBed) {
VillagerSchedule schedule; VillagerSchedule schedule;
TimeOfDay clock(0); TimeOfDay clock(0);
std::vector<VillagerActivity> seen;
Vec3i bellStand = pois.at(pois.bellIndex()).standCell;
bool reachedBellAtNoon = false;
for (WorldTick step = 0; step < 24000; step += 20) {
clock.setTick(step);
runTicks(world, villager, pois, clock, schedule, false, 20);
if (seen.empty() || seen.back() != villager.activity) seen.push_back(villager.activity);
if (villager.activity == VillagerActivity::Meet &&
villager.state == VillagerState::AtTarget) {
reachedBellAtNoon = true;
CHECK(horizontalGap(villager.body.position, bellStand) < 0.01f);
}
}
CHECK(reachedBellAtNoon);
CHECK(seen.size() >= 7);
CHECK(seen[0] == VillagerActivity::Sleep);
CHECK(seen[1] == VillagerActivity::Idle);
CHECK(seen[2] == VillagerActivity::SeekWorkstation);
CHECK(seen[3] == VillagerActivity::Work);
CHECK(seen[4] == VillagerActivity::Meet);
CHECK(seen[5] == VillagerActivity::Work);
CHECK(seen.back() == VillagerActivity::Sleep);
CHECK(villager.profession == VillagerProfession::Librarian);
CHECK(villager.workTicks > 1000);
CHECK(villager.bedIndex >= 0);
CHECK(villager.state == VillagerState::AtTarget);
CHECK(horizontalGap(villager.body.position, pois.at(villager.bedIndex).standCell) < 0.01f);
}
VF_TEST(breakingTheWorkstationDemotesAFreshVillagerBackToUnemployed) {
World world = makeVillage();
PoiRegistry pois;
pois.scan(world, villageCenter, 12, 4);
Villager villager = makeWorker(1, -1, 0, 21u);
TimeOfDay clock = clockAtFraction(0.35);
VillagerSchedule schedule;
runTicks(world, villager, pois, clock, schedule, false, 400);
CHECK(villager.profession == VillagerProfession::Librarian);
CHECK_EQ(villager.level, 1);
world.setBlock(-4, walkY, 0, Block::Air);
CHECK_EQ(pois.revalidate(world), 1);
runTicks(world, villager, pois, clock, schedule, false, 1);
CHECK(villager.profession == VillagerProfession::Unemployed);
CHECK_EQ(villager.workstationIndex, -1);
CHECK_EQ(villager.experience, 0);
runTicks(world, villager, pois, clock, schedule, false, 800);
CHECK(villager.profession == VillagerProfession::Farmer);
CHECK(pois.at(villager.workstationIndex).block == Block::Composter);
}
VF_TEST(aVillagerPastLevelOneKeepsItsTradeWhenTheWorkstationIsBroken) {
World world = makeVillage();
placePoi(world, -6, 0, Block::Lectern);
PoiRegistry pois;
pois.scan(world, villageCenter, 12, 4);
Villager villager = makeWorker(1, -1, 0, 31u);
TimeOfDay clock = clockAtFraction(0.35);
VillagerSchedule schedule;
runTicks(world, villager, pois, clock, schedule, false, 400);
CHECK(villager.profession == VillagerProfession::Librarian);
CHECK(grantVillagerExperience(villager, 20));
CHECK_EQ(villager.level, 2);
world.setBlock(-4, walkY, 0, Block::Air);
pois.revalidate(world);
runTicks(world, villager, pois, clock, schedule, false, 1);
CHECK(villager.profession == VillagerProfession::Librarian);
CHECK_EQ(villager.workstationIndex, -1);
CHECK_EQ(villager.experience, 20);
runTicks(world, villager, pois, clock, schedule, false, 400);
CHECK(villager.workstationIndex >= 0);
CHECK(pois.at(villager.workstationIndex).pos == Vec3i(-6, walkY, 0));
CHECK(villager.profession == VillagerProfession::Librarian);
}
VF_TEST(experienceThresholdsPromoteTheVillagerThroughAllFiveLevels) {
CHECK_EQ(villagerExperienceForLevel(1), 0);
CHECK_EQ(villagerLevelForExperience(0), 1);
CHECK_EQ(villagerLevelForExperience(villagerExperienceForLevel(5)), villagerMaxLevel);
Villager villager = makeWorker(1, 0, 0, 4u);
int reachedLevels = 1;
for (int step = 0; step < 60; ++step) {
if (grantVillagerExperience(villager, 5)) ++reachedLevels;
CHECK(villager.level <= villagerMaxLevel);
}
CHECK_EQ(reachedLevels, villagerMaxLevel);
CHECK_EQ(villager.level, villagerMaxLevel);
CHECK(!grantVillagerExperience(villager, 0));
for (int level = 2; level <= villagerMaxLevel; ++level)
CHECK(villagerExperienceForLevel(level) > villagerExperienceForLevel(level - 1));
}
VF_TEST(panicOverridesTheScheduleAndSendsTheVillagerBackToItsBed) {
World world = makeVillage();
PoiRegistry pois;
pois.scan(world, villageCenter, 12, 4);
Villager villager = makeWorker(1, -1, 0, 12u);
TimeOfDay clock = clockAtFraction(0.35);
VillagerSchedule schedule;
runTicks(world, villager, pois, clock, schedule, false, 400);
CHECK(villager.activity == VillagerActivity::Work);
CHECK(villager.profession == VillagerProfession::Librarian);
runTicks(world, villager, pois, clock, schedule, true, 1);
CHECK(villager.activity == VillagerActivity::Panic);
runTicks(world, villager, pois, clock, schedule, true, 600);
CHECK(villager.state == VillagerState::AtTarget);
CHECK(horizontalGap(villager.body.position, pois.at(villager.bedIndex).standCell) < 0.01f);
int workTicksUnderThreat = villager.workTicks;
runTicks(world, villager, pois, clock, schedule, true, 100);
CHECK_EQ(villager.workTicks, workTicksUnderThreat);
runTicks(world, villager, pois, clock, schedule, false, 1);
CHECK(villager.activity == VillagerActivity::Work);
}
VF_TEST(deathReleasesTheBedAndWorkstationForSomebodyElse) {
World world = makeVillage();
PoiRegistry pois;
pois.scan(world, villageCenter, 12, 4);
Villager villager = makeWorker(1, -1, 0, 55u);
TimeOfDay clock = clockAtFraction(0.35);
VillagerSchedule schedule;
runTicks(world, villager, pois, clock, schedule, false, 400);
CHECK_EQ(pois.freeWorkstationCount(), 1);
CHECK_EQ(pois.freeBedCount(), 1);
CHECK(!damageVillager(villager, pois, 10.0f));
CHECK(villager.alive);
CHECK(damageVillager(villager, pois, 10.0f));
CHECK(!villager.alive);
CHECK(villager.state == VillagerState::Dead);
CHECK_EQ(villager.workstationIndex, -1);
CHECK_EQ(pois.freeWorkstationCount(), 2);
CHECK_EQ(pois.freeBedCount(), 2);
CHECK(!damageVillager(villager, pois, 10.0f));
Villager heir = makeWorker(2, -1, 0, 56u);
runTicks(world, heir, pois, clock, schedule, false, 400);
CHECK(heir.profession == VillagerProfession::Librarian);
}