diff options
Diffstat (limited to 'tools/mapedit/src')
-rw-r--r-- | tools/mapedit/src/frame.cpp | 321 | ||||
-rw-r--r-- | tools/mapedit/src/frame.h | 32 | ||||
-rw-r--r-- | tools/mapedit/src/main.cpp | 2 | ||||
-rw-r--r-- | tools/mapedit/src/map.cpp | 289 | ||||
-rw-r--r-- | tools/mapedit/src/map.h | 45 | ||||
-rw-r--r-- | tools/mapedit/src/widget.cpp | 7 | ||||
-rw-r--r-- | tools/mapedit/src/widget.h | 3 | ||||
-rw-r--r-- | tools/mapedit/src/world.cpp | 369 | ||||
-rw-r--r-- | tools/mapedit/src/world.h | 45 |
9 files changed, 858 insertions, 255 deletions
diff --git a/tools/mapedit/src/frame.cpp b/tools/mapedit/src/frame.cpp index a38b861..9d489b8 100644 --- a/tools/mapedit/src/frame.cpp +++ b/tools/mapedit/src/frame.cpp | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <wx/statline.h> | 5 | #include <wx/statline.h> |
6 | #include "panel.h" | 6 | #include "panel.h" |
7 | #include <list> | 7 | #include <list> |
8 | #include <exception> | ||
8 | 9 | ||
9 | static std::list<wxWindow*> openWindows; | 10 | static std::list<wxWindow*> openWindows; |
10 | 11 | ||
@@ -15,9 +16,18 @@ enum { | |||
15 | MENU_FILE_OPEN, | 16 | MENU_FILE_OPEN, |
16 | MENU_FILE_SAVE, | 17 | MENU_FILE_SAVE, |
17 | MENU_FILE_CLOSE, | 18 | MENU_FILE_CLOSE, |
19 | MENU_MAP_ADD_ROOT, | ||
20 | MENU_MAP_ADD_CHILD, | ||
18 | TOOL_FILE_NEW, | 21 | TOOL_FILE_NEW, |
19 | TOOL_FILE_OPEN, | 22 | TOOL_FILE_OPEN, |
20 | TOOL_FILE_SAVE | 23 | TOOL_FILE_SAVE, |
24 | TOOL_MAP_ADD_ROOT, | ||
25 | TOOL_MAP_ADD_CHILD, | ||
26 | MAP_EDITOR_NOTEBOOK, | ||
27 | MAP_EDITOR_TREE, | ||
28 | MAP_TITLE_TEXTBOX, | ||
29 | ADD_ENTITY_BUTTON, | ||
30 | CANCEL_ENTITY_BUTTON | ||
21 | }; | 31 | }; |
22 | 32 | ||
23 | wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) | 33 | wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) |
@@ -27,22 +37,41 @@ wxBEGIN_EVENT_TABLE(MapeditFrame, wxFrame) | |||
27 | EVT_MENU(MENU_FILE_NEW, MapeditFrame::OnNew) | 37 | EVT_MENU(MENU_FILE_NEW, MapeditFrame::OnNew) |
28 | EVT_MENU(MENU_FILE_OPEN, MapeditFrame::OnOpen) | 38 | EVT_MENU(MENU_FILE_OPEN, MapeditFrame::OnOpen) |
29 | EVT_MENU(MENU_FILE_SAVE, MapeditFrame::OnSave) | 39 | EVT_MENU(MENU_FILE_SAVE, MapeditFrame::OnSave) |
40 | EVT_MENU(MENU_FILE_CLOSE, MapeditFrame::OnClose) | ||
41 | EVT_MENU(MENU_MAP_ADD_ROOT, MapeditFrame::OnAddRoot) | ||
42 | EVT_MENU(MENU_MAP_ADD_CHILD, MapeditFrame::OnAddChild) | ||
30 | EVT_TOOL(TOOL_FILE_NEW, MapeditFrame::OnNew) | 43 | EVT_TOOL(TOOL_FILE_NEW, MapeditFrame::OnNew) |
31 | EVT_TOOL(TOOL_FILE_OPEN, MapeditFrame::OnOpen) | 44 | EVT_TOOL(TOOL_FILE_OPEN, MapeditFrame::OnOpen) |
32 | EVT_TOOL(TOOL_FILE_SAVE, MapeditFrame::OnSave) | 45 | EVT_TOOL(TOOL_FILE_SAVE, MapeditFrame::OnSave) |
33 | EVT_MENU(MENU_FILE_CLOSE, MapeditFrame::OnClose) | 46 | EVT_TOOL(TOOL_MAP_ADD_ROOT, MapeditFrame::OnAddRoot) |
47 | EVT_TOOL(TOOL_MAP_ADD_CHILD, MapeditFrame::OnAddChild) | ||
34 | EVT_CLOSE(MapeditFrame::OnExit) | 48 | EVT_CLOSE(MapeditFrame::OnExit) |
49 | EVT_NOTEBOOK_PAGE_CHANGED(MAP_EDITOR_NOTEBOOK, MapeditFrame::OnTabChange) | ||
50 | EVT_NOTEBOOK_PAGE_CHANGING(MAP_EDITOR_NOTEBOOK, MapeditFrame::OnTabChanging) | ||
51 | EVT_TREE_SEL_CHANGING(MAP_EDITOR_TREE, MapeditFrame::OnWillSelectMap) | ||
52 | EVT_TREE_SEL_CHANGED(MAP_EDITOR_TREE, MapeditFrame::OnDidSelectMap) | ||
53 | EVT_TREE_BEGIN_DRAG(MAP_EDITOR_TREE, MapeditFrame::OnWillDragMap) | ||
54 | EVT_TREE_END_DRAG(MAP_EDITOR_TREE, MapeditFrame::OnDidDragMap) | ||
55 | EVT_TEXT(MAP_TITLE_TEXTBOX, MapeditFrame::OnTitleChange) | ||
56 | EVT_BUTTON(ADD_ENTITY_BUTTON, MapeditFrame::OnAddEntity) | ||
57 | EVT_BUTTON(CANCEL_ENTITY_BUTTON, MapeditFrame::OnCancelAddEntity) | ||
35 | wxEND_EVENT_TABLE() | 58 | wxEND_EVENT_TABLE() |
36 | 59 | ||
37 | MapeditFrame::MapeditFrame(Map map, std::string filename) : wxFrame(NULL, wxID_ANY, "Map Editor", wxDefaultPosition, wxSize(GAME_WIDTH*3, GAME_HEIGHT*2)), map(map), filename(filename) | 60 | MapeditFrame::MapeditFrame(std::unique_ptr<World> world) : wxFrame(NULL, wxID_ANY, "Map Editor", wxDefaultPosition, wxSize(GAME_WIDTH*2+TILE_WIDTH*6*6+10+10+150, GAME_HEIGHT*3)) |
38 | { | 61 | { |
39 | this->map.frame = this; | 62 | this->world = std::move(world); |
63 | this->world->setParent(this); | ||
64 | currentMap = this->world->getLastMap(); | ||
40 | 65 | ||
41 | wxMenu* menuFile = new wxMenu; | 66 | menuFile = new wxMenu; |
42 | menuFile->Append(MENU_FILE_NEW, "New\tCtrl-N"); | 67 | menuFile->Append(MENU_FILE_NEW, "New\tCtrl-N"); |
43 | menuFile->Append(MENU_FILE_OPEN, "Open\tCtrl-O"); | 68 | menuFile->Append(MENU_FILE_OPEN, "Open\tCtrl-O"); |
44 | menuFile->Append(MENU_FILE_SAVE, "Save\tCtrl-S"); | 69 | menuFile->Append(MENU_FILE_SAVE, "Save\tCtrl-S"); |
45 | menuFile->Append(MENU_FILE_CLOSE, "Close\tCtrl-W"); | 70 | menuFile->Append(MENU_FILE_CLOSE, "Close\tCtrl-W"); |
71 | menuFile->AppendSeparator(); | ||
72 | menuFile->Append(MENU_MAP_ADD_ROOT, "New Map\tCtrl-Alt-N"); | ||
73 | menuFile->Append(MENU_MAP_ADD_CHILD, "New Child Map\tCtrl-Alt-Shift-N"); | ||
74 | menuFile->AppendSeparator(); | ||
46 | menuFile->Append(wxID_EXIT); | 75 | menuFile->Append(wxID_EXIT); |
47 | 76 | ||
48 | wxMenu* menuView = new wxMenu; | 77 | wxMenu* menuView = new wxMenu; |
@@ -59,22 +88,27 @@ MapeditFrame::MapeditFrame(Map map, std::string filename) : wxFrame(NULL, wxID_A | |||
59 | // Layout 2: Non-splitter between layout 3 and notebook | 88 | // Layout 2: Non-splitter between layout 3 and notebook |
60 | // Layout 3: Splitter between map editor and properties editor | 89 | // Layout 3: Splitter between map editor and properties editor |
61 | 90 | ||
62 | wxSplitterWindow* layout3 = new wxSplitterWindow(this, wxID_ANY); | 91 | wxSplitterWindow* layout1 = new wxSplitterWindow(this, wxID_ANY); |
92 | mapTree = new wxTreeCtrl(layout1, MAP_EDITOR_TREE, wxDefaultPosition, wxSize(200, 0), wxTR_HIDE_ROOT | wxTR_HAS_BUTTONS); | ||
93 | wxTreeItemId mapTreeRoot = mapTree->AddRoot("root"); | ||
94 | populateMapTree(mapTreeRoot, this->world->getRootMaps()); | ||
95 | |||
96 | wxPanel* layout2 = new wxPanel(layout1, wxID_ANY); | ||
97 | |||
98 | wxSplitterWindow* layout3 = new wxSplitterWindow(layout2, wxID_ANY); | ||
63 | layout3->SetSashGravity(1.0); | 99 | layout3->SetSashGravity(1.0); |
64 | layout3->SetMinimumPaneSize(20); | ||
65 | 100 | ||
66 | notebook = new wxNotebook(this, wxID_ANY); | 101 | notebook = new wxNotebook(layout2, MAP_EDITOR_NOTEBOOK); |
67 | 102 | ||
68 | tileEditor = new TileWidget(notebook, wxID_ANY, 6, 6, wxPoint(0,0), wxSize(TILE_WIDTH*6*6,TILE_HEIGHT*10*6)); | 103 | tileEditor = new TileWidget(notebook, wxID_ANY, 6, 6, wxPoint(0,0), wxSize(TILE_WIDTH*6*6,TILE_HEIGHT*10*6)); |
69 | notebook->AddPage(tileEditor, "Tile Chooser", true); | 104 | notebook->AddPage(tileEditor, "Tile Chooser", false); |
70 | 105 | ||
71 | mapEditor = new MapeditWidget(layout3, wxID_ANY, &this->map, tileEditor, wxPoint(0,0), wxSize(GAME_WIDTH*2, GAME_HEIGHT*2)); | 106 | mapEditor = new MapeditWidget(layout3, wxID_ANY, currentMap, tileEditor, wxPoint(0,0), wxSize(GAME_WIDTH*2, GAME_HEIGHT*2)); |
72 | mapEditor->frame = this; | 107 | mapEditor->frame = this; |
73 | 108 | ||
74 | // Set up property editor | 109 | // Set up property editor |
75 | wxPanel* propertyEditor = new wxPanel(layout3, wxID_ANY); | 110 | wxPanel* propertyEditor = new wxPanel(layout3, wxID_ANY); |
76 | titleBox = new wxTextCtrl(propertyEditor, wxID_ANY, map.getTitle()); | 111 | titleBox = new wxTextCtrl(propertyEditor, MAP_TITLE_TEXTBOX, currentMap->getTitle()); |
77 | titleBox->Bind(wxEVT_TEXT, &MapeditFrame::OnTitleChange, this); | ||
78 | 112 | ||
79 | wxStaticText* titleLabel = new wxStaticText(propertyEditor, wxID_ANY, "Title:"); | 113 | wxStaticText* titleLabel = new wxStaticText(propertyEditor, wxID_ANY, "Title:"); |
80 | 114 | ||
@@ -103,12 +137,9 @@ MapeditFrame::MapeditFrame(Map map, std::string filename) : wxFrame(NULL, wxID_A | |||
103 | entityTypeBox->Append(entry.second->getType(), entry.second.get()); | 137 | entityTypeBox->Append(entry.second->getType(), entry.second.get()); |
104 | } | 138 | } |
105 | 139 | ||
106 | addEntityButton = new wxButton(entityEditor, wxID_ANY, "Add Entity"); | 140 | addEntityButton = new wxButton(entityEditor, ADD_ENTITY_BUTTON, "Add Entity"); |
107 | addEntityButton->Bind(wxEVT_BUTTON, &MapeditFrame::OnAddEntity, this); | 141 | cancelEntityButton = new wxButton(entityEditor, CANCEL_ENTITY_BUTTON, "Cancel"); |
108 | |||
109 | cancelEntityButton = new wxButton(entityEditor, wxID_ANY, "Cancel"); | ||
110 | cancelEntityButton->Disable(); | 142 | cancelEntityButton->Disable(); |
111 | cancelEntityButton->Bind(wxEVT_BUTTON, &MapeditFrame::OnCancelAddEntity, this); | ||
112 | 143 | ||
113 | wxStaticText* entityInfoLabel = new wxStaticText(entityEditor, wxID_ANY, "Click and drag an entity to move it.\nRight click an entity to delete it."); | 144 | wxStaticText* entityInfoLabel = new wxStaticText(entityEditor, wxID_ANY, "Click and drag an entity to move it.\nRight click an entity to delete it."); |
114 | 145 | ||
@@ -129,51 +160,65 @@ MapeditFrame::MapeditFrame(Map map, std::string filename) : wxFrame(NULL, wxID_A | |||
129 | 160 | ||
130 | // Finish setting up the layouts | 161 | // Finish setting up the layouts |
131 | layout3->SplitHorizontally(mapEditor, propertyEditor); | 162 | layout3->SplitHorizontally(mapEditor, propertyEditor); |
163 | layout1->SplitVertically(mapTree, layout2); | ||
132 | 164 | ||
133 | notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &MapeditFrame::OnTabChange, this); | 165 | wxBoxSizer* sizer1 = new wxBoxSizer(wxHORIZONTAL); |
134 | notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGING, &MapeditFrame::OnTabChanging, this); | 166 | sizer1->Add(layout1, 1, wxEXPAND, 0); |
167 | sizer1->Add(mapTree, 0, wxALIGN_TOP | wxALIGN_LEFT, 0); | ||
168 | sizer1->Add(layout2, 1, wxEXPAND, 0); | ||
169 | layout1->SetSizer(sizer1); | ||
170 | sizer1->SetSizeHints(layout1); | ||
135 | 171 | ||
136 | wxBoxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL); | 172 | wxBoxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL); |
137 | sizer2->Add(layout3, 1, wxEXPAND, 0); | 173 | sizer2->Add(layout3, 1, wxEXPAND, 0); |
138 | sizer2->Add(notebook, 0, wxALIGN_TOP | wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxEXPAND, 2); | 174 | sizer2->Add(notebook, 0, wxALIGN_TOP | wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxEXPAND, 2); |
139 | this->SetSizer(sizer2); | 175 | layout2->SetSizer(sizer2); |
140 | sizer2->SetSizeHints(this); | 176 | sizer2->SetSizeHints(layout2); |
141 | 177 | ||
142 | wxBoxSizer* splitterSizer = new wxBoxSizer(wxVERTICAL); | 178 | wxBoxSizer* splitterSizer = new wxBoxSizer(wxVERTICAL); |
143 | splitterSizer->Add(layout3, 1, wxEXPAND, 0); | 179 | splitterSizer->Add(layout3, 1, wxEXPAND, 0); |
144 | splitterSizer->Add(mapEditor, 1, wxEXPAND, 0); | 180 | splitterSizer->Add(mapEditor, 1, wxEXPAND, 0); |
145 | splitterSizer->Add(propertyEditor, 0, wxALIGN_TOP, wxALIGN_LEFT, 0); | 181 | splitterSizer->Add(propertyEditor, 0, wxALIGN_TOP | wxALIGN_LEFT, 0); |
146 | layout3->SetSizer(splitterSizer); | 182 | layout3->SetSizer(splitterSizer); |
147 | splitterSizer->SetSizeHints(layout3); | 183 | splitterSizer->SetSizeHints(layout3); |
148 | 184 | ||
149 | // Toolbar time! | 185 | // Toolbar time! |
150 | toolbar = CreateToolBar(); | 186 | toolbar = CreateToolBar(); |
151 | toolbar->AddTool(TOOL_FILE_NEW, "New", wxBitmap(wxImage("res/page_add.png"))); | 187 | toolbar->AddTool(TOOL_FILE_NEW, "New", wxBitmap(wxImage("res/page.png"))); |
152 | toolbar->AddTool(TOOL_FILE_OPEN, "Open", wxBitmap(wxImage("res/folder_page.png"))); | 188 | toolbar->AddTool(TOOL_FILE_OPEN, "Open", wxBitmap(wxImage("res/folder_page.png"))); |
153 | toolbar->AddTool(TOOL_FILE_SAVE, "Save", wxBitmap(wxImage("res/disk.png"))); | 189 | toolbar->AddTool(TOOL_FILE_SAVE, "Save", wxBitmap(wxImage("res/disk.png"))); |
154 | toolbar->EnableTool(TOOL_FILE_SAVE, this->map.getDirty()); | 190 | toolbar->AddSeparator(); |
191 | toolbar->AddTool(TOOL_MAP_ADD_ROOT, "Add Map", wxBitmap(wxImage("res/page_add.png"))); | ||
192 | toolbar->AddTool(TOOL_MAP_ADD_CHILD, "Add Child Map", wxBitmap(wxImage("res/page_white_add.png"))); | ||
193 | toolbar->EnableTool(TOOL_FILE_SAVE, this->world->getDirty()); | ||
155 | toolbar->Realize(); | 194 | toolbar->Realize(); |
195 | |||
196 | mapTree->SetFocusedItem(currentMap->getTreeItemId()); | ||
197 | SelectMap(currentMap); | ||
198 | |||
199 | Maximize(true); | ||
156 | } | 200 | } |
157 | 201 | ||
158 | void MapeditFrame::OnExit(wxCloseEvent& event) | 202 | void MapeditFrame::OnExit(wxCloseEvent& event) |
159 | { | 203 | { |
160 | if (event.CanVeto() && map.hasUnsavedChanges()) | 204 | if (event.CanVeto() && world->getDirty()) |
161 | { | 205 | { |
162 | switch (wxMessageBox("Current map has unsaved changes. Save before closing?", "Please confirm", wxICON_QUESTION|wxYES_NO|wxCANCEL, this)) | 206 | switch (wxMessageBox("One or more maps have unsaved changes. Save before closing?", "Please confirm", wxICON_QUESTION|wxYES_NO|wxCANCEL, this)) |
163 | { | 207 | { |
164 | case wxYES: | 208 | case wxYES: |
165 | if (filename == "") | 209 | if (world->getFilename() == "") |
166 | { | 210 | { |
167 | wxFileDialog saveFileDialog(this, "Save map", "", "", "XML files (*.xml)|*.xml", wxFD_SAVE); | 211 | wxFileDialog saveFileDialog(this, "Save world", "", "", "XML files (*.xml)|*.xml", wxFD_SAVE); |
168 | if (saveFileDialog.ShowModal() == wxID_CANCEL) | 212 | if (saveFileDialog.ShowModal() == wxID_CANCEL) |
169 | { | 213 | { |
170 | return; | 214 | return; |
171 | } | 215 | } |
172 | 216 | ||
173 | filename = saveFileDialog.GetPath().ToStdString(); | 217 | world->save(saveFileDialog.GetPath().ToStdString(), mapTree); |
218 | } else { | ||
219 | world->save(world->getFilename(), mapTree); | ||
174 | } | 220 | } |
175 | 221 | ||
176 | map.save(filename); | ||
177 | break; | 222 | break; |
178 | 223 | ||
179 | case wxCANCEL: | 224 | case wxCANCEL: |
@@ -204,34 +249,34 @@ void MapeditFrame::ZoomOut(wxCommandEvent&) | |||
204 | 249 | ||
205 | void MapeditFrame::OnNew(wxCommandEvent&) | 250 | void MapeditFrame::OnNew(wxCommandEvent&) |
206 | { | 251 | { |
207 | NewMap(); | 252 | NewWorld(); |
208 | } | 253 | } |
209 | 254 | ||
210 | void MapeditFrame::OnOpen(wxCommandEvent&) | 255 | void MapeditFrame::OnOpen(wxCommandEvent&) |
211 | { | 256 | { |
212 | wxFileDialog openFileDialog(this, "Open map", "", "", "XML files (*.xml)|*.xml", wxFD_OPEN|wxFD_FILE_MUST_EXIST); | 257 | wxFileDialog openFileDialog(this, "Open world", "", "", "XML files (*.xml)|*.xml", wxFD_OPEN|wxFD_FILE_MUST_EXIST); |
213 | if (openFileDialog.ShowModal() == wxID_CANCEL) | 258 | if (openFileDialog.ShowModal() == wxID_CANCEL) |
214 | { | 259 | { |
215 | return; | 260 | return; |
216 | } | 261 | } |
217 | 262 | ||
218 | OpenMap(openFileDialog.GetPath().c_str()); | 263 | OpenWorld(openFileDialog.GetPath().ToStdString()); |
219 | } | 264 | } |
220 | 265 | ||
221 | void MapeditFrame::OnSave(wxCommandEvent&) | 266 | void MapeditFrame::OnSave(wxCommandEvent&) |
222 | { | 267 | { |
223 | if (filename == "") | 268 | if (world->getFilename() == "") |
224 | { | 269 | { |
225 | wxFileDialog saveFileDialog(this, "Save map", "", "", "XML files (*.xml)|*.xml", wxFD_SAVE); | 270 | wxFileDialog saveFileDialog(this, "Save world", "", "", "XML files (*.xml)|*.xml", wxFD_SAVE); |
226 | if (saveFileDialog.ShowModal() == wxID_CANCEL) | 271 | if (saveFileDialog.ShowModal() == wxID_CANCEL) |
227 | { | 272 | { |
228 | return; | 273 | return; |
229 | } | 274 | } |
230 | 275 | ||
231 | filename = saveFileDialog.GetPath().ToStdString(); | 276 | world->save(saveFileDialog.GetPath().ToStdString(), mapTree); |
277 | } else { | ||
278 | world->save(world->getFilename(), mapTree); | ||
232 | } | 279 | } |
233 | |||
234 | map.save(filename); | ||
235 | } | 280 | } |
236 | 281 | ||
237 | void MapeditFrame::OnClose(wxCommandEvent&) | 282 | void MapeditFrame::OnClose(wxCommandEvent&) |
@@ -252,24 +297,8 @@ void MapeditFrame::OnQuit(wxCommandEvent&) | |||
252 | 297 | ||
253 | void MapeditFrame::OnTitleChange(wxCommandEvent&) | 298 | void MapeditFrame::OnTitleChange(wxCommandEvent&) |
254 | { | 299 | { |
255 | map.setTitle(titleBox->GetLineText(0).ToStdString()); | 300 | currentMap->setTitle(titleBox->GetValue().ToStdString()); |
256 | } | 301 | mapTree->SetItemText(currentMap->getTreeItemId(), currentMap->getTitle()); |
257 | |||
258 | void MapeditFrame::NewMap() | ||
259 | { | ||
260 | LaunchWindow(Map(), ""); | ||
261 | } | ||
262 | |||
263 | void MapeditFrame::OpenMap(const char* filename) | ||
264 | { | ||
265 | LaunchWindow(Map(filename), filename); | ||
266 | } | ||
267 | |||
268 | void MapeditFrame::LaunchWindow(Map map, const char* filename) | ||
269 | { | ||
270 | MapeditFrame* frame = new MapeditFrame(map, filename); | ||
271 | frame->closer = openWindows.insert(end(openWindows), frame); | ||
272 | frame->Show(true); | ||
273 | } | 302 | } |
274 | 303 | ||
275 | void MapeditFrame::OnTabChange(wxBookCtrlEvent& event) | 304 | void MapeditFrame::OnTabChange(wxBookCtrlEvent& event) |
@@ -317,11 +346,113 @@ void MapeditFrame::OnCancelAddEntity(wxCommandEvent&) | |||
317 | mapEditor->CancelAddingEntity(); | 346 | mapEditor->CancelAddingEntity(); |
318 | } | 347 | } |
319 | 348 | ||
349 | void MapeditFrame::OnAddRoot(wxCommandEvent&) | ||
350 | { | ||
351 | auto map = world->newMap(); | ||
352 | wxTreeItemId node = mapTree->AppendItem(mapTree->GetItemParent(mapTree->GetSelection()), map->getTitle()); | ||
353 | map->setTreeItemId(node); | ||
354 | mapTree->SetItemData(node, new MapPtrCtr(map.get())); | ||
355 | mapTree->SetFocusedItem(node); | ||
356 | SelectMap(map.get()); | ||
357 | } | ||
358 | |||
359 | void MapeditFrame::OnAddChild(wxCommandEvent&) | ||
360 | { | ||
361 | auto map = world->newMap(); | ||
362 | wxTreeItemId node = mapTree->AppendItem(mapTree->GetSelection(), map->getTitle()); | ||
363 | map->setTreeItemId(node); | ||
364 | mapTree->SetItemData(node, new MapPtrCtr(map.get())); | ||
365 | mapTree->SetFocusedItem(node); | ||
366 | mapTree->Expand(mapTree->GetSelection()); | ||
367 | SelectMap(map.get()); | ||
368 | } | ||
369 | |||
370 | void MapeditFrame::OnDidSelectMap(wxTreeEvent& event) | ||
371 | { | ||
372 | MapPtrCtr* data = (MapPtrCtr*) mapTree->GetItemData(event.GetItem()); | ||
373 | SelectMap(data->map); | ||
374 | } | ||
375 | |||
376 | void MapeditFrame::OnWillSelectMap(wxTreeEvent& event) | ||
377 | { | ||
378 | if (addingEntity) | ||
379 | { | ||
380 | event.Veto(); | ||
381 | return; | ||
382 | } | ||
383 | |||
384 | event.Skip(); | ||
385 | } | ||
386 | |||
387 | void MapeditFrame::OnWillDragMap(wxTreeEvent& event) | ||
388 | { | ||
389 | if (!addingEntity) | ||
390 | { | ||
391 | event.Allow(); | ||
392 | dragMap = event.GetItem(); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | void MapeditFrame::OnDidDragMap(wxTreeEvent& event) | ||
397 | { | ||
398 | if (!dragMap.IsOk()) | ||
399 | { | ||
400 | return; | ||
401 | } | ||
402 | |||
403 | wxTreeItemId newParent = event.GetItem(); | ||
404 | if (!newParent.IsOk()) | ||
405 | { | ||
406 | newParent = mapTree->GetRootItem(); | ||
407 | } | ||
408 | |||
409 | wxTreeItemId newChild = MoveTreeNode(dragMap, newParent); | ||
410 | dragMap.Unset(); | ||
411 | mapTree->SelectItem(newChild); | ||
412 | } | ||
413 | |||
414 | void MapeditFrame::NewWorld() | ||
415 | { | ||
416 | LaunchWindow(std::unique_ptr<World>(new World())); | ||
417 | } | ||
418 | |||
419 | void MapeditFrame::OpenWorld(std::string filename) | ||
420 | { | ||
421 | try | ||
422 | { | ||
423 | auto world = std::unique_ptr<World>(new World(filename)); | ||
424 | |||
425 | LaunchWindow(std::move(world)); | ||
426 | } catch (std::exception& ex) | ||
427 | { | ||
428 | wxMessageBox(ex.what(), "Error loading world", wxOK | wxCENTRE | wxICON_ERROR); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | void MapeditFrame::LaunchWindow(std::unique_ptr<World> world) | ||
433 | { | ||
434 | MapeditFrame* frame = new MapeditFrame(std::move(world)); | ||
435 | frame->closer = openWindows.insert(end(openWindows), frame); | ||
436 | frame->Show(true); | ||
437 | } | ||
438 | |||
320 | void MapeditFrame::StartAddingEntity() | 439 | void MapeditFrame::StartAddingEntity() |
321 | { | 440 | { |
322 | addingEntity = true; | 441 | addingEntity = true; |
323 | addEntityButton->Disable(); | 442 | addEntityButton->Disable(); |
324 | cancelEntityButton->Enable(); | 443 | cancelEntityButton->Enable(); |
444 | |||
445 | toolbar->EnableTool(TOOL_FILE_NEW, false); | ||
446 | toolbar->EnableTool(TOOL_FILE_OPEN, false); | ||
447 | toolbar->EnableTool(TOOL_FILE_SAVE, false); | ||
448 | toolbar->EnableTool(TOOL_MAP_ADD_ROOT, false); | ||
449 | toolbar->EnableTool(TOOL_MAP_ADD_CHILD, false); | ||
450 | |||
451 | menuFile->Enable(MENU_FILE_NEW, false); | ||
452 | menuFile->Enable(MENU_FILE_OPEN, false); | ||
453 | menuFile->Enable(MENU_FILE_SAVE, false); | ||
454 | menuFile->Enable(MENU_MAP_ADD_ROOT, false); | ||
455 | menuFile->Enable(MENU_MAP_ADD_CHILD, false); | ||
325 | } | 456 | } |
326 | 457 | ||
327 | void MapeditFrame::FinishAddingEntity() | 458 | void MapeditFrame::FinishAddingEntity() |
@@ -329,9 +460,87 @@ void MapeditFrame::FinishAddingEntity() | |||
329 | addingEntity = false; | 460 | addingEntity = false; |
330 | addEntityButton->Enable(); | 461 | addEntityButton->Enable(); |
331 | cancelEntityButton->Disable(); | 462 | cancelEntityButton->Disable(); |
463 | toolbar->Enable(); | ||
464 | |||
465 | toolbar->EnableTool(TOOL_FILE_NEW, true); | ||
466 | toolbar->EnableTool(TOOL_FILE_OPEN, true); | ||
467 | toolbar->EnableTool(TOOL_FILE_SAVE, world->getDirty()); | ||
468 | toolbar->EnableTool(TOOL_MAP_ADD_ROOT, true); | ||
469 | toolbar->EnableTool(TOOL_MAP_ADD_CHILD, true); | ||
470 | |||
471 | menuFile->Enable(MENU_FILE_NEW, true); | ||
472 | menuFile->Enable(MENU_FILE_OPEN, true); | ||
473 | menuFile->Enable(MENU_FILE_SAVE, world->getDirty()); | ||
474 | menuFile->Enable(MENU_MAP_ADD_ROOT, true); | ||
475 | menuFile->Enable(MENU_MAP_ADD_CHILD, true); | ||
332 | } | 476 | } |
333 | 477 | ||
334 | void MapeditFrame::MapDirtyDidChange(bool dirty) | 478 | void MapeditFrame::MapDirtyDidChange(bool dirty) |
335 | { | 479 | { |
336 | toolbar->EnableTool(TOOL_FILE_SAVE, dirty); | 480 | toolbar->EnableTool(TOOL_FILE_SAVE, dirty); |
481 | menuFile->Enable(MENU_FILE_SAVE, dirty); | ||
482 | |||
483 | if (dirty) | ||
484 | { | ||
485 | mapTree->SetItemBold(currentMap->getTreeItemId(), true); | ||
486 | } else { | ||
487 | for (auto map : world->getMaps()) | ||
488 | { | ||
489 | mapTree->SetItemBold(map.second->getTreeItemId(), false); | ||
490 | } | ||
491 | } | ||
492 | } | ||
493 | |||
494 | void MapeditFrame::populateMapTree(wxTreeItemId node, std::list<std::shared_ptr<Map>> maps) | ||
495 | { | ||
496 | for (auto map : maps) | ||
497 | { | ||
498 | wxTreeItemId childNode = mapTree->AppendItem(node, map->getTitle()); | ||
499 | mapTree->SetItemData(childNode, new MapPtrCtr(map.get())); | ||
500 | map->setTreeItemId(childNode); | ||
501 | |||
502 | populateMapTree(childNode, map->getChildren()); | ||
503 | |||
504 | if (map->getExpanded()) | ||
505 | { | ||
506 | mapTree->Expand(childNode); | ||
507 | } | ||
508 | } | ||
509 | } | ||
510 | |||
511 | void MapeditFrame::SelectMap(Map* map) | ||
512 | { | ||
513 | currentMap = map; | ||
514 | mapEditor->SetMap(map); | ||
515 | titleBox->ChangeValue(map->getTitle()); | ||
516 | } | ||
517 | |||
518 | wxTreeItemId MapeditFrame::MoveTreeNode(wxTreeItemId toCopy, wxTreeItemId newParent) | ||
519 | { | ||
520 | MapPtrCtr* ctl1 = (MapPtrCtr*) mapTree->GetItemData(toCopy); | ||
521 | MapPtrCtr* ctl2 = new MapPtrCtr(ctl1->map); | ||
522 | |||
523 | wxTreeItemId copied = mapTree->AppendItem(newParent, mapTree->GetItemText(toCopy), -1, -1, ctl2); | ||
524 | if (mapTree->IsBold(toCopy)) | ||
525 | { | ||
526 | mapTree->SetItemBold(toCopy, true); | ||
527 | } | ||
528 | |||
529 | if (mapTree->ItemHasChildren(toCopy)) | ||
530 | { | ||
531 | wxTreeItemIdValue cookie; | ||
532 | for (wxTreeItemId it = mapTree->GetFirstChild(toCopy, cookie); it.IsOk(); it = mapTree->GetNextChild(toCopy, cookie)) | ||
533 | { | ||
534 | MoveTreeNode(it, copied); | ||
535 | } | ||
536 | } | ||
537 | |||
538 | if (mapTree->IsExpanded(toCopy)) | ||
539 | { | ||
540 | mapTree->Expand(copied); | ||
541 | } | ||
542 | |||
543 | mapTree->Delete(toCopy); | ||
544 | |||
545 | return copied; | ||
337 | } | 546 | } |
diff --git a/tools/mapedit/src/frame.h b/tools/mapedit/src/frame.h index 4aa44c5..f1e4efc 100644 --- a/tools/mapedit/src/frame.h +++ b/tools/mapedit/src/frame.h | |||
@@ -12,24 +12,36 @@ | |||
12 | #include "tile_widget.h" | 12 | #include "tile_widget.h" |
13 | #include <list> | 13 | #include <list> |
14 | #include <wx/notebook.h> | 14 | #include <wx/notebook.h> |
15 | #include <memory> | ||
16 | #include <wx/treectrl.h> | ||
17 | |||
18 | class MapPtrCtr : public wxTreeItemData { | ||
19 | public: | ||
20 | Map* map; | ||
21 | |||
22 | MapPtrCtr(Map* map) : map(map) {} | ||
23 | }; | ||
15 | 24 | ||
16 | class MapeditFrame : public wxFrame { | 25 | class MapeditFrame : public wxFrame { |
17 | public: | 26 | public: |
18 | MapeditFrame() {} | 27 | MapeditFrame() {} |
19 | MapeditFrame(Map map, std::string filename); | 28 | MapeditFrame(std::unique_ptr<World> world); |
20 | 29 | ||
21 | MapeditWidget* GetMapEditor(); | 30 | MapeditWidget* GetMapEditor(); |
22 | void StartAddingEntity(); | 31 | void StartAddingEntity(); |
23 | void FinishAddingEntity(); | 32 | void FinishAddingEntity(); |
24 | void MapDirtyDidChange(bool dirty); | 33 | void MapDirtyDidChange(bool dirty); |
25 | 34 | ||
26 | static void NewMap(); | 35 | static void NewWorld(); |
27 | static void OpenMap(const char* filename); | 36 | static void OpenWorld(std::string filename); |
28 | 37 | ||
29 | std::list<wxWindow*>::iterator closer; | 38 | std::list<wxWindow*>::iterator closer; |
30 | 39 | ||
31 | private: | 40 | private: |
32 | static void LaunchWindow(Map map, const char* filename); | 41 | static void LaunchWindow(std::unique_ptr<World> world); |
42 | void populateMapTree(wxTreeItemId node, std::list<std::shared_ptr<Map>> maps); | ||
43 | void SelectMap(Map* map); | ||
44 | wxTreeItemId MoveTreeNode(wxTreeItemId toCopy, wxTreeItemId newParent); | ||
33 | 45 | ||
34 | void ZoomIn(wxCommandEvent& event); | 46 | void ZoomIn(wxCommandEvent& event); |
35 | void ZoomOut(wxCommandEvent& event); | 47 | void ZoomOut(wxCommandEvent& event); |
@@ -44,8 +56,15 @@ class MapeditFrame : public wxFrame { | |||
44 | void OnTabChanging(wxBookCtrlEvent& event); | 56 | void OnTabChanging(wxBookCtrlEvent& event); |
45 | void OnAddEntity(wxCommandEvent& event); | 57 | void OnAddEntity(wxCommandEvent& event); |
46 | void OnCancelAddEntity(wxCommandEvent& event); | 58 | void OnCancelAddEntity(wxCommandEvent& event); |
59 | void OnAddRoot(wxCommandEvent& event); | ||
60 | void OnAddChild(wxCommandEvent& event); | ||
61 | void OnDidSelectMap(wxTreeEvent& event); | ||
62 | void OnWillSelectMap(wxTreeEvent& event); | ||
63 | void OnWillDragMap(wxTreeEvent& event); | ||
64 | void OnDidDragMap(wxTreeEvent& event); | ||
47 | 65 | ||
48 | Map map; | 66 | std::unique_ptr<World> world; |
67 | Map* currentMap; | ||
49 | MapeditWidget* mapEditor; | 68 | MapeditWidget* mapEditor; |
50 | TileWidget* tileEditor; | 69 | TileWidget* tileEditor; |
51 | wxTextCtrl* titleBox; | 70 | wxTextCtrl* titleBox; |
@@ -55,6 +74,9 @@ class MapeditFrame : public wxFrame { | |||
55 | wxButton* addEntityButton; | 74 | wxButton* addEntityButton; |
56 | wxButton* cancelEntityButton; | 75 | wxButton* cancelEntityButton; |
57 | wxToolBar* toolbar; | 76 | wxToolBar* toolbar; |
77 | wxMenu* menuFile; | ||
78 | wxTreeCtrl* mapTree; | ||
79 | wxTreeItemId dragMap; | ||
58 | 80 | ||
59 | bool addingEntity = false; | 81 | bool addingEntity = false; |
60 | 82 | ||
diff --git a/tools/mapedit/src/main.cpp b/tools/mapedit/src/main.cpp index 91dd98f..b09ee9a 100644 --- a/tools/mapedit/src/main.cpp +++ b/tools/mapedit/src/main.cpp | |||
@@ -18,7 +18,7 @@ bool MapeditApp::OnInit() | |||
18 | { | 18 | { |
19 | wxInitAllImageHandlers(); | 19 | wxInitAllImageHandlers(); |
20 | 20 | ||
21 | MapeditFrame::NewMap(); | 21 | MapeditFrame::NewWorld(); |
22 | 22 | ||
23 | return true; | 23 | return true; |
24 | } | 24 | } |
diff --git a/tools/mapedit/src/map.cpp b/tools/mapedit/src/map.cpp index f9c07fc..32541e6 100644 --- a/tools/mapedit/src/map.cpp +++ b/tools/mapedit/src/map.cpp | |||
@@ -1,106 +1,27 @@ | |||
1 | #include "map.h" | 1 | #include "map.h" |
2 | #include <libxml/parser.h> | ||
3 | #include <libxml/xmlwriter.h> | ||
4 | #include <sstream> | ||
5 | #include "frame.h" | 2 | #include "frame.h" |
6 | 3 | ||
7 | Map::Map() | 4 | Map::Map(int id, World* world) : id(id), world(world) |
8 | { | 5 | { |
9 | mapdata = (int*) calloc(MAP_WIDTH * MAP_HEIGHT, sizeof(int)); | 6 | mapdata = (int*) calloc(MAP_WIDTH * MAP_HEIGHT, sizeof(int)); |
10 | } | 7 | } |
11 | 8 | ||
12 | Map::Map(std::string filename) | ||
13 | { | ||
14 | xmlDocPtr doc = xmlParseFile(filename.c_str()); | ||
15 | if (doc == nullptr) | ||
16 | { | ||
17 | throw MapLoadException(filename); | ||
18 | } | ||
19 | |||
20 | xmlNodePtr top = xmlDocGetRootElement(doc); | ||
21 | if (top == nullptr) | ||
22 | { | ||
23 | throw MapLoadException(filename); | ||
24 | } | ||
25 | |||
26 | if (xmlStrcmp(top->name, (const xmlChar*) "map-def")) | ||
27 | { | ||
28 | throw MapLoadException(filename); | ||
29 | } | ||
30 | |||
31 | for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) | ||
32 | { | ||
33 | if (!xmlStrcmp(node->name, (const xmlChar*) "name")) | ||
34 | { | ||
35 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
36 | title = (char*) key; | ||
37 | xmlFree(key); | ||
38 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "environment")) | ||
39 | { | ||
40 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
41 | mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); | ||
42 | mapdata[0] = atoi(strtok((char*) key, ",\n")); | ||
43 | for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++) | ||
44 | { | ||
45 | mapdata[i] = atoi(strtok(NULL, ",\n")); | ||
46 | } | ||
47 | xmlFree(key); | ||
48 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "leftmap")) | ||
49 | { | ||
50 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
51 | leftmap = (char*) key; | ||
52 | xmlFree(key); | ||
53 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "rightmap")) | ||
54 | { | ||
55 | xmlChar* key = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); | ||
56 | rightmap = (char*) key; | ||
57 | xmlFree(key); | ||
58 | } else if (!xmlStrcmp(node->name, (const xmlChar*) "entities")) | ||
59 | { | ||
60 | for (xmlNodePtr entityNode = node->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next) | ||
61 | { | ||
62 | if (!xmlStrcmp(entityNode->name, (const xmlChar*) "entity")) | ||
63 | { | ||
64 | auto data = std::make_shared<MapObjectEntry>(); | ||
65 | |||
66 | for (xmlNodePtr entityDataNode = entityNode->xmlChildrenNode; entityDataNode != NULL; entityDataNode = entityDataNode->next) | ||
67 | { | ||
68 | if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-type")) | ||
69 | { | ||
70 | xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); | ||
71 | data->object = MapObject::getAllObjects().at((char*) key).get(); | ||
72 | xmlFree(key); | ||
73 | } else if (!xmlStrcmp(entityDataNode->name, (const xmlChar*) "entity-position")) | ||
74 | { | ||
75 | xmlChar* key = xmlNodeListGetString(doc, entityDataNode->xmlChildrenNode, 1); | ||
76 | sscanf((char*) key, "%lf,%lf", &data->position.first, &data->position.second); | ||
77 | xmlFree(key); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | objects.push_back(data); | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | |||
87 | xmlFreeDoc(doc); | ||
88 | } | ||
89 | |||
90 | Map::Map(const Map& map) | 9 | Map::Map(const Map& map) |
91 | { | 10 | { |
92 | mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); | 11 | mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); |
93 | memcpy(mapdata, map.mapdata, MAP_WIDTH*MAP_HEIGHT*sizeof(int)); | 12 | memcpy(mapdata, map.mapdata, MAP_WIDTH*MAP_HEIGHT*sizeof(int)); |
94 | 13 | ||
14 | id = map.id; | ||
95 | title = map.title; | 15 | title = map.title; |
96 | leftmap = map.leftmap; | 16 | leftmap = map.leftmap; |
97 | rightmap = map.rightmap; | 17 | rightmap = map.rightmap; |
98 | dirty = map.dirty; | ||
99 | objects = map.objects; | 18 | objects = map.objects; |
100 | frame = map.frame; | 19 | world = map.world; |
20 | treeItemId = map.treeItemId; | ||
21 | children = map.children; | ||
101 | } | 22 | } |
102 | 23 | ||
103 | Map::Map(Map&& map) : Map() | 24 | Map::Map(Map&& map) : Map(-1, map.world) |
104 | { | 25 | { |
105 | swap(*this, map); | 26 | swap(*this, map); |
106 | } | 27 | } |
@@ -123,141 +44,157 @@ void swap(Map& first, Map& second) | |||
123 | std::swap(first.title, second.title); | 44 | std::swap(first.title, second.title); |
124 | std::swap(first.leftmap, second.leftmap); | 45 | std::swap(first.leftmap, second.leftmap); |
125 | std::swap(first.rightmap, second.rightmap); | 46 | std::swap(first.rightmap, second.rightmap); |
126 | std::swap(first.dirty, second.dirty); | ||
127 | std::swap(first.objects, second.objects); | 47 | std::swap(first.objects, second.objects); |
128 | std::swap(first.frame, second.frame); | 48 | std::swap(first.id, second.id); |
49 | std::swap(first.world, second.world); | ||
50 | std::swap(first.treeItemId, second.treeItemId); | ||
51 | std::swap(first.children, second.children); | ||
129 | } | 52 | } |
130 | 53 | ||
131 | #define MY_ENCODING "ISO-8859-1" | 54 | int Map::getID() const |
55 | { | ||
56 | return id; | ||
57 | } | ||
132 | 58 | ||
133 | void Map::save(std::string name) | 59 | std::string Map::getTitle() const |
134 | { | 60 | { |
135 | if (!dirty) return; | 61 | return title; |
136 | 62 | } | |
137 | int rc; | ||
138 | |||
139 | xmlTextWriterPtr writer = xmlNewTextWriterFilename(name.c_str(), 0); | ||
140 | if (writer == NULL) throw MapWriteException(name); | ||
141 | 63 | ||
142 | rc = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL); | 64 | int Map::getTileAt(int x, int y) const |
143 | if (rc < 0) throw MapWriteException(name); | 65 | { |
144 | 66 | return mapdata[x+y*MAP_WIDTH]; | |
145 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "map-def"); | 67 | } |
146 | if (rc < 0) throw MapWriteException(name); | 68 | |
147 | 69 | const std::list<std::shared_ptr<MapObjectEntry>>& Map::getObjects() const | |
148 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "name", (xmlChar*) title.c_str()); | 70 | { |
149 | if (rc < 0) throw MapWriteException(name); | 71 | return objects; |
150 | 72 | } | |
151 | std::ostringstream mapdata_out; | 73 | |
152 | for (int y=0; y<MAP_HEIGHT; y++) | 74 | std::shared_ptr<Map> Map::getLeftmap() const |
75 | { | ||
76 | if (leftmap == -1) | ||
153 | { | 77 | { |
154 | for (int x=0; x<MAP_WIDTH; x++) | 78 | return std::shared_ptr<Map>(); |
155 | { | 79 | } else { |
156 | mapdata_out << mapdata[x+y*MAP_WIDTH] << ","; | 80 | return world->getMap(leftmap); |
157 | } | ||
158 | |||
159 | mapdata_out << std::endl; | ||
160 | } | 81 | } |
161 | 82 | } | |
162 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "environment", (xmlChar*) mapdata_out.str().c_str()); | ||
163 | if (rc < 0) throw MapWriteException(name); | ||
164 | |||
165 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "leftmap", (xmlChar*) leftmap.c_str()); | ||
166 | if (rc < 0) throw MapWriteException(name); | ||
167 | 83 | ||
168 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "rightmap", (xmlChar*) rightmap.c_str()); | 84 | std::shared_ptr<Map> Map::getRightmap() const |
169 | if (rc < 0) throw MapWriteException(name); | 85 | { |
170 | 86 | if (rightmap == -1) | |
171 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "entities"); | ||
172 | if (rc < 0) throw MapWriteException(name); | ||
173 | |||
174 | for (auto object : objects) | ||
175 | { | 87 | { |
176 | rc = xmlTextWriterStartElement(writer, (xmlChar*) "entity"); | 88 | return std::shared_ptr<Map>(); |
177 | if (rc < 0) throw MapWriteException(name); | 89 | } else { |
178 | 90 | return world->getMap(rightmap); | |
179 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "entity-type", (xmlChar*) object->object->getType().c_str()); | ||
180 | if (rc < 0) throw MapWriteException(name); | ||
181 | |||
182 | std::ostringstream entpos_out; | ||
183 | entpos_out << object->position.first << "," << object->position.second; | ||
184 | |||
185 | rc = xmlTextWriterWriteElement(writer, (xmlChar*) "entity-position", (xmlChar*) entpos_out.str().c_str()); | ||
186 | if (rc < 0) throw MapWriteException(name); | ||
187 | |||
188 | rc = xmlTextWriterEndElement(writer); | ||
189 | if (rc < 0) throw MapWriteException(name); | ||
190 | } | 91 | } |
191 | |||
192 | rc = xmlTextWriterEndElement(writer); | ||
193 | if (rc < 0) throw MapWriteException(name); | ||
194 | |||
195 | rc = xmlTextWriterEndElement(writer); | ||
196 | if (rc < 0) throw MapWriteException(name); | ||
197 | |||
198 | rc = xmlTextWriterEndDocument(writer); | ||
199 | if (rc < 0) throw MapWriteException(name); | ||
200 | |||
201 | xmlFreeTextWriter(writer); | ||
202 | |||
203 | setDirty(false); | ||
204 | } | 92 | } |
205 | 93 | ||
206 | bool Map::hasUnsavedChanges() const | 94 | wxTreeItemId Map::getTreeItemId() const |
207 | { | 95 | { |
208 | return dirty; | 96 | return treeItemId; |
209 | } | 97 | } |
210 | 98 | ||
211 | void Map::setTileAt(int x, int y, int tile) | 99 | std::list<std::shared_ptr<Map>> Map::getChildren() const |
212 | { | 100 | { |
213 | setDirty(true); | 101 | std::list<std::shared_ptr<Map>> ret; |
214 | mapdata[x+y*MAP_WIDTH] = tile; | 102 | |
103 | for (auto id : children) | ||
104 | { | ||
105 | ret.push_back(world->getMap(id)); | ||
106 | } | ||
107 | |||
108 | return ret; | ||
215 | } | 109 | } |
216 | 110 | ||
217 | int Map::getTileAt(int x, int y) const | 111 | bool Map::getExpanded() const |
218 | { | 112 | { |
219 | return mapdata[x+y*MAP_WIDTH]; | 113 | return expanded; |
220 | } | 114 | } |
221 | 115 | ||
222 | std::string Map::getTitle() const | 116 | void Map::setTitle(std::string title, bool dirty) |
223 | { | 117 | { |
224 | return title; | 118 | this->title = title; |
119 | |||
120 | if (dirty) | ||
121 | { | ||
122 | world->setDirty(true); | ||
123 | } | ||
225 | } | 124 | } |
226 | 125 | ||
227 | void Map::setTitle(std::string title) | 126 | void Map::setTileAt(int x, int y, int tile, bool dirty) |
228 | { | 127 | { |
229 | setDirty(true); | 128 | mapdata[x+y*MAP_WIDTH] = tile; |
230 | this->title = title; | 129 | |
130 | if (dirty) | ||
131 | { | ||
132 | world->setDirty(true); | ||
133 | } | ||
231 | } | 134 | } |
232 | 135 | ||
233 | const std::list<std::shared_ptr<MapObjectEntry>>& Map::getObjects() const | 136 | void Map::setMapdata(int* mapdata, bool dirty) |
234 | { | 137 | { |
235 | return objects; | 138 | free(this->mapdata); |
139 | this->mapdata = mapdata; | ||
140 | |||
141 | if (dirty) | ||
142 | { | ||
143 | world->setDirty(true); | ||
144 | } | ||
236 | } | 145 | } |
237 | 146 | ||
238 | void Map::addObject(std::shared_ptr<MapObjectEntry>& obj) | 147 | void Map::addObject(std::shared_ptr<MapObjectEntry>& obj, bool dirty) |
239 | { | 148 | { |
240 | setDirty(true); | ||
241 | objects.push_back(obj); | 149 | objects.push_back(obj); |
150 | |||
151 | if (dirty) | ||
152 | { | ||
153 | world->setDirty(true); | ||
154 | } | ||
242 | } | 155 | } |
243 | 156 | ||
244 | void Map::removeObject(std::shared_ptr<MapObjectEntry>& obj) | 157 | void Map::removeObject(std::shared_ptr<MapObjectEntry>& obj, bool dirty) |
245 | { | 158 | { |
246 | setDirty(true); | ||
247 | objects.remove(obj); | 159 | objects.remove(obj); |
160 | |||
161 | if (dirty) | ||
162 | { | ||
163 | world->setDirty(true); | ||
164 | } | ||
248 | } | 165 | } |
249 | 166 | ||
250 | bool Map::getDirty() const | 167 | void Map::setLeftmap(int id, bool dirty) |
251 | { | 168 | { |
252 | return dirty; | 169 | leftmap = id; |
170 | |||
171 | if (dirty) | ||
172 | { | ||
173 | world->setDirty(true); | ||
174 | } | ||
253 | } | 175 | } |
254 | 176 | ||
255 | void Map::setDirty(bool dirty) | 177 | void Map::setRightmap(int id, bool dirty) |
256 | { | 178 | { |
257 | this->dirty = dirty; | 179 | rightmap = id; |
258 | 180 | ||
259 | if (frame != nullptr) | 181 | if (dirty) |
260 | { | 182 | { |
261 | frame->MapDirtyDidChange(dirty); | 183 | world->setDirty(true); |
262 | } | 184 | } |
263 | } | 185 | } |
186 | |||
187 | void Map::setTreeItemId(wxTreeItemId id) | ||
188 | { | ||
189 | this->treeItemId = id; | ||
190 | } | ||
191 | |||
192 | void Map::addChild(int id) | ||
193 | { | ||
194 | children.push_back(id); | ||
195 | } | ||
196 | |||
197 | void Map::setExpanded(bool exp) | ||
198 | { | ||
199 | expanded = exp; | ||
200 | } | ||
diff --git a/tools/mapedit/src/map.h b/tools/mapedit/src/map.h index a2b9cb8..5753cae 100644 --- a/tools/mapedit/src/map.h +++ b/tools/mapedit/src/map.h | |||
@@ -1,12 +1,16 @@ | |||
1 | #ifndef MAP_H | 1 | #ifndef MAP_H |
2 | #define MAP_H | 2 | #define MAP_H |
3 | 3 | ||
4 | class Map; | ||
5 | |||
4 | #include <string> | 6 | #include <string> |
5 | #include <exception> | 7 | #include <exception> |
6 | #include <utility> | 8 | #include <utility> |
7 | #include <list> | 9 | #include <list> |
8 | #include "object.h" | 10 | #include "object.h" |
9 | #include <memory> | 11 | #include <memory> |
12 | #include "world.h" | ||
13 | #include <wx/treectrl.h> | ||
10 | 14 | ||
11 | class MapeditFrame; | 15 | class MapeditFrame; |
12 | 16 | ||
@@ -57,36 +61,45 @@ struct MapObjectEntry { | |||
57 | 61 | ||
58 | class Map { | 62 | class Map { |
59 | public: | 63 | public: |
60 | Map(); | 64 | Map(int id, World* world); |
61 | Map(std::string name); | ||
62 | Map(const Map& map); | 65 | Map(const Map& map); |
63 | Map(Map&& map); | 66 | Map(Map&& map); |
64 | ~Map(); | 67 | ~Map(); |
65 | Map& operator= (Map other); | 68 | Map& operator= (Map other); |
66 | friend void swap(Map& first, Map& second); | 69 | friend void swap(Map& first, Map& second); |
67 | 70 | ||
71 | int getID() const; | ||
68 | std::string getTitle() const; | 72 | std::string getTitle() const; |
69 | void setTitle(std::string title); | ||
70 | void save(std::string name); | ||
71 | bool hasUnsavedChanges() const; | ||
72 | void setTileAt(int x, int y, int tile); | ||
73 | int getTileAt(int x, int y) const; | 73 | int getTileAt(int x, int y) const; |
74 | const std::list<std::shared_ptr<MapObjectEntry>>& getObjects() const; | 74 | const std::list<std::shared_ptr<MapObjectEntry>>& getObjects() const; |
75 | void addObject(std::shared_ptr<MapObjectEntry>& obj); | 75 | std::shared_ptr<Map> getLeftmap() const; |
76 | void removeObject(std::shared_ptr<MapObjectEntry>& obj); | 76 | std::shared_ptr<Map> getRightmap() const; |
77 | bool getDirty() const; | 77 | wxTreeItemId getTreeItemId() const; |
78 | std::list<std::shared_ptr<Map>> getChildren() const; | ||
79 | bool getExpanded() const; | ||
78 | 80 | ||
79 | MapeditFrame* frame; | 81 | void setTitle(std::string title, bool dirty = true); |
82 | void setTileAt(int x, int y, int tile, bool dirty = true); | ||
83 | void setMapdata(int* mapdata, bool dirty = true); | ||
84 | void addObject(std::shared_ptr<MapObjectEntry>& obj, bool dirty = true); | ||
85 | void removeObject(std::shared_ptr<MapObjectEntry>& obj, bool dirty = true); | ||
86 | void setLeftmap(int id, bool dirty = true); | ||
87 | void setRightmap(int id, bool dirty = true); | ||
88 | void setTreeItemId(wxTreeItemId id); | ||
89 | void addChild(int id); | ||
90 | void setExpanded(bool exp); | ||
80 | 91 | ||
81 | private: | 92 | private: |
82 | void setDirty(bool dirty); | 93 | int id; |
83 | 94 | World* world; | |
84 | std::list<std::shared_ptr<MapObjectEntry>> objects; | 95 | std::list<std::shared_ptr<MapObjectEntry>> objects; |
85 | int* mapdata; | 96 | int* mapdata; |
86 | std::string title; | 97 | std::string title {"Untitled Map"}; |
87 | std::string leftmap; | 98 | std::list<int> children; |
88 | std::string rightmap; | 99 | int leftmap = -1; |
89 | bool dirty; | 100 | int rightmap = -1; |
101 | wxTreeItemId treeItemId; | ||
102 | bool expanded = false; | ||
90 | }; | 103 | }; |
91 | 104 | ||
92 | #endif | 105 | #endif |
diff --git a/tools/mapedit/src/widget.cpp b/tools/mapedit/src/widget.cpp index c1f044c..d50cf91 100644 --- a/tools/mapedit/src/widget.cpp +++ b/tools/mapedit/src/widget.cpp | |||
@@ -297,3 +297,10 @@ void MapeditWidget::CancelAddingEntity() | |||
297 | { | 297 | { |
298 | addingEntity = nullptr; | 298 | addingEntity = nullptr; |
299 | } | 299 | } |
300 | |||
301 | void MapeditWidget::SetMap(Map* map) | ||
302 | { | ||
303 | this->map = map; | ||
304 | |||
305 | Refresh(); | ||
306 | } | ||
diff --git a/tools/mapedit/src/widget.h b/tools/mapedit/src/widget.h index a660f82..34627bc 100644 --- a/tools/mapedit/src/widget.h +++ b/tools/mapedit/src/widget.h | |||
@@ -29,6 +29,7 @@ class MapeditWidget : public wxScrolledWindow { | |||
29 | void SetEditMode(EditMode editMode); | 29 | void SetEditMode(EditMode editMode); |
30 | void StartAddingEntity(MapObject* object); | 30 | void StartAddingEntity(MapObject* object); |
31 | void CancelAddingEntity(); | 31 | void CancelAddingEntity(); |
32 | void SetMap(Map* map); | ||
32 | 33 | ||
33 | MapeditFrame* frame; | 34 | MapeditFrame* frame; |
34 | 35 | ||
@@ -46,7 +47,7 @@ class MapeditWidget : public wxScrolledWindow { | |||
46 | void SetTile(wxPoint pos); | 47 | void SetTile(wxPoint pos); |
47 | void SetZoomSize(int zoom); | 48 | void SetZoomSize(int zoom); |
48 | 49 | ||
49 | Map* const map = nullptr; | 50 | Map* map = nullptr; |
50 | wxBitmap tiles; | 51 | wxBitmap tiles; |
51 | TileWidget* tileWidget; | 52 | TileWidget* tileWidget; |
52 | bool mouseIsDown = false; | 53 | bool mouseIsDown = false; |
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 | } | ||
diff --git a/tools/mapedit/src/world.h b/tools/mapedit/src/world.h new file mode 100644 index 0000000..7d796cc --- /dev/null +++ b/tools/mapedit/src/world.h | |||
@@ -0,0 +1,45 @@ | |||
1 | #ifndef WORLD_H | ||
2 | #define WORLD_H | ||
3 | |||
4 | class World; | ||
5 | |||
6 | #include <wx/wxprec.h> | ||
7 | |||
8 | #ifndef WX_PRECOMP | ||
9 | #include <wx/wx.h> | ||
10 | #endif | ||
11 | |||
12 | #include <wx/treectrl.h> | ||
13 | #include <map> | ||
14 | #include <memory> | ||
15 | #include "map.h" | ||
16 | #include <list> | ||
17 | |||
18 | class MapeditFrame; | ||
19 | |||
20 | class World { | ||
21 | public: | ||
22 | World(); | ||
23 | World(std::string filename); | ||
24 | std::shared_ptr<Map> newMap(); | ||
25 | std::shared_ptr<Map> getMap(int id) const; | ||
26 | void setDirty(bool dirty); | ||
27 | bool getDirty() const; | ||
28 | std::string getFilename() const; | ||
29 | void setParent(MapeditFrame* parent); | ||
30 | void save(std::string filename, wxTreeCtrl* mapTree); | ||
31 | Map* getLastMap() const; | ||
32 | std::list<std::shared_ptr<Map>> getRootMaps() const; | ||
33 | const std::map<int, std::shared_ptr<Map>> getMaps() const; | ||
34 | |||
35 | private: | ||
36 | MapeditFrame* parent; | ||
37 | std::map<int, std::shared_ptr<Map>> maps; | ||
38 | int nextMapID = 0; | ||
39 | bool dirty = false; | ||
40 | std::string filename; | ||
41 | int lastmap = 0; | ||
42 | std::list<int> rootChildren; | ||
43 | }; | ||
44 | |||
45 | #endif | ||