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