summary refs log tree commit diff stats
path: root/src/systems/realizing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/systems/realizing.cpp')
-rw-r--r--src/systems/realizing.cpp321
1 files changed, 321 insertions, 0 deletions
diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp new file mode 100644 index 0000000..09c38f3 --- /dev/null +++ b/src/systems/realizing.cpp
@@ -0,0 +1,321 @@
1#include "realizing.h"
2#include <stdexcept>
3#include <libxml/parser.h>
4#include <cstring>
5#include "game.h"
6#include "consts.h"
7#include "components/realizable.h"
8#include "components/mappable.h"
9#include "components/animatable.h"
10#include "components/playable.h"
11#include "components/ponderable.h"
12#include "components/transformable.h"
13#include "systems/mapping.h"
14#include "systems/animating.h"
15#include "systems/pondering.h"
16
17inline xmlChar* getProp(xmlNodePtr node, const char* attr)
18{
19 xmlChar* key = xmlGetProp(node, reinterpret_cast<const xmlChar*>(attr));
20 if (key == nullptr)
21 {
22 throw std::invalid_argument("Error parsing world file");
23 }
24
25 return key;
26}
27
28// TODO: neither the XML doc nor any of the emplaced entities are properly
29// destroyed if this method throws an exception.
30EntityManager::id_type RealizingSystem::initSingleton(std::string filename)
31{
32 id_type world = game_.getEntityManager().emplaceEntity();
33
34 auto& realizable = game_.getEntityManager().
35 emplaceComponent<RealizableComponent>(world);
36
37 auto& mapping = game_.getSystemManager().getSystem<MappingSystem>();
38
39 xmlDocPtr doc = xmlParseFile(filename.c_str());
40 if (doc == nullptr)
41 {
42 throw std::invalid_argument("Cannot find world file");
43 }
44
45 xmlNodePtr top = xmlDocGetRootElement(doc);
46 if (top == nullptr)
47 {
48 throw std::invalid_argument("Error parsing world file");
49 }
50
51 if (xmlStrcmp(top->name, reinterpret_cast<const xmlChar*>("world")))
52 {
53 throw std::invalid_argument("Error parsing world file");
54 }
55
56 xmlChar* key = nullptr;
57
58 key = getProp(top, "startx");
59 realizable.startingX = atoi(reinterpret_cast<char*>(key));
60 xmlFree(key);
61
62 key = getProp(top, "starty");
63 realizable.startingY = atoi(reinterpret_cast<char*>(key));
64 xmlFree(key);
65
66 key = getProp(top, "startmap");
67 realizable.startingMapId = atoi(reinterpret_cast<char*>(key));
68 xmlFree(key);
69
70 for (xmlNodePtr node = top->xmlChildrenNode;
71 node != nullptr;
72 node = node->next)
73 {
74 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("map")))
75 {
76 id_type map = game_.getEntityManager().emplaceEntity();
77
78 auto& mappable = game_.getEntityManager().
79 emplaceComponent<MappableComponent>(map,
80 Texture("res/tiles.png"),
81 Texture("res/font.bmp"));
82
83 key = getProp(node, "id");
84 mappable.mapId = atoi(reinterpret_cast<char*>(key));
85 xmlFree(key);
86
87 key = getProp(node, "title");
88 mappable.title = reinterpret_cast<char*>(key);
89 xmlFree(key);
90
91 for (xmlNodePtr mapNode = node->xmlChildrenNode;
92 mapNode != nullptr;
93 mapNode = mapNode->next)
94 {
95 if (!xmlStrcmp(
96 mapNode->name,
97 reinterpret_cast<const xmlChar*>("environment")))
98 {
99 key = xmlNodeGetContent(mapNode);
100 if (key == nullptr)
101 {
102 throw std::invalid_argument("Error parsing world file");
103 }
104
105 mappable.tiles.clear();
106 mappable.tiles.push_back(atoi(strtok(
107 reinterpret_cast<char*>(key),
108 ",\n")));
109
110 for (size_t i = 1; i < (MAP_WIDTH * MAP_HEIGHT); i++)
111 {
112 mappable.tiles.push_back(atoi(strtok(nullptr, ",\n")));
113 }
114
115 xmlFree(key);
116 } else if (!xmlStrcmp(
117 mapNode->name,
118 reinterpret_cast<const xmlChar*>("adjacent")))
119 {
120 key = getProp(mapNode, "type");
121 std::string adjTypeStr(reinterpret_cast<char*>(key));
122 xmlFree(key);
123
124 MappableComponent::Adjacent::Type adjType;
125 if (adjTypeStr == "wall")
126 {
127 adjType = MappableComponent::Adjacent::Type::wall;
128 } else if (adjTypeStr == "wrap")
129 {
130 adjType = MappableComponent::Adjacent::Type::wrap;
131 } else if (adjTypeStr == "warp")
132 {
133 adjType = MappableComponent::Adjacent::Type::warp;
134 } else if (adjTypeStr == "reverseWarp")
135 {
136 adjType = MappableComponent::Adjacent::Type::reverse;
137 } else {
138 throw std::logic_error("Invalid adjacency type");
139 }
140
141 key = getProp(mapNode, "map");
142 size_t adjMapId = atoi(reinterpret_cast<char*>(key));
143 xmlFree(key);
144
145 key = getProp(mapNode, "dir");
146 std::string adjDir(reinterpret_cast<char*>(key));
147 xmlFree(key);
148
149 if (adjDir == "left")
150 {
151 mappable.leftAdjacent = {adjType, adjMapId};
152 } else if (adjDir == "right")
153 {
154 mappable.rightAdjacent = {adjType, adjMapId};
155 } else if (adjDir == "up")
156 {
157 mappable.upAdjacent = {adjType, adjMapId};
158 } else if (adjDir == "down")
159 {
160 mappable.downAdjacent = {adjType, adjMapId};
161 } else {
162 throw std::logic_error("Invalid adjacency direction");
163 }
164 }
165 }
166
167 mapping.generateBoundaries(map);
168
169 realizable.maps.insert(map);
170 realizable.entityByMapId[mappable.mapId] = map;
171 }
172 }
173
174 xmlFreeDoc(doc);
175
176 loadMap(realizable.entityByMapId[realizable.startingMapId]);
177
178 return world;
179}
180
181EntityManager::id_type RealizingSystem::getSingleton() const
182{
183 std::set<id_type> result =
184 game_.getEntityManager().getEntitiesWithComponents<
185 RealizableComponent>();
186
187 if (result.empty())
188 {
189 throw std::logic_error("No realizable entity found");
190 } else if (result.size() > 1)
191 {
192 throw std::logic_error("Multiple realizable entities found");
193 }
194
195 return *std::begin(result);
196}
197
198void RealizingSystem::loadMap(id_type mapEntity)
199{
200 id_type world = getSingleton();
201
202 auto& realizable = game_.getEntityManager().
203 getComponent<RealizableComponent>(world);
204
205 auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>();
206 auto& pondering = game_.getSystemManager().getSystem<PonderingSystem>();
207
208 std::set<id_type> players =
209 game_.getEntityManager().getEntitiesWithComponents<
210 PlayableComponent>();
211
212 if (realizable.hasActiveMap)
213 {
214 id_type oldMap = realizable.activeMap;
215
216 auto& oldMappable = game_.getEntityManager().
217 getComponent<MappableComponent>(oldMap);
218
219 // Deactivate any map objects from the old map.
220 for (id_type prototype : oldMappable.objects)
221 {
222 leaveActiveMap(prototype);
223 }
224
225 // Deactivate players that were on the old map.
226 for (id_type player : players)
227 {
228 auto& playable = game_.getEntityManager().
229 getComponent<PlayableComponent>(player);
230
231 if (playable.mapId == oldMap)
232 {
233 leaveActiveMap(player);
234 }
235 }
236 }
237
238 realizable.hasActiveMap = true;
239 realizable.activeMap = mapEntity;
240
241 auto& mappable = game_.getEntityManager().
242 getComponent<MappableComponent>(mapEntity);
243
244 // Initialize the new map's objects.
245 for (id_type prototype : mappable.objects)
246 {
247 if (game_.getEntityManager().
248 hasComponent<TransformableComponent>(prototype))
249 {
250 auto& transformable = game_.getEntityManager().
251 getComponent<TransformableComponent>(prototype);
252
253 transformable.x = transformable.origX;
254 transformable.y = transformable.origY;
255 transformable.w = transformable.origW;
256 transformable.h = transformable.origH;
257 }
258
259 if (game_.getEntityManager().hasComponent<AnimatableComponent>(prototype))
260 {
261 animating.initPrototype(prototype);
262 }
263
264 if (game_.getEntityManager().hasComponent<PonderableComponent>(prototype))
265 {
266 pondering.initPrototype(prototype);
267 }
268
269 enterActiveMap(prototype);
270 }
271
272 // Activate any players on the map.
273 for (id_type player : players)
274 {
275 auto& playable = game_.getEntityManager().
276 getComponent<PlayableComponent>(player);
277
278 if (playable.mapId == mapEntity)
279 {
280 enterActiveMap(player);
281 }
282 }
283}
284
285void RealizingSystem::enterActiveMap(id_type entity)
286{
287 if (game_.getEntityManager().hasComponent<AnimatableComponent>(entity))
288 {
289 auto& animatable = game_.getEntityManager().
290 getComponent<AnimatableComponent>(entity);
291
292 animatable.active = true;
293 }
294
295 if (game_.getEntityManager().hasComponent<PonderableComponent>(entity))
296 {
297 auto& ponderable = game_.getEntityManager().
298 getComponent<PonderableComponent>(entity);
299
300 ponderable.active = true;
301 }
302}
303
304void RealizingSystem::leaveActiveMap(id_type entity)
305{
306 if (game_.getEntityManager().hasComponent<AnimatableComponent>(entity))
307 {
308 auto& animatable = game_.getEntityManager().
309 getComponent<AnimatableComponent>(entity);
310
311 animatable.active = false;
312 }
313
314 if (game_.getEntityManager().hasComponent<PonderableComponent>(entity))
315 {
316 auto& ponderable = game_.getEntityManager().
317 getComponent<PonderableComponent>(entity);
318
319 ponderable.active = false;
320 }
321}