#include "vf/Behavior.h" #include #include #include namespace vf { namespace { constexpr int shadeProbeHeight = 8; bool cellIsShaded(const World& world, const Vec3i& cell) { for (int y = cell.y + 1; y <= cell.y + shadeProbeHeight; ++y) { if (world.solidAt(cell.x, y, cell.z)) return true; } return false; } Vec3 horizontalHeading(uint32_t& rng) { float angle = behaviorUnitFloat(rng) * 6.2831853f; return {std::cos(angle), 0.0f, std::sin(angle)}; } const SpeciesStats& statsOf(const BehaviorContext& ctx) { return speciesStats(ctx.agent->species); } std::unique_ptr condition(const char* name, BehaviorPredicate predicate) { return std::unique_ptr(new ConditionNode(name, std::move(predicate))); } std::unique_ptr action(const char* name, BehaviorAction fn) { return std::unique_ptr(new ActionNode(name, std::move(fn))); } BehaviorStatus followRouteAction(BehaviorContext& ctx) { return followRouteStep(ctx); } } // namespace const char* behaviorStatusName(BehaviorStatus status) { switch (status) { case BehaviorStatus::Failure: return "failure"; case BehaviorStatus::Success: return "success"; case BehaviorStatus::Running: return "running"; } return "unknown"; } uint32_t behaviorNextRandom(uint32_t& state) { if (state == 0u) state = 0x9e3779b9u; state ^= state << 13; state ^= state >> 17; state ^= state << 5; return state; } float behaviorUnitFloat(uint32_t& state) { return static_cast(behaviorNextRandom(state)) / 4294967296.0f; } int behaviorRandomRange(uint32_t& state, int minInclusive, int maxInclusive) { if (maxInclusive <= minInclusive) return minInclusive; uint32_t span = static_cast(maxInclusive - minInclusive + 1); return minInclusive + static_cast(behaviorNextRandom(state) % span); } Vec3i behaviorCellOf(const Vec3& position) { return {static_cast(std::floor(position.x)), static_cast(std::floor(position.y)), static_cast(std::floor(position.z))}; } Vec3 behaviorCellCenter(const Vec3i& cell) { return {static_cast(cell.x) + 0.5f, static_cast(cell.y), static_cast(cell.z) + 0.5f}; } float behaviorHorizontalDistance(const Vec3& a, const Vec3& b) { float dx = a.x - b.x; float dz = a.z - b.z; return std::sqrt(dx * dx + dz * dz); } void Blackboard::setNumber(const std::string& key, float value) { numbers[key] = value; } void Blackboard::setCount(const std::string& key, int value) { counts[key] = value; } void Blackboard::setFlag(const std::string& key, bool value) { flags[key] = value; } void Blackboard::setPoint(const std::string& key, const Vec3& value) { points[key] = value; } void Blackboard::setCell(const std::string& key, const Vec3i& value) { cells[key] = value; } void Blackboard::setRoute(const std::string& key, std::vector cellList) { routes[key] = std::move(cellList); } bool Blackboard::hasNumber(const std::string& key) const { return numbers.count(key) != 0; } bool Blackboard::hasCount(const std::string& key) const { return counts.count(key) != 0; } bool Blackboard::hasFlag(const std::string& key) const { return flags.count(key) != 0; } bool Blackboard::hasPoint(const std::string& key) const { return points.count(key) != 0; } bool Blackboard::hasCell(const std::string& key) const { return cells.count(key) != 0; } bool Blackboard::hasRoute(const std::string& key) const { return routes.count(key) != 0; } float Blackboard::number(const std::string& key, float fallback) const { auto found = numbers.find(key); return found == numbers.end() ? fallback : found->second; } int Blackboard::count(const std::string& key, int fallback) const { auto found = counts.find(key); return found == counts.end() ? fallback : found->second; } bool Blackboard::flag(const std::string& key, bool fallback) const { auto found = flags.find(key); return found == flags.end() ? fallback : found->second; } Vec3 Blackboard::point(const std::string& key, const Vec3& fallback) const { auto found = points.find(key); return found == points.end() ? fallback : found->second; } Vec3i Blackboard::cell(const std::string& key, const Vec3i& fallback) const { auto found = cells.find(key); return found == cells.end() ? fallback : found->second; } const std::vector* Blackboard::route(const std::string& key) const { auto found = routes.find(key); return found == routes.end() ? nullptr : &found->second; } void Blackboard::eraseNumber(const std::string& key) { numbers.erase(key); } void Blackboard::eraseRoute(const std::string& key) { routes.erase(key); } void Blackboard::clear() { numbers.clear(); counts.clear(); flags.clear(); points.clear(); cells.clear(); routes.clear(); } std::size_t Blackboard::entryCount() const { return numbers.size() + counts.size() + flags.size() + points.size() + cells.size() + routes.size(); } BehaviorNode::BehaviorNode(std::string name) : nodeName(std::move(name)) {} BehaviorNode::~BehaviorNode() = default; BehaviorNode* BehaviorNode::childAt(int index) const { (void)index; return nullptr; }