diff options
Diffstat (limited to 'tools/mapedit/src/world.cpp')
-rw-r--r-- | tools/mapedit/src/world.cpp | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/tools/mapedit/src/world.cpp b/tools/mapedit/src/world.cpp new file mode 100644 index 0000000..4c42593 --- /dev/null +++ b/tools/mapedit/src/world.cpp | |||
@@ -0,0 +1,369 @@ | |||
1 | #include "world.h" | ||
2 | #include <libxml/parser.h> | ||
3 | #include <libxml/xmlwriter.h> | ||
4 | #include "frame.h" | ||
5 | #include <sstream> | ||
6 | |||
7 | World::World() | ||
8 | { | ||
9 | newMap(); | ||
10 | |||
11 | rootChildren.push_back(0); | ||
12 | } | ||
13 | |||
14 | World::World(std::string filename) | ||
15 | { | ||
16 | this->filename = filename; | ||
17 | |||
18 | xmlDocPtr doc = xmlParseFile(filename.c_str()); | ||
19 | if (doc == nullptr) | ||
20 | { | ||
21 | throw MapLoadException(filename); | ||
22 | } | ||
23 | |||
24 | xmlNodePtr top = xmlDocGetRootElement(doc); | ||
25 | if (top == nullptr) | ||
26 | { | ||
27 | throw MapLoadException(filename); | ||
28 | } | ||
29 | |||
30 | if (xmlStrcmp(top->name, (const xmlChar*) "world")) | ||
31 | { | ||
32 | throw MapLoadException(filename); | ||
33 | } | ||
34 | |||
35 | for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) | ||
36 | { | ||
37 | if (!xmlStrcmp(node->name, (const xmlChar*) "nextmapid")) | ||
38 | { | ||
39 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
40 | if (key != 0) | ||
41 | { | ||
42 | nextMapID = atoi((char*) key); | ||
43 | } | ||
44 | xmlFree(key); | ||
45 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "lastmap")) | ||
46 | { | ||
47 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
48 | if (key != 0) | ||
49 | { | ||
50 | lastmap = atoi((char*) key); | ||
51 | } | ||
52 | xmlFree(key); | ||
53 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "root")) | ||
54 | { | ||
55 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
56 | if (key != 0) | ||
57 | { | ||
58 | rootChildren.push_back(atoi((char*) key)); | ||
59 | } | ||
60 | xmlFree(key); | ||
61 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "map")) | ||
62 | { | ||
63 | xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id"); | ||
64 | if (idKey == 0) throw MapLoadException(filename); | ||
65 | int id = atoi((char*) idKey); | ||
66 | xmlFree(idKey); | ||
67 | |||
68 | auto map = std::make_shared<Map>(id, this); | ||
69 | |||
70 | for (xmlNodePtr mapNode = node->xmlChildrenNode; mapNode != NULL; mapNode = mapNode->next) | ||
71 | { | ||
72 | if (!xmlStrcmp(mapNode->name, (const xmlChar*) "name")) | ||
73 | { | ||
74 | xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); | ||
75 | if (key != 0) | ||
76 | { | ||
77 | map->setTitle((char*) key, false); | ||
78 | } | ||
79 | |||
80 | xmlFree(key); | ||
81 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "environment")) | ||
82 | { | ||
83 | xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); | ||
84 | int* mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); | ||
85 | mapdata[0] = atoi(strtok((char*) key, ",\n")); | ||
86 | for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++) | ||
87 | { | ||
88 | mapdata[i] = atoi(strtok(NULL, ",\n")); | ||
89 | } | ||
90 | map->setMapdata(mapdata, false); | ||
91 | xmlFree(key); | ||
92 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "leftmap")) | ||
93 | { | ||
94 | xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); | ||
95 | if (key != 0) | ||
96 | { | ||
97 | map->setLeftmap(atoi((char*) key), false); | ||
98 | } | ||
99 | xmlFree(key); | ||
100 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "rightmap")) | ||
101 | { | ||
102 | xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); | ||
103 | if (key != 0) | ||
104 | { | ||
105 | map->setRightmap(atoi((char*) key)); | ||
106 | } | ||
107 | xmlFree(key); | ||
108 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "entities")) | ||
109 | { | ||
110 | for (xmlNodePtr entityNode = mapNode->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next) | ||
111 | { | ||
112 | if (!xmlStrcmp(entityNode->name, (const xmlChar*) "entity")) | ||
113 | { | ||
114 | auto data = std::make_shared<MapObjectEntry>(); | ||
115 | |||
116 | for (xmlNodePtr entityDataNode = entityNode->xmlChildrenNode; entityDataNode != NULL; entityDataNode = entityDataNode->next) | ||
117 | { | ||
118 | if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-type")) | ||
119 | { | ||
120 | xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); | ||
121 | data->object = MapObject::getAllObjects().at((char*) key).get(); | ||
122 | xmlFree(key); | ||
123 | } else if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-position")) | ||
124 | { | ||
125 | xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); | ||
126 | sscanf((char*) key, "%lf,%lf", &data->position.first, &data->position.second); | ||
127 | xmlFree(key); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | map->addObject(data, false); | ||
132 | } | ||
133 | } | ||
134 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "child")) | ||
135 | { | ||
136 | xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); | ||
137 | if (key != 0) | ||
138 | { | ||
139 | map->addChild(atoi((char*) key)); | ||
140 | } | ||
141 | xmlFree(key); | ||
142 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "expanded")) | ||
143 | { | ||
144 | xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); | ||
145 | if ((key != 0) && ((char) key[0] == '1')) | ||
146 | { | ||
147 | map->setExpanded(true); | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | |||
152 | maps[map->getID()] = map; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | xmlFreeDoc(doc); | ||
157 | } | ||
158 | |||
159 | std::shared_ptr<Map> World::newMap() | ||
160 | { | ||
161 | auto nm = std::make_shared<Map>(nextMapID++, this); | ||
162 | maps[nm->getID()] = nm; | ||
163 | return nm; | ||
164 | } | ||
165 | |||
166 | std::shared_ptr<Map> World::getMap(int id) const | ||
167 | { | ||
168 | return maps.at(id); | ||
169 | } | ||
170 | |||
171 | void World::setDirty(bool dirty) | ||
172 | { | ||
173 | this->dirty = dirty; | ||
174 | parent->MapDirtyDidChange(dirty); | ||
175 | } | ||
176 | |||
177 | bool World::getDirty() const | ||
178 | { | ||
179 | return dirty; | ||
180 | } | ||
181 | |||
182 | std::string World::getFilename() const | ||
183 | { | ||
184 | return filename; | ||
185 | } | ||
186 | |||
187 | void World::setParent(MapeditFrame* parent) | ||
188 | { | ||
189 | this->parent = parent; | ||
190 | } | ||
191 | |||
192 | Map* World::getLastMap() const | ||
193 | { | ||
194 | return getMap(lastmap).get(); | ||
195 | } | ||
196 | |||
197 | #define MY_ENCODING "ISO-8859-1" | ||
198 | |||
199 | void World::save(std::string name, wxTreeCtrl* mapTree) | ||
200 | { | ||
201 | int rc; | ||
202 | |||
203 | xmlTextWriterPtr writer = xmlNewTextWriterFilename(name.c_str(), 0); | ||
204 | if (writer == NULL) throw MapWriteException(name); | ||
205 | |||
206 | rc = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL); | ||
207 | if (rc < 0) throw MapWriteException(name); | ||
208 | |||
209 | // <world> | ||
210 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "world"); | ||
211 | if (rc < 0) throw MapWriteException(name); | ||
212 | |||
213 | // <nextmapid/> | ||
214 | std::ostringstream nextMap_out; | ||
215 | nextMap_out << nextMapID; | ||
216 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "nextmapid", (xmlChar*) nextMap_out.str().c_str()); | ||
217 | if (rc < 0) throw MapWriteException(name); | ||
218 | |||
219 | // <lastmap/> | ||
220 | std::ostringstream lastMap_out; | ||
221 | lastMap_out << lastmap; | ||
222 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "lastmap", (xmlChar*) lastMap_out.str().c_str()); | ||
223 | if (rc < 0) throw MapWriteException(name); | ||
224 | |||
225 | // ASSUMPTION: There will always be at least one child of the invisible root element. i.e. you cannot delete to zero maps. | ||
226 | wxTreeItemId root = mapTree->GetRootItem(); | ||
227 | wxTreeItemIdValue cookie1; | ||
228 | for (wxTreeItemId it = mapTree->GetFirstChild(root, cookie1); it.IsOk(); it = mapTree->GetNextChild(root, cookie1)) | ||
229 | { | ||
230 | // <root> | ||
231 | MapPtrCtr* ctl = (MapPtrCtr*) mapTree->GetItemData(it); | ||
232 | std::ostringstream rootid_out; | ||
233 | rootid_out << ctl->map->getID(); | ||
234 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "root", (xmlChar*) rootid_out.str().c_str()); | ||
235 | if (rc < 0) throw MapWriteException(name); | ||
236 | } | ||
237 | |||
238 | for (auto mapPair : maps) | ||
239 | { | ||
240 | Map& map = *mapPair.second; | ||
241 | |||
242 | // <map> | ||
243 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "map"); | ||
244 | if (rc < 0) throw MapWriteException(name); | ||
245 | |||
246 | // id= | ||
247 | std::ostringstream id_out; | ||
248 | id_out << map.getID(); | ||
249 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "id", (xmlChar*) id_out.str().c_str()); | ||
250 | if (rc < 0) throw MapWriteException(name); | ||
251 | |||
252 | // <name/> | ||
253 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "name", (xmlChar*) map.getTitle().c_str()); | ||
254 | if (rc < 0) throw MapWriteException(name); | ||
255 | |||
256 | // <environment/> | ||
257 | std::ostringstream mapdata_out; | ||
258 | for (int y=0; y<MAP_HEIGHT; y++) | ||
259 | { | ||
260 | for (int x=0; x<MAP_WIDTH; x++) | ||
261 | { | ||
262 | mapdata_out << map.getTileAt(x,y) << ","; | ||
263 | } | ||
264 | |||
265 | mapdata_out << std::endl; | ||
266 | } | ||
267 | |||
268 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "environment", (xmlChar*) mapdata_out.str().c_str()); | ||
269 | if (rc < 0) throw MapWriteException(name); | ||
270 | |||
271 | // <leftmap/> | ||
272 | std::ostringstream leftmap_out; | ||
273 | if (map.getLeftmap()) | ||
274 | { | ||
275 | leftmap_out << map.getLeftmap()->getID(); | ||
276 | } | ||
277 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "leftmap", (xmlChar*) leftmap_out.str().c_str()); | ||
278 | if (rc < 0) throw MapWriteException(name); | ||
279 | |||
280 | // <rightmap/> | ||
281 | std::ostringstream rightmap_out; | ||
282 | if (map.getRightmap()) | ||
283 | { | ||
284 | rightmap_out << map.getRightmap()->getID(); | ||
285 | } | ||
286 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "rightmap", (xmlChar*) rightmap_out.str().c_str()); | ||
287 | if (rc < 0) throw MapWriteException(name); | ||
288 | |||
289 | // <entities> | ||
290 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "entities"); | ||
291 | if (rc < 0) throw MapWriteException(name); | ||
292 | |||
293 | for (auto object : map.getObjects()) | ||
294 | { | ||
295 | // <entity> | ||
296 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "entity"); | ||
297 | if (rc < 0) throw MapWriteException(name); | ||
298 | |||
299 | // <entity-type/> | ||
300 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "entity-type", (xmlChar*) object->object->getType().c_str()); | ||
301 | if (rc < 0) throw MapWriteException(name); | ||
302 | |||
303 | // <entity-position/> | ||
304 | std::ostringstream entpos_out; | ||
305 | entpos_out << object->position.first << "," << object->position.second; | ||
306 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "entity-position", (xmlChar*) entpos_out.str().c_str()); | ||
307 | if (rc < 0) throw MapWriteException(name); | ||
308 | |||
309 | // </entity> | ||
310 | rc = xmlTextWriterEndElement(writer); | ||
311 | if (rc < 0) throw MapWriteException(name); | ||
312 | } | ||
313 | |||
314 | // </entities> | ||
315 | rc = xmlTextWriterEndElement(writer); | ||
316 | if (rc < 0) throw MapWriteException(name); | ||
317 | |||
318 | wxTreeItemId node = map.getTreeItemId(); | ||
319 | if (mapTree->ItemHasChildren(node)) | ||
320 | { | ||
321 | wxTreeItemIdValue cookie2; | ||
322 | for (wxTreeItemId it = mapTree->GetFirstChild(node, cookie2); it.IsOk(); it = mapTree->GetNextChild(node, cookie2)) | ||
323 | { | ||
324 | // <child/> | ||
325 | MapPtrCtr* ctl = (MapPtrCtr*) mapTree->GetItemData(it); | ||
326 | std::ostringstream childid_out; | ||
327 | childid_out << ctl->map->getID(); | ||
328 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "child", (xmlChar*) childid_out.str().c_str()); | ||
329 | if (rc < 0) throw MapWriteException(name); | ||
330 | } | ||
331 | |||
332 | if (mapTree->IsExpanded(node)) | ||
333 | { | ||
334 | // <expanded/> | ||
335 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "expanded", (xmlChar*) "1"); | ||
336 | if (rc < 0) throw MapWriteException(name); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | // </map> | ||
341 | rc = xmlTextWriterEndElement(writer); | ||
342 | if (rc < 0) throw MapWriteException(name); | ||
343 | } | ||
344 | |||
345 | // </world> | ||
346 | rc = xmlTextWriterEndDocument(writer); | ||
347 | if (rc < 0) throw MapWriteException(name); | ||
348 | |||
349 | xmlFreeTextWriter(writer); | ||
350 | |||
351 | setDirty(false); | ||
352 | } | ||
353 | |||
354 | std::list<std::shared_ptr<Map>> World::getRootMaps() const | ||
355 | { | ||
356 | std::list<std::shared_ptr<Map>> ret; | ||
357 | |||
358 | for (auto id : rootChildren) | ||
359 | { | ||
360 | ret.push_back(getMap(id)); | ||
361 | } | ||
362 | |||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | const std::map<int, std::shared_ptr<Map>> World::getMaps() const | ||
367 | { | ||
368 | return maps; | ||
369 | } | ||