feat(vf): add SpawnResult and DespawnPolicy to Spawning
This commit is contained in:
1 parent
ad742d3423
commit
66cd109fe1
1 file changed
+141
@@ -153,3 +153,144 @@ struct SpawnTrial {
|
||||
bool cellFound = false;
|
||||
};
|
||||
|
||||
struct SpawnResult {
|
||||
bool spawned = false;
|
||||
SpawnDenial denial = SpawnDenial::NoRuleMatched;
|
||||
Species species = Species::Zombie;
|
||||
SpawnCategory category = SpawnCategory::Hostile;
|
||||
BehaviorRole role = BehaviorRole::HostileHunter;
|
||||
Vec3i origin;
|
||||
std::vector<Vec3> positions;
|
||||
|
||||
int packSize() const { return static_cast<int>(positions.size()); }
|
||||
};
|
||||
|
||||
// Deterministic 64-bit mix. Same seed, same cell, same salt, same number.
|
||||
uint64_t spawnHash(uint64_t seed, int x, int y, int z, int salt);
|
||||
|
||||
// Standable, has the headroom the rule wants and nothing solid in the way.
|
||||
bool hasSpawnRoom(const World& world, const Vec3i& cell, int headroom);
|
||||
|
||||
// The full per-cell verdict, checked in a fixed order so a caller can tell
|
||||
// exactly which condition failed.
|
||||
SpawnDenial checkSpawnRule(const SpawnRule& rule, const SpawnEnvironment& env, const Vec3i& cell,
|
||||
const MobCap& cap);
|
||||
|
||||
// Picks the highest standable cell in one column of the chunk, chosen from the
|
||||
// seed rather than scanned in order.
|
||||
bool pickSpawnCell(const SpawnEnvironment& env, const Vec3i& chunkColumn, uint64_t seed,
|
||||
int attemptIndex, Vec3i& outCell);
|
||||
|
||||
// Spreads a pack around an accepted origin. Members that land somewhere the
|
||||
// rule rejects are simply left out; the origin is always member zero.
|
||||
std::vector<Vec3> spreadPack(const SpawnRule& rule, const SpawnEnvironment& env,
|
||||
const Vec3i& origin, int packSize, uint32_t& rng);
|
||||
|
||||
enum class DespawnBand : uint8_t {
|
||||
Protected = 0,
|
||||
Random = 1,
|
||||
Immediate = 2,
|
||||
};
|
||||
|
||||
// Distance bands around the player. Beyond `instantDistance` a mob is gone the
|
||||
// moment it is checked; between the two distances it rolls every tick; closer
|
||||
// than `randomDistance` it never despawns on its own.
|
||||
struct DespawnPolicy {
|
||||
float instantDistance = 128.0f;
|
||||
float randomDistance = 32.0f;
|
||||
int randomChanceDenominator = 800;
|
||||
bool despawnNamed = false;
|
||||
bool despawnLeashed = false;
|
||||
};
|
||||
|
||||
struct DespawnCandidate {
|
||||
Vec3 position;
|
||||
bool named = false;
|
||||
bool leashed = false;
|
||||
bool persistent = false;
|
||||
};
|
||||
|
||||
DespawnBand despawnBandFor(const DespawnPolicy& policy, const Vec3& position,
|
||||
const Vec3& playerPosition);
|
||||
bool despawnCandidateIsProtected(const DespawnPolicy& policy, const DespawnCandidate& candidate);
|
||||
bool shouldDespawn(const DespawnPolicy& policy, const DespawnCandidate& candidate,
|
||||
const Vec3& playerPosition, uint32_t& rng);
|
||||
|
||||
// A monster spawner block: counts down, refuses to fire without a player in
|
||||
// range or with too many of its own kind already nearby, then picks a fresh
|
||||
// delay from its range.
|
||||
struct SpawnerBlockState {
|
||||
Species species = Species::Zombie;
|
||||
Vec3i position;
|
||||
int spawnCount = 4;
|
||||
int spawnRange = 4;
|
||||
int nearbyLimit = 6;
|
||||
int requiredHeadroom = 2;
|
||||
float activationRange = 16.0f;
|
||||
int minDelay = 200;
|
||||
int maxDelay = 800;
|
||||
int delay = 20;
|
||||
int totalSpawned = 0;
|
||||
int cyclesFired = 0;
|
||||
uint32_t rng = 0x1f123bb5u;
|
||||
};
|
||||
|
||||
struct SpawnerTickResult {
|
||||
bool playerInRange = false;
|
||||
bool fired = false;
|
||||
SpawnDenial denial = SpawnDenial::None;
|
||||
std::vector<Vec3> positions;
|
||||
int delayAfter = 0;
|
||||
};
|
||||
|
||||
SpawnerTickResult tickSpawnerBlock(SpawnerBlockState& spawner, const SpawnEnvironment& env,
|
||||
int nearbyOfKind);
|
||||
|
||||
// Runs spawn cycles over loaded chunk columns and keeps a per-reason tally of
|
||||
// everything it refused, so a world that never spawns anything can be
|
||||
// diagnosed instead of guessed at.
|
||||
class Spawner {
|
||||
public:
|
||||
Spawner();
|
||||
explicit Spawner(std::vector<SpawnRule> ruleTable, const MobCap& caps = {});
|
||||
|
||||
const std::vector<SpawnRule>& rules() const { return ruleTable; }
|
||||
const MobCap& caps() const { return capTable; }
|
||||
|
||||
void setAttemptsPerColumn(int attempts) { attemptsPerColumnCount = attempts; }
|
||||
int attemptsPerColumn() const { return attemptsPerColumnCount; }
|
||||
|
||||
// Weighted pick among the rules of one category that fit the dimension.
|
||||
const SpawnRule* pickRule(const SpawnEnvironment& env, SpawnCategory category,
|
||||
uint64_t seed) const;
|
||||
|
||||
// Draws a rule and a cell without touching the world state.
|
||||
SpawnTrial planSpawn(const SpawnEnvironment& env, SpawnCategory category,
|
||||
const Vec3i& chunkColumn, uint64_t seed, int attemptIndex) const;
|
||||
|
||||
SpawnResult attemptSpawn(const SpawnEnvironment& env, const SpawnRule& rule,
|
||||
const SpawnTrial& trial, uint64_t seed);
|
||||
|
||||
SpawnResult runColumn(SpawnEnvironment& env, SpawnCategory category, const Vec3i& chunkColumn,
|
||||
uint64_t seed, int attemptIndex);
|
||||
|
||||
std::vector<SpawnResult> runCycle(SpawnEnvironment& env, SpawnCategory category,
|
||||
const std::vector<Vec3i>& chunkColumns, uint64_t seed);
|
||||
|
||||
int denialCount(SpawnDenial denial) const;
|
||||
int spawnedCount() const { return spawned; }
|
||||
void resetStats();
|
||||
|
||||
private:
|
||||
std::vector<SpawnRule> ruleTable;
|
||||
MobCap capTable;
|
||||
int attemptsPerColumnCount = 3;
|
||||
int spawned = 0;
|
||||
std::array<int, spawnDenialCount> denials{};
|
||||
};
|
||||
|
||||
// Hands a finished spawn straight to the behaviour layer: every member of the
|
||||
// pack becomes an agent already carrying the tree role for its species.
|
||||
std::vector<BehaviorAgent> agentsFromSpawn(const SpawnResult& result, uint32_t seed);
|
||||
|
||||
} // namespace vf
|
||||
Reference in new issue
Block a user