From 77c5b822d7cce219d1603103571b9bbde70686f2 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 6 Sep 2026 17:12:00 +0200 Subject: [PATCH] feat: add cellIsShaded and horizontalHeading --- core/src/Behavior.cpp | 155 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 core/src/Behavior.cpp diff --git a/core/src/Behavior.cpp b/core/src/Behavior.cpp new file mode 100644 index 0000000..e2c5fbe --- /dev/null +++ b/core/src/Behavior.cpp @@ -0,0 +1,155 @@ +#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; +} +