+ state.pos = pos;
+}
+
+
+Steering::Steering(const Creature &c)
+: c(c)
+, target(0.0)
+, haste(0.0)
+, max_accel(1.0)
+, max_speed(1.0)
+, min_dist(0.0)
+, max_look(0.0)
+, separating(false)
+, halting(true)
+, seeking(false)
+, arriving(false) {
+}
+
+Steering::~Steering() {
+}
+
+void Steering::Separate(double min_distance, double max_lookaround) noexcept {
+ separating = true;
+ min_dist = min_distance;
+ max_look = max_lookaround;
+}
+
+void Steering::DontSeparate() noexcept {
+ separating = false;
+}
+
+void Steering::Halt() noexcept {
+ halting = true;
+ seeking = false;
+ arriving = false;
+}
+
+void Steering::Pass(const glm::dvec3 &t) noexcept {
+ target = t;
+ halting = false;
+ seeking = true;
+ arriving = false;
+}
+
+void Steering::GoTo(const glm::dvec3 &t) noexcept {
+ target = t;
+ halting = false;
+ seeking = false;
+ arriving = true;
+}
+
+glm::dvec3 Steering::Acceleration(const Situation::State &s) const noexcept {
+ double speed = max_speed * glm::clamp(max_speed * haste * haste, 0.25, 1.0);
+ double accel = max_speed * glm::clamp(max_accel * haste * haste, 0.5, 1.0);
+ glm::dvec3 result(0.0);
+ if (separating) {
+ // TODO: off surface situation
+ glm::dvec3 repulse(0.0);
+ const Situation &s = c.GetSituation();
+ for (auto &other : s.GetPlanet().Creatures()) {
+ if (&*other == &c) continue;
+ glm::dvec3 diff = s.Position() - other->GetSituation().Position();
+ if (length2(diff) > max_look * max_look) continue;
+ double sep = length(diff) - other->Size() * 0.707 - c.Size() * 0.707;
+ if (sep < min_dist) {
+ repulse += normalize(diff) * (1.0 - sep / min_dist);
+ }
+ }
+ SumForce(result, repulse, accel);
+ }
+ if (halting) {
+ SumForce(result, s.vel * -accel, accel);
+ }
+ if (seeking) {
+ glm::dvec3 diff = target - s.pos;
+ if (!allzero(diff)) {
+ SumForce(result, TargetVelocity(s, (normalize(diff) * speed), accel), accel);
+ }
+ }
+ if (arriving) {
+ glm::dvec3 diff = target - s.pos;
+ double dist = length(diff);
+ if (!allzero(diff) && dist > std::numeric_limits<double>::epsilon()) {
+ SumForce(result, TargetVelocity(s, diff * std::min(dist * accel, speed) / dist, accel), accel);
+ }
+ }
+ return result;
+}
+
+bool Steering::SumForce(glm::dvec3 &out, const glm::dvec3 &in, double max) const noexcept {
+ if (allzero(in) || anynan(in)) {
+ return false;
+ }
+ double cur = allzero(out) ? 0.0 : length(out);
+ double rem = max - cur;
+ if (rem < 0.0) {
+ return true;
+ }
+ double add = length(in);
+ if (add > rem) {
+ // this method is off if in and out are in different
+ // directions, but gives okayish results
+ out += in * (1.0 / add);
+ return true;
+ } else {
+ out += in;
+ return false;
+ }
+}
+
+glm::dvec3 Steering::TargetVelocity(const Situation::State &s, const glm::dvec3 &vel, double acc) const noexcept {
+ return (vel - s.vel) * acc;