diff options
author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2015-03-16 16:53:05 -0400 |
---|---|---|
committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2015-03-16 16:53:05 -0400 |
commit | 0d30e9b57229905f78e7bd60fe5d3cde72851f28 (patch) | |
tree | 4ca2abff9fb1933685f570e97a8b9e88a976c95f /tools/mapedit/src/world.cpp | |
parent | 36536297aac5c07e3d5fb96abed74570fc7615e9 (diff) | |
download | therapy-0d30e9b57229905f78e7bd60fe5d3cde72851f28.tar.gz therapy-0d30e9b57229905f78e7bd60fe5d3cde72851f28.tar.bz2 therapy-0d30e9b57229905f78e7bd60fe5d3cde72851f28.zip |
Rewrote map editor so a single file contains all maps
Maps are viewed in a tree control on the left. They can be dragged and dropped. Maps are bolded when they are dirty. Saving saves expansion status and order of maps in tree.
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 | } | ||