]> git.localhorst.tv Git - blobs.git/blob - src/creature/creature.cpp
extract situation from creature
[blobs.git] / src / creature / creature.cpp
1 #include "Creature.hpp"
2 #include "Need.hpp"
3 #include "Situation.hpp"
4
5 #include "../app/Assets.hpp"
6 #include "../world/Body.hpp"
7 #include "../world/Planet.hpp"
8 #include "../world/TileType.hpp"
9
10 #include <glm/gtx/transform.hpp>
11
12 #include <iostream>
13
14
15 namespace blobs {
16 namespace creature {
17
18 Creature::Creature()
19 : name()
20 , health(1.0)
21 , needs()
22 , situation()
23 , vao() {
24 }
25
26 Creature::~Creature() {
27 }
28
29
30 void Creature::Tick(double dt) {
31         for (Need &need : needs) {
32                 need.Tick(dt);
33                 if (!need.IsSatisfied()) {
34                         health = std::max(0.0, health - need.penalty * dt);
35                 }
36         }
37 }
38
39 glm::dmat4 Creature::LocalTransform() noexcept {
40         // TODO: surface transform
41         constexpr double half_height = 0.25;
42         const glm::dvec3 &pos = situation.Position();
43         return glm::translate(glm::dvec3(pos.x, pos.y, pos.z + situation.GetPlanet().Radius() + half_height))
44                 * glm::scale(glm::dvec3(half_height, half_height, half_height));
45 }
46
47 void Creature::BuildVAO() {
48         vao.Bind();
49         vao.BindAttributes();
50         vao.EnableAttribute(0);
51         vao.EnableAttribute(1);
52         vao.EnableAttribute(2);
53         vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
54         vao.AttributePointer<glm::vec3>(1, false, offsetof(Attributes, normal));
55         vao.AttributePointer<glm::vec3>(2, false, offsetof(Attributes, texture));
56         vao.ReserveAttributes(6 * 4, GL_STATIC_DRAW);
57         {
58                 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
59                 const float offset = 1.0f;
60                 for (int surface = 0; surface < 6; ++surface) {
61                         const float tex_u_begin = surface < 3 ? 1.0f : 0.0f;
62                         const float tex_u_end = surface < 3 ? 0.0f : 1.0f;
63
64                         attrib[4 * surface + 0].position[(surface + 0) % 3] = -offset;
65                         attrib[4 * surface + 0].position[(surface + 1) % 3] = -offset;
66                         attrib[4 * surface + 0].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
67                         attrib[4 * surface + 0].normal[(surface + 0) % 3] = 0.0f;
68                         attrib[4 * surface + 0].normal[(surface + 1) % 3] = 0.0f;
69                         attrib[4 * surface + 0].normal[(surface + 2) % 3] = surface < 3 ? 1.0f : -1.0f;
70                         attrib[4 * surface + 0].texture.x = tex_u_begin;
71                         attrib[4 * surface + 0].texture.y = 1.0f;
72                         attrib[4 * surface + 0].texture.z = surface;
73
74                         attrib[4 * surface + 1].position[(surface + 0) % 3] = -offset;
75                         attrib[4 * surface + 1].position[(surface + 1) % 3] =  offset;
76                         attrib[4 * surface + 1].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
77                         attrib[4 * surface + 1].normal[(surface + 0) % 3] = 0.0f;
78                         attrib[4 * surface + 1].normal[(surface + 1) % 3] = 0.0f;
79                         attrib[4 * surface + 1].normal[(surface + 2) % 3] = surface < 3 ? 1.0f : -1.0f;
80                         attrib[4 * surface + 1].texture.x = tex_u_end;
81                         attrib[4 * surface + 1].texture.y = 1.0f;
82                         attrib[4 * surface + 1].texture.z = surface;
83
84                         attrib[4 * surface + 2].position[(surface + 0) % 3] =  offset;
85                         attrib[4 * surface + 2].position[(surface + 1) % 3] = -offset;
86                         attrib[4 * surface + 2].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
87                         attrib[4 * surface + 2].normal[(surface + 0) % 3] = 0.0f;
88                         attrib[4 * surface + 2].normal[(surface + 1) % 3] = 0.0f;
89                         attrib[4 * surface + 2].normal[(surface + 2) % 3] = surface < 3 ? 1.0f : -1.0f;
90                         attrib[4 * surface + 2].texture.x = tex_u_begin;
91                         attrib[4 * surface + 2].texture.y = 0.0f;
92                         attrib[4 * surface + 2].texture.z = surface;
93
94                         attrib[4 * surface + 3].position[(surface + 0) % 3] = offset;
95                         attrib[4 * surface + 3].position[(surface + 1) % 3] = offset;
96                         attrib[4 * surface + 3].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
97                         attrib[4 * surface + 3].normal[(surface + 0) % 3] = 0.0f;
98                         attrib[4 * surface + 3].normal[(surface + 1) % 3] = 0.0f;
99                         attrib[4 * surface + 3].normal[(surface + 2) % 3] = surface < 3 ? 1.0f : -1.0f;
100                         attrib[4 * surface + 3].texture.x = tex_u_end;
101                         attrib[4 * surface + 3].texture.y = 0.0f;
102                         attrib[4 * surface + 3].texture.z = surface;
103                 }
104         }
105         vao.BindElements();
106         vao.ReserveElements(6 * 6, GL_STATIC_DRAW);
107         {
108                 auto element = vao.MapElements(GL_WRITE_ONLY);
109                 for (int surface = 0; surface < 3; ++surface) {
110                         element[6 * surface + 0] = 4 * surface + 0;
111                         element[6 * surface + 1] = 4 * surface + 2;
112                         element[6 * surface + 2] = 4 * surface + 1;
113                         element[6 * surface + 3] = 4 * surface + 1;
114                         element[6 * surface + 4] = 4 * surface + 2;
115                         element[6 * surface + 5] = 4 * surface + 3;
116                 }
117                 for (int surface = 3; surface < 6; ++surface) {
118                         element[6 * surface + 0] = 4 * surface + 0;
119                         element[6 * surface + 1] = 4 * surface + 1;
120                         element[6 * surface + 2] = 4 * surface + 2;
121                         element[6 * surface + 3] = 4 * surface + 2;
122                         element[6 * surface + 4] = 4 * surface + 1;
123                         element[6 * surface + 5] = 4 * surface + 3;
124                 }
125         }
126         vao.Unbind();
127 }
128
129 void Creature::Draw(app::Assets &assets, graphics::Viewport &viewport) {
130         vao.Bind();
131         vao.DrawTriangles(6 * 6);
132 }
133
134
135 void Spawn(Creature &c, world::Planet &p, app::Assets &assets) {
136         p.AddCreature(&c);
137         c.GetSituation().SetPlanetSurface(p, 0, glm::dvec3(0.0, 0.0, 0.0));
138
139         // probe surrounding area for common resources
140         int start = p.SideLength() / 2 - 2;
141         int end = start + 5;
142         std::map<int, double> yields;
143         for (int y = start; y < end; ++y) {
144                 for (int x = start; x < end; ++x) {
145                         const world::TileType &t = assets.data.tiles[p.TileAt(0, x, y).type];
146                         for (auto yield : t.resources) {
147                                 yields[yield.resource] += yield.ubiquity;
148                         }
149                 }
150         }
151         int liquid = -1;
152         int solid = -1;
153         for (auto e : yields) {
154                 if (assets.data.resources[e.first].state == world::Resource::LIQUID) {
155                         if (liquid < 0 || e.second > yields[liquid]) {
156                                 liquid = e.first;
157                         }
158                 } else if (assets.data.resources[e.first].state == world::Resource::SOLID) {
159                         if (solid < 0 || e.second > yields[solid]) {
160                                 solid = e.first;
161                         }
162                 }
163         }
164
165         if (p.HasAtmosphere()) {
166                 std::cout << "require breathing " << assets.data.resources[p.Atmosphere()].label << std::endl;
167                 Need need;
168                 need.resource = p.Atmosphere();
169                 need.gain = 0.25;
170                 need.critical = 0.95;
171                 need.penalty = 0.1;
172                 c.AddNeed(need);
173         }
174         if (liquid > -1) {
175                 std::cout << "require drinking " << assets.data.resources[liquid].label << std::endl;
176                 Need need;
177                 need.resource = liquid;
178                 need.gain = 0.0001;
179                 need.critical = 0.95;
180                 need.penalty = 0.01;
181                 c.AddNeed(need);
182         }
183         if (solid > -1) {
184                 std::cout << "require eating " << assets.data.resources[solid].label << std::endl;
185                 Need need;
186                 need.resource = solid;
187                 need.gain = 0.00001;
188                 need.critical = 0.95;
189                 need.penalty = 0.001;
190                 c.AddNeed(need);
191         }
192 }
193
194
195 void Need::Tick(double dt) noexcept {
196         value = std::min(1.0, value + gain * dt);
197 }
198
199
200 Situation::Situation()
201 : planet(nullptr)
202 , position(0.0)
203 , surface(0)
204 , type(LOST) {
205 }
206
207 Situation::~Situation() {
208 }
209
210 bool Situation::OnPlanet() const noexcept {
211         return type == PLANET_SURFACE;
212 }
213
214 void Situation::SetPlanetSurface(world::Planet &p, int srf, const glm::dvec3 &pos) noexcept {
215         type = PLANET_SURFACE;
216         planet = &p;
217         surface = srf;
218         position = pos;
219 }
220
221 }
222 }