]> git.localhorst.tv Git - blobs.git/commitdiff
aggression
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 13 Dec 2017 01:28:42 +0000 (02:28 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 13 Dec 2017 01:28:42 +0000 (02:28 +0100)
src/creature/AttackGoal.hpp [new file with mode: 0644]
src/creature/Composition.hpp
src/creature/Creature.hpp
src/creature/Memory.hpp
src/creature/creature.cpp
src/creature/goal.cpp
src/world/world.cpp

diff --git a/src/creature/AttackGoal.hpp b/src/creature/AttackGoal.hpp
new file mode 100644 (file)
index 0000000..ab8056f
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef BLOBS_CREATURE_ATTACKGOAL_HPP_
+#define BLOBS_CREATURE_ATTACKGOAL_HPP_
+
+#include "Goal.hpp"
+
+namespace blobs {
+namespace creature {
+
+class AttackGoal
+: public Goal {
+
+public:
+       AttackGoal(Creature &self, Creature &target);
+       ~AttackGoal() override;
+
+public:
+       std::string Describe() const override;
+       void Tick(double dt) override;
+       void Action() override;
+       void OnBackground() override;
+
+       void SetDamageTarget(double t) noexcept { damage_target = t; }
+
+private:
+       Creature &target;
+       double damage_target;
+       double damage_dealt;
+       double cooldown;
+
+};
+
+}
+}
+
+#endif
index 969407f89b1ff7d42e6cf7c3a6dfef43699a9d9a..243c079c899bca91e9c36af607e89d00e592bc04 100644 (file)
@@ -41,6 +41,8 @@ public:
        double StateProportion(int res) const noexcept;
        double Compatibility(int res) const noexcept;
        double TotalMass() const noexcept { return total_mass; }
+       double TotalVolume() const noexcept { return total_volume; }
+       double TotalDensity() const noexcept { return total_mass / total_volume; }
        double StateMass(world::Resource::State s) const noexcept { return state_mass[s]; }
 
 public:
@@ -56,6 +58,7 @@ private:
        const world::Set<world::Resource> &resources;
        std::vector<Component> components;
        double total_mass;
+       double total_volume;
        double state_mass[4];
 
 };
index d55ab6f0c51790cebad22bc49617b7a347f630e7..f22f3da2e9cf461d5caabde8468046133dfcc65a 100644 (file)
@@ -180,6 +180,8 @@ public:
        math::AABB CollisionBounds() const noexcept;
        glm::dmat4 CollisionTransform() const noexcept;
 
+       void OnCollide(Creature &other);
+
        glm::dmat4 LocalTransform() noexcept;
 
        void BuildVAO();
index 1d72c751bc694516fc608e5a19058d854f925315..192d03aab091574b30199dce1c70407ca3b585ef 100644 (file)
@@ -35,6 +35,8 @@ public:
        /// location of the best fitting resource
        bool RememberLocation(const Composition &, glm::dvec3 &pos) const noexcept;
 
+       void TrackCollision(Creature &);
+
        void Tick(double dt);
 
 private:
@@ -52,6 +54,11 @@ private:
                double time_spent;
        };
        std::map<int, Stay> known_types;
+       struct Profile {
+               double annoyance = 0.0;
+               double familiarity = 0.0;
+       };
+       std::map<Creature *, Profile> known_creatures;
 
 };
 
index 1cf4a3a5c511aa16e9874fd30b71dce9215c10f7..7ad0657e0d176f2a14412b5eb984255e6f707706 100644 (file)
@@ -6,6 +6,7 @@
 #include "Situation.hpp"
 #include "Steering.hpp"
 
+#include "AttackGoal.hpp"
 #include "BlobBackgroundTask.hpp"
 #include "Goal.hpp"
 #include "IdleGoal.hpp"
@@ -33,6 +34,7 @@ Composition::Composition(const world::Set<world::Resource> &resources)
 : resources(resources)
 , components()
 , total_mass(0.0)
+, total_volume(0.0)
 , state_mass{0.0} {
 }
 
@@ -64,6 +66,7 @@ void Composition::Add(int res, double amount) {
        std::sort(components.begin(), components.end(), CompositionCompare);
        state_mass[resources[res].state] += amount;
        total_mass += amount;
+       total_volume += amount / resources[res].density;
 }
 
 bool Composition::Has(int res) const noexcept {
@@ -591,6 +594,10 @@ glm::dmat4 Creature::CollisionTransform() const noexcept {
                * glm::translate(glm::dvec3(0.0, half_size, 0.0));
 }
 
+void Creature::OnCollide(Creature &other) {
+       memory.TrackCollision(other);
+}
+
 glm::dmat4 Creature::LocalTransform() noexcept {
        const double half_size = size * 0.5;
        return CollisionTransform()
@@ -844,6 +851,7 @@ Memory::~Memory() {
 
 void Memory::Erase() {
        known_types.clear();
+       known_creatures.clear();
 }
 
 bool Memory::RememberLocation(const Composition &accept, glm::dvec3 &pos) const noexcept {
@@ -877,6 +885,21 @@ bool Memory::RememberLocation(const Composition &accept, glm::dvec3 &pos) const
        }
 }
 
+void Memory::TrackCollision(Creature &other) {
+       // TODO: find out whose fault it was
+       // TODO: source values from personality
+       Profile &p = known_creatures[&other];
+       p.annoyance += 0.1;
+       const double annoy_fact = p.annoyance / (p.annoyance + 1.0);
+       if (c.GetSimulation().Assets().random.UNorm() > annoy_fact * 0.1 * (1.0 - c.GetStats().Damage().value)) {
+               AttackGoal *g = new AttackGoal(c, other);
+               g->SetDamageTarget(annoy_fact);
+               g->Urgency(annoy_fact);
+               c.AddGoal(std::unique_ptr<Goal>(g));
+               p.annoyance *= 0.5;
+       }
+}
+
 void Memory::Tick(double dt) {
        Situation &s = c.GetSituation();
        if (s.OnSurface()) {
index abac4679dcbb93f822f7e54339e9c930071c5d5b..41f91f37e0ec63fa0b6f9b0cb432a3de48346cad 100644 (file)
@@ -1,3 +1,4 @@
+#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)
index 2f0d130312916bd6a289ae9bcc2ca50c7f9cce2b..1758c5e431ea4ebfb862dde58b4290408b5dd0e5 100644 (file)
@@ -208,11 +208,12 @@ void Body::CheckCollision() noexcept {
                }
        }
        for (auto &c : collisions) {
+               c.A().OnCollide(c.B());
+               c.B().OnCollide(c.A());
                c.A().GetSituation().Move(c.Normal() * (c.Depth() * -0.5));
                c.B().GetSituation().Move(c.Normal() * (c.Depth() * 0.5));
                c.A().GetSituation().Accelerate(c.Normal() * -glm::dot(c.Normal(), c.AVel()));
                c.B().GetSituation().Accelerate(c.Normal() * -glm::dot(c.Normal(), c.BVel()));
-               // TODO: notify participants so they can be annoyed
        }
 }