feat: add straightDistance and groundAndRoomFit

This commit is contained in:
dualfroz committed 2026-09-09 18:52:40 +02:00
1 parent fea440d31f
commit ebcace7837
1 file changed
+160
+160
View File
@@ -0,0 +1,160 @@
#include "vf/Spawning.h"
#include <algorithm>
#include <cmath>
#include "vf/Effect.h"
namespace vf {
namespace {
constexpr int nightSkyLightPenalty = 11;
float straightDistance(const Vec3& a, const Vec3& b) {
Vec3 delta = a - b;
return length(delta);
}
bool groundAndRoomFit(const SpawnRule& rule, const SpawnEnvironment& env, const Vec3i& cell) {
Block ground = env.world->blockAt(cell.x, cell.y - 1, cell.z);
if (!isSolid(ground)) return false;
if (!rule.allowsGround(ground)) return false;
return hasSpawnRoom(*env.world, cell, rule.requiredHeadroom);
}
bool lightFits(const SpawnRule& rule, const SpawnEnvironment& env, const Vec3i& cell) {
int blockLight = env.blockLightAt(cell);
int skyLight = env.skyLightAt(cell);
if (blockLight > rule.maxBlockLight) return false;
if (skyLight > rule.maxSkyLight) return false;
if (blockLight < rule.minBlockLight) return false;
if (skyLight < rule.minSkyLight) return false;
return true;
}
SpawnRule makeHostileRule(Species species, int packMin, int packMax) {
SpawnRule rule;
rule.species = species;
rule.category = SpawnCategory::Hostile;
rule.dimension = DimensionId::Overworld;
rule.maxBlockLight = 7;
rule.maxSkyLight = 7;
rule.minY = 1;
rule.maxY = 127;
rule.requiredHeadroom = 2;
rule.dayAllowed = false;
rule.nightAllowed = true;
rule.packMin = packMin;
rule.packMax = packMax;
rule.packSpread = 3;
rule.weight = 10;
rule.minPlayerDistance = 24.0f;
rule.maxPlayerDistance = 128.0f;
return rule;
}
SpawnRule makePassiveRule(Species species, int packMin, int packMax,
std::vector<BiomeKind> biomeList) {
SpawnRule rule;
rule.species = species;
rule.category = SpawnCategory::Passive;
rule.dimension = DimensionId::Overworld;
rule.minBlockLight = 0;
rule.minSkyLight = 9;
rule.maxBlockLight = 15;
rule.maxSkyLight = 15;
rule.minY = 48;
rule.maxY = 127;
rule.groundBlocks = {Block::Grass};
rule.requiredHeadroom = 2;
rule.biomes = std::move(biomeList);
rule.dayAllowed = true;
rule.nightAllowed = true;
rule.packMin = packMin;
rule.packMax = packMax;
rule.packSpread = 4;
rule.weight = 12;
rule.minPlayerDistance = 12.0f;
rule.maxPlayerDistance = 96.0f;
return rule;
}
} // namespace
const char* spawnCategoryName(SpawnCategory category) {
switch (category) {
case SpawnCategory::Hostile: return "hostile";
case SpawnCategory::Passive: return "passive";
case SpawnCategory::Water: return "water";
case SpawnCategory::Ambient: return "ambient";
case SpawnCategory::Count: break;
}
return "unknown";
}
SpawnCategory categoryForSpecies(Species species) {
return isHostile(species) ? SpawnCategory::Hostile : SpawnCategory::Passive;
}
const char* spawnDenialName(SpawnDenial denial) {
switch (denial) {
case SpawnDenial::None: return "none";
case SpawnDenial::CategoryCapReached: return "categoryCapReached";
case SpawnDenial::WrongDimension: return "wrongDimension";
case SpawnDenial::WrongBiome: return "wrongBiome";
case SpawnDenial::WrongTimeOfDay: return "wrongTimeOfDay";
case SpawnDenial::HeightOutOfRange: return "heightOutOfRange";
case SpawnDenial::UnsuitableGround: return "unsuitableGround";
case SpawnDenial::NoHeadroom: return "noHeadroom";
case SpawnDenial::BlockLightTooHigh: return "blockLightTooHigh";
case SpawnDenial::SkyLightTooHigh: return "skyLightTooHigh";
case SpawnDenial::LightTooLow: return "lightTooLow";
case SpawnDenial::TooCloseToPlayer: return "tooCloseToPlayer";
case SpawnDenial::TooFarFromPlayer: return "tooFarFromPlayer";
case SpawnDenial::NoStandableCell: return "noStandableCell";
case SpawnDenial::NoRuleMatched: return "noRuleMatched";
case SpawnDenial::Count: break;
}
return "unknown";
}
bool SpawnRule::allowsBiome(BiomeKind biome) const {
if (biomes.empty()) return true;
return std::find(biomes.begin(), biomes.end(), biome) != biomes.end();
}
bool SpawnRule::allowsGround(Block block) const {
if (groundBlocks.empty()) return isSolid(block);
return std::find(groundBlocks.begin(), groundBlocks.end(), block) != groundBlocks.end();
}
std::vector<SpawnRule> defaultSpawnRules() {
std::vector<SpawnRule> rules;
rules.push_back(makeHostileRule(Species::Zombie, 2, 4));
rules.push_back(makeHostileRule(Species::Skeleton, 1, 3));
SpawnRule creeper = makeHostileRule(Species::Creeper, 1, 2);
creeper.biomes = {BiomeKind::Plains, BiomeKind::Forest, BiomeKind::Taiga,
BiomeKind::Tundra, BiomeKind::Swamp, BiomeKind::Jungle,
BiomeKind::Savanna, BiomeKind::Mountains, BiomeKind::Desert};
rules.push_back(creeper);
rules.push_back(makePassiveRule(
Species::Sheep, 2, 4,
{BiomeKind::Plains, BiomeKind::Forest, BiomeKind::Savanna, BiomeKind::Taiga}));
rules.push_back(makePassiveRule(
Species::Cow, 2, 4,
{BiomeKind::Plains, BiomeKind::Forest, BiomeKind::Savanna, BiomeKind::Taiga}));
rules.push_back(makePassiveRule(
Species::Pig, 1, 3, {BiomeKind::Plains, BiomeKind::Forest, BiomeKind::Swamp}));
return rules;
}
const SpawnRule* findSpawnRule(const std::vector<SpawnRule>& rules, Species species) {
for (const SpawnRule& rule : rules) {
if (rule.species == species) return &rule;
}
return nullptr;
}