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