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