156 lines
5.2 KiB
C++
156 lines
5.2 KiB
C++
#include "vf/Behavior.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <utility>
|
|
|
|
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<BehaviorNode> condition(const char* name, BehaviorPredicate predicate) {
|
|
return std::unique_ptr<BehaviorNode>(new ConditionNode(name, std::move(predicate)));
|
|
}
|
|
|
|
std::unique_ptr<BehaviorNode> action(const char* name, BehaviorAction fn) {
|
|
return std::unique_ptr<BehaviorNode>(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<float>(behaviorNextRandom(state)) / 4294967296.0f;
|
|
}
|
|
|
|
int behaviorRandomRange(uint32_t& state, int minInclusive, int maxInclusive) {
|
|
if (maxInclusive <= minInclusive) return minInclusive;
|
|
uint32_t span = static_cast<uint32_t>(maxInclusive - minInclusive + 1);
|
|
return minInclusive + static_cast<int>(behaviorNextRandom(state) % span);
|
|
}
|
|
|
|
Vec3i behaviorCellOf(const Vec3& position) {
|
|
return {static_cast<int>(std::floor(position.x)), static_cast<int>(std::floor(position.y)),
|
|
static_cast<int>(std::floor(position.z))};
|
|
}
|
|
|
|
Vec3 behaviorCellCenter(const Vec3i& cell) {
|
|
return {static_cast<float>(cell.x) + 0.5f, static_cast<float>(cell.y),
|
|
static_cast<float>(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<Vec3i> 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<Vec3i>* 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;
|
|
}
|
|
|