summary refs log tree commit diff stats
path: root/src/systems/realizing.cpp
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-05-17 15:55:37 -0400
committerGitHub <noreply@github.com>2018-05-17 15:55:37 -0400
commit90aadf3844386824140a20d7fbb847bc16009a94 (patch)
tree6f83fce90e71abb22b1a8f3e09c79963b2a34d5d /src/systems/realizing.cpp
parentbc63fa57ced1c7329f7fdcfd168eaf7e290158bc (diff)
parent86f0106d0523825549f1e74b835688c78a10cf6c (diff)
downloadtherapy-90aadf3844386824140a20d7fbb847bc16009a94.tar.gz
therapy-90aadf3844386824140a20d7fbb847bc16009a94.tar.bz2
therapy-90aadf3844386824140a20d7fbb847bc16009a94.zip
Merge pull request #7 from hatkirby/es-rewrite
The ECS rewrite exceeds the original branch in functionality, so it is time to merge it in.
Diffstat (limited to 'src/systems/realizing.cpp')
-rw-r--r--src/systems/realizing.cpp438
1 files changed, 438 insertions, 0 deletions
diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp new file mode 100644 index 0000000..baacf5a --- /dev/null +++ b/src/systems/realizing.cpp
@@ -0,0 +1,438 @@
1#include "realizing.h"
2#include <stdexcept>
3#include <libxml/parser.h>
4#include <cstring>
5#include <map>
6#include "game.h"
7#include "consts.h"
8#include "animation.h"
9#include "components/mappable.h"
10#include "components/animatable.h"
11#include "components/playable.h"
12#include "components/ponderable.h"
13#include "components/transformable.h"
14#include "components/prototypable.h"
15#include "components/automatable.h"
16#include "systems/mapping.h"
17#include "systems/animating.h"
18#include "systems/pondering.h"
19#include "systems/scripting.h"
20
21inline xmlChar* getProp(xmlNodePtr node, const char* attr)
22{
23 xmlChar* key = xmlGetProp(node, reinterpret_cast<const xmlChar*>(attr));
24 if (key == nullptr)
25 {
26 throw std::invalid_argument("Error parsing world file");
27 }
28
29 return key;
30}
31
32// TODO: neither the XML doc nor any of the emplaced entities are properly
33// destroyed if this constructor throws an exception.
34RealizingSystem::RealizingSystem(
35 Game& game,
36 std::string worldFile,
37 std::string prototypeFile) :
38 System(game),
39 worldFile_(std::move(worldFile)),
40 prototypeFile_(std::move(prototypeFile))
41{
42 auto& mapping = game_.getSystemManager().getSystem<MappingSystem>();
43
44 xmlChar* key = nullptr;
45
46 // Create a mapping between prototype names and the XML trees defining them.
47 xmlDocPtr protoXml = xmlParseFile(prototypeFile_.c_str());
48 if (protoXml == nullptr)
49 {
50 throw std::invalid_argument("Cannot find prototypes file");
51 }
52
53 xmlNodePtr protoTop = xmlDocGetRootElement(protoXml);
54 if (protoTop == nullptr)
55 {
56 throw std::invalid_argument("Error parsing prototypes file");
57 }
58
59 if (xmlStrcmp(protoTop->name, reinterpret_cast<const xmlChar*>("entities")))
60 {
61 throw std::invalid_argument("Error parsing prototypes file");
62 }
63
64 std::map<std::string, xmlNodePtr> prototypes;
65
66 for (xmlNodePtr node = protoTop->xmlChildrenNode;
67 node != nullptr;
68 node = node->next)
69 {
70 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("entity")))
71 {
72 key = getProp(node, "id");
73 std::string prototypeId = reinterpret_cast<char*>(key);
74 xmlFree(key);
75
76 prototypes[prototypeId] = node;
77 }
78 }
79
80 // Create entities from the world definition.
81 xmlDocPtr doc = xmlParseFile(worldFile_.c_str());
82 if (doc == nullptr)
83 {
84 throw std::invalid_argument("Cannot find world file");
85 }
86
87 xmlNodePtr top = xmlDocGetRootElement(doc);
88 if (top == nullptr)
89 {
90 throw std::invalid_argument("Error parsing world file");
91 }
92
93 if (xmlStrcmp(top->name, reinterpret_cast<const xmlChar*>("world")))
94 {
95 throw std::invalid_argument("Error parsing world file");
96 }
97
98 key = getProp(top, "startx");
99 startingPos_.x() = atoi(reinterpret_cast<char*>(key));
100 xmlFree(key);
101
102 key = getProp(top, "starty");
103 startingPos_.y() = atoi(reinterpret_cast<char*>(key));
104 xmlFree(key);
105
106 key = getProp(top, "startmap");
107 startingMapId_ = atoi(reinterpret_cast<char*>(key));
108 xmlFree(key);
109
110 for (xmlNodePtr node = top->xmlChildrenNode;
111 node != nullptr;
112 node = node->next)
113 {
114 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("map")))
115 {
116 id_type map = game_.getEntityManager().emplaceEntity();
117
118 auto& mappable = game_.getEntityManager().
119 emplaceComponent<MappableComponent>(map,
120 Texture("res/tiles.png"),
121 Texture("res/font.bmp"));
122
123 key = getProp(node, "id");
124 mappable.mapId = atoi(reinterpret_cast<char*>(key));
125 xmlFree(key);
126
127 key = getProp(node, "title");
128 mappable.title = reinterpret_cast<char*>(key);
129 xmlFree(key);
130
131 for (xmlNodePtr mapNode = node->xmlChildrenNode;
132 mapNode != nullptr;
133 mapNode = mapNode->next)
134 {
135 if (!xmlStrcmp(
136 mapNode->name,
137 reinterpret_cast<const xmlChar*>("environment")))
138 {
139 key = xmlNodeGetContent(mapNode);
140 if (key == nullptr)
141 {
142 throw std::invalid_argument("Error parsing world file");
143 }
144
145 mappable.tiles.clear();
146 mappable.tiles.push_back(atoi(strtok(
147 reinterpret_cast<char*>(key),
148 ",\n")));
149
150 for (size_t i = 1; i < (MAP_WIDTH * MAP_HEIGHT); i++)
151 {
152 mappable.tiles.push_back(atoi(strtok(nullptr, ",\n")));
153 }
154
155 xmlFree(key);
156 } else if (!xmlStrcmp(
157 mapNode->name,
158 reinterpret_cast<const xmlChar*>("entity")))
159 {
160 id_type mapObject = game_.getEntityManager().emplaceEntity();
161
162 key = getProp(mapNode, "type");
163 std::string prototypeId = reinterpret_cast<char*>(key);
164 xmlFree(key);
165
166 xmlNodePtr prototypeNode = prototypes[prototypeId];
167
168 // Set the coordinates from the object definition.
169 auto& transformable = game_.getEntityManager().
170 emplaceComponent<TransformableComponent>(mapObject);
171
172 key = getProp(mapNode, "x");
173 transformable.origPos.x() = atoi(reinterpret_cast<char*>(key));
174 xmlFree(key);
175
176 key = getProp(mapNode, "y");
177 transformable.origPos.y() = atoi(reinterpret_cast<char*>(key));
178 xmlFree(key);
179
180 // Set the sprite and size using the prototype definition.
181 key = getProp(prototypeNode, "sprite");
182 std::string spritePath = reinterpret_cast<char*>(key);
183 xmlFree(key);
184
185 key = getProp(prototypeNode, "width");
186 transformable.origSize.w() = atoi(reinterpret_cast<char*>(key));
187 xmlFree(key);
188
189 key = getProp(prototypeNode, "height");
190 transformable.origSize.h() = atoi(reinterpret_cast<char*>(key));
191 xmlFree(key);
192
193 AnimationSet objectAnim(
194 spritePath.c_str(),
195 transformable.origSize.w(),
196 transformable.origSize.h(),
197 1);
198
199 objectAnim.emplaceAnimation("static", 0, 1, 1);
200
201 auto& animatable = game_.getEntityManager().
202 emplaceComponent<AnimatableComponent>(
203 mapObject,
204 std::move(objectAnim));
205
206 animatable.origAnimation = "static";
207
208 // Create a physics body.
209 game_.getSystemManager().getSystem<PonderingSystem>().
210 initializeBody(mapObject, PonderableComponent::Type::vacuumed);
211
212
213
214
215
216 auto& prototypable = game_.getEntityManager().
217 emplaceComponent<PrototypableComponent>(mapObject);
218
219 prototypable.prototypeId = prototypeId;
220
221 key = getProp(mapNode, "index");
222 prototypable.mapObjectIndex = atoi(reinterpret_cast<char*>(key));
223 xmlFree(key);
224
225 if (prototypeId == "movplat")
226 {
227 auto& automatable = game_.getEntityManager().
228 emplaceComponent<AutomatableComponent>(mapObject);
229
230 automatable.table = prototypeId;
231 } else if (prototypeId == "checkpoint")
232 {
233 auto& ponderable = game_.getEntityManager().
234 getComponent<PonderableComponent>(mapObject);
235
236 ponderable.colliderType = PonderableComponent::Collision::event;
237 }
238
239 mappable.objects.push_back(mapObject);
240 } else if (!xmlStrcmp(
241 mapNode->name,
242 reinterpret_cast<const xmlChar*>("adjacent")))
243 {
244 key = getProp(mapNode, "type");
245 std::string adjTypeStr(reinterpret_cast<char*>(key));
246 xmlFree(key);
247
248 MappableComponent::Adjacent::Type adjType;
249 if (adjTypeStr == "wall")
250 {
251 adjType = MappableComponent::Adjacent::Type::wall;
252 } else if (adjTypeStr == "wrap")
253 {
254 adjType = MappableComponent::Adjacent::Type::wrap;
255 } else if (adjTypeStr == "warp")
256 {
257 adjType = MappableComponent::Adjacent::Type::warp;
258 } else if (adjTypeStr == "reverseWarp")
259 {
260 adjType = MappableComponent::Adjacent::Type::reverse;
261 } else {
262 throw std::logic_error("Invalid adjacency type");
263 }
264
265 key = getProp(mapNode, "map");
266 size_t adjMapId = atoi(reinterpret_cast<char*>(key));
267 xmlFree(key);
268
269 key = getProp(mapNode, "dir");
270 std::string adjDir(reinterpret_cast<char*>(key));
271 xmlFree(key);
272
273 if (adjDir == "left")
274 {
275 mappable.leftAdjacent = {adjType, adjMapId};
276 } else if (adjDir == "right")
277 {
278 mappable.rightAdjacent = {adjType, adjMapId};
279 } else if (adjDir == "up")
280 {
281 mappable.upAdjacent = {adjType, adjMapId};
282 } else if (adjDir == "down")
283 {
284 mappable.downAdjacent = {adjType, adjMapId};
285 } else {
286 throw std::logic_error("Invalid adjacency direction");
287 }
288 }
289 }
290
291 mapping.generateBoundaries(map);
292
293 entityByMapId_[mappable.mapId] = map;
294 }
295 }
296
297 xmlFreeDoc(doc);
298 xmlFreeDoc(protoXml);
299
300 activateMap(entityByMapId_[startingMapId_]);
301}
302
303void RealizingSystem::loadMap(id_type mapEntity)
304{
305 deactivateMap();
306 activateMap(mapEntity);
307}
308
309void RealizingSystem::deactivateMap()
310{
311 id_type oldMap = activeMap_;
312
313 auto& oldMappable = game_.getEntityManager().
314 getComponent<MappableComponent>(oldMap);
315
316 // Deactivate any map objects from the old map.
317 for (id_type prototype : oldMappable.objects)
318 {
319 leaveActiveMap(prototype);
320 }
321
322 // Deactivate players that were on the old map.
323 std::set<id_type> players =
324 game_.getEntityManager().getEntitiesWithComponents<
325 PlayableComponent>();
326
327 for (id_type player : players)
328 {
329 auto& playable = game_.getEntityManager().
330 getComponent<PlayableComponent>(player);
331
332 if (playable.mapId == oldMap)
333 {
334 leaveActiveMap(player);
335 }
336 }
337}
338
339void RealizingSystem::activateMap(id_type mapEntity)
340{
341 auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>();
342 auto& pondering = game_.getSystemManager().getSystem<PonderingSystem>();
343
344 std::set<id_type> players =
345 game_.getEntityManager().getEntitiesWithComponents<
346 PlayableComponent>();
347
348 activeMap_ = mapEntity;
349
350 auto& mappable = game_.getEntityManager().
351 getComponent<MappableComponent>(mapEntity);
352
353 // Initialize the new map's objects.
354 for (id_type prototype : mappable.objects)
355 {
356 if (game_.getEntityManager().
357 hasComponent<TransformableComponent>(prototype))
358 {
359 auto& transformable = game_.getEntityManager().
360 getComponent<TransformableComponent>(prototype);
361
362 transformable.pos = transformable.origPos;
363 transformable.size = transformable.origSize;
364 }
365
366 if (game_.getEntityManager().hasComponent<AnimatableComponent>(prototype))
367 {
368 animating.initPrototype(prototype);
369 }
370
371 if (game_.getEntityManager().hasComponent<PonderableComponent>(prototype))
372 {
373 pondering.initPrototype(prototype);
374 }
375
376 enterActiveMap(prototype);
377 }
378
379 // Activate any players on the map.
380 for (id_type player : players)
381 {
382 auto& playable = game_.getEntityManager().
383 getComponent<PlayableComponent>(player);
384
385 if (playable.mapId == mapEntity)
386 {
387 enterActiveMap(player);
388 }
389 }
390}
391
392void RealizingSystem::enterActiveMap(id_type entity)
393{
394 if (game_.getEntityManager().hasComponent<AnimatableComponent>(entity))
395 {
396 auto& animatable = game_.getEntityManager().
397 getComponent<AnimatableComponent>(entity);
398
399 animatable.active = true;
400 }
401
402 if (game_.getEntityManager().hasComponent<PonderableComponent>(entity))
403 {
404 auto& ponderable = game_.getEntityManager().
405 getComponent<PonderableComponent>(entity);
406
407 ponderable.active = true;
408 }
409
410 if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity))
411 {
412 game_.getSystemManager().getSystem<ScriptingSystem>().startBehavior(entity);
413 }
414}
415
416void RealizingSystem::leaveActiveMap(id_type entity)
417{
418 if (game_.getEntityManager().hasComponent<AnimatableComponent>(entity))
419 {
420 auto& animatable = game_.getEntityManager().
421 getComponent<AnimatableComponent>(entity);
422
423 animatable.active = false;
424 }
425
426 if (game_.getEntityManager().hasComponent<PonderableComponent>(entity))
427 {
428 auto& ponderable = game_.getEntityManager().
429 getComponent<PonderableComponent>(entity);
430
431 ponderable.active = false;
432 }
433
434 if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity))
435 {
436 game_.getSystemManager().getSystem<ScriptingSystem>().stopBehavior(entity);
437 }
438}