feat(core): declare mob AI state machine for wandering and targeting interface
This commit is contained in:
1 parent
b2559daa94
commit
a3fc5f6731
1 file changed
+118
@@ -0,0 +1,118 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "Entity.h"
|
||||
#include "Item.h"
|
||||
#include "Math.h"
|
||||
#include "Pathfind.h"
|
||||
#include "World.h"
|
||||
#include "WorldGen.h"
|
||||
|
||||
namespace vf {
|
||||
|
||||
enum class Species : uint8_t { Sheep, Cow, Pig, Zombie, Skeleton, Creeper, Count };
|
||||
|
||||
bool isHostile(Species species);
|
||||
inline bool isPassive(Species species) { return !isHostile(species); }
|
||||
|
||||
struct SpeciesStats {
|
||||
float maxHealth = 10.0f;
|
||||
float width = 0.6f;
|
||||
float height = 1.8f;
|
||||
float walkSpeed = 2.0f;
|
||||
float sprintMultiplier = 1.5f; // chase (hostile) or flee (passive) speed factor
|
||||
float attackDamage = 0.0f;
|
||||
float attackRange = 1.4f;
|
||||
float attackCooldown = 1.0f;
|
||||
float alertRadius = 12.0f; // hostile: aggro distance; passive: flee-trigger distance
|
||||
float disengageRadius = 16.0f; // hysteresis give-up radius once engaged
|
||||
int spawnLightMax = 7; // hostile: spawns only at or below this light
|
||||
int spawnLightMin = 9; // passive: spawns only at or above this light
|
||||
};
|
||||
|
||||
const SpeciesStats& speciesStats(Species species);
|
||||
|
||||
enum class CreatureState : uint8_t { Idle, Wander, Flee, Chase, Attack };
|
||||
|
||||
// A gameplay mob: species identity, health and an AI state machine layered on
|
||||
// top of the physics body from Entity.h. `body.wanderDir` is reused as the
|
||||
// creature's persistent wander/flee heading between ticks.
|
||||
struct Creature {
|
||||
Mob body;
|
||||
Species species = Species::Sheep;
|
||||
CreatureState state = CreatureState::Idle;
|
||||
float health = 10.0f;
|
||||
float attackCooldownRemaining = 0.0f;
|
||||
float stateTimer = 0.0f;
|
||||
uint32_t rng = 0x9e3779b9u;
|
||||
bool alive = true;
|
||||
};
|
||||
|
||||
Creature spawnCreature(Species species, const Vec3& position, uint32_t seed);
|
||||
|
||||
struct CreatureConfig {
|
||||
MobConfig physics;
|
||||
};
|
||||
|
||||
// One AI+physics tick. `hasThreat` false means no relevant target this tick
|
||||
// (out of range, dead, or none nearby); the creature then wanders or idles.
|
||||
// Hostile species chase and attack a present threat; passive species flee it.
|
||||
void updateCreature(const World& world, Creature& creature, const Vec3& threatPos, bool hasThreat,
|
||||
const CreatureConfig& config, float dt);
|
||||
|
||||
bool damageCreature(Creature& creature, float amount);
|
||||
bool creatureCanAttack(const Creature& creature, const Vec3& targetPos);
|
||||
void creatureAttack(Creature& creature);
|
||||
|
||||
struct DropEntry {
|
||||
ItemId item = ItemId::None;
|
||||
int minCount = 0;
|
||||
int maxCount = 0;
|
||||
float chance = 1.0f;
|
||||
};
|
||||
|
||||
std::vector<DropEntry> dropsFor(Species species);
|
||||
|
||||
// Rolls the drop table for `species`, advancing `rng`. Deterministic given the
|
||||
// same rng state.
|
||||
std::vector<ItemSlot> rollDrops(Species species, uint32_t& rng);
|
||||
|
||||
struct SpawnConfig {
|
||||
int maxPerArea = 24;
|
||||
float spawnAreaRadius = 64.0f;
|
||||
float minPlayerDistance = 12.0f;
|
||||
float maxPlayerDistance = 40.0f;
|
||||
};
|
||||
|
||||
// Approximate ambient light at a cell for spawn checks: full skylight when the
|
||||
// column above is unobstructed, combined with the strongest nearby block
|
||||
// emitter attenuated per Manhattan step.
|
||||
int mobSpawnLightLevel(const World& world, const Vec3i& cell, int searchRadius = 6);
|
||||
|
||||
bool speciesAllowsBiome(Species species, Biome biome);
|
||||
|
||||
bool canSpawnAt(const World& world, const Vec3i& cell, Species species, Biome biome,
|
||||
const Vec3& playerPos, int currentPopulationInArea, const SpawnConfig& config = {});
|
||||
|
||||
struct SpawnAttempt {
|
||||
bool spawned = false;
|
||||
Species species = Species::Sheep;
|
||||
Vec3 position;
|
||||
};
|
||||
|
||||
// Tests every species against canSpawnAt and, if at least one qualifies, picks
|
||||
// one deterministically from `rng`.
|
||||
SpawnAttempt trySpawn(const World& world, const Vec3i& cell, Biome biome, const Vec3& playerPos,
|
||||
int currentPopulationInArea, uint32_t& rng, const SpawnConfig& config = {});
|
||||
|
||||
struct SpawnCycle {
|
||||
float interval = 1.0f;
|
||||
float timer = 0.0f;
|
||||
};
|
||||
|
||||
// Advances the cycle timer; returns true on ticks where a spawn attempt should
|
||||
// run. Catches up at most once per call even after a large dt.
|
||||
bool advanceSpawnCycle(SpawnCycle& cycle, float dt);
|
||||
|
||||
} // namespace vf
|
||||
Reference in new issue
Block a user