diff options
Diffstat (limited to 'tools/mapedit')
| -rw-r--r-- | tools/mapedit/src/frame.cpp | 82 | ||||
| -rw-r--r-- | tools/mapedit/src/frame.h | 1 | ||||
| -rw-r--r-- | tools/mapedit/src/map.h | 18 | ||||
| -rw-r--r-- | tools/mapedit/src/object.cpp | 304 | ||||
| -rw-r--r-- | tools/mapedit/src/object.h | 91 | ||||
| -rw-r--r-- | tools/mapedit/src/undo.cpp | 74 | ||||
| -rw-r--r-- | tools/mapedit/src/undo.h | 30 | ||||
| -rw-r--r-- | tools/mapedit/src/widget.cpp | 86 | ||||
| -rw-r--r-- | tools/mapedit/src/widget.h | 7 | ||||
| -rw-r--r-- | tools/mapedit/src/world.cpp | 109 |
10 files changed, 666 insertions, 136 deletions
| diff --git a/tools/mapedit/src/frame.cpp b/tools/mapedit/src/frame.cpp index 06102f7..aad3294 100644 --- a/tools/mapedit/src/frame.cpp +++ b/tools/mapedit/src/frame.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #include "mapselect_combo.h" | 2 | #include "mapselect_combo.h" |
| 3 | #include <wx/statline.h> | 3 | #include <wx/statline.h> |
| 4 | #include <list> | 4 | #include <list> |
| 5 | #include <wx/valgen.h> | ||
| 5 | #include <exception> | 6 | #include <exception> |
| 6 | #include <sstream> | 7 | #include <sstream> |
| 7 | #include "widget.h" | 8 | #include "widget.h" |
| @@ -29,6 +30,7 @@ enum { | |||
| 29 | TOOL_FILE_SAVE, | 30 | TOOL_FILE_SAVE, |
| 30 | TOOL_MAP_ADD_ROOT, | 31 | TOOL_MAP_ADD_ROOT, |
| 31 | TOOL_MAP_ADD_CHILD, | 32 | TOOL_MAP_ADD_CHILD, |
| 33 | MAP_EDITOR_WIDGET, | ||
| 32 | MAP_EDITOR_NOTEBOOK, | 34 | MAP_EDITOR_NOTEBOOK, |
| 33 | MAP_EDITOR_TREE, | 35 | MAP_EDITOR_TREE, |
| 34 | MAP_TITLE_TEXTBOX, | 36 | MAP_TITLE_TEXTBOX, |
| @@ -45,7 +47,10 @@ enum { | |||
| 45 | UPMAP_TYPE_CHOICE, | 47 | UPMAP_TYPE_CHOICE, |
| 46 | UPMAP_MAP_CHOICE, | 48 | UPMAP_MAP_CHOICE, |
| 47 | DOWNMAP_TYPE_CHOICE, | 49 | DOWNMAP_TYPE_CHOICE, |
| 48 | DOWNMAP_MAP_CHOICE | 50 | DOWNMAP_MAP_CHOICE, |
| 51 | ENTITY_EDITOR, | ||
| 52 | ENTITY_PROPERTY_EDITOR, | ||
| 53 | PROPERTY_EDITOR | ||
| 49 | }; | 54 | }; |
| 50 | 55 | ||
| 51 | wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) | 56 | wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) |
| @@ -87,6 +92,7 @@ wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) | |||
| 87 | EVT_COMBOBOX_CLOSEUP(RIGHTMAP_MAP_CHOICE, MapeditFrame::OnSetRightmapMap) | 92 | EVT_COMBOBOX_CLOSEUP(RIGHTMAP_MAP_CHOICE, MapeditFrame::OnSetRightmapMap) |
| 88 | EVT_COMBOBOX_CLOSEUP(UPMAP_MAP_CHOICE, MapeditFrame::OnSetUpmapMap) | 93 | EVT_COMBOBOX_CLOSEUP(UPMAP_MAP_CHOICE, MapeditFrame::OnSetUpmapMap) |
| 89 | EVT_COMBOBOX_CLOSEUP(DOWNMAP_MAP_CHOICE, MapeditFrame::OnSetDownmapMap) | 94 | EVT_COMBOBOX_CLOSEUP(DOWNMAP_MAP_CHOICE, MapeditFrame::OnSetDownmapMap) |
| 95 | EVT_COMMAND(wxID_ANY, EVT_MAP_SELECTED_ENTITY, MapeditFrame::OnSelectEntity) | ||
| 90 | wxEND_EVENT_TABLE() | 96 | wxEND_EVENT_TABLE() |
| 91 | 97 | ||
| 92 | MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | 98 | MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") |
| @@ -171,7 +177,7 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
| 171 | tileEditor = new TileWidget(notebook, wxID_ANY, 6, 6, wxPoint(0,0), wxSize(TILE_WIDTH*6*6,TILE_HEIGHT*10*6)); | 177 | tileEditor = new TileWidget(notebook, wxID_ANY, 6, 6, wxPoint(0,0), wxSize(TILE_WIDTH*6*6,TILE_HEIGHT*10*6)); |
| 172 | notebook->AddPage(tileEditor, "Tile Chooser", false); | 178 | notebook->AddPage(tileEditor, "Tile Chooser", false); |
| 173 | 179 | ||
| 174 | mapEditor = new MapeditWidget(layout3, wxID_ANY, currentMap, tileEditor, wxPoint(0,0), wxSize(GAME_WIDTH*2, GAME_HEIGHT*2)); | 180 | mapEditor = new MapeditWidget(layout3, MAP_EDITOR_WIDGET, currentMap, tileEditor, wxPoint(0,0), wxSize(GAME_WIDTH*2, GAME_HEIGHT*2)); |
| 175 | mapEditor->frame = this; | 181 | mapEditor->frame = this; |
| 176 | 182 | ||
| 177 | // Set up property editor | 183 | // Set up property editor |
| @@ -181,7 +187,7 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
| 181 | 187 | ||
| 182 | wxStaticText* titleLabel = new wxStaticText(propertyEditor, wxID_ANY, "Title:"); | 188 | wxStaticText* titleLabel = new wxStaticText(propertyEditor, wxID_ANY, "Title:"); |
| 183 | 189 | ||
| 184 | startposLabel = new wxStaticText(propertyEditor, wxID_ANY, "Starting Position:"); | 190 | startposLabel = new wxStaticText(propertyEditor, PROPERTY_EDITOR, "Starting Position:"); |
| 185 | 191 | ||
| 186 | setStartposButton = new wxButton(propertyEditor, SET_STARTPOS_BUTTON, "Set Starting Position"); | 192 | setStartposButton = new wxButton(propertyEditor, SET_STARTPOS_BUTTON, "Set Starting Position"); |
| 187 | cancelStartposButton = new wxButton(propertyEditor, CANCEL_STARTPOS_BUTTON, "Cancel"); | 193 | cancelStartposButton = new wxButton(propertyEditor, CANCEL_STARTPOS_BUTTON, "Cancel"); |
| @@ -264,7 +270,7 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
| 264 | propertySizer->SetSizeHints(propertyEditor); | 270 | propertySizer->SetSizeHints(propertyEditor); |
| 265 | 271 | ||
| 266 | // Set up entity editor | 272 | // Set up entity editor |
| 267 | wxPanel* entityEditor = new wxPanel(notebook, wxID_ANY); | 273 | wxPanel* entityEditor = new wxPanel(notebook, ENTITY_EDITOR); |
| 268 | notebook->AddPage(entityEditor, "Entity Manager", false); | 274 | notebook->AddPage(entityEditor, "Entity Manager", false); |
| 269 | 275 | ||
| 270 | wxStaticText* entityHeader = new wxStaticText(entityEditor, wxID_ANY, "Add Entity"); | 276 | wxStaticText* entityHeader = new wxStaticText(entityEditor, wxID_ANY, "Add Entity"); |
| @@ -275,9 +281,9 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
| 275 | wxStaticText* entityTypeLabel = new wxStaticText(entityEditor, wxID_ANY, "Entity Type:"); | 281 | wxStaticText* entityTypeLabel = new wxStaticText(entityEditor, wxID_ANY, "Entity Type:"); |
| 276 | 282 | ||
| 277 | entityTypeBox = new wxChoice(entityEditor, wxID_ANY); | 283 | entityTypeBox = new wxChoice(entityEditor, wxID_ANY); |
| 278 | for (auto entry : MapObject::getAllObjects()) | 284 | for (auto& entry : MapObject::getAllObjects()) |
| 279 | { | 285 | { |
| 280 | entityTypeBox->Append(entry.second->getType(), entry.second.get()); | 286 | entityTypeBox->Append(entry.second.getName(), (void*) &entry.second); |
| 281 | } | 287 | } |
| 282 | 288 | ||
| 283 | addEntityButton = new wxButton(entityEditor, ADD_ENTITY_BUTTON, "Add Entity"); | 289 | addEntityButton = new wxButton(entityEditor, ADD_ENTITY_BUTTON, "Add Entity"); |
| @@ -286,6 +292,8 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
| 286 | 292 | ||
| 287 | wxStaticText* entityInfoLabel = new wxStaticText(entityEditor, wxID_ANY, "Click and drag an entity to move it.\nRight click an entity to delete it."); | 293 | wxStaticText* entityInfoLabel = new wxStaticText(entityEditor, wxID_ANY, "Click and drag an entity to move it.\nRight click an entity to delete it."); |
| 288 | 294 | ||
| 295 | wxPanel* entityPropertyEditor = new wxPanel(entityEditor, ENTITY_PROPERTY_EDITOR); | ||
| 296 | |||
| 289 | wxBoxSizer* entitySizer = new wxBoxSizer(wxVERTICAL); | 297 | wxBoxSizer* entitySizer = new wxBoxSizer(wxVERTICAL); |
| 290 | entitySizer->Add(entityHeader, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, 5); | 298 | entitySizer->Add(entityHeader, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, 5); |
| 291 | wxBoxSizer* entitySizer1 = new wxBoxSizer(wxHORIZONTAL); | 299 | wxBoxSizer* entitySizer1 = new wxBoxSizer(wxHORIZONTAL); |
| @@ -298,6 +306,12 @@ MapeditFrame::MapeditFrame(World* world) : wxFrame(NULL, wxID_ANY, "Map Editor") | |||
| 298 | entitySizer->Add(entitySizer2, 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); | 306 | entitySizer->Add(entitySizer2, 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); |
| 299 | entitySizer->Add(new wxStaticLine(entityEditor), 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); | 307 | entitySizer->Add(new wxStaticLine(entityEditor), 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); |
| 300 | entitySizer->Add(entityInfoLabel, 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); | 308 | entitySizer->Add(entityInfoLabel, 0, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALL, 5); |
| 309 | entitySizer->Add(entityPropertyEditor, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP | wxALL, 5); | ||
| 310 | wxBoxSizer* entityPropertySizer = new wxBoxSizer(wxVERTICAL); | ||
| 311 | entityPropertySizer->Add(new wxStaticLine(entityPropertyEditor), 1, wxEXPAND, 0); | ||
| 312 | entityPropertyEditor->SetSizer(entityPropertySizer); | ||
| 313 | entityPropertySizer->SetSizeHints(entityPropertyEditor); | ||
| 314 | //entitySizer->Add(entityPropertySizer, 1, wxEXPAND, 0); | ||
| 301 | entityEditor->SetSizer(entitySizer); | 315 | entityEditor->SetSizer(entitySizer); |
| 302 | entitySizer->SetSizeHints(entityEditor); | 316 | entitySizer->SetSizeHints(entityEditor); |
| 303 | 317 | ||
| @@ -840,6 +854,62 @@ void MapeditFrame::OnSetDownmapMap(wxCommandEvent&) | |||
| 840 | })); | 854 | })); |
| 841 | } | 855 | } |
| 842 | 856 | ||
| 857 | void MapeditFrame::OnSelectEntity(wxCommandEvent& event) | ||
| 858 | { | ||
| 859 | MapObjectEntry* entry = (MapObjectEntry*) event.GetClientData(); | ||
| 860 | wxPanel* entityPropertyEditor = (wxPanel*) wxWindow::FindWindowById(ENTITY_PROPERTY_EDITOR, this); | ||
| 861 | |||
| 862 | if (entry == nullptr) | ||
| 863 | { | ||
| 864 | entityPropertyEditor->GetSizer()->Clear(); | ||
| 865 | entityPropertyEditor->DestroyChildren(); | ||
| 866 | } else { | ||
| 867 | wxSizer* sizer = entityPropertyEditor->GetSizer(); | ||
| 868 | for (auto input : entry->getObject().getInputs()) | ||
| 869 | { | ||
| 870 | wxStaticText* inputText = new wxStaticText(entityPropertyEditor, wxID_ANY, input.second.name + ":"); | ||
| 871 | sizer->Add(inputText, 0, wxEXPAND | wxALIGN_LEFT | wxBOTTOM, 0); | ||
| 872 | |||
| 873 | MapObjectEntry::Item& item = entry->getItem(input.first); | ||
| 874 | |||
| 875 | wxWindow* inputObject = nullptr; | ||
| 876 | switch (input.second.type) | ||
| 877 | { | ||
| 878 | case MapObject::Input::Type::Choice: | ||
| 879 | { | ||
| 880 | UndoableChoice* thechoice = new UndoableChoice(entityPropertyEditor, wxID_ANY, this, wxDefaultPosition, wxDefaultSize, 0, NULL, 0, VariableChoiceValidator(*world, item), input.second.name); | ||
| 881 | int selected = 0; | ||
| 882 | for (auto choice : input.second.choices) | ||
| 883 | { | ||
| 884 | thechoice->Append(choice.second, (void*) choice.first); | ||
| 885 | |||
| 886 | if (item.intvalue == choice.first) | ||
| 887 | { | ||
| 888 | selected = thechoice->GetCount()-1; | ||
| 889 | } | ||
| 890 | } | ||
| 891 | |||
| 892 | thechoice->SetSelection(selected); | ||
| 893 | inputObject = thechoice; | ||
| 894 | break; | ||
| 895 | } | ||
| 896 | |||
| 897 | case MapObject::Input::Type::Slider: | ||
| 898 | { | ||
| 899 | if (item.intvalue < input.second.minvalue) item.intvalue = input.second.minvalue; | ||
| 900 | if (item.intvalue > input.second.maxvalue) item.intvalue = input.second.maxvalue; | ||
| 901 | inputObject = new UndoableSlider(entityPropertyEditor, wxID_ANY, this, item.intvalue, input.second.minvalue, input.second.maxvalue, wxDefaultPosition, wxDefaultSize, wxHORIZONTAL | wxSL_LABELS, SliderItemValidator(*world, item), input.second.name); | ||
| 902 | break; | ||
| 903 | } | ||
| 904 | } | ||
| 905 | |||
| 906 | sizer->Add(inputObject, 0, wxEXPAND | wxALIGN_LEFT | wxBOTTOM, 10); | ||
| 907 | } | ||
| 908 | |||
| 909 | entityPropertyEditor->Layout(); | ||
| 910 | } | ||
| 911 | } | ||
| 912 | |||
| 843 | void MapeditFrame::NewWorld() | 913 | void MapeditFrame::NewWorld() |
| 844 | { | 914 | { |
| 845 | LaunchWindow(new World()); | 915 | LaunchWindow(new World()); |
| diff --git a/tools/mapedit/src/frame.h b/tools/mapedit/src/frame.h index dd8424c..9f9ea1f 100644 --- a/tools/mapedit/src/frame.h +++ b/tools/mapedit/src/frame.h | |||
| @@ -74,6 +74,7 @@ class MapeditFrame : public wxFrame { | |||
| 74 | void OnSetUpmapMap(wxCommandEvent& event); | 74 | void OnSetUpmapMap(wxCommandEvent& event); |
| 75 | void OnSetDownmapType(wxCommandEvent& event); | 75 | void OnSetDownmapType(wxCommandEvent& event); |
| 76 | void OnSetDownmapMap(wxCommandEvent& event); | 76 | void OnSetDownmapMap(wxCommandEvent& event); |
| 77 | void OnSelectEntity(wxCommandEvent& event); | ||
| 77 | 78 | ||
| 78 | World* world; | 79 | World* world; |
| 79 | Map* currentMap; | 80 | Map* currentMap; |
| diff --git a/tools/mapedit/src/map.h b/tools/mapedit/src/map.h index c7f5b30..9c14218 100644 --- a/tools/mapedit/src/map.h +++ b/tools/mapedit/src/map.h | |||
| @@ -8,10 +8,11 @@ | |||
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <wx/treectrl.h> | 9 | #include <wx/treectrl.h> |
| 10 | #include <map> | 10 | #include <map> |
| 11 | #include "object.h" | ||
| 11 | 12 | ||
| 12 | class MapObject; | ||
| 13 | class World; | 13 | class World; |
| 14 | class MapeditFrame; | 14 | class MapeditFrame; |
| 15 | class MapEntryObject; | ||
| 15 | 16 | ||
| 16 | class MapLoadException: public std::exception | 17 | class MapLoadException: public std::exception |
| 17 | { | 18 | { |
| @@ -41,21 +42,6 @@ class MapWriteException: public std::exception | |||
| 41 | std::string mapname; | 42 | std::string mapname; |
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | struct MapObjectEntry { | ||
| 45 | MapObject* object; | ||
| 46 | std::pair<int, int> position; | ||
| 47 | |||
| 48 | bool operator==(MapObjectEntry& other) const | ||
| 49 | { | ||
| 50 | return (object == other.object) && (position == other.position); | ||
| 51 | } | ||
| 52 | |||
| 53 | bool operator!=(MapObjectEntry& other) const | ||
| 54 | { | ||
| 55 | return (object != other.object) && (position != other.position); | ||
| 56 | } | ||
| 57 | }; | ||
| 58 | |||
| 59 | class Map { | 45 | class Map { |
| 60 | public: | 46 | public: |
| 61 | Map(int id, World* world); | 47 | Map(int id, World* world); |
| diff --git a/tools/mapedit/src/object.cpp b/tools/mapedit/src/object.cpp index a783691..8ed29af 100644 --- a/tools/mapedit/src/object.cpp +++ b/tools/mapedit/src/object.cpp | |||
| @@ -2,29 +2,130 @@ | |||
| 2 | #include <dirent.h> | 2 | #include <dirent.h> |
| 3 | #include <libxml/parser.h> | 3 | #include <libxml/parser.h> |
| 4 | #include <memory> | 4 | #include <memory> |
| 5 | #include "world.h" | ||
| 5 | 6 | ||
| 6 | static std::map<std::string, std::shared_ptr<MapObject>> allObjects; | 7 | static std::map<std::string, MapObject> allObjects; |
| 7 | static bool objsInit = false; | 8 | static bool objsInit = false; |
| 8 | 9 | ||
| 9 | const std::map<std::string, std::shared_ptr<MapObject>> MapObject::getAllObjects() | 10 | const std::map<std::string, MapObject>& MapObject::getAllObjects() |
| 10 | { | 11 | { |
| 11 | if (!objsInit) | 12 | if (!objsInit) |
| 12 | { | 13 | { |
| 13 | DIR* dir = opendir("entities/"); | 14 | try |
| 14 | if (dir != NULL) | ||
| 15 | { | 15 | { |
| 16 | struct dirent* ent; | 16 | xmlDocPtr doc = xmlParseFile("res/entities.xml"); |
| 17 | while ((ent = readdir(dir)) != NULL) | 17 | if (doc == nullptr) |
| 18 | { | 18 | { |
| 19 | std::string path = ent->d_name; | 19 | throw MapObjectLoadException("can't open file"); |
| 20 | if ((path.length() >= 4) && (path.substr(path.length() - 4, 4) == ".xml")) | 20 | } |
| 21 | |||
| 22 | xmlNodePtr top = xmlDocGetRootElement(doc); | ||
| 23 | if (top == nullptr) | ||
| 24 | { | ||
| 25 | throw MapObjectLoadException("missing root element"); | ||
| 26 | } | ||
| 27 | |||
| 28 | if (xmlStrcmp(top->name, (const xmlChar*) "entities")) | ||
| 29 | { | ||
| 30 | throw MapObjectLoadException("root element is not entities"); | ||
| 31 | } | ||
| 32 | |||
| 33 | for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) | ||
| 34 | { | ||
| 35 | if (!xmlStrcmp(node->name, (const xmlChar*) "entity")) | ||
| 21 | { | 36 | { |
| 22 | std::string name = path.substr(0, path.length() - 4); | 37 | xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id"); |
| 23 | auto obj = std::make_shared<MapObject>(name.c_str()); | 38 | if (idKey == 0) throw MapObjectLoadException("entity missing id"); |
| 24 | 39 | std::string theID = (char*) idKey; | |
| 25 | allObjects[name] = obj; | 40 | xmlFree(idKey); |
| 41 | |||
| 42 | allObjects.emplace(theID, theID); | ||
| 43 | MapObject& mapObject = allObjects.at(theID); | ||
| 44 | |||
| 45 | xmlChar* nameKey = xmlGetProp(node, (xmlChar*) "name"); | ||
| 46 | if (nameKey == 0) throw MapObjectLoadException("entity missing name"); | ||
| 47 | mapObject.name = (char*) nameKey; | ||
| 48 | xmlFree(nameKey); | ||
| 49 | |||
| 50 | xmlChar* spriteKey = xmlGetProp(node, (xmlChar*) "sprite"); | ||
| 51 | if (spriteKey == 0) throw MapObjectLoadException("entity missing sprite"); | ||
| 52 | mapObject.sprite = wxImage((char*) spriteKey); | ||
| 53 | xmlFree(spriteKey); | ||
| 54 | |||
| 55 | xmlChar* widthKey = xmlGetProp(node, (xmlChar*) "width"); | ||
| 56 | if (widthKey == 0) throw MapObjectLoadException("entity missing width"); | ||
| 57 | mapObject.width = atoi((char*) widthKey); | ||
| 58 | xmlFree(widthKey); | ||
| 59 | |||
| 60 | xmlChar* heightKey = xmlGetProp(node, (xmlChar*) "height"); | ||
| 61 | if (heightKey == 0) throw MapObjectLoadException("entity missing height"); | ||
| 62 | mapObject.height = atoi((char*) heightKey); | ||
| 63 | xmlFree(heightKey); | ||
| 64 | |||
| 65 | for (xmlNodePtr entityNode = node->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next) | ||
| 66 | { | ||
| 67 | if (!xmlStrcmp(entityNode->name, (const xmlChar*) "input")) | ||
| 68 | { | ||
| 69 | xmlChar* key = xmlGetProp(entityNode, (xmlChar*) "id"); | ||
| 70 | if (key == 0) throw MapObjectLoadException("input missing id"); | ||
| 71 | std::string inputID = (char*) key; | ||
| 72 | xmlFree(key); | ||
| 73 | |||
| 74 | Input& input = mapObject.inputs[inputID]; | ||
| 75 | |||
| 76 | key = xmlGetProp(entityNode, (xmlChar*) "name"); | ||
| 77 | if (key == 0) throw MapObjectLoadException("input missing name"); | ||
| 78 | input.name = (char*) key; | ||
| 79 | xmlFree(key); | ||
| 80 | |||
| 81 | key = xmlGetProp(entityNode, (xmlChar*) "type"); | ||
| 82 | if (key == 0) throw MapObjectLoadException("input missing type"); | ||
| 83 | std::string inputType = (char*) key; | ||
| 84 | xmlFree(key); | ||
| 85 | |||
| 86 | if (inputType == "choice") | ||
| 87 | { | ||
| 88 | input.type = Input::Type::Choice; | ||
| 89 | |||
| 90 | for (xmlNodePtr choiceNode = entityNode->xmlChildrenNode; choiceNode != NULL; choiceNode = choiceNode->next) | ||
| 91 | { | ||
| 92 | if (!xmlStrcmp(choiceNode->name, (xmlChar*) "value")) | ||
| 93 | { | ||
| 94 | key = xmlGetProp(choiceNode, (xmlChar*) "id"); | ||
| 95 | if (key == 0) throw MapObjectLoadException("input value missing id"); | ||
| 96 | int valueId = atoi((char*) key); | ||
| 97 | xmlFree(key); | ||
| 98 | |||
| 99 | key = xmlNodeGetContent(choiceNode); | ||
| 100 | if (key == 0) throw MapObjectLoadException("input value missing content"); | ||
| 101 | std::string choiceText = (char*) key; | ||
| 102 | xmlFree(key); | ||
| 103 | |||
| 104 | input.choices[valueId] = choiceText; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | } else if (inputType == "slider") | ||
| 108 | { | ||
| 109 | input.type = Input::Type::Slider; | ||
| 110 | |||
| 111 | key = xmlGetProp(entityNode, (xmlChar*) "minvalue"); | ||
| 112 | if (key == 0) throw MapObjectLoadException("integer input missing minvalue"); | ||
| 113 | input.minvalue = atoi((char*) key); | ||
| 114 | xmlFree(key); | ||
| 115 | |||
| 116 | key = xmlGetProp(entityNode, (xmlChar*) "maxvalue"); | ||
| 117 | if (key == 0) throw MapObjectLoadException("integer input missing maxvalue"); | ||
| 118 | input.maxvalue = atoi((char*) key); | ||
| 119 | xmlFree(key); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 26 | } | 123 | } |
| 27 | } | 124 | } |
| 125 | } catch (std::exception& ex) | ||
| 126 | { | ||
| 127 | wxMessageBox(ex.what(), "Error loading objects", wxOK | wxCENTRE | wxICON_ERROR); | ||
| 128 | exit(3); | ||
| 28 | } | 129 | } |
| 29 | 130 | ||
| 30 | objsInit = true; | 131 | objsInit = true; |
| @@ -33,67 +134,170 @@ const std::map<std::string, std::shared_ptr<MapObject>> MapObject::getAllObjects | |||
| 33 | return allObjects; | 134 | return allObjects; |
| 34 | } | 135 | } |
| 35 | 136 | ||
| 36 | MapObject::MapObject(const char* filename) | 137 | MapObject::MapObject(std::string id) : id(id) |
| 37 | { | 138 | { |
| 38 | type = filename; | ||
| 39 | 139 | ||
| 40 | xmlDocPtr doc = xmlParseFile(("entities/" + std::string(filename) + ".xml").c_str()); | 140 | } |
| 41 | if (doc == nullptr) throw MapObjectLoadException(filename); | ||
| 42 | 141 | ||
| 43 | xmlNodePtr top = xmlDocGetRootElement(doc); | 142 | std::string MapObject::getID() const |
| 44 | if (top == nullptr) throw MapObjectLoadException(filename); | 143 | { |
| 144 | return id; | ||
| 145 | } | ||
| 45 | 146 | ||
| 46 | if (xmlStrcmp(top->name, (const xmlChar*) "entity-def")) | 147 | std::string MapObject::getName() const |
| 47 | { | 148 | { |
| 48 | throw MapObjectLoadException(filename); | 149 | return name; |
| 49 | } | 150 | } |
| 151 | |||
| 152 | wxBitmap MapObject::getSprite() const | ||
| 153 | { | ||
| 154 | return sprite; | ||
| 155 | } | ||
| 156 | |||
| 157 | int MapObject::getWidth() const | ||
| 158 | { | ||
| 159 | return width; | ||
| 160 | } | ||
| 161 | |||
| 162 | int MapObject::getHeight() const | ||
| 163 | { | ||
| 164 | return height; | ||
| 165 | } | ||
| 166 | |||
| 167 | const std::map<std::string, MapObject::Input>& MapObject::getInputs() const | ||
| 168 | { | ||
| 169 | return inputs; | ||
| 170 | } | ||
| 171 | |||
| 172 | const MapObject::Input& MapObject::getInput(std::string id) const | ||
| 173 | { | ||
| 174 | return inputs.at(id); | ||
| 175 | } | ||
| 176 | |||
| 177 | bool MapObject::operator==(const MapObject& other) const | ||
| 178 | { | ||
| 179 | return id == other.id; | ||
| 180 | } | ||
| 181 | |||
| 182 | bool MapObject::operator!=(const MapObject& other) const | ||
| 183 | { | ||
| 184 | return id != other.id; | ||
| 185 | } | ||
| 186 | |||
| 187 | MapObjectEntry::MapObjectEntry(const MapObject& object, int posx, int posy) : object(object) | ||
| 188 | { | ||
| 189 | position = std::make_pair(posx, posy); | ||
| 190 | } | ||
| 191 | |||
| 192 | const MapObject& MapObjectEntry::getObject() const | ||
| 193 | { | ||
| 194 | return object; | ||
| 195 | } | ||
| 196 | |||
| 197 | std::pair<int, int> MapObjectEntry::getPosition() const | ||
| 198 | { | ||
| 199 | return position; | ||
| 200 | } | ||
| 201 | |||
| 202 | MapObjectEntry::Item& MapObjectEntry::getItem(std::string str) | ||
| 203 | { | ||
| 204 | return items[str]; | ||
| 205 | } | ||
| 206 | |||
| 207 | const std::map<std::string, MapObjectEntry::Item>& MapObjectEntry::getItems() const | ||
| 208 | { | ||
| 209 | return items; | ||
| 210 | } | ||
| 211 | |||
| 212 | void MapObjectEntry::addItem(std::string id, Item& item) | ||
| 213 | { | ||
| 214 | items[id] = item; | ||
| 215 | } | ||
| 216 | |||
| 217 | void MapObjectEntry::setPosition(int x, int y) | ||
| 218 | { | ||
| 219 | position = std::make_pair(x, y); | ||
| 220 | } | ||
| 221 | |||
| 222 | bool MapObjectEntry::operator==(const MapObjectEntry& other) const | ||
| 223 | { | ||
| 224 | return (object == other.object) && (position == other.position); | ||
| 225 | } | ||
| 226 | |||
| 227 | bool MapObjectEntry::operator!=(const MapObjectEntry& other) const | ||
| 228 | { | ||
| 229 | return (object != other.object) && (position != other.position); | ||
| 230 | } | ||
| 231 | |||
| 232 | VariableChoiceValidator::VariableChoiceValidator(World& world, MapObjectEntry::Item& item) : world(world), item(item) | ||
| 233 | { | ||
| 234 | |||
| 235 | } | ||
| 50 | 236 | ||
| 51 | for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) | 237 | wxObject* VariableChoiceValidator::Clone() const |
| 238 | { | ||
| 239 | return new VariableChoiceValidator(world, item); | ||
| 240 | } | ||
| 241 | |||
| 242 | bool VariableChoiceValidator::TransferFromWindow() | ||
| 243 | { | ||
| 244 | wxChoice* choice = (wxChoice*) GetWindow(); | ||
| 245 | int sel = choice->GetSelection(); | ||
| 246 | int val = (intptr_t) choice->GetClientData(sel); | ||
| 247 | item.intvalue = val; | ||
| 248 | world.setDirty(true); | ||
| 249 | |||
| 250 | return true; | ||
| 251 | } | ||
| 252 | |||
| 253 | bool VariableChoiceValidator::TransferToWindow() | ||
| 254 | { | ||
| 255 | wxChoice* choice = (wxChoice*) GetWindow(); | ||
| 256 | for (size_t i=0; i<choice->GetCount(); i++) | ||
| 52 | { | 257 | { |
| 53 | if (!xmlStrcmp(node->name, (const xmlChar*) "sprite")) | 258 | if ((intptr_t) choice->GetClientData(i) == item.intvalue) |
| 54 | { | ||
| 55 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
| 56 | std::string spriteFile = (char*) key; | ||
| 57 | xmlFree(key); | ||
| 58 | |||
| 59 | sprite = wxImage(spriteFile); | ||
| 60 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "action")) | ||
| 61 | { | 259 | { |
| 62 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | 260 | choice->SetSelection(i); |
| 63 | action = (char*) key; | 261 | return true; |
| 64 | xmlFree(key); | ||
| 65 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "size")) | ||
| 66 | { | ||
| 67 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
| 68 | sscanf((char*) key, "%d,%d", &width, &height); | ||
| 69 | xmlFree(key); | ||
| 70 | } | 262 | } |
| 71 | } | 263 | } |
| 264 | |||
| 265 | return false; | ||
| 266 | } | ||
| 72 | 267 | ||
| 73 | xmlFreeDoc(doc); | 268 | bool VariableChoiceValidator::Validate(wxWindow*) |
| 269 | { | ||
| 270 | return true; | ||
| 74 | } | 271 | } |
| 75 | 272 | ||
| 76 | wxBitmap MapObject::getSprite() const | 273 | SliderItemValidator::SliderItemValidator(World& world, MapObjectEntry::Item& item) : world(world), item(item) |
| 77 | { | 274 | { |
| 78 | return sprite; | 275 | |
| 79 | } | 276 | } |
| 80 | 277 | ||
| 81 | std::string MapObject::getAction() const | 278 | wxObject* SliderItemValidator::Clone() const |
| 82 | { | 279 | { |
| 83 | return action; | 280 | return new SliderItemValidator(world, item); |
| 84 | } | 281 | } |
| 85 | 282 | ||
| 86 | int MapObject::getWidth() const | 283 | bool SliderItemValidator::TransferFromWindow() |
| 87 | { | 284 | { |
| 88 | return width; | 285 | wxSlider* slider = (wxSlider*) GetWindow(); |
| 286 | item.intvalue = slider->GetValue(); | ||
| 287 | world.setDirty(true); | ||
| 288 | |||
| 289 | return true; | ||
| 89 | } | 290 | } |
| 90 | 291 | ||
| 91 | int MapObject::getHeight() const | 292 | bool SliderItemValidator::TransferToWindow() |
| 92 | { | 293 | { |
| 93 | return height; | 294 | wxSlider* slider = (wxSlider*) GetWindow(); |
| 295 | slider->SetValue(item.intvalue); | ||
| 296 | |||
| 297 | return true; | ||
| 94 | } | 298 | } |
| 95 | 299 | ||
| 96 | std::string MapObject::getType() const | 300 | bool SliderItemValidator::Validate(wxWindow*) |
| 97 | { | 301 | { |
| 98 | return type; | 302 | return true; |
| 99 | } | 303 | } |
| diff --git a/tools/mapedit/src/object.h b/tools/mapedit/src/object.h index bfb493c..a870a2e 100644 --- a/tools/mapedit/src/object.h +++ b/tools/mapedit/src/object.h | |||
| @@ -10,38 +10,111 @@ | |||
| 10 | #include <string> | 10 | #include <string> |
| 11 | #include <map> | 11 | #include <map> |
| 12 | 12 | ||
| 13 | class World; | ||
| 14 | |||
| 13 | class MapObjectLoadException: public std::exception | 15 | class MapObjectLoadException: public std::exception |
| 14 | { | 16 | { |
| 15 | public: | 17 | public: |
| 16 | MapObjectLoadException(std::string mapname) : mapname(mapname) {} | 18 | MapObjectLoadException(std::string stuff) : stuff(stuff) {} |
| 17 | 19 | ||
| 18 | virtual const char* what() const throw() | 20 | virtual const char* what() const throw() |
| 19 | { | 21 | { |
| 20 | return ("An error occured loading map object " + mapname).c_str(); | 22 | return ("An error occured loading map objects: " + stuff).c_str(); |
| 21 | } | 23 | } |
| 22 | 24 | ||
| 23 | private: | 25 | private: |
| 24 | std::string mapname; | 26 | std::string stuff; |
| 25 | }; | 27 | }; |
| 26 | 28 | ||
| 27 | class MapObject { | 29 | class MapObject { |
| 28 | public: | 30 | public: |
| 29 | MapObject(const char* filename); | 31 | MapObject(std::string id); |
| 32 | |||
| 33 | static const std::map<std::string, MapObject>& getAllObjects(); | ||
| 30 | 34 | ||
| 31 | static const std::map<std::string, std::shared_ptr<MapObject>> getAllObjects(); | 35 | struct Input { |
| 36 | enum class Type { | ||
| 37 | Slider, | ||
| 38 | Choice | ||
| 39 | }; | ||
| 40 | |||
| 41 | std::string name; | ||
| 42 | Type type; | ||
| 43 | int minvalue; | ||
| 44 | int maxvalue; | ||
| 45 | std::map<int, std::string> choices; | ||
| 46 | }; | ||
| 32 | 47 | ||
| 33 | std::string getType() const; | 48 | std::string getID() const; |
| 49 | std::string getName() const; | ||
| 34 | wxBitmap getSprite() const; | 50 | wxBitmap getSprite() const; |
| 35 | std::string getAction() const; | ||
| 36 | int getWidth() const; | 51 | int getWidth() const; |
| 37 | int getHeight() const; | 52 | int getHeight() const; |
| 53 | const std::map<std::string, Input>& getInputs() const; | ||
| 54 | const Input& getInput(std::string id) const; | ||
| 55 | |||
| 56 | bool operator==(const MapObject& other) const; | ||
| 57 | bool operator!=(const MapObject& other) const; | ||
| 38 | 58 | ||
| 39 | private: | 59 | private: |
| 40 | std::string type; | 60 | const std::string id; |
| 61 | std::string name; | ||
| 41 | wxBitmap sprite; | 62 | wxBitmap sprite; |
| 42 | std::string action; | ||
| 43 | int width; | 63 | int width; |
| 44 | int height; | 64 | int height; |
| 65 | std::map<std::string, Input> inputs; | ||
| 66 | }; | ||
| 67 | |||
| 68 | class MapObjectEntry { | ||
| 69 | public: | ||
| 70 | MapObjectEntry(const MapObject& object, int posx, int posy); | ||
| 71 | |||
| 72 | struct Item { | ||
| 73 | MapObject::Input::Type type; | ||
| 74 | int intvalue; | ||
| 75 | }; | ||
| 76 | |||
| 77 | const MapObject& getObject() const; | ||
| 78 | std::pair<int, int> getPosition() const; | ||
| 79 | Item& getItem(std::string str); | ||
| 80 | const std::map<std::string, Item>& getItems() const; | ||
| 81 | |||
| 82 | void setPosition(int x, int y); | ||
| 83 | void addItem(std::string id, Item& item); | ||
| 84 | |||
| 85 | bool operator==(const MapObjectEntry& other) const; | ||
| 86 | bool operator!=(const MapObjectEntry& other) const; | ||
| 87 | |||
| 88 | private: | ||
| 89 | const MapObject& object; | ||
| 90 | std::pair<int, int> position; | ||
| 91 | std::map<std::string, Item> items; | ||
| 92 | }; | ||
| 93 | |||
| 94 | class VariableChoiceValidator : public wxValidator { | ||
| 95 | public: | ||
| 96 | VariableChoiceValidator(World& world, MapObjectEntry::Item& item); | ||
| 97 | wxObject* Clone() const; | ||
| 98 | bool TransferFromWindow(); | ||
| 99 | bool TransferToWindow(); | ||
| 100 | bool Validate(wxWindow* parent); | ||
| 101 | |||
| 102 | private: | ||
| 103 | World& world; | ||
| 104 | MapObjectEntry::Item& item; | ||
| 105 | }; | ||
| 106 | |||
| 107 | class SliderItemValidator : public wxValidator { | ||
| 108 | public: | ||
| 109 | SliderItemValidator(World& world, MapObjectEntry::Item& item); | ||
| 110 | wxObject* Clone() const; | ||
| 111 | bool TransferFromWindow(); | ||
| 112 | bool TransferToWindow(); | ||
| 113 | bool Validate(wxWindow* parent); | ||
| 114 | |||
| 115 | private: | ||
| 116 | World& world; | ||
| 117 | MapObjectEntry::Item& item; | ||
| 45 | }; | 118 | }; |
| 46 | 119 | ||
| 47 | #endif | 120 | #endif |
| diff --git a/tools/mapedit/src/undo.cpp b/tools/mapedit/src/undo.cpp index bcf7b92..12cafc9 100644 --- a/tools/mapedit/src/undo.cpp +++ b/tools/mapedit/src/undo.cpp | |||
| @@ -28,7 +28,7 @@ wxBEGIN_EVENT_TABLE(UndoableTextBox, wxTextCtrl) | |||
| 28 | EVT_KILL_FOCUS(UndoableTextBox::OnKillFocus) | 28 | EVT_KILL_FOCUS(UndoableTextBox::OnKillFocus) |
| 29 | wxEND_EVENT_TABLE() | 29 | wxEND_EVENT_TABLE() |
| 30 | 30 | ||
| 31 | UndoableTextBox::UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, wxPoint pos, wxSize size, long style) : wxTextCtrl(parent, id, startText, pos, size, style) | 31 | UndoableTextBox::UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, const wxPoint& pos, const wxSize& size, long style) : wxTextCtrl(parent, id, startText, pos, size, style) |
| 32 | { | 32 | { |
| 33 | this->undoText = undoType; | 33 | this->undoText = undoType; |
| 34 | this->realParent = realParent; | 34 | this->realParent = realParent; |
| @@ -93,3 +93,75 @@ void UndoableTextBox::Undo::endChanges() | |||
| 93 | { | 93 | { |
| 94 | parent.undo.reset(); | 94 | parent.undo.reset(); |
| 95 | } | 95 | } |
| 96 | |||
| 97 | UndoableChoice::UndoableChoice() | ||
| 98 | { | ||
| 99 | Init(); | ||
| 100 | } | ||
| 101 | |||
| 102 | UndoableChoice::UndoableChoice(wxWindow* parent, wxWindowID id, MapeditFrame* realParent, const wxPoint& pos, const wxSize& size, int n, const wxString choices[], long style, const wxValidator& validator, const wxString& name) : wxChoice(parent, id, pos, size, n, choices, style, validator, name) | ||
| 103 | { | ||
| 104 | this->realParent = realParent; | ||
| 105 | |||
| 106 | Init(); | ||
| 107 | } | ||
| 108 | |||
| 109 | void UndoableChoice::Init() | ||
| 110 | { | ||
| 111 | Bind(wxEVT_CHOICE, &UndoableChoice::OnChoose, this); | ||
| 112 | } | ||
| 113 | |||
| 114 | void UndoableChoice::OnChoose(wxCommandEvent& event) | ||
| 115 | { | ||
| 116 | int new_selection = GetSelection(); | ||
| 117 | GetValidator()->TransferToWindow(); | ||
| 118 | int old_selection = GetSelection(); | ||
| 119 | |||
| 120 | realParent->commitAction(std::make_shared<Undoable>(("Set " + GetName()).ToStdString(), [=] () { | ||
| 121 | SetSelection(new_selection); | ||
| 122 | GetValidator()->TransferFromWindow(); | ||
| 123 | }, [=] () { | ||
| 124 | SetSelection(old_selection); | ||
| 125 | GetValidator()->TransferFromWindow(); | ||
| 126 | })); | ||
| 127 | |||
| 128 | event.Skip(); | ||
| 129 | } | ||
| 130 | |||
| 131 | wxBEGIN_EVENT_TABLE(UndoableSlider, wxSlider) | ||
| 132 | EVT_SCROLL(UndoableSlider::OnSlide) | ||
| 133 | wxEND_EVENT_TABLE() | ||
| 134 | |||
| 135 | UndoableSlider::UndoableSlider() | ||
| 136 | { | ||
| 137 | Init(); | ||
| 138 | } | ||
| 139 | |||
| 140 | UndoableSlider::UndoableSlider(wxWindow* parent, wxWindowID id, MapeditFrame* realParent, int value, int minvalue, int maxvalue, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, const wxString& name) : wxSlider(parent, id, value, minvalue, maxvalue, pos, size, style, validator, name) | ||
| 141 | { | ||
| 142 | this->realParent = realParent; | ||
| 143 | |||
| 144 | Init(); | ||
| 145 | } | ||
| 146 | |||
| 147 | void UndoableSlider::Init() | ||
| 148 | { | ||
| 149 | |||
| 150 | } | ||
| 151 | |||
| 152 | void UndoableSlider::OnSlide(wxScrollEvent& event) | ||
| 153 | { | ||
| 154 | int new_value = GetValue(); | ||
| 155 | GetValidator()->TransferToWindow(); | ||
| 156 | int old_value = GetValue(); | ||
| 157 | |||
| 158 | realParent->commitAction(std::make_shared<Undoable>(("Set " + GetName()).ToStdString(), [=] () { | ||
| 159 | SetValue(new_value); | ||
| 160 | GetValidator()->TransferFromWindow(); | ||
| 161 | }, [=] () { | ||
| 162 | SetValue(old_value); | ||
| 163 | GetValidator()->TransferFromWindow(); | ||
| 164 | })); | ||
| 165 | |||
| 166 | event.Skip(); | ||
| 167 | } | ||
| diff --git a/tools/mapedit/src/undo.h b/tools/mapedit/src/undo.h index 794f993..621f42c 100644 --- a/tools/mapedit/src/undo.h +++ b/tools/mapedit/src/undo.h | |||
| @@ -32,7 +32,7 @@ class Undoable { | |||
| 32 | class UndoableTextBox : public wxTextCtrl { | 32 | class UndoableTextBox : public wxTextCtrl { |
| 33 | public: | 33 | public: |
| 34 | UndoableTextBox(); | 34 | UndoableTextBox(); |
| 35 | UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize, long style = 0); | 35 | UndoableTextBox(wxWindow* parent, wxWindowID id, wxString startText, std::string undoType, MapeditFrame* realParent, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0); |
| 36 | 36 | ||
| 37 | private: | 37 | private: |
| 38 | class Undo : public Undoable { | 38 | class Undo : public Undoable { |
| @@ -60,4 +60,32 @@ class UndoableTextBox : public wxTextCtrl { | |||
| 60 | wxDECLARE_EVENT_TABLE(); | 60 | wxDECLARE_EVENT_TABLE(); |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | class UndoableChoice : public wxChoice { | ||
| 64 | public: | ||
| 65 | UndoableChoice(); | ||
| 66 | UndoableChoice(wxWindow* parent, wxWindowID id, MapeditFrame* realParent, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, int n = 0, const wxString choices[] = NULL, long style = 0, const wxValidator& validator = wxDefaultValidator, const wxString& name = wxChoiceNameStr); | ||
| 67 | |||
| 68 | protected: | ||
| 69 | void Init(); | ||
| 70 | void OnChoose(wxCommandEvent& event); | ||
| 71 | |||
| 72 | private: | ||
| 73 | MapeditFrame* realParent; | ||
| 74 | }; | ||
| 75 | |||
| 76 | class UndoableSlider : public wxSlider { | ||
| 77 | public: | ||
| 78 | UndoableSlider(); | ||
| 79 | UndoableSlider(wxWindow* parent, wxWindowID id, MapeditFrame* realParent, int value, int minvalue, int maxvalue, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxSL_HORIZONTAL, const wxValidator& validator = wxDefaultValidator, const wxString& name = wxSliderNameStr); | ||
| 80 | |||
| 81 | protected: | ||
| 82 | void Init(); | ||
| 83 | void OnSlide(wxScrollEvent& event); | ||
| 84 | |||
| 85 | private: | ||
| 86 | MapeditFrame* realParent; | ||
| 87 | |||
| 88 | wxDECLARE_EVENT_TABLE(); | ||
| 89 | }; | ||
| 90 | |||
| 63 | #endif | 91 | #endif |
| diff --git a/tools/mapedit/src/widget.cpp b/tools/mapedit/src/widget.cpp index fa0af39..8d74b39 100644 --- a/tools/mapedit/src/widget.cpp +++ b/tools/mapedit/src/widget.cpp | |||
| @@ -16,6 +16,8 @@ BEGIN_EVENT_TABLE(MapeditWidget, wxScrolledCanvas) | |||
| 16 | EVT_LEAVE_WINDOW(MapeditWidget::OnMouseOut) | 16 | EVT_LEAVE_WINDOW(MapeditWidget::OnMouseOut) |
| 17 | EVT_SCROLLWIN(MapeditWidget::OnScroll) | 17 | EVT_SCROLLWIN(MapeditWidget::OnScroll) |
| 18 | END_EVENT_TABLE() | 18 | END_EVENT_TABLE() |
| 19 | |||
| 20 | wxDEFINE_EVENT(EVT_MAP_SELECTED_ENTITY, wxCommandEvent); | ||
| 19 | 21 | ||
| 20 | MapeditWidget::MapeditWidget() | 22 | MapeditWidget::MapeditWidget() |
| 21 | { | 23 | { |
| @@ -107,12 +109,12 @@ void MapeditWidget::OnPaint(wxPaintEvent&) | |||
| 107 | { | 109 | { |
| 108 | tiles_dc.SelectObject(wxNullBitmap); | 110 | tiles_dc.SelectObject(wxNullBitmap); |
| 109 | 111 | ||
| 110 | wxBitmap sprite = object->object->getSprite(); | 112 | wxBitmap sprite = object->getObject().getSprite(); |
| 111 | tiles_dc.SelectObject(sprite); | 113 | tiles_dc.SelectObject(sprite); |
| 112 | 114 | ||
| 113 | wxPoint pos {(object->position.first + EDITOR_SPACING_X)*scale-vX, (object->position.second + EDITOR_SPACING_Y)*scale-vY}; | 115 | wxPoint pos {(object->getPosition().first + EDITOR_SPACING_X)*scale-vX, (object->getPosition().second + EDITOR_SPACING_Y)*scale-vY}; |
| 114 | wxSize size {object->object->getWidth()*scale, object->object->getHeight()*scale}; | 116 | wxSize size {object->getObject().getWidth()*scale, object->getObject().getHeight()*scale}; |
| 115 | dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, object->object->getWidth(), object->object->getHeight()); | 117 | dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, object->getObject().getWidth(), object->getObject().getHeight()); |
| 116 | 118 | ||
| 117 | if (editMode == EditEntities) | 119 | if (editMode == EditEntities) |
| 118 | { | 120 | { |
| @@ -197,14 +199,14 @@ void MapeditWidget::OnPaint(wxPaintEvent&) | |||
| 197 | dc.DrawRectangle(pos.x, pos.y, size.GetWidth(), size.GetHeight()); | 199 | dc.DrawRectangle(pos.x, pos.y, size.GetWidth(), size.GetHeight()); |
| 198 | } else if ((editMode == EditEntities) && (movingEntity != nullptr)) | 200 | } else if ((editMode == EditEntities) && (movingEntity != nullptr)) |
| 199 | { | 201 | { |
| 200 | wxBitmap sprite = movingEntity->object->getSprite(); | 202 | wxBitmap sprite = movingEntity->getObject().getSprite(); |
| 201 | tiles_dc.SelectObject(wxNullBitmap); | 203 | tiles_dc.SelectObject(wxNullBitmap); |
| 202 | tiles_dc.SelectObject(sprite); | 204 | tiles_dc.SelectObject(sprite); |
| 203 | 205 | ||
| 204 | wxPoint pos {mousePos.x - movingEntity->object->getWidth()/2*scale, mousePos.y - movingEntity->object->getHeight()/2*scale}; | 206 | wxPoint pos {mousePos.x - movingEntity->getObject().getWidth()/2*scale, mousePos.y - movingEntity->getObject().getHeight()/2*scale}; |
| 205 | wxSize size {movingEntity->object->getWidth()*scale, movingEntity->object->getHeight()*scale}; | 207 | wxSize size {movingEntity->getObject().getWidth()*scale, movingEntity->getObject().getHeight()*scale}; |
| 206 | 208 | ||
| 207 | dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, movingEntity->object->getWidth(), movingEntity->object->getHeight()); | 209 | dc.StretchBlit(pos.x, pos.y, size.GetWidth(), size.GetHeight(), &tiles_dc, 0, 0, movingEntity->getObject().getWidth(), movingEntity->getObject().getHeight()); |
| 208 | 210 | ||
| 209 | wxPen pen(*wxGREEN, 2); | 211 | wxPen pen(*wxGREEN, 2); |
| 210 | dc.SetPen(pen); | 212 | dc.SetPen(pen); |
| @@ -254,17 +256,23 @@ void MapeditWidget::OnClick(wxMouseEvent& event) | |||
| 254 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale - (addingEntity->getWidth() / 2); | 256 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale - (addingEntity->getWidth() / 2); |
| 255 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale - (addingEntity->getHeight() / 2); | 257 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale - (addingEntity->getHeight() / 2); |
| 256 | 258 | ||
| 257 | auto data = std::make_shared<MapObjectEntry>(); | 259 | auto data = std::make_shared<MapObjectEntry>(*addingEntity, x, y); |
| 258 | data->object = addingEntity; | 260 | frame->commitAction(std::make_shared<Undoable>("Add " + addingEntity->getName(), [=] () { |
| 259 | data->position = std::make_pair(x,y); | ||
| 260 | |||
| 261 | frame->commitAction(std::make_shared<Undoable>("Add " + addingEntity->getType(), [=] () { | ||
| 262 | map->addObject(data); | 261 | map->addObject(data); |
| 263 | 262 | ||
| 264 | Refresh(); | 263 | Refresh(); |
| 265 | }, [=] () { | 264 | }, [=] () { |
| 266 | map->removeObject(data); | 265 | map->removeObject(data); |
| 267 | 266 | ||
| 267 | if (data == selectedEntity) | ||
| 268 | { | ||
| 269 | selectedEntity.reset(); | ||
| 270 | |||
| 271 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
| 272 | sev.SetClientData(0); | ||
| 273 | ProcessEvent(sev); | ||
| 274 | } | ||
| 275 | |||
| 268 | Refresh(); | 276 | Refresh(); |
| 269 | })); | 277 | })); |
| 270 | 278 | ||
| @@ -272,17 +280,17 @@ void MapeditWidget::OnClick(wxMouseEvent& event) | |||
| 272 | addingEntity = nullptr; | 280 | addingEntity = nullptr; |
| 273 | } else if (movingEntity != nullptr) | 281 | } else if (movingEntity != nullptr) |
| 274 | { | 282 | { |
| 275 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale - (movingEntity->object->getWidth() / 2); | 283 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale - (movingEntity->getObject().getWidth() / 2); |
| 276 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale - (movingEntity->object->getHeight() / 2); | 284 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale - (movingEntity->getObject().getHeight() / 2); |
| 277 | auto oldPos = movingEntity->position; | 285 | auto oldPos = movingEntity->getPosition(); |
| 278 | MapObjectEntry* me = movingEntity; | 286 | MapObjectEntry* me = movingEntity; |
| 279 | 287 | ||
| 280 | frame->commitAction(std::make_shared<Undoable>("Move " + movingEntity->object->getType(), [=] () { | 288 | frame->commitAction(std::make_shared<Undoable>("Move " + movingEntity->getObject().getName(), [=] () { |
| 281 | me->position = std::make_pair(x,y); | 289 | me->setPosition(x, y); |
| 282 | 290 | ||
| 283 | Refresh(); | 291 | Refresh(); |
| 284 | }, [=] () { | 292 | }, [=] () { |
| 285 | me->position = oldPos; | 293 | me->setPosition(oldPos.first, oldPos.second); |
| 286 | 294 | ||
| 287 | Refresh(); | 295 | Refresh(); |
| 288 | })); | 296 | })); |
| @@ -295,24 +303,34 @@ void MapeditWidget::OnClick(wxMouseEvent& event) | |||
| 295 | 303 | ||
| 296 | if (selectedEntity) | 304 | if (selectedEntity) |
| 297 | { | 305 | { |
| 298 | if ((x > selectedEntity->position.first) && (x < selectedEntity->position.first + selectedEntity->object->getWidth()) | 306 | if ((x > selectedEntity->getPosition().first) |
| 299 | && (y > selectedEntity->position.second) && (y < selectedEntity->position.second + selectedEntity->object->getHeight())) | 307 | && (x < selectedEntity->getPosition().first + selectedEntity->getObject().getWidth()) |
| 308 | && (y > selectedEntity->getPosition().second) | ||
| 309 | && (y < selectedEntity->getPosition().second + selectedEntity->getObject().getHeight())) | ||
| 300 | { | 310 | { |
| 301 | movingEntity = selectedEntity.get(); | 311 | movingEntity = selectedEntity.get(); |
| 302 | frame->SetIsAddingEntity(true); | 312 | frame->SetIsAddingEntity(true); |
| 303 | } else { | 313 | } else { |
| 304 | selectedEntity.reset(); | 314 | selectedEntity.reset(); |
| 315 | |||
| 316 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
| 317 | sev.SetClientData(0); | ||
| 318 | ProcessEvent(sev); | ||
| 305 | } | 319 | } |
| 306 | 320 | ||
| 307 | Refresh(); | 321 | Refresh(); |
| 308 | } else { | 322 | } else { |
| 309 | for (auto object : map->getObjects()) | 323 | for (auto object : map->getObjects()) |
| 310 | { | 324 | { |
| 311 | if ((x >= object->position.first) && (x <= object->position.first + object->object->getWidth()) | 325 | if ((x >= object->getPosition().first) && (x <= object->getPosition().first + object->getObject().getWidth()) |
| 312 | && (y >= object->position.second) && (y <= object->position.second + object->object->getHeight())) | 326 | && (y >= object->getPosition().second) && (y <= object->getPosition().second + object->getObject().getHeight())) |
| 313 | { | 327 | { |
| 314 | selectedEntity = object; | 328 | selectedEntity = object; |
| 315 | 329 | ||
| 330 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
| 331 | sev.SetClientData(object.get()); | ||
| 332 | ProcessEvent(sev); | ||
| 333 | |||
| 316 | Refresh(); | 334 | Refresh(); |
| 317 | 335 | ||
| 318 | break; | 336 | break; |
| @@ -364,12 +382,18 @@ void MapeditWidget::OnRightClick(wxMouseEvent& event) | |||
| 364 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale; | 382 | int x = (event.GetPosition().x + vX - EDITOR_SPACING_X*scale) / scale; |
| 365 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale; | 383 | int y = (event.GetPosition().y + vY - EDITOR_SPACING_Y*scale) / scale; |
| 366 | 384 | ||
| 367 | if ((x > selectedEntity->position.first) && (x < selectedEntity->position.first + selectedEntity->object->getWidth()) | 385 | if ((x > selectedEntity->getPosition().first) |
| 368 | && (y > selectedEntity->position.second) && (y < selectedEntity->position.second + selectedEntity->object->getHeight())) | 386 | && (x < selectedEntity->getPosition().first + selectedEntity->getObject().getWidth()) |
| 387 | && (y > selectedEntity->getPosition().second) | ||
| 388 | && (y < selectedEntity->getPosition().second + selectedEntity->getObject().getHeight())) | ||
| 369 | { | 389 | { |
| 370 | map->removeObject(selectedEntity); | 390 | map->removeObject(selectedEntity); |
| 371 | selectedEntity.reset(); | 391 | selectedEntity.reset(); |
| 372 | 392 | ||
| 393 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
| 394 | sev.SetClientData(0); | ||
| 395 | ProcessEvent(sev); | ||
| 396 | |||
| 373 | Refresh(); | 397 | Refresh(); |
| 374 | } | 398 | } |
| 375 | } | 399 | } |
| @@ -494,6 +518,10 @@ void MapeditWidget::StartAddingEntity(MapObject* object) | |||
| 494 | selectedEntity = nullptr; | 518 | selectedEntity = nullptr; |
| 495 | isSettingPos = false; | 519 | isSettingPos = false; |
| 496 | frame->SetIsSettingStart(false); | 520 | frame->SetIsSettingStart(false); |
| 521 | |||
| 522 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
| 523 | sev.SetClientData(0); | ||
| 524 | ProcessEvent(sev); | ||
| 497 | } | 525 | } |
| 498 | 526 | ||
| 499 | void MapeditWidget::CancelAddingEntity() | 527 | void MapeditWidget::CancelAddingEntity() |
| @@ -511,6 +539,10 @@ void MapeditWidget::SetIsSettingStart(bool isSetting) | |||
| 511 | frame->SetIsAddingEntity(false); | 539 | frame->SetIsAddingEntity(false); |
| 512 | addingEntity = nullptr; | 540 | addingEntity = nullptr; |
| 513 | selectedEntity = nullptr; | 541 | selectedEntity = nullptr; |
| 542 | |||
| 543 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
| 544 | sev.SetClientData(0); | ||
| 545 | ProcessEvent(sev); | ||
| 514 | } else { | 546 | } else { |
| 515 | isSettingPos = false; | 547 | isSettingPos = false; |
| 516 | } | 548 | } |
| @@ -524,6 +556,10 @@ void MapeditWidget::SetMap(Map* map) | |||
| 524 | movingEntity = nullptr; | 556 | movingEntity = nullptr; |
| 525 | isSettingPos = false; | 557 | isSettingPos = false; |
| 526 | 558 | ||
| 559 | wxCommandEvent sev {EVT_MAP_SELECTED_ENTITY}; | ||
| 560 | sev.SetClientData(0); | ||
| 561 | ProcessEvent(sev); | ||
| 562 | |||
| 527 | Refresh(); | 563 | Refresh(); |
| 528 | } | 564 | } |
| 529 | 565 | ||
| diff --git a/tools/mapedit/src/widget.h b/tools/mapedit/src/widget.h index 864e299..937b699 100644 --- a/tools/mapedit/src/widget.h +++ b/tools/mapedit/src/widget.h | |||
| @@ -16,7 +16,7 @@ class MapeditFrame; | |||
| 16 | class TileWidget; | 16 | class TileWidget; |
| 17 | class Map; | 17 | class Map; |
| 18 | class MapObject; | 18 | class MapObject; |
| 19 | struct MapObjectEntry; | 19 | class MapObjectEntry; |
| 20 | 20 | ||
| 21 | #include "consts.h" | 21 | #include "consts.h" |
| 22 | 22 | ||
| @@ -76,5 +76,10 @@ class MapeditWidget : public wxScrolledCanvas { | |||
| 76 | DECLARE_DYNAMIC_CLASS(MapeditWidget) | 76 | DECLARE_DYNAMIC_CLASS(MapeditWidget) |
| 77 | DECLARE_EVENT_TABLE() | 77 | DECLARE_EVENT_TABLE() |
| 78 | }; | 78 | }; |
| 79 | |||
| 80 | // sends when an entity is selected OR deselected. | ||
| 81 | // client data will be a pointer to the MapObjectEntry if selection. | ||
| 82 | // client data will be nullptr if deselection. | ||
| 83 | wxDECLARE_EVENT(EVT_MAP_SELECTED_ENTITY, wxCommandEvent); | ||
| 79 | 84 | ||
| 80 | #endif | 85 | #endif |
| diff --git a/tools/mapedit/src/world.cpp b/tools/mapedit/src/world.cpp index 01225cf..79f5a58 100644 --- a/tools/mapedit/src/world.cpp +++ b/tools/mapedit/src/world.cpp | |||
| @@ -22,18 +22,18 @@ World::World(std::string filename) | |||
| 22 | xmlDocPtr doc = xmlParseFile(filename.c_str()); | 22 | xmlDocPtr doc = xmlParseFile(filename.c_str()); |
| 23 | if (doc == nullptr) | 23 | if (doc == nullptr) |
| 24 | { | 24 | { |
| 25 | throw MapLoadException(filename); | 25 | throw MapLoadException("file not found"); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | xmlNodePtr top = xmlDocGetRootElement(doc); | 28 | xmlNodePtr top = xmlDocGetRootElement(doc); |
| 29 | if (top == nullptr) | 29 | if (top == nullptr) |
| 30 | { | 30 | { |
| 31 | throw MapLoadException(filename); | 31 | throw MapLoadException("no root element"); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | if (xmlStrcmp(top->name, (const xmlChar*) "world")) | 34 | if (xmlStrcmp(top->name, (const xmlChar*) "world")) |
| 35 | { | 35 | { |
| 36 | throw MapLoadException(filename); | 36 | throw MapLoadException("no world element"); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | xmlChar* nextmapKey = xmlGetProp(top, (xmlChar*) "nextmap"); | 39 | xmlChar* nextmapKey = xmlGetProp(top, (xmlChar*) "nextmap"); |
| @@ -51,17 +51,17 @@ World::World(std::string filename) | |||
| 51 | xmlFree(lastmapKey); | 51 | xmlFree(lastmapKey); |
| 52 | 52 | ||
| 53 | xmlChar* startxKey = xmlGetProp(top, (xmlChar*) "startx"); | 53 | xmlChar* startxKey = xmlGetProp(top, (xmlChar*) "startx"); |
| 54 | if (startxKey == 0) throw MapLoadException(filename); | 54 | if (startxKey == 0) throw MapLoadException("world missing startx attribute"); |
| 55 | startingPosition.first = atoi((char*) startxKey); | 55 | startingPosition.first = atoi((char*) startxKey); |
| 56 | xmlFree(startxKey); | 56 | xmlFree(startxKey); |
| 57 | 57 | ||
| 58 | xmlChar* startyKey = xmlGetProp(top, (xmlChar*) "starty"); | 58 | xmlChar* startyKey = xmlGetProp(top, (xmlChar*) "starty"); |
| 59 | if (startyKey == 0) throw MapLoadException(filename); | 59 | if (startyKey == 0) throw MapLoadException("world missing starty attribute"); |
| 60 | startingPosition.second = atoi((char*) startyKey); | 60 | startingPosition.second = atoi((char*) startyKey); |
| 61 | xmlFree(startyKey); | 61 | xmlFree(startyKey); |
| 62 | 62 | ||
| 63 | xmlChar* startmapKey = xmlGetProp(top, (xmlChar*) "startmap"); | 63 | xmlChar* startmapKey = xmlGetProp(top, (xmlChar*) "startmap"); |
| 64 | if (startxKey == 0) throw MapLoadException(filename); | 64 | if (startxKey == 0) throw MapLoadException("world missing startmap attribute"); |
| 65 | startingMap = atoi((char*) startmapKey); | 65 | startingMap = atoi((char*) startmapKey); |
| 66 | xmlFree(startmapKey); | 66 | xmlFree(startmapKey); |
| 67 | 67 | ||
| @@ -69,14 +69,14 @@ World::World(std::string filename) | |||
| 69 | { | 69 | { |
| 70 | if (!xmlStrcmp(node->name, (const xmlChar*) "root")) | 70 | if (!xmlStrcmp(node->name, (const xmlChar*) "root")) |
| 71 | { | 71 | { |
| 72 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | 72 | xmlChar* key = xmlNodeGetContent(node); |
| 73 | if (key == 0) throw MapLoadException(filename); | 73 | if (key == 0) throw MapLoadException("root missing content"); |
| 74 | rootChildren.push_back(atoi((char*) key)); | 74 | rootChildren.push_back(atoi((char*) key)); |
| 75 | xmlFree(key); | 75 | xmlFree(key); |
| 76 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "map")) | 76 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "map")) |
| 77 | { | 77 | { |
| 78 | xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id"); | 78 | xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id"); |
| 79 | if (idKey == 0) throw MapLoadException(filename); | 79 | if (idKey == 0) throw MapLoadException("map missing id attribute"); |
| 80 | int id = atoi((char*) idKey); | 80 | int id = atoi((char*) idKey); |
| 81 | xmlFree(idKey); | 81 | xmlFree(idKey); |
| 82 | 82 | ||
| @@ -90,7 +90,7 @@ World::World(std::string filename) | |||
| 90 | xmlFree(expandKey); | 90 | xmlFree(expandKey); |
| 91 | 91 | ||
| 92 | xmlChar* titleKey = xmlGetProp(node, (xmlChar*) "title"); | 92 | xmlChar* titleKey = xmlGetProp(node, (xmlChar*) "title"); |
| 93 | if (titleKey == 0) throw MapLoadException(filename); | 93 | if (titleKey == 0) throw MapLoadException("map missing title attribute"); |
| 94 | map->setTitle((char*) titleKey, false); | 94 | map->setTitle((char*) titleKey, false); |
| 95 | xmlFree(titleKey); | 95 | xmlFree(titleKey); |
| 96 | 96 | ||
| @@ -98,7 +98,8 @@ World::World(std::string filename) | |||
| 98 | { | 98 | { |
| 99 | if (!xmlStrcmp(mapNode->name, (const xmlChar*) "environment")) | 99 | if (!xmlStrcmp(mapNode->name, (const xmlChar*) "environment")) |
| 100 | { | 100 | { |
| 101 | xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); | 101 | xmlChar* key = xmlNodeGetContent(mapNode); |
| 102 | if (key == 0) throw MapLoadException("map missing environment content"); | ||
| 102 | int* mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); | 103 | int* mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); |
| 103 | mapdata[0] = atoi(strtok((char*) key, ",\n")); | 104 | mapdata[0] = atoi(strtok((char*) key, ",\n")); |
| 104 | for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++) | 105 | for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++) |
| @@ -109,24 +110,52 @@ World::World(std::string filename) | |||
| 109 | xmlFree(key); | 110 | xmlFree(key); |
| 110 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "entity")) | 111 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "entity")) |
| 111 | { | 112 | { |
| 112 | auto data = std::make_shared<MapObjectEntry>(); | ||
| 113 | |||
| 114 | xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type"); | 113 | xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type"); |
| 115 | if (typeKey == 0) throw MapLoadException(filename); | 114 | if (typeKey == 0) throw MapLoadException("entity missing type attribute"); |
| 116 | data->object = MapObject::getAllObjects().at((char*) typeKey).get(); | 115 | const MapObject& obj = MapObject::getAllObjects().at((char*) typeKey); |
| 117 | xmlFree(typeKey); | 116 | xmlFree(typeKey); |
| 118 | 117 | ||
| 119 | xmlChar* xKey = xmlGetProp(mapNode, (const xmlChar*) "x"); | 118 | xmlChar* xKey = xmlGetProp(mapNode, (const xmlChar*) "x"); |
| 120 | if (xKey == 0) throw MapLoadException(filename); | 119 | if (xKey == 0) throw MapLoadException("entity missing x attribute"); |
| 121 | data->position.first = atoi((char*) xKey); | 120 | int xpos = atoi((char*) xKey); |
| 122 | xmlFree(xKey); | 121 | xmlFree(xKey); |
| 123 | 122 | ||
| 124 | xmlChar* yKey = xmlGetProp(mapNode, (const xmlChar*) "y"); | 123 | xmlChar* yKey = xmlGetProp(mapNode, (const xmlChar*) "y"); |
| 125 | if (yKey == 0) throw MapLoadException(filename); | 124 | if (yKey == 0) throw MapLoadException("entity missing y attribute"); |
| 126 | data->position.second = atoi((char*) yKey); | 125 | int ypos = atoi((char*) yKey); |
| 127 | xmlFree(yKey); | 126 | xmlFree(yKey); |
| 128 | 127 | ||
| 128 | auto data = std::make_shared<MapObjectEntry>(obj, xpos, ypos); | ||
| 129 | |||
| 129 | map->addObject(data, false); | 130 | map->addObject(data, false); |
| 131 | |||
| 132 | for (xmlNodePtr objectNode = mapNode->xmlChildrenNode; objectNode != NULL; objectNode = objectNode->next) | ||
| 133 | { | ||
| 134 | if (!xmlStrcmp(objectNode->name, (const xmlChar*) "item")) | ||
| 135 | { | ||
| 136 | xmlChar* key = xmlGetProp(objectNode, (const xmlChar*) "id"); | ||
| 137 | if (key == 0) throw MapLoadException("item missing id attribute"); | ||
| 138 | std::string itemID = (char*) key; | ||
| 139 | xmlFree(key); | ||
| 140 | |||
| 141 | MapObjectEntry::Item item; | ||
| 142 | item.type = data->getObject().getInput(itemID).type; | ||
| 143 | |||
| 144 | key = xmlNodeGetContent(objectNode); | ||
| 145 | if (key == 0) throw MapLoadException("item missing content"); | ||
| 146 | switch (item.type) | ||
| 147 | { | ||
| 148 | case MapObject::Input::Type::Choice: | ||
| 149 | case MapObject::Input::Type::Slider: | ||
| 150 | { | ||
| 151 | item.intvalue = atoi((char*) key); | ||
| 152 | break; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | data->addItem(itemID, item); | ||
| 157 | } | ||
| 158 | } | ||
| 130 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "adjacent")) | 159 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "adjacent")) |
| 131 | { | 160 | { |
| 132 | Map::MoveDir direction; | 161 | Map::MoveDir direction; |
| @@ -134,12 +163,12 @@ World::World(std::string filename) | |||
| 134 | int mapId = 0; | 163 | int mapId = 0; |
| 135 | 164 | ||
| 136 | xmlChar* dirKey = xmlGetProp(mapNode, (const xmlChar*) "dir"); | 165 | xmlChar* dirKey = xmlGetProp(mapNode, (const xmlChar*) "dir"); |
| 137 | if (dirKey == 0) throw MapLoadException(filename); | 166 | if (dirKey == 0) throw MapLoadException("adjacent missing dir attribute"); |
| 138 | direction = Map::moveDirForShort((char*) dirKey); | 167 | direction = Map::moveDirForShort((char*) dirKey); |
| 139 | xmlFree(dirKey); | 168 | xmlFree(dirKey); |
| 140 | 169 | ||
| 141 | xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type"); | 170 | xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type"); |
| 142 | if (typeKey == 0) throw MapLoadException(filename); | 171 | if (typeKey == 0) throw MapLoadException("adjacent missing type attribute"); |
| 143 | moveType = Map::moveTypeForShort((char*) typeKey); | 172 | moveType = Map::moveTypeForShort((char*) typeKey); |
| 144 | xmlFree(typeKey); | 173 | xmlFree(typeKey); |
| 145 | 174 | ||
| @@ -153,7 +182,7 @@ World::World(std::string filename) | |||
| 153 | map->setAdjacent(direction, moveType, mapId, false); | 182 | map->setAdjacent(direction, moveType, mapId, false); |
| 154 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "child")) | 183 | } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "child")) |
| 155 | { | 184 | { |
| 156 | xmlChar* key = xmlNodeListGetString(doc, mapNode->xmlChildrenNode, 1); | 185 | xmlChar* key = xmlNodeGetContent(mapNode); |
| 157 | if (key != 0) | 186 | if (key != 0) |
| 158 | { | 187 | { |
| 159 | map->addChild(atoi((char*) key)); | 188 | map->addChild(atoi((char*) key)); |
| @@ -281,7 +310,7 @@ void World::save(std::string name, wxTreeCtrl* mapTree) | |||
| 281 | } | 310 | } |
| 282 | 311 | ||
| 283 | // title= | 312 | // title= |
| 284 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "name", (xmlChar*) map.getTitle().c_str()); | 313 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "title", (xmlChar*) map.getTitle().c_str()); |
| 285 | if (rc < 0) throw MapWriteException(name); | 314 | if (rc < 0) throw MapWriteException(name); |
| 286 | 315 | ||
| 287 | // <environment | 316 | // <environment |
| @@ -304,7 +333,7 @@ void World::save(std::string name, wxTreeCtrl* mapTree) | |||
| 304 | mapdata_out << std::endl; | 333 | mapdata_out << std::endl; |
| 305 | } | 334 | } |
| 306 | 335 | ||
| 307 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "environment", (xmlChar*) mapdata_out.str().c_str()); | 336 | rc = xmlTextWriterWriteString(writer, (xmlChar*) mapdata_out.str().c_str()); |
| 308 | if (rc < 0) throw MapWriteException(name); | 337 | if (rc < 0) throw MapWriteException(name); |
| 309 | 338 | ||
| 310 | // </environment> | 339 | // </environment> |
| @@ -318,16 +347,42 @@ void World::save(std::string name, wxTreeCtrl* mapTree) | |||
| 318 | if (rc < 0) throw MapWriteException(name); | 347 | if (rc < 0) throw MapWriteException(name); |
| 319 | 348 | ||
| 320 | // type= | 349 | // type= |
| 321 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "type", (xmlChar*) object->object->getType().c_str()); | 350 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "type", (xmlChar*) object->getObject().getID().c_str()); |
| 322 | if (rc < 0) throw MapWriteException(name); | 351 | if (rc < 0) throw MapWriteException(name); |
| 323 | 352 | ||
| 324 | // x= | 353 | // x= |
| 325 | rc = xmlTextWriterWriteFormatAttribute(writer, (xmlChar*) "x", "%d", object->position.first); | 354 | rc = xmlTextWriterWriteFormatAttribute(writer, (xmlChar*) "x", "%d", object->getPosition().first); |
| 326 | if (rc < 0) throw MapWriteException(name); | 355 | if (rc < 0) throw MapWriteException(name); |
| 327 | 356 | ||
| 328 | // y= | 357 | // y= |
| 329 | rc = xmlTextWriterWriteFormatAttribute(writer, (xmlChar*) "y", "%d", object->position.second); | 358 | rc = xmlTextWriterWriteFormatAttribute(writer, (xmlChar*) "y", "%d", object->getPosition().second); |
| 330 | if (rc < 0) throw MapWriteException(name); | 359 | if (rc < 0) throw MapWriteException(name); |
| 360 | |||
| 361 | for (auto item : object->getItems()) | ||
| 362 | { | ||
| 363 | // <item | ||
| 364 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "item"); | ||
| 365 | if (rc < 0) throw MapWriteException(name); | ||
| 366 | |||
| 367 | // id= | ||
| 368 | rc = xmlTextWriterWriteAttribute(writer, (xmlChar*) "id", (xmlChar*) item.first.c_str()); | ||
| 369 | if (rc < 0) throw MapWriteException(name); | ||
| 370 | |||
| 371 | // > | ||
| 372 | switch (item.second.type) | ||
| 373 | { | ||
| 374 | case MapObject::Input::Type::Slider: | ||
| 375 | case MapObject::Input::Type::Choice: | ||
| 376 | { | ||
| 377 | rc = xmlTextWriterWriteFormatString(writer, "%d", item.second.intvalue); | ||
| 378 | break; | ||
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | // </item> | ||
| 383 | rc = xmlTextWriterEndElement(writer); | ||
| 384 | if (rc < 0) throw MapWriteException(name); | ||
| 385 | } | ||
| 331 | 386 | ||
| 332 | // </entity> | 387 | // </entity> |
| 333 | rc = xmlTextWriterEndElement(writer); | 388 | rc = xmlTextWriterEndElement(writer); |
