]> git.localhorst.tv Git - blobs.git/blob - src/creature/goal.cpp
229dffc8f3e38e04510e13a82fa1141093bf9e32
[blobs.git] / src / creature / goal.cpp
1 #include "Goal.hpp"
2 #include "IdleGoal.hpp"
3 #include "LocateResourceGoal.hpp"
4
5 #include "Creature.hpp"
6 #include "../app/Assets.hpp"
7 #include "../world/Planet.hpp"
8 #include "../world/Resource.hpp"
9 #include "../world/Simulation.hpp"
10 #include "../world/TileType.hpp"
11
12 #include <iostream>
13 #include <glm/gtx/io.hpp>
14
15
16 namespace blobs {
17 namespace creature {
18
19 Goal::Goal(Creature &c)
20 : c(c)
21 , on_complete()
22 , urgency(0.0)
23 , interruptible(true)
24 , complete(false) {
25 }
26
27 Goal::~Goal() noexcept {
28 }
29
30 Situation &Goal::GetSituation() noexcept {
31         return c.GetSituation();
32 }
33
34 const Situation &Goal::GetSituation() const noexcept {
35         return c.GetSituation();
36 }
37
38 Steering &Goal::GetSteering() noexcept {
39         return c.GetSteering();
40 }
41
42 const Steering &Goal::GetSteering() const noexcept {
43         return c.GetSteering();
44 }
45
46 app::Assets &Goal::Assets() noexcept {
47         return c.GetSimulation().Assets();
48 }
49
50 const app::Assets &Goal::Assets() const noexcept {
51         return c.GetSimulation().Assets();
52 }
53
54 void Goal::SetComplete() noexcept {
55         if (!complete) {
56                 complete = true;
57                 if (on_complete) {
58                         on_complete(*this);
59                 }
60         }
61 }
62
63 void Goal::OnComplete(std::function<void(Goal &)> cb) noexcept {
64         on_complete = cb;
65         if (complete) {
66                 on_complete(*this);
67         }
68 }
69
70
71 IdleGoal::IdleGoal(Creature &c)
72 : Goal(c) {
73         Urgency(-1.0);
74         Interruptible(true);
75 }
76
77 IdleGoal::~IdleGoal() {
78 }
79
80 std::string IdleGoal::Describe() const {
81         return "idle";
82 }
83
84 void IdleGoal::Enable() {
85 }
86
87 void IdleGoal::Tick(double dt) {
88 }
89
90 void IdleGoal::Action() {
91         double fert = GetCreature().Fertility();
92         double rand = Assets().random.UNorm();
93         if (fert > rand) {
94                 std::cout << "[" << int(GetCreature().GetSimulation().Time())
95                         << "s] splitting " << GetCreature().Name()
96                         << " because " << fert << " > " << rand << std::endl;
97                 Split(GetCreature());
98         }
99 }
100
101
102 LocateResourceGoal::LocateResourceGoal(Creature &c, int res)
103 : Goal(c)
104 , res(res)
105 , found(false)
106 , target_pos(0.0)
107 , target_srf(0)
108 , target_tile(0) {
109 }
110
111 LocateResourceGoal::~LocateResourceGoal() noexcept {
112 }
113
114 std::string LocateResourceGoal::Describe() const {
115         return "locate " + GetCreature().GetSimulation().Resources()[res].name;
116 }
117
118 void LocateResourceGoal::Enable() {
119         LocateResource();
120 }
121
122 void LocateResourceGoal::Tick(double dt) {
123 }
124
125 void LocateResourceGoal::Action() {
126         if (!found) {
127                 LocateResource();
128         } else if (OnTargetTile()) {
129                 GetSteering().Halt();
130                 if (!GetCreature().Moving()) {
131                         SetComplete();
132                 }
133         } else {
134                 GetSteering().GoTo(target_pos);
135         }
136 }
137
138 void LocateResourceGoal::LocateResource() {
139         if (GetSituation().OnSurface()) {
140                 const world::TileType &t = GetSituation().GetTileType();
141                 auto yield = t.FindResource(res);
142                 if (yield != t.resources.cend()) {
143                         // hoooray
144                         GetSteering().Halt();
145                         found = true;
146                         target_pos = GetSituation().Position();
147                         target_srf = GetSituation().Surface();
148                         target_tile = GetSituation().GetPlanet().SurfacePosition(target_srf, target_pos);
149                 } else {
150                         // go find somewhere else
151                         SearchVicinity();
152                 }
153         } else {
154                 // well, what now?
155         }
156 }
157
158 void LocateResourceGoal::SearchVicinity() {
159         const world::Planet &planet = GetSituation().GetPlanet();
160         int srf = GetSituation().Surface();
161         const glm::dvec3 &pos = GetSituation().Position();
162
163         glm::ivec2 loc = planet.SurfacePosition(srf, pos);
164         glm::ivec2 seek_radius(2);
165         glm::ivec2 begin(glm::max(glm::ivec2(0), loc - seek_radius));
166         glm::ivec2 end(glm::min(glm::ivec2(planet.SideLength()), loc + seek_radius));
167
168         const world::TileType::Yield *best = nullptr;
169         glm::ivec2 best_pos;
170         double best_distance;
171
172         for (int y = begin.y; y < end.y; ++y) {
173                 for (int x = begin.x; x < end.x; ++x) {
174                         const world::TileType &type = planet.TypeAt(srf, x, y);
175                         auto yield = type.FindResource(res);
176                         if (yield != type.resources.cend()) {
177                                 double dist = glm::length2(planet.TileCenter(srf, x, y) - pos);
178                                 if (!best) {
179                                         best = &*yield;
180                                         best_pos = glm::ivec2(x, y);
181                                         best_distance = dist;
182                                 } else if (yield->ubiquity - (dist * 0.125) > best->ubiquity - (best_distance * 0.125)) {
183                                         best = &*yield;
184                                         best_pos = glm::ivec2(x, y);
185                                         best_distance = dist;
186                                 }
187                         }
188                 }
189         }
190         if (best) {
191                 found = true;
192                 target_pos = planet.TileCenter(srf, best_pos.x, best_pos.y);
193                 target_srf = srf;
194                 target_tile = best_pos;
195                 GetSteering().GoTo(target_pos);
196         } else {
197                 // oh crap
198         }
199 }
200
201 bool LocateResourceGoal::OnTargetTile() const noexcept {
202         const Situation &s = GetSituation();
203         return s.OnSurface()
204                 && s.Surface() == target_srf
205                 && s.GetPlanet().SurfacePosition(s.Surface(), s.Position()) == target_tile;
206 }
207
208 }
209 }