]> git.localhorst.tv Git - blobs.git/blobdiff - src/creature/creature.cpp
aggression
[blobs.git] / src / creature / creature.cpp
index 9b85eff73a81d68d98bc308d3bbc3b146f257d04..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 {
@@ -139,6 +142,11 @@ Creature::Creature(world::Simulation &sim)
 , goals()
 , situation()
 , steering(*this)
+, perception_range(1.0)
+, perception_range_squared(1.0)
+, perception_omni_range(1.0)
+, perception_omni_range_squared(1.0)
+, perception_field(1.0)
 , vao() {
        sim.SetAlive(this);
        // all creatures avoid each other for now
@@ -331,7 +339,8 @@ double Creature::Strength() const noexcept {
 }
 
 double Creature::StrengthFactor() const noexcept {
-       return Strength() / (Strength() + 1.0);
+       double str = Strength();
+       return str / (str + 1.0);
 }
 
 double Creature::Stamina() const noexcept {
@@ -339,7 +348,8 @@ double Creature::Stamina() const noexcept {
 }
 
 double Creature::StaminaFactor() const noexcept {
-       return Stamina() / (Stamina() + 1.0);
+       double stm = Stamina();
+       return stm / (stm + 1.0);
 }
 
 double Creature::Dexerty() const noexcept {
@@ -347,7 +357,8 @@ double Creature::Dexerty() const noexcept {
 }
 
 double Creature::DexertyFactor() const noexcept {
-       return Dexerty() / (Dexerty() + 1.0);
+       double dex = Dexerty();
+       return dex / (dex + 1.0);
 }
 
 double Creature::Intelligence() const noexcept {
@@ -355,7 +366,8 @@ double Creature::Intelligence() const noexcept {
 }
 
 double Creature::IntelligenceFactor() const noexcept {
-       return Intelligence() / (Intelligence() + 1.0);
+       double intl = Intelligence();
+       return intl / (intl + 1.0);
 }
 
 double Creature::Lifetime() const noexcept {
@@ -379,25 +391,23 @@ double Creature::OffspringMass() const noexcept {
 }
 
 double Creature::PerceptionRange() const noexcept {
-       return 3.0 * DexertyFactor() + Size();
+       return perception_range;
 }
 
 double Creature::PerceptionOmniRange() const noexcept {
-       return 0.5 * DexertyFactor() + Size();
+       return perception_omni_range;
 }
 
 double Creature::PerceptionField() const noexcept {
-       // this is the cosine of half the angle, so 1.0 is none, -1.0 is perfect
-       return 0.8 - DexertyFactor();
+       return perception_field;
 }
 
 bool Creature::PerceptionTest(const glm::dvec3 &p) const noexcept {
        const glm::dvec3 diff(p - situation.Position());
-       double omni_range = PerceptionOmniRange();
-       if (glm::length2(diff) < omni_range * omni_range) return true;
-       double range = PerceptionRange();
-       if (glm::length2(diff) > range * range) return false;
-       return glm::dot(glm::normalize(diff), situation.Heading()) > PerceptionField();
+       double ldiff = glm::length2(diff);
+       if (ldiff < perception_omni_range_squared) return true;
+       if (ldiff > perception_range_squared) return false;
+       return glm::dot(diff / std::sqrt(ldiff), situation.Heading()) > perception_field;
 }
 
 double Creature::OffspringChance() const noexcept {
@@ -429,11 +439,22 @@ bool GoalCompare(const std::unique_ptr<Goal> &a, const std::unique_ptr<Goal> &b)
 }
 
 void Creature::Tick(double dt) {
+       Cache();
        TickState(dt);
        TickStats(dt);
        TickBrain(dt);
 }
 
+void Creature::Cache() noexcept {
+       double dex_fact = DexertyFactor();
+       perception_range = 3.0 * dex_fact + size;
+       perception_range_squared = perception_range * perception_range;
+       perception_omni_range = 0.5 * dex_fact + size;
+       perception_omni_range_squared = perception_omni_range * perception_omni_range;
+       // this is the cosine of half the angle, so 1.0 is none, -1.0 is perfect
+       perception_field = 0.8 - dex_fact;
+}
+
 void Creature::TickState(double dt) {
        steering.MaxSpeed(Dexerty());
        steering.MaxForce(Strength());
@@ -573,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()
@@ -826,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 {
@@ -859,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()) {