+#include "AttackGoal.hpp"
#include "BlobBackgroundTask.hpp"
#include "Goal.hpp"
#include "IdleGoal.hpp"
namespace blobs {
namespace creature {
+AttackGoal::AttackGoal(Creature &self, Creature &target)
+: Goal(self)
+, target(target)
+, damage_target(0.25)
+, damage_dealt(0.0)
+, cooldown(0.0) {
+}
+
+AttackGoal::~AttackGoal() {
+}
+
+std::string AttackGoal::Describe() const {
+ return "attack " + target.Name();
+}
+
+void AttackGoal::Tick(double dt) {
+ cooldown -= dt;
+}
+
+void AttackGoal::Action() {
+ if (target.Dead() || !GetCreature().PerceptionTest(target.GetSituation().Position())) {
+ SetComplete();
+ return;
+ }
+ const glm::dvec3 diff(GetCreature().GetSituation().Position() - target.GetSituation().Position());
+ const double hit_range = GetCreature().Size() * 0.5 * GetCreature().DexertyFactor();
+ const double hit_dist = hit_range + (0.5 * GetCreature().Size()) + 0.5 * (target.Size());
+ if (GetCreature().GetStats().Damage().Critical()) {
+ // flee
+ GetCreature().GetSteering().Pass(diff * 5.0);
+ GetCreature().GetSteering().DontSeparate();
+ GetCreature().GetSteering().Haste(1.0);
+ } else if (glm::length2(diff) > hit_dist * hit_dist) {
+ // full throttle chase
+ GetCreature().GetSteering().Pass(target.GetSituation().Position());
+ GetCreature().GetSteering().DontSeparate();
+ GetCreature().GetSteering().Haste(1.0);
+ } else {
+ // attack
+ GetCreature().GetSteering().Halt();
+ GetCreature().GetSteering().DontSeparate();
+ GetCreature().GetSteering().Haste(1.0);
+ if (cooldown <= 0.0) {
+ constexpr double impulse = 0.05;
+ const double force = GetCreature().Strength();
+ const double damage =
+ force * impulse
+ * (GetCreature().GetComposition().TotalDensity() / target.GetComposition().TotalDensity())
+ * (GetCreature().Mass() / target.Mass())
+ / target.Mass();
+ GetCreature().DoWork(force * impulse * glm::length(diff));
+ target.Hurt(damage);
+ target.GetSituation().Accelerate(glm::normalize(diff) * force * -impulse);
+ damage_dealt += damage;
+ if (damage_dealt >= damage_target || target.Dead()) {
+ SetComplete();
+ if (target.Dead()) {
+ GetCreature().GetSimulation().Log() << GetCreature().Name()
+ << " killed " << target.Name() << std::endl;
+ }
+ }
+ cooldown = 1.0 + (4.0 * (1.0 - GetCreature().DexertyFactor()));
+ }
+ }
+}
+
+void AttackGoal::OnBackground() {
+ // abort if something more important comes up
+ SetComplete();
+}
+
+
BlobBackgroundTask::BlobBackgroundTask(Creature &c)
: Goal(c)
, breathing(false)
if (!searching) {
LocateResource();
} else {
- double dist = glm::length2(GetSituation().Position() - target_pos);
- if (dist < 0.0001) {
+ if (OnTarget()) {
searching = false;
LocateResource();
} else {
GetSteering().GoTo(target_pos);
}
}
- } else if (NearTarget()) {
+ } else if (OnTarget()) {
GetSteering().Halt();
if (!GetSituation().Moving()) {
SetComplete();
const world::Planet &planet = GetSituation().GetPlanet();
const glm::dvec3 &pos = GetSituation().Position();
const glm::dvec3 normal(planet.NormalAt(pos));
- const glm::dvec3 step_x(glm::normalize(glm::cross(normal, glm::dvec3(normal.z, normal.x, normal.y))));
- const glm::dvec3 step_y(glm::normalize(glm::cross(step_x, normal)));
+ const glm::dvec3 step_x(glm::normalize(glm::cross(normal, glm::dvec3(normal.z, normal.x, normal.y))) * (GetCreature().PerceptionOmniRange() * 0.7));
+ const glm::dvec3 step_y(glm::normalize(glm::cross(step_x, normal)) * (GetCreature().PerceptionOmniRange() * 0.7));
- constexpr int search_radius = 2;
- double rating[2 * search_radius + 1][2 * search_radius + 1] = {0};
+ const int search_radius = int(GetCreature().PerceptionRange() / (GetCreature().PerceptionOmniRange() * 0.7));
+ double rating[2 * search_radius + 1][2 * search_radius + 1];
+ std::memset(rating, '\0', (2 * search_radius + 1) * (2 * search_radius + 1) * sizeof(double));
// find close and rich field
for (int y = -search_radius; y < search_radius + 1; ++y) {
found = false;
searching = true;
target_pos = GetSituation().Position();
- target_pos += Random().SNorm() * step_x;
- target_pos += Random().SNorm() * step_y;
+ target_pos += Random().SNorm() * 3.0 * step_x;
+ target_pos += Random().SNorm() * 3.0 * step_y;
// bias towards current heading
target_pos += GetSituation().Heading() * 1.5;
target_pos = glm::normalize(target_pos) * planet.Radius();
GetSteering().GoTo(target_pos);
}
-bool LocateResourceGoal::NearTarget() const noexcept {
+bool LocateResourceGoal::OnTarget() const noexcept {
const Situation &s = GetSituation();
- return s.OnSurface() && glm::length2(s.Position() - target_pos) < 0.5;
+ return s.OnGround() && glm::length2(s.Position() - target_pos) < 0.0001;
}