test: extend coverage of testSpawning
This commit is contained in:
1 parent
832d5f6b8b
commit
5dbfacf76f
1 file changed
+158
@@ -314,3 +314,161 @@ VF_TEST(aRunningCycleStopsSpawningOnceTheCapIsReached) {
|
|||||||
spawner.runCycle(env, SpawnCategory::Hostile, columns, 1234u + static_cast<uint64_t>(cycle));
|
spawner.runCycle(env, SpawnCategory::Hostile, columns, 1234u + static_cast<uint64_t>(cycle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHECK(env.populationOf(SpawnCategory::Hostile) > 0);
|
||||||
|
CHECK(env.populationOf(SpawnCategory::Hostile) <= limit + 4);
|
||||||
|
CHECK(spawner.denialCount(SpawnDenial::CategoryCapReached) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aPackArrivesSpreadAroundItsOriginCell) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
|
||||||
|
SpawnRule rule = zombieRule();
|
||||||
|
rule.packMin = 4;
|
||||||
|
rule.packMax = 4;
|
||||||
|
rule.packSpread = 3;
|
||||||
|
|
||||||
|
Spawner spawner({rule});
|
||||||
|
SpawnTrial trial;
|
||||||
|
trial.cell = originCell();
|
||||||
|
trial.species = Species::Zombie;
|
||||||
|
trial.category = SpawnCategory::Hostile;
|
||||||
|
trial.ruleFound = true;
|
||||||
|
trial.cellFound = true;
|
||||||
|
trial.packSize = 4;
|
||||||
|
|
||||||
|
SpawnResult result = spawner.attemptSpawn(env, rule, trial, 4242u);
|
||||||
|
CHECK(result.spawned);
|
||||||
|
CHECK(result.denial == SpawnDenial::None);
|
||||||
|
CHECK(result.packSize() >= 2);
|
||||||
|
CHECK(result.packSize() <= 4);
|
||||||
|
CHECK(result.role == BehaviorRole::HostileHunter);
|
||||||
|
|
||||||
|
for (const Vec3& spot : result.positions) {
|
||||||
|
CHECK(std::fabs(spot.x - 0.5f) <= static_cast<float>(rule.packSpread));
|
||||||
|
CHECK(std::fabs(spot.z - 0.5f) <= static_cast<float>(rule.packSpread));
|
||||||
|
CHECK(world.solidAt(static_cast<int>(std::floor(spot.x)), floorY,
|
||||||
|
static_cast<int>(std::floor(spot.z))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aSpawnedPackBecomesAgentsCarryingTheRightBehaviourRole) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
|
||||||
|
SpawnRule rule = zombieRule();
|
||||||
|
rule.packMin = 3;
|
||||||
|
rule.packMax = 3;
|
||||||
|
Spawner spawner({rule});
|
||||||
|
|
||||||
|
SpawnTrial trial;
|
||||||
|
trial.cell = originCell();
|
||||||
|
trial.species = Species::Zombie;
|
||||||
|
trial.ruleFound = true;
|
||||||
|
trial.cellFound = true;
|
||||||
|
trial.packSize = 3;
|
||||||
|
|
||||||
|
SpawnResult result = spawner.attemptSpawn(env, rule, trial, 77u);
|
||||||
|
CHECK(result.spawned);
|
||||||
|
|
||||||
|
std::vector<BehaviorAgent> agents = agentsFromSpawn(result, 5u);
|
||||||
|
CHECK_EQ(agents.size(), result.positions.size());
|
||||||
|
const SpeciesStats& stats = speciesStats(Species::Zombie);
|
||||||
|
for (const BehaviorAgent& agent : agents) {
|
||||||
|
CHECK(agent.species == Species::Zombie);
|
||||||
|
CHECK_NEAR(agent.health, stats.maxHealth, 1e-6f);
|
||||||
|
CHECK_NEAR(agent.maxHealth, stats.maxHealth, 1e-6f);
|
||||||
|
CHECK(agent.moveStep > 0.0f);
|
||||||
|
CHECK(agent.rng != 0u);
|
||||||
|
}
|
||||||
|
CHECK(makeTreeForRole(result.role).structureValid());
|
||||||
|
|
||||||
|
SpawnResult refused;
|
||||||
|
CHECK(agentsFromSpawn(refused, 5u).empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(despawnNeverTouchesAMobStandingNextToThePlayer) {
|
||||||
|
DespawnPolicy policy;
|
||||||
|
DespawnCandidate mob;
|
||||||
|
mob.position = {10.0f, 64.0f, 0.0f};
|
||||||
|
Vec3 player{0.0f, 64.0f, 0.0f};
|
||||||
|
|
||||||
|
CHECK(despawnBandFor(policy, mob.position, player) == DespawnBand::Protected);
|
||||||
|
uint32_t rng = 12345u;
|
||||||
|
for (int tick = 0; tick < 2000; ++tick) {
|
||||||
|
CHECK(!shouldDespawn(policy, mob, player, rng));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(despawnRemovesAMobBeyondTheHardDistanceImmediately) {
|
||||||
|
DespawnPolicy policy;
|
||||||
|
DespawnCandidate mob;
|
||||||
|
mob.position = {200.0f, 64.0f, 0.0f};
|
||||||
|
Vec3 player{0.0f, 64.0f, 0.0f};
|
||||||
|
|
||||||
|
CHECK(despawnBandFor(policy, mob.position, player) == DespawnBand::Immediate);
|
||||||
|
uint32_t rng = 1u;
|
||||||
|
CHECK(shouldDespawn(policy, mob, player, rng));
|
||||||
|
CHECK_EQ(rng, 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(despawnInTheMiddleBandIsARollThatMatchesItsStatedOdds) {
|
||||||
|
DespawnPolicy policy;
|
||||||
|
policy.randomChanceDenominator = 50;
|
||||||
|
DespawnCandidate mob;
|
||||||
|
mob.position = {64.0f, 64.0f, 0.0f};
|
||||||
|
Vec3 player{0.0f, 64.0f, 0.0f};
|
||||||
|
CHECK(despawnBandFor(policy, mob.position, player) == DespawnBand::Random);
|
||||||
|
|
||||||
|
int hits = 0;
|
||||||
|
uint32_t rng = 0x1337u;
|
||||||
|
for (int tick = 0; tick < 5000; ++tick) {
|
||||||
|
if (shouldDespawn(policy, mob, player, rng)) ++hits;
|
||||||
|
}
|
||||||
|
CHECK(hits > 40);
|
||||||
|
CHECK(hits < 180);
|
||||||
|
|
||||||
|
// Same seed, same sequence of rolls.
|
||||||
|
int replay = 0;
|
||||||
|
uint32_t again = 0x1337u;
|
||||||
|
for (int tick = 0; tick < 5000; ++tick) {
|
||||||
|
if (shouldDespawn(policy, mob, player, again)) ++replay;
|
||||||
|
}
|
||||||
|
CHECK_EQ(replay, hits);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(namedAndLeashedMobsSurviveEvenAtTheEdgeOfTheWorld) {
|
||||||
|
DespawnPolicy policy;
|
||||||
|
Vec3 player{0.0f, 64.0f, 0.0f};
|
||||||
|
uint32_t rng = 9u;
|
||||||
|
|
||||||
|
DespawnCandidate named;
|
||||||
|
named.position = {500.0f, 64.0f, 0.0f};
|
||||||
|
named.named = true;
|
||||||
|
CHECK(despawnCandidateIsProtected(policy, named));
|
||||||
|
CHECK(!shouldDespawn(policy, named, player, rng));
|
||||||
|
|
||||||
|
DespawnCandidate leashed;
|
||||||
|
leashed.position = {500.0f, 64.0f, 0.0f};
|
||||||
|
leashed.leashed = true;
|
||||||
|
CHECK(!shouldDespawn(policy, leashed, player, rng));
|
||||||
|
|
||||||
|
DespawnCandidate persistent;
|
||||||
|
persistent.position = {500.0f, 64.0f, 0.0f};
|
||||||
|
persistent.persistent = true;
|
||||||
|
CHECK(!shouldDespawn(policy, persistent, player, rng));
|
||||||
|
|
||||||
|
DespawnPolicy ruthless;
|
||||||
|
ruthless.despawnNamed = true;
|
||||||
|
CHECK(!despawnCandidateIsProtected(ruthless, named));
|
||||||
|
CHECK(shouldDespawn(ruthless, named, player, rng));
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(theSpawnerBlockCountsDownActivatesAndRespectsItsNearbyLimit) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
env.playerPosition = {0.5f, static_cast<float>(spawnY), 0.5f};
|
||||||
|
|
||||||
Reference in new issue
Block a user