| @@ -0,0 +1,370 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #ifndef RME_MAIN_BAR_H_ | |
| 19 | + | #define RME_MAIN_BAR_H_ | |
| 20 | + | ||
| 21 | + | #include <wx/docview.h> | |
| 22 | + | ||
| 23 | + | namespace MenuBar { | |
| 24 | + | struct Action; | |
| 25 | + | ||
| 26 | + | enum ActionID { | |
| 27 | + | NEW, | |
| 28 | + | OPEN, | |
| 29 | + | SAVE, | |
| 30 | + | SAVE_AS, | |
| 31 | + | GENERATE_MAP, | |
| 32 | + | GENERATE_PROCEDURAL_MAP, | |
| 33 | + | CLOSE, | |
| 34 | + | IMPORT_MAP, | |
| 35 | + | IMPORT_MONSTERS, | |
| 36 | + | IMPORT_MINIMAP, | |
| 37 | + | EXPORT_MINIMAP, | |
| 38 | + | EXPORT_TILESETS, | |
| 39 | + | RELOAD_DATA, | |
| 40 | + | RECENT_FILES, | |
| 41 | + | PREFERENCES, | |
| 42 | + | EXIT, | |
| 43 | + | UNDO, | |
| 44 | + | REDO, | |
| 45 | + | FIND_ITEM, | |
| 46 | + | FIND_CREATURE, | |
| 47 | + | REPLACE_ITEMS, | |
| 48 | + | AUTOMAGIC, | |
| 49 | + | SEARCH_ON_MAP_EVERYTHING, | |
| 50 | + | SEARCH_ON_MAP_ZONES, | |
| 51 | + | SEARCH_ON_MAP_UNIQUE, | |
| 52 | + | SEARCH_ON_MAP_ACTION, | |
| 53 | + | SEARCH_ON_MAP_CONTAINER, | |
| 54 | + | SEARCH_ON_MAP_WRITEABLE, | |
| 55 | + | SEARCH_ON_SELECTION_EVERYTHING, | |
| 56 | + | SEARCH_ON_SELECTION_ZONES, | |
| 57 | + | SEARCH_ON_SELECTION_UNIQUE, | |
| 58 | + | SEARCH_ON_SELECTION_ACTION, | |
| 59 | + | SEARCH_ON_SELECTION_CONTAINER, | |
| 60 | + | SEARCH_ON_SELECTION_WRITEABLE, | |
| 61 | + | SEARCH_ON_SELECTION_ITEM, | |
| 62 | + | REPLACE_ON_SELECTION_ITEMS, | |
| 63 | + | REMOVE_ON_SELECTION_ITEM, | |
| 64 | + | SELECT_MODE_COMPENSATE, | |
| 65 | + | SELECT_MODE_CURRENT, | |
| 66 | + | SELECT_MODE_LOWER, | |
| 67 | + | SELECT_MODE_VISIBLE, | |
| 68 | + | // AUTOMAGIC removed - now controlled by 'A' hotkey | |
| 69 | + | BORDERIZE_SELECTION, | |
| 70 | + | BORDERIZE_MAP, | |
| 71 | + | RANDOMIZE_SELECTION, | |
| 72 | + | RANDOMIZE_MAP, | |
| 73 | + | GOTO_PREVIOUS_POSITION, | |
| 74 | + | GOTO_POSITION, | |
| 75 | + | JUMP_TO_BRUSH, | |
| 76 | + | JUMP_TO_ITEM_BRUSH, | |
| 77 | + | CLEAR_INVALID_HOUSES, | |
| 78 | + | CLEAR_MODIFIED_STATE, | |
| 79 | + | CUT, | |
| 80 | + | COPY, | |
| 81 | + | PASTE, | |
| 82 | + | EDIT_TOWNS, | |
| 83 | + | EDIT_ITEMS, | |
| 84 | + | EDIT_MONSTERS, | |
| 85 | + | MAP_CLEANUP, | |
| 86 | + | MAP_REMOVE_ITEMS, | |
| 87 | + | MAP_REMOVE_CORPSES, | |
| 88 | + | MAP_REMOVE_UNREACHABLE_TILES, | |
| 89 | + | MAP_CLEAN_HOUSE_ITEMS, | |
| 90 | + | MAP_PROPERTIES, | |
| 91 | + | MAP_STATISTICS, | |
| 92 | + | VIEW_TOOLBARS_BRUSHES, | |
| 93 | + | VIEW_TOOLBARS_POSITION, | |
| 94 | + | VIEW_TOOLBARS_SIZES, | |
| 95 | + | VIEW_TOOLBARS_STANDARD, | |
| 96 | + | NEW_VIEW, | |
| 97 | + | // RD | |
| 98 | + | NEW_DETACHED_VIEW, | |
| 99 | + | TOGGLE_FULLSCREEN, | |
| 100 | + | ZOOM_IN, | |
| 101 | + | ZOOM_OUT, | |
| 102 | + | ZOOM_NORMAL, | |
| 103 | + | SHOW_SHADE, | |
| 104 | + | SHOW_ALL_FLOORS, | |
| 105 | + | GHOST_ITEMS, | |
| 106 | + | GHOST_HIGHER_FLOORS, | |
| 107 | + | HIGHLIGHT_ITEMS, | |
| 108 | + | HIGHLIGHT_LOCKED_DOORS, | |
| 109 | + | SHOW_INGAME_BOX, | |
| 110 | + | SHOW_LIGHTS, | |
| 111 | + | SHOW_LIGHT_STR, | |
| 112 | + | SHOW_TECHNICAL_ITEMS, | |
| 113 | + | SHOW_WAYPOINTS, | |
| 114 | + | SHOW_GRID, | |
| 115 | + | SHOW_EXTRA, | |
| 116 | + | SHOW_CREATURES, | |
| 117 | + | SHOW_SPAWNS, | |
| 118 | + | SHOW_SPECIAL, | |
| 119 | + | SHOW_ZONES, | |
| 120 | + | SHOW_AS_MINIMAP, | |
| 121 | + | SHOW_ONLY_COLORS, | |
| 122 | + | SHOW_ONLY_MODIFIED, | |
| 123 | + | SHOW_HOUSES, | |
| 124 | + | SHOW_PATHING, | |
| 125 | + | SHOW_TOOLTIPS, | |
| 126 | + | SHOW_PREVIEW, | |
| 127 | + | SHOW_WALL_HOOKS, | |
| 128 | + | SHOW_TOWNS, | |
| 129 | + | ALWAYS_SHOW_ZONES, | |
| 130 | + | EXT_HOUSE_SHADER, | |
| 131 | + | REFRESH_ITEMS, | |
| 132 | + | ||
| 133 | + | WIN_MINIMAP, | |
| 134 | + | NEW_PALETTE, | |
| 135 | + | TAKE_SCREENSHOT, | |
| 136 | + | LIVE_START, | |
| 137 | + | LIVE_JOIN, | |
| 138 | + | LIVE_CLOSE, | |
| 139 | + | SELECT_TERRAIN, | |
| 140 | + | SELECT_DOODAD, | |
| 141 | + | SELECT_ITEM, | |
| 142 | + | SELECT_COLLECTION, | |
| 143 | + | SELECT_CREATURE, | |
| 144 | + | SELECT_HOUSE, | |
| 145 | + | SELECT_WAYPOINT, | |
| 146 | + | SELECT_RAW, | |
| 147 | + | FLOOR_0, | |
| 148 | + | FLOOR_1, | |
| 149 | + | FLOOR_2, | |
| 150 | + | FLOOR_3, | |
| 151 | + | FLOOR_4, | |
| 152 | + | FLOOR_5, | |
| 153 | + | FLOOR_6, | |
| 154 | + | FLOOR_7, | |
| 155 | + | FLOOR_8, | |
| 156 | + | FLOOR_9, | |
| 157 | + | FLOOR_10, | |
| 158 | + | FLOOR_11, | |
| 159 | + | FLOOR_12, | |
| 160 | + | FLOOR_13, | |
| 161 | + | FLOOR_14, | |
| 162 | + | FLOOR_15, | |
| 163 | + | DEBUG_VIEW_DAT, | |
| 164 | + | EXTENSIONS, | |
| 165 | + | GOTO_WEBSITE, | |
| 166 | + | ABOUT, | |
| 167 | + | ID_MENU_SERVER_HOST, | |
| 168 | + | ID_MENU_SERVER_CONNECT, | |
| 169 | + | ||
| 170 | + | EXPERIMENTAL_FOG, | |
| 171 | + | MAP_REMOVE_DUPLICATES, | |
| 172 | + | SHOW_HOTKEYS, | |
| 173 | + | MAP_MENU_REPLACE_ITEMS, | |
| 174 | + | MAP_MENU_GENERATE_ISLAND, | |
| 175 | + | MAP_VALIDATE_GROUND, | |
| 176 | + | MAP_CREATE_BORDER, | |
| 177 | + | MAP_SUMMARIZE, | |
| 178 | + | ||
| 179 | + | ||
| 180 | + | ||
| 181 | + | }; | |
| 182 | + | } | |
| 183 | + | ||
| 184 | + | class MainFrame; | |
| 185 | + | ||
| 186 | + | class MainMenuBar : public wxEvtHandler { | |
| 187 | + | public: | |
| 188 | + | MainMenuBar(MainFrame* frame); | |
| 189 | + | virtual ~MainMenuBar(); | |
| 190 | + | ||
| 191 | + | bool Load(const FileName&, wxArrayString& warnings, wxString& error); | |
| 192 | + | ||
| 193 | + | // Update | |
| 194 | + | // Turn on/off all buttons according to current editor state | |
| 195 | + | void Update(); | |
| 196 | + | void UpdateFloorMenu(); // Only concerns the floor menu | |
| 197 | + | ||
| 198 | + | void AddRecentFile(FileName file); | |
| 199 | + | void LoadRecentFiles(); | |
| 200 | + | void SaveRecentFiles(); | |
| 201 | + | std::vector<wxString> GetRecentFiles(); | |
| 202 | + | ||
| 203 | + | // Interface | |
| 204 | + | void EnableItem(MenuBar::ActionID id, bool enable); | |
| 205 | + | void CheckItem(MenuBar::ActionID id, bool enable); | |
| 206 | + | bool IsItemChecked(MenuBar::ActionID id) const; | |
| 207 | + | ||
| 208 | + | // Event handlers for all menu buttons | |
| 209 | + | // File Menu | |
| 210 | + | void OnNew(wxCommandEvent& event); | |
| 211 | + | void OnOpen(wxCommandEvent& event); | |
| 212 | + | void OnGenerateMap(wxCommandEvent& event); | |
| 213 | + | void OnGenerateProceduralMap(wxCommandEvent& event); | |
| 214 | + | void OnOpenRecent(wxCommandEvent& event); | |
| 215 | + | void OnSave(wxCommandEvent& event); | |
| 216 | + | void OnSaveAs(wxCommandEvent& event); | |
| 217 | + | void OnClose(wxCommandEvent& event); | |
| 218 | + | void OnPreferences(wxCommandEvent& event); | |
| 219 | + | void OnQuit(wxCommandEvent& event); | |
| 220 | + | ||
| 221 | + | // Import Menu | |
| 222 | + | // Export Menu | |
| 223 | + | void OnImportMap(wxCommandEvent& event); | |
| 224 | + | void OnImportMonsterData(wxCommandEvent& event); | |
| 225 | + | void OnImportMinimap(wxCommandEvent& event); | |
| 226 | + | void OnExportMinimap(wxCommandEvent& event); | |
| 227 | + | void OnExportTilesets(wxCommandEvent& event); | |
| 228 | + | void OnReloadDataFiles(wxCommandEvent& event); | |
| 229 | + | ||
| 230 | + | // Edit Menu | |
| 231 | + | void OnUndo(wxCommandEvent& event); | |
| 232 | + | void OnRedo(wxCommandEvent& event); | |
| 233 | + | void OnBorderizeSelection(wxCommandEvent& event); | |
| 234 | + | void OnBorderizeMap(wxCommandEvent& event); | |
| 235 | + | void OnRandomizeSelection(wxCommandEvent& event); | |
| 236 | + | void OnRandomizeMap(wxCommandEvent& event); | |
| 237 | + | void OnJumpToBrush(wxCommandEvent& event); | |
| 238 | + | void OnJumpToItemBrush(wxCommandEvent& event); | |
| 239 | + | void OnGotoPreviousPosition(wxCommandEvent& event); | |
| 240 | + | void OnGotoPosition(wxCommandEvent& event); | |
| 241 | + | void OnMapRemoveItems(wxCommandEvent& event); | |
| 242 | + | void OnMapRemoveCorpses(wxCommandEvent& event); | |
| 243 | + | void OnMapRemoveUnreachable(wxCommandEvent& event); | |
| 244 | + | void OnClearHouseTiles(wxCommandEvent& event); | |
| 245 | + | void OnClearModifiedState(wxCommandEvent& event); | |
| 246 | + | void OnSelectionTypeChange(wxCommandEvent& event); | |
| 247 | + | void OnCut(wxCommandEvent& event); | |
| 248 | + | void OnCopy(wxCommandEvent& event); | |
| 249 | + | void OnPaste(wxCommandEvent& event); | |
| 250 | + | void OnSearchForItem(wxCommandEvent& event); | |
| 251 | + | void OnSearchForCreature(wxCommandEvent& event); | |
| 252 | + | void OnReplaceItems(wxCommandEvent& event); | |
| 253 | + | void OnSearchForStuffOnMap(wxCommandEvent& event); | |
| 254 | + | void OnSearchForZonesOnMap(wxCommandEvent& event); | |
| 255 | + | void OnSearchForUniqueOnMap(wxCommandEvent& event); | |
| 256 | + | void OnSearchForActionOnMap(wxCommandEvent& event); | |
| 257 | + | void OnSearchForContainerOnMap(wxCommandEvent& event); | |
| 258 | + | void OnSearchForWriteableOnMap(wxCommandEvent& event); | |
| 259 | + | ||
| 260 | + | // Select menu | |
| 261 | + | void OnSearchForStuffOnSelection(wxCommandEvent& event); | |
| 262 | + | void OnSearchForZonesOnSelection(wxCommandEvent& event); | |
| 263 | + | void OnSearchForUniqueOnSelection(wxCommandEvent& event); | |
| 264 | + | void OnSearchForActionOnSelection(wxCommandEvent& event); | |
| 265 | + | void OnSearchForContainerOnSelection(wxCommandEvent& event); | |
| 266 | + | void OnSearchForWriteableOnSelection(wxCommandEvent& event); | |
| 267 | + | void OnSearchForItemOnSelection(wxCommandEvent& event); | |
| 268 | + | void OnReplaceItemsOnSelection(wxCommandEvent& event); | |
| 269 | + | void OnRemoveItemOnSelection(wxCommandEvent& event); | |
| 270 | + | ||
| 271 | + | // Map menu | |
| 272 | + | void OnMapEditTowns(wxCommandEvent& event); | |
| 273 | + | void OnMapEditItems(wxCommandEvent& event); | |
| 274 | + | void OnMapEditMonsters(wxCommandEvent& event); | |
| 275 | + | void OnMapCleanHouseItems(wxCommandEvent& event); | |
| 276 | + | void OnMapCleanup(wxCommandEvent& event); | |
| 277 | + | void OnMapProperties(wxCommandEvent& event); | |
| 278 | + | void OnMapStatistics(wxCommandEvent& event); | |
| 279 | + | void OnMapRemoveDuplicates(wxCommandEvent& event); | |
| 280 | + | void OnMapValidateGround(wxCommandEvent& event); | |
| 281 | + | ||
| 282 | + | // View Menu | |
| 283 | + | void OnToolbars(wxCommandEvent& event); | |
| 284 | + | void OnNewView(wxCommandEvent& event); | |
| 285 | + | void OnNewDetachedView(wxCommandEvent& event); | |
| 286 | + | void OnToggleFullscreen(wxCommandEvent& event); | |
| 287 | + | void OnZoomIn(wxCommandEvent& event); | |
| 288 | + | void OnZoomOut(wxCommandEvent& event); | |
| 289 | + | void OnZoomNormal(wxCommandEvent& event); | |
| 290 | + | void OnChangeViewSettings(wxCommandEvent& event); | |
| 291 | + | ||
| 292 | + | // Network menu | |
| 293 | + | void OnStartLive(wxCommandEvent& event); | |
| 294 | + | void OnJoinLive(wxCommandEvent& event); | |
| 295 | + | void OnCloseLive(wxCommandEvent& event); | |
| 296 | + | void onServerHost(wxCommandEvent& event); | |
| 297 | + | void onServerConnect(wxCommandEvent& event); | |
| 298 | + | ||
| 299 | + | // Window Menu | |
| 300 | + | void OnMinimapWindow(wxCommandEvent& event); | |
| 301 | + | void OnNewPalette(wxCommandEvent& event); | |
| 302 | + | void OnTakeScreenshot(wxCommandEvent& event); | |
| 303 | + | void OnSelectTerrainPalette(wxCommandEvent& event); | |
| 304 | + | void OnSelectDoodadPalette(wxCommandEvent& event); | |
| 305 | + | void OnSelectItemPalette(wxCommandEvent& event); | |
| 306 | + | void OnSelectCollectionPalette(wxCommandEvent& event); | |
| 307 | + | void OnSelectHousePalette(wxCommandEvent& event); | |
| 308 | + | void OnSelectCreaturePalette(wxCommandEvent& event); | |
| 309 | + | void OnSelectWaypointPalette(wxCommandEvent& event); | |
| 310 | + | void OnSelectRawPalette(wxCommandEvent& event); | |
| 311 | + | ||
| 312 | + | // Floor menu | |
| 313 | + | void OnChangeFloor(wxCommandEvent& event); | |
| 314 | + | ||
| 315 | + | // About Menu | |
| 316 | + | void OnDebugViewDat(wxCommandEvent& event); | |
| 317 | + | void OnListExtensions(wxCommandEvent& event); | |
| 318 | + | void OnGotoWebsite(wxCommandEvent& event); | |
| 319 | + | void OnAbout(wxCommandEvent& event); | |
| 320 | + | void OnShowHotkeys(wxCommandEvent& event); | |
| 321 | + | ||
| 322 | + | // Add to class MainMenuBar private section: | |
| 323 | + | void OnRefreshItems(wxCommandEvent& event); | |
| 324 | + | void OnGenerateIsland(wxCommandEvent& event); | |
| 325 | + | void OnCreateBorder(wxCommandEvent& event); | |
| 326 | + | void OnMapSummarize(wxCommandEvent& event); | |
| 327 | + | ||
| 328 | + | protected: | |
| 329 | + | // Load and returns a menu item, also sets accelerator | |
| 330 | + | wxObject* LoadItem(pugi::xml_node node, wxMenu* parent, wxArrayString& warnings, wxString& error); | |
| 331 | + | // Checks the items in the menus according to the settings (in config) | |
| 332 | + | void LoadValues(); | |
| 333 | + | void SearchItems(bool unique, bool action, bool container, bool writable, bool zones, bool onSelection = false); | |
| 334 | + | ||
| 335 | + | protected: | |
| 336 | + | MainFrame* frame; | |
| 337 | + | wxMenuBar* menubar; | |
| 338 | + | ||
| 339 | + | // Used so that calling Check on menu items don't trigger events (avoids infinite recursion) | |
| 340 | + | bool checking_programmaticly; | |
| 341 | + | ||
| 342 | + | std::map<MenuBar::ActionID, std::list<wxMenuItem*>> items; | |
| 343 | + | ||
| 344 | + | // Hardcoded recent files | |
| 345 | + | wxFileHistory recentFiles; | |
| 346 | + | ||
| 347 | + | std::map<std::string, MenuBar::Action*> actions; | |
| 348 | + | ||
| 349 | + | DECLARE_EVENT_TABLE(); | |
| 350 | + | }; | |
| 351 | + | ||
| 352 | + | namespace MenuBar { | |
| 353 | + | struct Action { | |
| 354 | + | Action() : | |
| 355 | + | id(0), kind(wxITEM_NORMAL) { } | |
| 356 | + | Action(std::string s, int id, wxItemKind kind, wxCommandEventFunction handler) : | |
| 357 | + | id(id), setting(0), name(s), kind(kind), handler(handler) { } | |
| 358 | + | ||
| 359 | + | int id; | |
| 360 | + | int setting; | |
| 361 | + | std::string name; | |
| 362 | + | wxItemKind kind; | |
| 363 | + | wxCommandEventFunction handler; | |
| 364 | + | }; | |
| 365 | + | } | |
| 366 | + | ||
| 367 | + | // Add this declaration before the MainMenuBar class | |
| 368 | + | std::vector<std::pair<uint16_t, uint16_t>> ParseRangeString(const wxString& input); | |
| 369 | + | ||
| 370 | + | #endif |
| @@ -0,0 +1,658 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #include "main.h" | |
| 19 | + | #include "main_toolbar.h" | |
| 20 | + | #include "gui.h" | |
| 21 | + | #include "editor.h" | |
| 22 | + | #include "settings.h" | |
| 23 | + | #include "brush.h" | |
| 24 | + | #include "pngfiles.h" | |
| 25 | + | #include "artprovider.h" | |
| 26 | + | #include <wx/artprov.h> | |
| 27 | + | #include <wx/mstream.h> | |
| 28 | + | #include "hotkey_manager.h" | |
| 29 | + | #include "ext/pugixml.hpp" | |
| 30 | + | ||
| 31 | + | const wxString MainToolBar::STANDARD_BAR_NAME = "standard_toolbar"; | |
| 32 | + | const wxString MainToolBar::BRUSHES_BAR_NAME = "brushes_toolbar"; | |
| 33 | + | const wxString MainToolBar::POSITION_BAR_NAME = "position_toolbar"; | |
| 34 | + | const wxString MainToolBar::SIZES_BAR_NAME = "sizes_toolbar"; | |
| 35 | + | ||
| 36 | + | #define loadPNGFile(name) _wxGetBitmapFromMemory(name, sizeof(name)) | |
| 37 | + | inline wxBitmap* _wxGetBitmapFromMemory(const unsigned char* data, int length) { | |
| 38 | + | wxMemoryInputStream is(data, length); | |
| 39 | + | wxImage img(is, "image/png"); | |
| 40 | + | if (!img.IsOk()) { | |
| 41 | + | return nullptr; | |
| 42 | + | } | |
| 43 | + | return newd wxBitmap(img, -1); | |
| 44 | + | } | |
| 45 | + | ||
| 46 | + | MainToolBar::MainToolBar(wxWindow* parent, wxAuiManager* manager) { | |
| 47 | + | wxSize icon_size = FROM_DIP(parent, wxSize(16, 16)); | |
| 48 | + | wxBitmap new_bitmap = wxArtProvider::GetBitmap(wxART_NEW, wxART_TOOLBAR, icon_size); | |
| 49 | + | wxBitmap open_bitmap = wxArtProvider::GetBitmap(wxART_FILE_OPEN, wxART_TOOLBAR, icon_size); | |
| 50 | + | wxBitmap save_bitmap = wxArtProvider::GetBitmap(wxART_FILE_SAVE, wxART_TOOLBAR, icon_size); | |
| 51 | + | wxBitmap saveas_bitmap = wxArtProvider::GetBitmap(wxART_FILE_SAVE_AS, wxART_TOOLBAR, icon_size); | |
| 52 | + | wxBitmap undo_bitmap = wxArtProvider::GetBitmap(wxART_UNDO, wxART_TOOLBAR, icon_size); | |
| 53 | + | wxBitmap redo_bitmap = wxArtProvider::GetBitmap(wxART_REDO, wxART_TOOLBAR, icon_size); | |
| 54 | + | wxBitmap cut_bitmap = wxArtProvider::GetBitmap(wxART_CUT, wxART_TOOLBAR, icon_size); | |
| 55 | + | wxBitmap copy_bitmap = wxArtProvider::GetBitmap(wxART_COPY, wxART_TOOLBAR, icon_size); | |
| 56 | + | wxBitmap paste_bitmap = wxArtProvider::GetBitmap(wxART_PASTE, wxART_TOOLBAR, icon_size); | |
| 57 | + | ||
| 58 | + | standard_toolbar = newd wxAuiToolBar(parent, TOOLBAR_STANDARD, wxDefaultPosition, wxDefaultSize, wxAUI_TB_DEFAULT_STYLE); | |
| 59 | + | standard_toolbar->SetToolBitmapSize(icon_size); | |
| 60 | + | standard_toolbar->AddTool(wxID_NEW, wxEmptyString, new_bitmap, wxNullBitmap, wxITEM_NORMAL, "New Map", wxEmptyString, NULL); | |
| 61 | + | standard_toolbar->AddTool(wxID_OPEN, wxEmptyString, open_bitmap, wxNullBitmap, wxITEM_NORMAL, "Open Map", wxEmptyString, NULL); | |
| 62 | + | standard_toolbar->AddTool(wxID_SAVE, wxEmptyString, save_bitmap, wxNullBitmap, wxITEM_NORMAL, "Save Map", wxEmptyString, NULL); | |
| 63 | + | standard_toolbar->AddTool(wxID_SAVEAS, wxEmptyString, saveas_bitmap, wxNullBitmap, wxITEM_NORMAL, "Save Map As...", wxEmptyString, NULL); | |
| 64 | + | standard_toolbar->AddSeparator(); | |
| 65 | + | standard_toolbar->AddTool(wxID_UNDO, wxEmptyString, undo_bitmap, wxNullBitmap, wxITEM_NORMAL, "Undo", wxEmptyString, NULL); | |
| 66 | + | standard_toolbar->AddTool(wxID_REDO, wxEmptyString, redo_bitmap, wxNullBitmap, wxITEM_NORMAL, "Redo", wxEmptyString, NULL); | |
| 67 | + | standard_toolbar->AddSeparator(); | |
| 68 | + | standard_toolbar->AddTool(wxID_CUT, wxEmptyString, cut_bitmap, wxNullBitmap, wxITEM_NORMAL, "Cut", wxEmptyString, NULL); | |
| 69 | + | standard_toolbar->AddTool(wxID_COPY, wxEmptyString, copy_bitmap, wxNullBitmap, wxITEM_NORMAL, "Copy", wxEmptyString, NULL); | |
| 70 | + | standard_toolbar->AddTool(wxID_PASTE, wxEmptyString, paste_bitmap, wxNullBitmap, wxITEM_NORMAL, "Paste", wxEmptyString, NULL); | |
| 71 | + | standard_toolbar->Realize(); | |
| 72 | + | ||
| 73 | + | wxBitmap* border_bitmap = loadPNGFile(optional_border_small_png); | |
| 74 | + | wxBitmap* eraser_bitmap = loadPNGFile(eraser_small_png); | |
| 75 | + | wxBitmap pz_bitmap = wxArtProvider::GetBitmap(ART_PZ_BRUSH, wxART_TOOLBAR, icon_size); | |
| 76 | + | wxBitmap nopvp_bitmap = wxArtProvider::GetBitmap(ART_NOPVP_BRUSH, wxART_TOOLBAR, icon_size); | |
| 77 | + | wxBitmap nologout_bitmap = wxArtProvider::GetBitmap(ART_NOLOOUT_BRUSH, wxART_TOOLBAR, icon_size); | |
| 78 | + | wxBitmap pvp_bitmap = wxArtProvider::GetBitmap(ART_PVP_BRUSH, wxART_TOOLBAR, icon_size); | |
| 79 | + | wxBitmap normal_bitmap = wxArtProvider::GetBitmap(ART_DOOR_NORMAL_SMALL, wxART_TOOLBAR, icon_size); | |
| 80 | + | wxBitmap locked_bitmap = wxArtProvider::GetBitmap(ART_DOOR_LOCKED_SMALL, wxART_TOOLBAR, icon_size); | |
| 81 | + | wxBitmap magic_bitmap = wxArtProvider::GetBitmap(ART_DOOR_MAGIC_SMALL, wxART_TOOLBAR, icon_size); | |
| 82 | + | wxBitmap quest_bitmap = wxArtProvider::GetBitmap(ART_DOOR_QUEST_SMALL, wxART_TOOLBAR, icon_size); | |
| 83 | + | wxBitmap normal_alt_bitmap = wxArtProvider::GetBitmap(ART_DOOR_NORMAL_ALT_SMALL, wxART_TOOLBAR, icon_size); | |
| 84 | + | wxBitmap archway_bitmap = wxArtProvider::GetBitmap(ART_DOOR_ARCHWAY_SMALL, wxART_TOOLBAR, icon_size); | |
| 85 | + | ||
| 86 | + | wxBitmap* hatch_bitmap = loadPNGFile(window_hatch_small_png); | |
| 87 | + | wxBitmap* window_bitmap = loadPNGFile(window_normal_small_png); | |
| 88 | + | ||
| 89 | + | brushes_toolbar = newd wxAuiToolBar(parent, TOOLBAR_BRUSHES, wxDefaultPosition, wxDefaultSize, wxAUI_TB_DEFAULT_STYLE); | |
| 90 | + | brushes_toolbar->SetToolBitmapSize(icon_size); | |
| 91 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_OPTIONAL_BORDER_TOOL, wxEmptyString, *border_bitmap, wxNullBitmap, wxITEM_CHECK, "Border", wxEmptyString, NULL); | |
| 92 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_ERASER, wxEmptyString, *eraser_bitmap, wxNullBitmap, wxITEM_CHECK, "Eraser", wxEmptyString, NULL); | |
| 93 | + | brushes_toolbar->AddSeparator(); | |
| 94 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_PZ_TOOL, wxEmptyString, pz_bitmap, wxNullBitmap, wxITEM_CHECK, "Protected Zone", wxEmptyString, NULL); | |
| 95 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_NOPVP_TOOL, wxEmptyString, nopvp_bitmap, wxNullBitmap, wxITEM_CHECK, "No PvP Zone", wxEmptyString, NULL); | |
| 96 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_NOLOGOUT_TOOL, wxEmptyString, nologout_bitmap, wxNullBitmap, wxITEM_CHECK, "No Logout Zone", wxEmptyString, NULL); | |
| 97 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_PVPZONE_TOOL, wxEmptyString, pvp_bitmap, wxNullBitmap, wxITEM_CHECK, "PvP Zone", wxEmptyString, NULL); | |
| 98 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_ZONE_BRUSH, wxEmptyString, normal_bitmap, wxNullBitmap, wxITEM_CHECK, "Zone Brush", wxEmptyString, NULL); | |
| 99 | + | brushes_toolbar->AddSeparator(); | |
| 100 | + | ||
| 101 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_NORMAL_DOOR, wxEmptyString, normal_bitmap, wxNullBitmap, wxITEM_CHECK, "Normal Door", wxEmptyString, NULL); | |
| 102 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_LOCKED_DOOR, wxEmptyString, locked_bitmap, wxNullBitmap, wxITEM_CHECK, "Locked Door", wxEmptyString, NULL); | |
| 103 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_MAGIC_DOOR, wxEmptyString, magic_bitmap, wxNullBitmap, wxITEM_CHECK, "Magic Door", wxEmptyString, NULL); | |
| 104 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_QUEST_DOOR, wxEmptyString, quest_bitmap, wxNullBitmap, wxITEM_CHECK, "Quest Door", wxEmptyString, NULL); | |
| 105 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_NORMAL_ALT_DOOR, wxEmptyString, normal_alt_bitmap, wxNullBitmap, wxITEM_CHECK, "Normal Door (alt)", wxEmptyString, NULL); | |
| 106 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_ARCHWAY_DOOR, wxEmptyString, archway_bitmap, wxNullBitmap, wxITEM_CHECK, "Archway", wxEmptyString, NULL); | |
| 107 | + | brushes_toolbar->AddSeparator(); | |
| 108 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_HATCH_DOOR, wxEmptyString, *hatch_bitmap, wxNullBitmap, wxITEM_CHECK, "Hatch Window", wxEmptyString, NULL); | |
| 109 | + | brushes_toolbar->AddTool(PALETTE_TERRAIN_WINDOW_DOOR, wxEmptyString, *window_bitmap, wxNullBitmap, wxITEM_CHECK, "Window", wxEmptyString, NULL); | |
| 110 | + | brushes_toolbar->Realize(); | |
| 111 | + | ||
| 112 | + | wxBitmap go_bitmap = wxArtProvider::GetBitmap(ART_POSITION_GO, wxART_TOOLBAR, icon_size); | |
| 113 | + | ||
| 114 | + | position_toolbar = newd wxAuiToolBar(parent, TOOLBAR_POSITION, wxDefaultPosition, wxDefaultSize, wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_HORZ_TEXT); | |
| 115 | + | position_toolbar->SetToolBitmapSize(icon_size); | |
| 116 | + | x_control = newd NumberTextCtrl(position_toolbar, wxID_ANY, 0, 0, MAP_MAX_WIDTH, wxTE_PROCESS_ENTER, "X", wxDefaultPosition, FROM_DIP(parent, wxSize(60, 20))); | |
| 117 | + | x_control->SetToolTip("X Coordinate"); | |
| 118 | + | y_control = newd NumberTextCtrl(position_toolbar, wxID_ANY, 0, 0, MAP_MAX_HEIGHT, wxTE_PROCESS_ENTER, "Y", wxDefaultPosition, FROM_DIP(parent, wxSize(60, 20))); | |
| 119 | + | y_control->SetToolTip("Y Coordinate"); | |
| 120 | + | z_control = newd NumberTextCtrl(position_toolbar, wxID_ANY, 0, 0, MAP_MAX_LAYER, wxTE_PROCESS_ENTER, "Z", wxDefaultPosition, FROM_DIP(parent, wxSize(35, 20))); | |
| 121 | + | z_control->SetToolTip("Z Coordinate"); | |
| 122 | + | go_button = newd wxButton(position_toolbar, TOOLBAR_POSITION_GO, wxEmptyString, wxDefaultPosition, parent->FromDIP(wxSize(22, 20))); | |
| 123 | + | go_button->SetBitmap(go_bitmap); | |
| 124 | + | go_button->SetToolTip("Go To Position"); | |
| 125 | + | position_toolbar->AddControl(x_control); | |
| 126 | + | position_toolbar->AddControl(y_control); | |
| 127 | + | position_toolbar->AddControl(z_control); | |
| 128 | + | position_toolbar->AddControl(go_button); | |
| 129 | + | position_toolbar->Realize(); | |
| 130 | + | ||
| 131 | + | wxBitmap circular_bitmap = wxArtProvider::GetBitmap(ART_CIRCULAR, wxART_TOOLBAR, icon_size); | |
| 132 | + | wxBitmap rectangular_bitmap = wxArtProvider::GetBitmap(ART_RECTANGULAR, wxART_TOOLBAR, icon_size); | |
| 133 | + | wxBitmap size1_bitmap = wxArtProvider::GetBitmap(ART_RECTANGULAR_1, wxART_TOOLBAR, icon_size); | |
| 134 | + | wxBitmap size2_bitmap = wxArtProvider::GetBitmap(ART_RECTANGULAR_2, wxART_TOOLBAR, icon_size); | |
| 135 | + | wxBitmap size3_bitmap = wxArtProvider::GetBitmap(ART_RECTANGULAR_3, wxART_TOOLBAR, icon_size); | |
| 136 | + | wxBitmap size4_bitmap = wxArtProvider::GetBitmap(ART_RECTANGULAR_4, wxART_TOOLBAR, icon_size); | |
| 137 | + | wxBitmap size5_bitmap = wxArtProvider::GetBitmap(ART_RECTANGULAR_5, wxART_TOOLBAR, icon_size); | |
| 138 | + | wxBitmap size6_bitmap = wxArtProvider::GetBitmap(ART_RECTANGULAR_6, wxART_TOOLBAR, icon_size); | |
| 139 | + | wxBitmap size7_bitmap = wxArtProvider::GetBitmap(ART_RECTANGULAR_7, wxART_TOOLBAR, icon_size); | |
| 140 | + | ||
| 141 | + | sizes_toolbar = newd wxAuiToolBar(parent, TOOLBAR_SIZES, wxDefaultPosition, wxDefaultSize, wxAUI_TB_DEFAULT_STYLE); | |
| 142 | + | sizes_toolbar->SetToolBitmapSize(icon_size); | |
| 143 | + | sizes_toolbar->AddTool(TOOLBAR_SIZES_RECTANGULAR, wxEmptyString, rectangular_bitmap, wxNullBitmap, wxITEM_CHECK, "Rectangular Brush", wxEmptyString, NULL); | |
| 144 | + | sizes_toolbar->AddTool(TOOLBAR_SIZES_CIRCULAR, wxEmptyString, circular_bitmap, wxNullBitmap, wxITEM_CHECK, "Circular Brush", wxEmptyString, NULL); | |
| 145 | + | sizes_toolbar->AddSeparator(); | |
| 146 | + | sizes_toolbar->AddTool(TOOLBAR_SIZES_1, wxEmptyString, size1_bitmap, wxNullBitmap, wxITEM_CHECK, "Size 1", wxEmptyString, NULL); | |
| 147 | + | sizes_toolbar->AddTool(TOOLBAR_SIZES_2, wxEmptyString, size2_bitmap, wxNullBitmap, wxITEM_CHECK, "Size 2", wxEmptyString, NULL); | |
| 148 | + | sizes_toolbar->AddTool(TOOLBAR_SIZES_3, wxEmptyString, size3_bitmap, wxNullBitmap, wxITEM_CHECK, "Size 3", wxEmptyString, NULL); | |
| 149 | + | sizes_toolbar->AddTool(TOOLBAR_SIZES_4, wxEmptyString, size4_bitmap, wxNullBitmap, wxITEM_CHECK, "Size 4", wxEmptyString, NULL); | |
| 150 | + | sizes_toolbar->AddTool(TOOLBAR_SIZES_5, wxEmptyString, size5_bitmap, wxNullBitmap, wxITEM_CHECK, "Size 5", wxEmptyString, NULL); | |
| 151 | + | sizes_toolbar->AddTool(TOOLBAR_SIZES_6, wxEmptyString, size6_bitmap, wxNullBitmap, wxITEM_CHECK, "Size 6", wxEmptyString, NULL); | |
| 152 | + | sizes_toolbar->AddTool(TOOLBAR_SIZES_7, wxEmptyString, size7_bitmap, wxNullBitmap, wxITEM_CHECK, "Size 7", wxEmptyString, NULL); | |
| 153 | + | sizes_toolbar->Realize(); | |
| 154 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_RECTANGULAR, true); | |
| 155 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_1, true); | |
| 156 | + | ||
| 157 | + | manager->AddPane(standard_toolbar, wxAuiPaneInfo().Name(STANDARD_BAR_NAME).ToolbarPane().Top().Row(1).Position(1).Floatable(false)); | |
| 158 | + | manager->AddPane(brushes_toolbar, wxAuiPaneInfo().Name(BRUSHES_BAR_NAME).ToolbarPane().Top().Row(1).Position(2).Floatable(false)); | |
| 159 | + | manager->AddPane(position_toolbar, wxAuiPaneInfo().Name(POSITION_BAR_NAME).ToolbarPane().Top().Row(1).Position(4).Floatable(false)); | |
| 160 | + | manager->AddPane(sizes_toolbar, wxAuiPaneInfo().Name(SIZES_BAR_NAME).ToolbarPane().Top().Row(1).Position(3).Floatable(false)); | |
| 161 | + | ||
| 162 | + | standard_toolbar->Bind(wxEVT_COMMAND_MENU_SELECTED, &MainToolBar::OnStandardButtonClick, this); | |
| 163 | + | brushes_toolbar->Bind(wxEVT_COMMAND_MENU_SELECTED, &MainToolBar::OnBrushesButtonClick, this); | |
| 164 | + | x_control->Bind(wxEVT_TEXT_PASTE, &MainToolBar::OnPastePositionText, this); | |
| 165 | + | x_control->Bind(wxEVT_KEY_UP, &MainToolBar::OnPositionKeyUp, this); | |
| 166 | + | y_control->Bind(wxEVT_TEXT_PASTE, &MainToolBar::OnPastePositionText, this); | |
| 167 | + | y_control->Bind(wxEVT_KEY_UP, &MainToolBar::OnPositionKeyUp, this); | |
| 168 | + | z_control->Bind(wxEVT_TEXT_PASTE, &MainToolBar::OnPastePositionText, this); | |
| 169 | + | z_control->Bind(wxEVT_KEY_UP, &MainToolBar::OnPositionKeyUp, this); | |
| 170 | + | go_button->Bind(wxEVT_BUTTON, &MainToolBar::OnPositionButtonClick, this); | |
| 171 | + | sizes_toolbar->Bind(wxEVT_COMMAND_MENU_SELECTED, &MainToolBar::OnSizesButtonClick, this); | |
| 172 | + | ||
| 173 | + | HideAll(); | |
| 174 | + | } | |
| 175 | + | ||
| 176 | + | MainToolBar::~MainToolBar() { | |
| 177 | + | standard_toolbar->Unbind(wxEVT_COMMAND_MENU_SELECTED, &MainToolBar::OnStandardButtonClick, this); | |
| 178 | + | brushes_toolbar->Unbind(wxEVT_COMMAND_MENU_SELECTED, &MainToolBar::OnBrushesButtonClick, this); | |
| 179 | + | x_control->Unbind(wxEVT_TEXT_PASTE, &MainToolBar::OnPastePositionText, this); | |
| 180 | + | x_control->Unbind(wxEVT_KEY_UP, &MainToolBar::OnPositionKeyUp, this); | |
| 181 | + | y_control->Unbind(wxEVT_TEXT_PASTE, &MainToolBar::OnPastePositionText, this); | |
| 182 | + | y_control->Unbind(wxEVT_KEY_UP, &MainToolBar::OnPositionKeyUp, this); | |
| 183 | + | z_control->Unbind(wxEVT_TEXT_PASTE, &MainToolBar::OnPastePositionText, this); | |
| 184 | + | z_control->Unbind(wxEVT_KEY_UP, &MainToolBar::OnPositionKeyUp, this); | |
| 185 | + | go_button->Unbind(wxEVT_BUTTON, &MainToolBar::OnPositionButtonClick, this); | |
| 186 | + | sizes_toolbar->Unbind(wxEVT_COMMAND_MENU_SELECTED, &MainToolBar::OnSizesButtonClick, this); | |
| 187 | + | } | |
| 188 | + | ||
| 189 | + | void MainToolBar::UpdateButtons() { | |
| 190 | + | Editor* editor = g_gui.GetCurrentEditor(); | |
| 191 | + | if (editor) { | |
| 192 | + | standard_toolbar->EnableTool(wxID_UNDO, editor->actionQueue->canUndo()); | |
| 193 | + | standard_toolbar->EnableTool(wxID_REDO, editor->actionQueue->canRedo()); | |
| 194 | + | standard_toolbar->EnableTool(wxID_PASTE, editor->copybuffer.canPaste()); | |
| 195 | + | } else { | |
| 196 | + | standard_toolbar->EnableTool(wxID_UNDO, false); | |
| 197 | + | standard_toolbar->EnableTool(wxID_REDO, false); | |
| 198 | + | standard_toolbar->EnableTool(wxID_PASTE, false); | |
| 199 | + | } | |
| 200 | + | ||
| 201 | + | bool has_map = editor != nullptr; | |
| 202 | + | bool is_host = has_map && !editor->IsLiveClient(); | |
| 203 | + | ||
| 204 | + | standard_toolbar->EnableTool(wxID_SAVE, is_host); | |
| 205 | + | standard_toolbar->EnableTool(wxID_SAVEAS, is_host); | |
| 206 | + | standard_toolbar->EnableTool(wxID_CUT, has_map); | |
| 207 | + | standard_toolbar->EnableTool(wxID_COPY, has_map); | |
| 208 | + | ||
| 209 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_OPTIONAL_BORDER_TOOL, has_map); | |
| 210 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_ERASER, has_map); | |
| 211 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_PZ_TOOL, has_map); | |
| 212 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_NOPVP_TOOL, has_map); | |
| 213 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_NOLOGOUT_TOOL, has_map); | |
| 214 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_PVPZONE_TOOL, has_map); | |
| 215 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_ZONE_BRUSH, has_map); | |
| 216 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_NORMAL_DOOR, has_map); | |
| 217 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_LOCKED_DOOR, has_map); | |
| 218 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_MAGIC_DOOR, has_map); | |
| 219 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_QUEST_DOOR, has_map); | |
| 220 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_NORMAL_ALT_DOOR, has_map); | |
| 221 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_ARCHWAY_DOOR, has_map); | |
| 222 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_HATCH_DOOR, has_map); | |
| 223 | + | brushes_toolbar->EnableTool(PALETTE_TERRAIN_WINDOW_DOOR, has_map); | |
| 224 | + | ||
| 225 | + | position_toolbar->EnableTool(TOOLBAR_POSITION_GO, has_map); | |
| 226 | + | x_control->Enable(has_map); | |
| 227 | + | y_control->Enable(has_map); | |
| 228 | + | z_control->Enable(has_map); | |
| 229 | + | ||
| 230 | + | if (has_map) { | |
| 231 | + | x_control->SetMaxValue(editor->getMapWidth()); | |
| 232 | + | y_control->SetMaxValue(editor->getMapHeight()); | |
| 233 | + | } | |
| 234 | + | ||
| 235 | + | sizes_toolbar->EnableTool(TOOLBAR_SIZES_CIRCULAR, has_map); | |
| 236 | + | sizes_toolbar->EnableTool(TOOLBAR_SIZES_RECTANGULAR, has_map); | |
| 237 | + | sizes_toolbar->EnableTool(TOOLBAR_SIZES_1, has_map); | |
| 238 | + | sizes_toolbar->EnableTool(TOOLBAR_SIZES_2, has_map); | |
| 239 | + | sizes_toolbar->EnableTool(TOOLBAR_SIZES_3, has_map); | |
| 240 | + | sizes_toolbar->EnableTool(TOOLBAR_SIZES_4, has_map); | |
| 241 | + | sizes_toolbar->EnableTool(TOOLBAR_SIZES_5, has_map); | |
| 242 | + | sizes_toolbar->EnableTool(TOOLBAR_SIZES_6, has_map); | |
| 243 | + | sizes_toolbar->EnableTool(TOOLBAR_SIZES_7, has_map); | |
| 244 | + | } | |
| 245 | + | ||
| 246 | + | void MainToolBar::UpdateBrushButtons() { | |
| 247 | + | Brush* brush = g_gui.GetCurrentBrush(); | |
| 248 | + | if (brush) { | |
| 249 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_OPTIONAL_BORDER_TOOL, brush == g_gui.optional_brush); | |
| 250 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_ERASER, brush == g_gui.eraser); | |
| 251 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_PZ_TOOL, brush == g_gui.pz_brush); | |
| 252 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_NOPVP_TOOL, brush == g_gui.rook_brush); | |
| 253 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_NOLOGOUT_TOOL, brush == g_gui.nolog_brush); | |
| 254 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_PVPZONE_TOOL, brush == g_gui.pvp_brush); | |
| 255 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_ZONE_BRUSH, brush == g_gui.zone_brush); | |
| 256 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_NORMAL_DOOR, brush == g_gui.normal_door_brush); | |
| 257 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_LOCKED_DOOR, brush == g_gui.locked_door_brush); | |
| 258 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_MAGIC_DOOR, brush == g_gui.magic_door_brush); | |
| 259 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_QUEST_DOOR, brush == g_gui.quest_door_brush); | |
| 260 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_NORMAL_ALT_DOOR, brush == g_gui.normal_door_alt_brush); | |
| 261 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_ARCHWAY_DOOR, brush == g_gui.archway_door_brush); | |
| 262 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_HATCH_DOOR, brush == g_gui.hatch_door_brush); | |
| 263 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_WINDOW_DOOR, brush == g_gui.window_door_brush); | |
| 264 | + | } else { | |
| 265 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_OPTIONAL_BORDER_TOOL, false); | |
| 266 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_ERASER, false); | |
| 267 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_PZ_TOOL, false); | |
| 268 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_NOPVP_TOOL, false); | |
| 269 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_NOLOGOUT_TOOL, false); | |
| 270 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_PVPZONE_TOOL, false); | |
| 271 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_ZONE_BRUSH, false); | |
| 272 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_NORMAL_DOOR, false); | |
| 273 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_LOCKED_DOOR, false); | |
| 274 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_MAGIC_DOOR, false); | |
| 275 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_QUEST_DOOR, false); | |
| 276 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_NORMAL_ALT_DOOR, false); | |
| 277 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_ARCHWAY_DOOR, false); | |
| 278 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_HATCH_DOOR, false); | |
| 279 | + | brushes_toolbar->ToggleTool(PALETTE_TERRAIN_WINDOW_DOOR, false); | |
| 280 | + | } | |
| 281 | + | g_gui.GetAuiManager()->Update(); | |
| 282 | + | } | |
| 283 | + | ||
| 284 | + | void MainToolBar::UpdateBrushSize(BrushShape shape, int size) { | |
| 285 | + | if (shape == BRUSHSHAPE_CIRCLE) { | |
| 286 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_CIRCULAR, true); | |
| 287 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_RECTANGULAR, false); | |
| 288 | + | ||
| 289 | + | wxSize icon_size = wxSize(16, 16); | |
| 290 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_1, wxArtProvider::GetBitmap(ART_CIRCULAR_1, wxART_TOOLBAR, icon_size)); | |
| 291 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_2, wxArtProvider::GetBitmap(ART_CIRCULAR_2, wxART_TOOLBAR, icon_size)); | |
| 292 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_3, wxArtProvider::GetBitmap(ART_CIRCULAR_3, wxART_TOOLBAR, icon_size)); | |
| 293 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_4, wxArtProvider::GetBitmap(ART_CIRCULAR_4, wxART_TOOLBAR, icon_size)); | |
| 294 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_5, wxArtProvider::GetBitmap(ART_CIRCULAR_5, wxART_TOOLBAR, icon_size)); | |
| 295 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_6, wxArtProvider::GetBitmap(ART_CIRCULAR_6, wxART_TOOLBAR, icon_size)); | |
| 296 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_7, wxArtProvider::GetBitmap(ART_CIRCULAR_7, wxART_TOOLBAR, icon_size)); | |
| 297 | + | } else { | |
| 298 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_CIRCULAR, false); | |
| 299 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_RECTANGULAR, true); | |
| 300 | + | ||
| 301 | + | wxSize icon_size = wxSize(16, 16); | |
| 302 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_1, wxArtProvider::GetBitmap(ART_RECTANGULAR_1, wxART_TOOLBAR, icon_size)); | |
| 303 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_2, wxArtProvider::GetBitmap(ART_RECTANGULAR_2, wxART_TOOLBAR, icon_size)); | |
| 304 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_3, wxArtProvider::GetBitmap(ART_RECTANGULAR_3, wxART_TOOLBAR, icon_size)); | |
| 305 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_4, wxArtProvider::GetBitmap(ART_RECTANGULAR_4, wxART_TOOLBAR, icon_size)); | |
| 306 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_5, wxArtProvider::GetBitmap(ART_RECTANGULAR_5, wxART_TOOLBAR, icon_size)); | |
| 307 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_6, wxArtProvider::GetBitmap(ART_RECTANGULAR_6, wxART_TOOLBAR, icon_size)); | |
| 308 | + | sizes_toolbar->SetToolBitmap(TOOLBAR_SIZES_7, wxArtProvider::GetBitmap(ART_RECTANGULAR_7, wxART_TOOLBAR, icon_size)); | |
| 309 | + | } | |
| 310 | + | ||
| 311 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_1, size == 0); | |
| 312 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_2, size == 1); | |
| 313 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_3, size == 2); | |
| 314 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_4, size == 4); | |
| 315 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_5, size == 6); | |
| 316 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_6, size == 8); | |
| 317 | + | sizes_toolbar->ToggleTool(TOOLBAR_SIZES_7, size == 11); | |
| 318 | + | ||
| 319 | + | g_gui.GetAuiManager()->Update(); | |
| 320 | + | } | |
| 321 | + | ||
| 322 | + | void MainToolBar::Show(ToolBarID id, bool show) { | |
| 323 | + | wxAuiManager* manager = g_gui.GetAuiManager(); | |
| 324 | + | if (manager) { | |
| 325 | + | wxAuiPaneInfo& pane = GetPane(id); | |
| 326 | + | if (pane.IsOk()) { | |
| 327 | + | pane.Show(show); | |
| 328 | + | manager->Update(); | |
| 329 | + | } | |
| 330 | + | } | |
| 331 | + | } | |
| 332 | + | ||
| 333 | + | void MainToolBar::HideAll(bool update) { | |
| 334 | + | wxAuiManager* manager = g_gui.GetAuiManager(); | |
| 335 | + | if (!manager) { | |
| 336 | + | return; | |
| 337 | + | } | |
| 338 | + | ||
| 339 | + | wxAuiPaneInfoArray& panes = manager->GetAllPanes(); | |
| 340 | + | for (int i = 0, count = panes.GetCount(); i < count; ++i) { | |
| 341 | + | if (!panes.Item(i).IsToolbar()) { | |
| 342 | + | panes.Item(i).Hide(); | |
| 343 | + | } | |
| 344 | + | } | |
| 345 | + | ||
| 346 | + | if (update) { | |
| 347 | + | manager->Update(); | |
| 348 | + | } | |
| 349 | + | } | |
| 350 | + | ||
| 351 | + | void MainToolBar::LoadPerspective() { | |
| 352 | + | wxAuiManager* manager = g_gui.GetAuiManager(); | |
| 353 | + | if (!manager) { | |
| 354 | + | return; | |
| 355 | + | } | |
| 356 | + | ||
| 357 | + | if (g_settings.getBoolean(Config::SHOW_TOOLBAR_STANDARD)) { | |
| 358 | + | std::string info = g_settings.getString(Config::TOOLBAR_STANDARD_LAYOUT); | |
| 359 | + | if (!info.empty()) { | |
| 360 | + | manager->LoadPaneInfo(wxString(info), GetPane(TOOLBAR_STANDARD)); | |
| 361 | + | } | |
| 362 | + | GetPane(TOOLBAR_STANDARD).Show(); | |
| 363 | + | } else { | |
| 364 | + | GetPane(TOOLBAR_STANDARD).Hide(); | |
| 365 | + | } | |
| 366 | + | ||
| 367 | + | if (g_settings.getBoolean(Config::SHOW_TOOLBAR_BRUSHES)) { | |
| 368 | + | std::string info = g_settings.getString(Config::TOOLBAR_BRUSHES_LAYOUT); | |
| 369 | + | if (!info.empty()) { | |
| 370 | + | manager->LoadPaneInfo(wxString(info), GetPane(TOOLBAR_BRUSHES)); | |
| 371 | + | } | |
| 372 | + | GetPane(TOOLBAR_BRUSHES).Show(); | |
| 373 | + | } else { | |
| 374 | + | GetPane(TOOLBAR_BRUSHES).Hide(); | |
| 375 | + | } | |
| 376 | + | ||
| 377 | + | if (g_settings.getBoolean(Config::SHOW_TOOLBAR_POSITION)) { | |
| 378 | + | std::string info = g_settings.getString(Config::TOOLBAR_POSITION_LAYOUT); | |
| 379 | + | if (!info.empty()) { | |
| 380 | + | manager->LoadPaneInfo(wxString(info), GetPane(TOOLBAR_POSITION)); | |
| 381 | + | } | |
| 382 | + | GetPane(TOOLBAR_POSITION).Show(); | |
| 383 | + | } else { | |
| 384 | + | GetPane(TOOLBAR_POSITION).Hide(); | |
| 385 | + | } | |
| 386 | + | ||
| 387 | + | if (g_settings.getBoolean(Config::SHOW_TOOLBAR_SIZES)) { | |
| 388 | + | std::string info = g_settings.getString(Config::TOOLBAR_SIZES_LAYOUT); | |
| 389 | + | if (!info.empty()) { | |
| 390 | + | manager->LoadPaneInfo(wxString(info), GetPane(TOOLBAR_SIZES)); | |
| 391 | + | } | |
| 392 | + | GetPane(TOOLBAR_SIZES).Show(); | |
| 393 | + | } else { | |
| 394 | + | GetPane(TOOLBAR_SIZES).Hide(); | |
| 395 | + | } | |
| 396 | + | ||
| 397 | + | manager->Update(); | |
| 398 | + | } | |
| 399 | + | ||
| 400 | + | void MainToolBar::SavePerspective() { | |
| 401 | + | wxAuiManager* manager = g_gui.GetAuiManager(); | |
| 402 | + | if (!manager) { | |
| 403 | + | return; | |
| 404 | + | } | |
| 405 | + | ||
| 406 | + | if (g_settings.getBoolean(Config::SHOW_TOOLBAR_STANDARD)) { | |
| 407 | + | wxString info = manager->SavePaneInfo(GetPane(TOOLBAR_STANDARD)); | |
| 408 | + | g_settings.setString(Config::TOOLBAR_STANDARD_LAYOUT, info.ToStdString()); | |
| 409 | + | } | |
| 410 | + | ||
| 411 | + | if (g_settings.getBoolean(Config::SHOW_TOOLBAR_BRUSHES)) { | |
| 412 | + | wxString info = manager->SavePaneInfo(GetPane(TOOLBAR_BRUSHES)); | |
| 413 | + | g_settings.setString(Config::TOOLBAR_BRUSHES_LAYOUT, info.ToStdString()); | |
| 414 | + | } | |
| 415 | + | ||
| 416 | + | if (g_settings.getBoolean(Config::SHOW_TOOLBAR_POSITION)) { | |
| 417 | + | wxString info = manager->SavePaneInfo(GetPane(TOOLBAR_POSITION)); | |
| 418 | + | g_settings.setString(Config::TOOLBAR_POSITION_LAYOUT, info.ToStdString()); | |
| 419 | + | } | |
| 420 | + | ||
| 421 | + | if (g_settings.getBoolean(Config::SHOW_TOOLBAR_SIZES)) { | |
| 422 | + | wxString info = manager->SavePaneInfo(GetPane(TOOLBAR_SIZES)); | |
| 423 | + | g_settings.setString(Config::TOOLBAR_SIZES_LAYOUT, info.ToStdString()); | |
| 424 | + | } | |
| 425 | + | } | |
| 426 | + | ||
| 427 | + | void MainToolBar::OnStandardButtonClick(wxCommandEvent& event) { | |
| 428 | + | switch (event.GetId()) { | |
| 429 | + | case wxID_NEW: | |
| 430 | + | g_gui.NewMap(); | |
| 431 | + | break; | |
| 432 | + | case wxID_OPEN: | |
| 433 | + | g_gui.OpenMap(); | |
| 434 | + | break; | |
| 435 | + | case wxID_SAVE: | |
| 436 | + | g_gui.SaveMap(); | |
| 437 | + | break; | |
| 438 | + | case wxID_SAVEAS: | |
| 439 | + | g_gui.SaveMapAs(); | |
| 440 | + | break; | |
| 441 | + | case wxID_UNDO: | |
| 442 | + | g_gui.DoUndo(); | |
| 443 | + | break; | |
| 444 | + | case wxID_REDO: | |
| 445 | + | g_gui.DoRedo(); | |
| 446 | + | break; | |
| 447 | + | case wxID_CUT: | |
| 448 | + | g_gui.DoCut(); | |
| 449 | + | break; | |
| 450 | + | case wxID_COPY: | |
| 451 | + | g_gui.DoCopy(); | |
| 452 | + | break; | |
| 453 | + | case wxID_PASTE: | |
| 454 | + | g_gui.PreparePaste(); | |
| 455 | + | break; | |
| 456 | + | default: | |
| 457 | + | break; | |
| 458 | + | } | |
| 459 | + | } | |
| 460 | + | ||
| 461 | + | void MainToolBar::OnBrushesButtonClick(wxCommandEvent& event) { | |
| 462 | + | if (!g_gui.IsEditorOpen()) { | |
| 463 | + | return; | |
| 464 | + | } | |
| 465 | + | ||
| 466 | + | switch (event.GetId()) { | |
| 467 | + | case PALETTE_TERRAIN_OPTIONAL_BORDER_TOOL: | |
| 468 | + | g_gui.SelectBrush(g_gui.optional_brush); | |
| 469 | + | break; | |
| 470 | + | case PALETTE_TERRAIN_ERASER: | |
| 471 | + | g_gui.SelectBrush(g_gui.eraser); | |
| 472 | + | break; | |
| 473 | + | case PALETTE_TERRAIN_PZ_TOOL: | |
| 474 | + | g_gui.SelectBrush(g_gui.pz_brush); | |
| 475 | + | break; | |
| 476 | + | case PALETTE_TERRAIN_NOPVP_TOOL: | |
| 477 | + | g_gui.SelectBrush(g_gui.rook_brush); | |
| 478 | + | break; | |
| 479 | + | case PALETTE_TERRAIN_NOLOGOUT_TOOL: | |
| 480 | + | g_gui.SelectBrush(g_gui.nolog_brush); | |
| 481 | + | break; | |
| 482 | + | case PALETTE_TERRAIN_PVPZONE_TOOL: | |
| 483 | + | g_gui.SelectBrush(g_gui.pvp_brush); | |
| 484 | + | break; | |
| 485 | + | case PALETTE_TERRAIN_NORMAL_DOOR: | |
| 486 | + | g_gui.SelectBrush(g_gui.normal_door_brush); | |
| 487 | + | break; | |
| 488 | + | case PALETTE_TERRAIN_LOCKED_DOOR: | |
| 489 | + | g_gui.SelectBrush(g_gui.locked_door_brush); | |
| 490 | + | break; | |
| 491 | + | case PALETTE_TERRAIN_MAGIC_DOOR: | |
| 492 | + | g_gui.SelectBrush(g_gui.magic_door_brush); | |
| 493 | + | break; | |
| 494 | + | case PALETTE_TERRAIN_QUEST_DOOR: | |
| 495 | + | g_gui.SelectBrush(g_gui.quest_door_brush); | |
| 496 | + | break; | |
| 497 | + | case PALETTE_TERRAIN_NORMAL_ALT_DOOR: | |
| 498 | + | g_gui.SelectBrush(g_gui.normal_door_alt_brush); | |
| 499 | + | break; | |
| 500 | + | case PALETTE_TERRAIN_ARCHWAY_DOOR: | |
| 501 | + | g_gui.SelectBrush(g_gui.archway_door_brush); | |
| 502 | + | break; | |
| 503 | + | case PALETTE_TERRAIN_HATCH_DOOR: | |
| 504 | + | g_gui.SelectBrush(g_gui.hatch_door_brush); | |
| 505 | + | break; | |
| 506 | + | case PALETTE_TERRAIN_WINDOW_DOOR: | |
| 507 | + | g_gui.SelectBrush(g_gui.window_door_brush); | |
| 508 | + | break; | |
| 509 | + | case PALETTE_TERRAIN_ZONE_BRUSH: | |
| 510 | + | g_gui.SelectBrush(g_gui.zone_brush); | |
| 511 | + | break; | |
| 512 | + | default: | |
| 513 | + | break; | |
| 514 | + | } | |
| 515 | + | } | |
| 516 | + | ||
| 517 | + | void MainToolBar::OnPositionButtonClick(wxCommandEvent& event) { | |
| 518 | + | if (!g_gui.IsEditorOpen()) { | |
| 519 | + | return; | |
| 520 | + | } | |
| 521 | + | ||
| 522 | + | if (event.GetId() == TOOLBAR_POSITION_GO) { | |
| 523 | + | Position pos(x_control->GetIntValue(), y_control->GetIntValue(), z_control->GetIntValue()); | |
| 524 | + | if (pos.isValid()) { | |
| 525 | + | g_gui.SetScreenCenterPosition(pos); | |
| 526 | + | } | |
| 527 | + | } | |
| 528 | + | } | |
| 529 | + | ||
| 530 | + | void MainToolBar::OnPositionKeyUp(wxKeyEvent& event) { | |
| 531 | + | if (event.GetKeyCode() == WXK_TAB) { | |
| 532 | + | if (x_control->HasFocus()) { | |
| 533 | + | y_control->SelectAll(); | |
| 534 | + | y_control->SetFocus(); | |
| 535 | + | } else if (y_control->HasFocus()) { | |
| 536 | + | z_control->SelectAll(); | |
| 537 | + | z_control->SetFocus(); | |
| 538 | + | } else if (z_control->HasFocus()) { | |
| 539 | + | go_button->SetFocus(); | |
| 540 | + | } | |
| 541 | + | } else if (event.GetKeyCode() == WXK_NUMPAD_ENTER || event.GetKeyCode() == WXK_RETURN) { | |
| 542 | + | Position pos(x_control->GetIntValue(), y_control->GetIntValue(), z_control->GetIntValue()); | |
| 543 | + | if (pos.isValid()) { | |
| 544 | + | g_gui.SetScreenCenterPosition(pos); | |
| 545 | + | } | |
| 546 | + | } | |
| 547 | + | event.Skip(); | |
| 548 | + | } | |
| 549 | + | ||
| 550 | + | void MainToolBar::OnPastePositionText(wxClipboardTextEvent& event) { | |
| 551 | + | Position position; | |
| 552 | + | const Map& currentMap = g_gui.GetCurrentMap(); | |
| 553 | + | if (posFromClipboard(position, currentMap.getWidth(), currentMap.getHeight())) { | |
| 554 | + | x_control->SetIntValue(position.x); | |
| 555 | + | y_control->SetIntValue(position.y); | |
| 556 | + | z_control->SetIntValue(position.z); | |
| 557 | + | } else { | |
| 558 | + | event.Skip(); | |
| 559 | + | } | |
| 560 | + | } | |
| 561 | + | ||
| 562 | + | void MainToolBar::OnSizesButtonClick(wxCommandEvent& event) { | |
| 563 | + | if (!g_gui.IsEditorOpen()) { | |
| 564 | + | return; | |
| 565 | + | } | |
| 566 | + | ||
| 567 | + | switch (event.GetId()) { | |
| 568 | + | case TOOLBAR_SIZES_CIRCULAR: | |
| 569 | + | g_gui.SetBrushShape(BRUSHSHAPE_CIRCLE); | |
| 570 | + | break; | |
| 571 | + | case TOOLBAR_SIZES_RECTANGULAR: | |
| 572 | + | g_gui.SetBrushShape(BRUSHSHAPE_SQUARE); | |
| 573 | + | break; | |
| 574 | + | case TOOLBAR_SIZES_1: | |
| 575 | + | g_gui.SetBrushSize(0); | |
| 576 | + | break; | |
| 577 | + | case TOOLBAR_SIZES_2: | |
| 578 | + | g_gui.SetBrushSize(1); | |
| 579 | + | break; | |
| 580 | + | case TOOLBAR_SIZES_3: | |
| 581 | + | g_gui.SetBrushSize(2); | |
| 582 | + | break; | |
| 583 | + | case TOOLBAR_SIZES_4: | |
| 584 | + | g_gui.SetBrushSize(4); | |
| 585 | + | break; | |
| 586 | + | case TOOLBAR_SIZES_5: | |
| 587 | + | g_gui.SetBrushSize(6); | |
| 588 | + | break; | |
| 589 | + | case TOOLBAR_SIZES_6: | |
| 590 | + | g_gui.SetBrushSize(8); | |
| 591 | + | break; | |
| 592 | + | case TOOLBAR_SIZES_7: | |
| 593 | + | g_gui.SetBrushSize(11); | |
| 594 | + | break; | |
| 595 | + | default: | |
| 596 | + | break; | |
| 597 | + | } | |
| 598 | + | } | |
| 599 | + | ||
| 600 | + | wxAuiPaneInfo& MainToolBar::GetPane(ToolBarID id) { | |
| 601 | + | wxAuiManager* manager = g_gui.GetAuiManager(); | |
| 602 | + | if (!manager) { | |
| 603 | + | return wxAuiNullPaneInfo; | |
| 604 | + | } | |
| 605 | + | ||
| 606 | + | switch (id) { | |
| 607 | + | case TOOLBAR_STANDARD: | |
| 608 | + | return manager->GetPane(STANDARD_BAR_NAME); | |
| 609 | + | case TOOLBAR_BRUSHES: | |
| 610 | + | return manager->GetPane(BRUSHES_BAR_NAME); | |
| 611 | + | case TOOLBAR_POSITION: | |
| 612 | + | return manager->GetPane(POSITION_BAR_NAME); | |
| 613 | + | case TOOLBAR_SIZES: | |
| 614 | + | return manager->GetPane(SIZES_BAR_NAME); | |
| 615 | + | default: | |
| 616 | + | return wxAuiNullPaneInfo; | |
| 617 | + | } | |
| 618 | + | } | |
| 619 | + | ||
| 620 | + | void MainToolBar::RegisterHotkeys() { | |
| 621 | + | // Load hotkeys from menubar.xml | |
| 622 | + | pugi::xml_document doc; | |
| 623 | + | pugi::xml_parse_result result = doc.load_file("data/menubar.xml"); | |
| 624 | + | if (!result) { | |
| 625 | + | g_gui.PopupDialog("Error", "Could not load menubar.xml", wxOK); | |
| 626 | + | return; | |
| 627 | + | } | |
| 628 | + | ||
| 629 | + | pugi::xml_node menubar = doc.child("menubar"); | |
| 630 | + | if (!menubar) return; | |
| 631 | + | ||
| 632 | + | // Traverse all menu items and register their hotkeys | |
| 633 | + | for (pugi::xml_node menu = menubar.child("menu"); menu; menu = menu.next_sibling("menu")) { | |
| 634 | + | for (pugi::xml_node item = menu.child("item"); item; item = item.next_sibling("item")) { | |
| 635 | + | std::string hotkey = item.attribute("hotkey").as_string(); | |
| 636 | + | std::string action = item.attribute("action").as_string(); | |
| 637 | + | std::string help = item.attribute("help").as_string(); | |
| 638 | + | ||
| 639 | + | if (!hotkey.empty()) { | |
| 640 | + | g_hotkey_manager.RegisterHotkey(action, hotkey, help, [this, action]() { | |
| 641 | + | // Convert action to event ID and trigger it | |
| 642 | + | int eventId = g_gui.GetHotkeyEventId(action); | |
| 643 | + | if (eventId != -1) { | |
| 644 | + | wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, eventId); | |
| 645 | + | g_gui.root->GetEventHandler()->ProcessEvent(evt); | |
| 646 | + | } | |
| 647 | + | }); | |
| 648 | + | } | |
| 649 | + | } | |
| 650 | + | } | |
| 651 | + | ||
| 652 | + | // Register position dialog hotkey (moved from F3 to F4) | |
| 653 | + | g_hotkey_manager.RegisterHotkey("GOTO_POSITION", "F4", "Go to Position", [this]() { | |
| 654 | + | if (!g_gui.IsEditorOpen()) return; | |
| 655 | + | GotoPositionDialog dialog(g_gui.root, *g_gui.GetCurrentEditor()); | |
| 656 | + | dialog.ShowModal(); | |
| 657 | + | }); | |
| 658 | + | } |
| @@ -0,0 +1,66 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #ifndef RME_MAINTOOLBAR_H_ | |
| 19 | + | #define RME_MAINTOOLBAR_H_ | |
| 20 | + | ||
| 21 | + | #include <wx/wx.h> | |
| 22 | + | #include <wx/aui/aui.h> | |
| 23 | + | #include <wx/aui/auibar.h> | |
| 24 | + | ||
| 25 | + | #include "gui_ids.h" | |
| 26 | + | #include "numbertextctrl.h" | |
| 27 | + | ||
| 28 | + | class MainToolBar : public wxEvtHandler { | |
| 29 | + | public: | |
| 30 | + | MainToolBar(wxWindow* parent, wxAuiManager* manager); | |
| 31 | + | ~MainToolBar(); | |
| 32 | + | ||
| 33 | + | wxAuiPaneInfo& GetPane(ToolBarID id); | |
| 34 | + | void UpdateButtons(); | |
| 35 | + | void UpdateBrushButtons(); | |
| 36 | + | void UpdateBrushSize(BrushShape shape, int size); | |
| 37 | + | void Show(ToolBarID id, bool show); | |
| 38 | + | void HideAll(bool update = true); | |
| 39 | + | void LoadPerspective(); | |
| 40 | + | void SavePerspective(); | |
| 41 | + | void RegisterHotkeys(); | |
| 42 | + | ||
| 43 | + | void OnStandardButtonClick(wxCommandEvent& event); | |
| 44 | + | void OnBrushesButtonClick(wxCommandEvent& event); | |
| 45 | + | void OnPositionButtonClick(wxCommandEvent& event); | |
| 46 | + | void OnPositionKeyUp(wxKeyEvent& event); | |
| 47 | + | void OnPastePositionText(wxClipboardTextEvent& event); | |
| 48 | + | void OnSizesButtonClick(wxCommandEvent& event); | |
| 49 | + | ||
| 50 | + | private: | |
| 51 | + | static const wxString STANDARD_BAR_NAME; | |
| 52 | + | static const wxString BRUSHES_BAR_NAME; | |
| 53 | + | static const wxString POSITION_BAR_NAME; | |
| 54 | + | static const wxString SIZES_BAR_NAME; | |
| 55 | + | ||
| 56 | + | wxAuiToolBar* standard_toolbar; | |
| 57 | + | wxAuiToolBar* brushes_toolbar; | |
| 58 | + | wxAuiToolBar* position_toolbar; | |
| 59 | + | NumberTextCtrl* x_control; | |
| 60 | + | NumberTextCtrl* y_control; | |
| 61 | + | NumberTextCtrl* z_control; | |
| 62 | + | wxButton* go_button; | |
| 63 | + | wxAuiToolBar* sizes_toolbar; | |
| 64 | + | }; | |
| 65 | + | ||
| 66 | + | #endif // RME_MAINTOOLBAR_H_ |
| @@ -0,0 +1,918 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #include "main.h" | |
| 19 | + | ||
| 20 | + | #include "gui.h" // loadbar | |
| 21 | + | ||
| 22 | + | #include "map.h" | |
| 23 | + | ||
| 24 | + | #include <sstream> | |
| 25 | + | #include "string_utils.h" | |
| 26 | + | ||
| 27 | + | Map::Map() : | |
| 28 | + | BaseMap(), | |
| 29 | + | width(512), | |
| 30 | + | height(512), | |
| 31 | + | houses(*this), | |
| 32 | + | has_changed(false), | |
| 33 | + | unnamed(false), | |
| 34 | + | waypoints(*this) { | |
| 35 | + | // Earliest version possible | |
| 36 | + | // Caller is responsible for converting us to proper version | |
| 37 | + | mapVersion.otbm = MAP_OTBM_1; | |
| 38 | + | mapVersion.client = CLIENT_VERSION_NONE; | |
| 39 | + | } | |
| 40 | + | ||
| 41 | + | Map::~Map() { | |
| 42 | + | //// | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | bool Map::open(const std::string file) { | |
| 46 | + | if (file == filename) { | |
| 47 | + | return true; // Do not reopen ourselves! | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | tilecount = 0; | |
| 51 | + | ||
| 52 | + | IOMapOTBM maploader(getVersion()); | |
| 53 | + | ||
| 54 | + | bool success = maploader.loadMap(*this, wxstr(file)); | |
| 55 | + | ||
| 56 | + | mapVersion = maploader.version; | |
| 57 | + | ||
| 58 | + | warnings = maploader.getWarnings(); | |
| 59 | + | ||
| 60 | + | if (!success) { | |
| 61 | + | error = maploader.getError(); | |
| 62 | + | return false; | |
| 63 | + | } | |
| 64 | + | ||
| 65 | + | has_changed = false; | |
| 66 | + | ||
| 67 | + | wxFileName fn = wxstr(file); | |
| 68 | + | filename = fn.GetFullPath().mb_str(wxConvUTF8); | |
| 69 | + | name = fn.GetFullName().mb_str(wxConvUTF8); | |
| 70 | + | ||
| 71 | + | // convert(getReplacementMapClassic(), true); | |
| 72 | + | ||
| 73 | + | #if 0 // This will create a replacement map out of one of SO's template files | |
| 74 | + | std::ofstream out("templateshit.cpp"); | |
| 75 | + | out << "\tConversionMap replacement_map;\n"; | |
| 76 | + | int count = 0; | |
| 77 | + | out << "\tstd::vector<uint16_t> veckey, vecval;\n\n"; | |
| 78 | + | ||
| 79 | + | for(int x = 20; ; x += 2) { | |
| 80 | + | int y = 22; | |
| 81 | + | Tile* old = getTile(x, y, GROUND_LAYER); | |
| 82 | + | if(old) { | |
| 83 | + | y -= 2; | |
| 84 | + | Tile* new_ = getTile(x, y, GROUND_LAYER); | |
| 85 | + | if(new_) { | |
| 86 | + | if(old->ground || old->items.size()) { | |
| 87 | + | out << "\tvecval.clear();\n"; | |
| 88 | + | if(new_->ground) | |
| 89 | + | out << "\tvecval.push_back(" << new_->ground->getID() << ");\n"; | |
| 90 | + | for(ItemVector::iterator iter = new_->items.begin(); iter != new_->items.end(); ++iter) | |
| 91 | + | out << "\tvecval.push_back(" << (*iter)->getID() << ");\n"; | |
| 92 | + | ||
| 93 | + | if(old->ground && old->items.empty()) // Single item | |
| 94 | + | out << "\treplacement_map.stm[" << old->ground->getID() << "] = vecval;\n\n"; | |
| 95 | + | else if(old->ground == nullptr && old->items.size() == 1) // Single item | |
| 96 | + | out << "\treplacement_map.stm[" << old->items.front()->getID() << "] = vecval;\n\n"; | |
| 97 | + | else { | |
| 98 | + | // Many items | |
| 99 | + | out << "\tveckey.clear();\n"; | |
| 100 | + | if(old->ground) | |
| 101 | + | out << "\tveckey.push_back(" << old->ground->getID() << ");\n"; | |
| 102 | + | for(ItemVector::iterator iter = old->items.begin(); iter != old->items.end(); ++iter) | |
| 103 | + | out << "\tveckey.push_back(" << (*iter)->getID() << ");\n"; | |
| 104 | + | out << "\tstd::sort(veckey.begin(), veckey.end());\n"; | |
| 105 | + | out << "\treplacement_map.mtm[veckey] = vecval;\n\n"; | |
| 106 | + | } | |
| 107 | + | } | |
| 108 | + | } | |
| 109 | + | } else { | |
| 110 | + | break; | |
| 111 | + | } | |
| 112 | + | } | |
| 113 | + | out.close(); | |
| 114 | + | #endif | |
| 115 | + | return true; | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | bool Map::convert(MapVersion to, bool showdialog) { | |
| 119 | + | if (mapVersion.client == to.client) { | |
| 120 | + | // Only OTBM version differs | |
| 121 | + | // No changes necessary | |
| 122 | + | mapVersion = to; | |
| 123 | + | return true; | |
| 124 | + | } | |
| 125 | + | ||
| 126 | + | /* TODO | |
| 127 | + | ||
| 128 | + | if(to.otbm == MAP_OTBM_4 && to.client < CLIENT_VERSION_850) | |
| 129 | + | return false; | |
| 130 | + | ||
| 131 | + | if(mapVersion.client >= CLIENT_VERSION_760 && to.client < CLIENT_VERSION_760) | |
| 132 | + | convert(getReplacementMapFrom760To740(), showdialog); | |
| 133 | + | ||
| 134 | + | if(mapVersion.client < CLIENT_VERSION_810 && to.client >= CLIENT_VERSION_810) | |
| 135 | + | convert(getReplacementMapFrom800To810(), showdialog); | |
| 136 | + | ||
| 137 | + | if(mapVersion.client == CLIENT_VERSION_854_BAD && to.client >= CLIENT_VERSION_854) | |
| 138 | + | convert(getReplacementMapFrom854To854(), showdialog); | |
| 139 | + | */ | |
| 140 | + | mapVersion = to; | |
| 141 | + | ||
| 142 | + | return true; | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | bool Map::convert(const ConversionMap& rm, bool showdialog) { | |
| 146 | + | if (showdialog) { | |
| 147 | + | g_gui.CreateLoadBar("Converting map ..."); | |
| 148 | + | } | |
| 149 | + | ||
| 150 | + | uint64_t tiles_done = 0; | |
| 151 | + | std::vector<uint16_t> id_list; | |
| 152 | + | ||
| 153 | + | // std::ofstream conversions("converted_items.txt"); | |
| 154 | + | ||
| 155 | + | for (MapIterator miter = begin(); miter != end(); ++miter) { | |
| 156 | + | Tile* tile = (*miter)->get(); | |
| 157 | + | ASSERT(tile); | |
| 158 | + | ||
| 159 | + | if (tile->size() == 0) { | |
| 160 | + | continue; | |
| 161 | + | } | |
| 162 | + | ||
| 163 | + | // id_list try MTM conversion | |
| 164 | + | id_list.clear(); | |
| 165 | + | ||
| 166 | + | if (tile->ground) { | |
| 167 | + | id_list.push_back(tile->ground->getID()); | |
| 168 | + | } | |
| 169 | + | for (ItemVector::const_iterator item_iter = tile->items.begin(); item_iter != tile->items.end(); ++item_iter) { | |
| 170 | + | if ((*item_iter)->isBorder()) { | |
| 171 | + | id_list.push_back((*item_iter)->getID()); | |
| 172 | + | } | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | std::sort(id_list.begin(), id_list.end()); | |
| 176 | + | ||
| 177 | + | ConversionMap::MTM::const_iterator cfmtm = rm.mtm.end(); | |
| 178 | + | ||
| 179 | + | while (id_list.size()) { | |
| 180 | + | cfmtm = rm.mtm.find(id_list); | |
| 181 | + | if (cfmtm != rm.mtm.end()) { | |
| 182 | + | break; | |
| 183 | + | } | |
| 184 | + | id_list.pop_back(); | |
| 185 | + | } | |
| 186 | + | ||
| 187 | + | // Keep track of how many items have been inserted at the bottom | |
| 188 | + | size_t inserted_items = 0; | |
| 189 | + | ||
| 190 | + | if (cfmtm != rm.mtm.end()) { | |
| 191 | + | const std::vector<uint16_t>& v = cfmtm->first; | |
| 192 | + | ||
| 193 | + | if (tile->ground && std::find(v.begin(), v.end(), tile->ground->getID()) != v.end()) { | |
| 194 | + | delete tile->ground; | |
| 195 | + | tile->ground = nullptr; | |
| 196 | + | } | |
| 197 | + | ||
| 198 | + | for (ItemVector::iterator item_iter = tile->items.begin(); item_iter != tile->items.end();) { | |
| 199 | + | if (std::find(v.begin(), v.end(), (*item_iter)->getID()) != v.end()) { | |
| 200 | + | delete *item_iter; | |
| 201 | + | item_iter = tile->items.erase(item_iter); | |
| 202 | + | } else { | |
| 203 | + | ++item_iter; | |
| 204 | + | } | |
| 205 | + | } | |
| 206 | + | ||
| 207 | + | const std::vector<uint16_t>& new_items = cfmtm->second; | |
| 208 | + | for (std::vector<uint16_t>::const_iterator iit = new_items.begin(); iit != new_items.end(); ++iit) { | |
| 209 | + | Item* item = Item::Create(*iit); | |
| 210 | + | if (item->isGroundTile()) { | |
| 211 | + | tile->ground = item; | |
| 212 | + | } else { | |
| 213 | + | tile->items.insert(tile->items.begin(), item); | |
| 214 | + | ++inserted_items; | |
| 215 | + | } | |
| 216 | + | } | |
| 217 | + | } | |
| 218 | + | ||
| 219 | + | if (tile->ground) { | |
| 220 | + | ConversionMap::STM::const_iterator cfstm = rm.stm.find(tile->ground->getID()); | |
| 221 | + | if (cfstm != rm.stm.end()) { | |
| 222 | + | uint16_t aid = tile->ground->getActionID(); | |
| 223 | + | uint16_t uid = tile->ground->getUniqueID(); | |
| 224 | + | delete tile->ground; | |
| 225 | + | tile->ground = nullptr; | |
| 226 | + | ||
| 227 | + | const std::vector<uint16_t>& v = cfstm->second; | |
| 228 | + | // conversions << "Converted " << tile->getX() << ":" << tile->getY() << ":" << tile->getZ() << " " << id << " -> "; | |
| 229 | + | for (std::vector<uint16_t>::const_iterator iit = v.begin(); iit != v.end(); ++iit) { | |
| 230 | + | Item* item = Item::Create(*iit); | |
| 231 | + | // conversions << *iit << " "; | |
| 232 | + | if (item->isGroundTile()) { | |
| 233 | + | item->setActionID(aid); | |
| 234 | + | item->setUniqueID(uid); | |
| 235 | + | tile->addItem(item); | |
| 236 | + | } else { | |
| 237 | + | tile->items.insert(tile->items.begin(), item); | |
| 238 | + | ++inserted_items; | |
| 239 | + | } | |
| 240 | + | } | |
| 241 | + | // conversions << std::endl; | |
| 242 | + | } | |
| 243 | + | } | |
| 244 | + | ||
| 245 | + | for (ItemVector::iterator replace_item_iter = tile->items.begin() + inserted_items; replace_item_iter != tile->items.end();) { | |
| 246 | + | uint16_t id = (*replace_item_iter)->getID(); | |
| 247 | + | ConversionMap::STM::const_iterator cf = rm.stm.find(id); | |
| 248 | + | if (cf != rm.stm.end()) { | |
| 249 | + | // uint16_t aid = (*replace_item_iter)->getActionID(); | |
| 250 | + | // uint16_t uid = (*replace_item_iter)->getUniqueID(); | |
| 251 | + | delete *replace_item_iter; | |
| 252 | + | ||
| 253 | + | replace_item_iter = tile->items.erase(replace_item_iter); | |
| 254 | + | const std::vector<uint16_t>& v = cf->second; | |
| 255 | + | for (std::vector<uint16_t>::const_iterator iit = v.begin(); iit != v.end(); ++iit) { | |
| 256 | + | replace_item_iter = tile->items.insert(replace_item_iter, Item::Create(*iit)); | |
| 257 | + | // conversions << "Converted " << tile->getX() << ":" << tile->getY() << ":" << tile->getZ() << " " << id << " -> " << *iit << std::endl; | |
| 258 | + | ++replace_item_iter; | |
| 259 | + | } | |
| 260 | + | } else { | |
| 261 | + | ++replace_item_iter; | |
| 262 | + | } | |
| 263 | + | } | |
| 264 | + | ||
| 265 | + | ++tiles_done; | |
| 266 | + | if (showdialog && tiles_done % 0x10000 == 0) { | |
| 267 | + | g_gui.SetLoadDone(int(tiles_done / double(getTileCount()) * 100.0)); | |
| 268 | + | } | |
| 269 | + | } | |
| 270 | + | ||
| 271 | + | if (showdialog) { | |
| 272 | + | g_gui.DestroyLoadBar(); | |
| 273 | + | } | |
| 274 | + | ||
| 275 | + | return true; | |
| 276 | + | } | |
| 277 | + | ||
| 278 | + | void Map::cleanInvalidTiles(bool showdialog) { | |
| 279 | + | uint64_t tiles_done = 0; | |
| 280 | + | uint64_t removed_count = 0; | |
| 281 | + | bool has_invalid_tiles = false; | |
| 282 | + | ||
| 283 | + | // First check if there are any invalid tiles to remove | |
| 284 | + | for (MapIterator miter = begin(); miter != end(); ++miter) { | |
| 285 | + | Tile* tile = (*miter)->get(); | |
| 286 | + | if (!tile || tile->size() == 0) { | |
| 287 | + | continue; | |
| 288 | + | } | |
| 289 | + | ||
| 290 | + | for (ItemVector::iterator item_iter = tile->items.begin(); item_iter != tile->items.end(); ++item_iter) { | |
| 291 | + | if (!g_items.typeExists((*item_iter)->getID())) { | |
| 292 | + | has_invalid_tiles = true; | |
| 293 | + | break; | |
| 294 | + | } | |
| 295 | + | } | |
| 296 | + | ||
| 297 | + | if (has_invalid_tiles) { | |
| 298 | + | break; | |
| 299 | + | } | |
| 300 | + | } | |
| 301 | + | ||
| 302 | + | if (!has_invalid_tiles) { | |
| 303 | + | if (showdialog) { | |
| 304 | + | g_gui.SetLoadDone(100); | |
| 305 | + | g_gui.PopupDialog("Cleanup Complete", "No invalid tiles found.", wxOK); | |
| 306 | + | } | |
| 307 | + | return; | |
| 308 | + | } | |
| 309 | + | ||
| 310 | + | // Note: We don't create a loading bar here anymore, it should be created by the caller | |
| 311 | + | ||
| 312 | + | for (MapIterator miter = begin(); miter != end(); ++miter) { | |
| 313 | + | Tile* tile = (*miter)->get(); | |
| 314 | + | ASSERT(tile); | |
| 315 | + | ||
| 316 | + | if (tile->size() == 0) { | |
| 317 | + | continue; | |
| 318 | + | } | |
| 319 | + | ||
| 320 | + | for (ItemVector::iterator item_iter = tile->items.begin(); item_iter != tile->items.end();) { | |
| 321 | + | if (g_items.typeExists((*item_iter)->getID())) { | |
| 322 | + | ++item_iter; | |
| 323 | + | } else { | |
| 324 | + | delete *item_iter; | |
| 325 | + | item_iter = tile->items.erase(item_iter); | |
| 326 | + | ++removed_count; | |
| 327 | + | } | |
| 328 | + | } | |
| 329 | + | ||
| 330 | + | ++tiles_done; | |
| 331 | + | if (showdialog && tiles_done % 0x10000 == 0) { | |
| 332 | + | g_gui.SetLoadDone(int(tiles_done / double(getTileCount()) * 100.0)); | |
| 333 | + | } | |
| 334 | + | } | |
| 335 | + | ||
| 336 | + | if (showdialog) { | |
| 337 | + | g_gui.SetLoadDone(100); | |
| 338 | + | // Note: We don't destroy the loading bar here anymore, it should be destroyed by the caller | |
| 339 | + | g_gui.PopupDialog("Cleanup Complete", "Removed " + i2ws(removed_count) + " invalid tiles.", wxOK); | |
| 340 | + | } | |
| 341 | + | } | |
| 342 | + | ||
| 343 | + | void Map::convertHouseTiles(uint32_t fromId, uint32_t toId) { | |
| 344 | + | g_gui.CreateLoadBar("Converting house tiles..."); | |
| 345 | + | uint64_t tiles_done = 0; | |
| 346 | + | ||
| 347 | + | for (MapIterator miter = begin(); miter != end(); ++miter) { | |
| 348 | + | Tile* tile = (*miter)->get(); | |
| 349 | + | ASSERT(tile); | |
| 350 | + | ||
| 351 | + | uint32_t houseId = tile->getHouseID(); | |
| 352 | + | if (houseId == 0 || houseId != fromId) { | |
| 353 | + | continue; | |
| 354 | + | } | |
| 355 | + | ||
| 356 | + | tile->setHouseID(toId); | |
| 357 | + | ++tiles_done; | |
| 358 | + | if (tiles_done % 0x10000 == 0) { | |
| 359 | + | g_gui.SetLoadDone(int(tiles_done / double(getTileCount()) * 100.0)); | |
| 360 | + | } | |
| 361 | + | } | |
| 362 | + | ||
| 363 | + | g_gui.DestroyLoadBar(); | |
| 364 | + | } | |
| 365 | + | ||
| 366 | + | MapVersion Map::getVersion() const { | |
| 367 | + | return mapVersion; | |
| 368 | + | } | |
| 369 | + | ||
| 370 | + | bool Map::hasChanged() const { | |
| 371 | + | return has_changed; | |
| 372 | + | } | |
| 373 | + | ||
| 374 | + | bool Map::doChange() { | |
| 375 | + | bool doupdate = !has_changed; | |
| 376 | + | has_changed = true; | |
| 377 | + | return doupdate; | |
| 378 | + | } | |
| 379 | + | ||
| 380 | + | bool Map::clearChanges() { | |
| 381 | + | bool doupdate = has_changed; | |
| 382 | + | has_changed = false; | |
| 383 | + | return doupdate; | |
| 384 | + | } | |
| 385 | + | ||
| 386 | + | bool Map::hasFile() const { | |
| 387 | + | return filename != ""; | |
| 388 | + | } | |
| 389 | + | ||
| 390 | + | void Map::setWidth(int new_width) { | |
| 391 | + | if (new_width > 65000) { | |
| 392 | + | width = 65000; | |
| 393 | + | } else if (new_width < 64) { | |
| 394 | + | width = 64; | |
| 395 | + | } else { | |
| 396 | + | width = new_width; | |
| 397 | + | } | |
| 398 | + | } | |
| 399 | + | ||
| 400 | + | void Map::setHeight(int new_height) { | |
| 401 | + | if (new_height > 65000) { | |
| 402 | + | height = 65000; | |
| 403 | + | } else if (new_height < 64) { | |
| 404 | + | height = 64; | |
| 405 | + | } else { | |
| 406 | + | height = new_height; | |
| 407 | + | } | |
| 408 | + | } | |
| 409 | + | void Map::setMapDescription(const std::string& new_description) { | |
| 410 | + | description = new_description; | |
| 411 | + | } | |
| 412 | + | ||
| 413 | + | void Map::setHouseFilename(const std::string& new_housefile) { | |
| 414 | + | housefile = new_housefile; | |
| 415 | + | unnamed = false; | |
| 416 | + | } | |
| 417 | + | ||
| 418 | + | void Map::setSpawnFilename(const std::string& new_spawnfile) { | |
| 419 | + | spawnfile = new_spawnfile; | |
| 420 | + | unnamed = false; | |
| 421 | + | } | |
| 422 | + | ||
| 423 | + | bool Map::addSpawn(Tile* tile) { | |
| 424 | + | Spawn* spawn = tile->spawn; | |
| 425 | + | if (spawn) { | |
| 426 | + | int z = tile->getZ(); | |
| 427 | + | int start_x = tile->getX() - spawn->getSize(); | |
| 428 | + | int start_y = tile->getY() - spawn->getSize(); | |
| 429 | + | int end_x = tile->getX() + spawn->getSize(); | |
| 430 | + | int end_y = tile->getY() + spawn->getSize(); | |
| 431 | + | ||
| 432 | + | for (int y = start_y; y <= end_y; ++y) { | |
| 433 | + | for (int x = start_x; x <= end_x; ++x) { | |
| 434 | + | TileLocation* ctile_loc = createTileL(x, y, z); | |
| 435 | + | ctile_loc->increaseSpawnCount(); | |
| 436 | + | } | |
| 437 | + | } | |
| 438 | + | spawns.addSpawn(tile); | |
| 439 | + | return true; | |
| 440 | + | } | |
| 441 | + | return false; | |
| 442 | + | } | |
| 443 | + | ||
| 444 | + | void Map::removeSpawnInternal(Tile* tile) { | |
| 445 | + | Spawn* spawn = tile->spawn; | |
| 446 | + | ASSERT(spawn); | |
| 447 | + | ||
| 448 | + | int z = tile->getZ(); | |
| 449 | + | int start_x = tile->getX() - spawn->getSize(); | |
| 450 | + | int start_y = tile->getY() - spawn->getSize(); | |
| 451 | + | int end_x = tile->getX() + spawn->getSize(); | |
| 452 | + | int end_y = tile->getY() + spawn->getSize(); | |
| 453 | + | ||
| 454 | + | for (int y = start_y; y <= end_y; ++y) { | |
| 455 | + | for (int x = start_x; x <= end_x; ++x) { | |
| 456 | + | TileLocation* ctile_loc = getTileL(x, y, z); | |
| 457 | + | if (ctile_loc != nullptr && ctile_loc->getSpawnCount() > 0) { | |
| 458 | + | ctile_loc->decreaseSpawnCount(); | |
| 459 | + | } | |
| 460 | + | } | |
| 461 | + | } | |
| 462 | + | } | |
| 463 | + | ||
| 464 | + | void Map::removeSpawn(Tile* tile) { | |
| 465 | + | if (tile->spawn) { | |
| 466 | + | removeSpawnInternal(tile); | |
| 467 | + | spawns.removeSpawn(tile); | |
| 468 | + | } | |
| 469 | + | } | |
| 470 | + | ||
| 471 | + | SpawnList Map::getSpawnList(Tile* where) { | |
| 472 | + | SpawnList list; | |
| 473 | + | TileLocation* tile_loc = where->getLocation(); | |
| 474 | + | if (tile_loc) { | |
| 475 | + | if (tile_loc->getSpawnCount() > 0) { | |
| 476 | + | uint32_t found = 0; | |
| 477 | + | if (where->spawn) { | |
| 478 | + | ++found; | |
| 479 | + | list.push_back(where->spawn); | |
| 480 | + | } | |
| 481 | + | ||
| 482 | + | // Scans the border tiles in an expanding square around the original spawn | |
| 483 | + | int z = where->getZ(); | |
| 484 | + | int start_x = where->getX() - 1, end_x = where->getX() + 1; | |
| 485 | + | int start_y = where->getY() - 1, end_y = where->getY() + 1; | |
| 486 | + | while (found != tile_loc->getSpawnCount()) { | |
| 487 | + | for (int x = start_x; x <= end_x; ++x) { | |
| 488 | + | Tile* tile = getTile(x, start_y, z); | |
| 489 | + | if (tile && tile->spawn) { | |
| 490 | + | list.push_back(tile->spawn); | |
| 491 | + | ++found; | |
| 492 | + | } | |
| 493 | + | tile = getTile(x, end_y, z); | |
| 494 | + | if (tile && tile->spawn) { | |
| 495 | + | list.push_back(tile->spawn); | |
| 496 | + | ++found; | |
| 497 | + | } | |
| 498 | + | } | |
| 499 | + | ||
| 500 | + | for (int y = start_y + 1; y < end_y; ++y) { | |
| 501 | + | Tile* tile = getTile(start_x, y, z); | |
| 502 | + | if (tile && tile->spawn) { | |
| 503 | + | list.push_back(tile->spawn); | |
| 504 | + | ++found; | |
| 505 | + | } | |
| 506 | + | tile = getTile(end_x, y, z); | |
| 507 | + | if (tile && tile->spawn) { | |
| 508 | + | list.push_back(tile->spawn); | |
| 509 | + | ++found; | |
| 510 | + | } | |
| 511 | + | } | |
| 512 | + | --start_x, --start_y; | |
| 513 | + | ++end_x, ++end_y; | |
| 514 | + | } | |
| 515 | + | } | |
| 516 | + | } | |
| 517 | + | return list; | |
| 518 | + | } | |
| 519 | + | ||
| 520 | + | bool Map::exportMinimap(FileName filename, int floor, bool displaydialog) { | |
| 521 | + | uint8_t* pic = nullptr; | |
| 522 | + | ||
| 523 | + | try { | |
| 524 | + | const int MAX_AREA_SIZE = 2500; | |
| 525 | + | std::vector<std::pair<Position, Position>> initial_areas; | |
| 526 | + | std::map<uint32_t, bool> processed_tiles; | |
| 527 | + | ||
| 528 | + | // Helper function to get tile key | |
| 529 | + | auto getTileKey = [](int x, int y) -> uint32_t { | |
| 530 | + | return (uint32_t(x) << 16) | uint32_t(y); | |
| 531 | + | }; | |
| 532 | + | ||
| 533 | + | // Helper function to check if two areas can be merged within size limits | |
| 534 | + | auto canMergeAreas = [MAX_AREA_SIZE](const Position& min1, const Position& max1, | |
| 535 | + | const Position& min2, const Position& max2) -> bool { | |
| 536 | + | // Calculate combined bounds | |
| 537 | + | Position combined_min( | |
| 538 | + | std::min(min1.x, min2.x), | |
| 539 | + | std::min(min1.y, min2.y), | |
| 540 | + | min1.z | |
| 541 | + | ); | |
| 542 | + | Position combined_max( | |
| 543 | + | std::max(max1.x, max2.x), | |
| 544 | + | std::max(max1.y, max2.y), | |
| 545 | + | max1.z | |
| 546 | + | ); | |
| 547 | + | ||
| 548 | + | // Check if combined area is within limits | |
| 549 | + | return (combined_max.x - combined_min.x + 1 <= MAX_AREA_SIZE) && | |
| 550 | + | (combined_max.y - combined_min.y + 1 <= MAX_AREA_SIZE); | |
| 551 | + | }; | |
| 552 | + | ||
| 553 | + | // Helper function to check if areas are adjacent or close enough to merge | |
| 554 | + | auto areAreasNearby = [](const Position& max1, const Position& min2, | |
| 555 | + | const Position& min1, const Position& max2) -> bool { | |
| 556 | + | const int MERGE_DISTANCE = 1000; // Maximum distance to consider areas for merging | |
| 557 | + | ||
| 558 | + | // Check if areas are within merge distance of each other | |
| 559 | + | bool x_overlap = (min1.x <= max2.x + MERGE_DISTANCE) && (max1.x + MERGE_DISTANCE >= min2.x); | |
| 560 | + | bool y_overlap = (min1.y <= max2.y + MERGE_DISTANCE) && (max1.y + MERGE_DISTANCE >= min2.y); | |
| 561 | + | ||
| 562 | + | return x_overlap && y_overlap; | |
| 563 | + | }; | |
| 564 | + | ||
| 565 | + | // First pass - collect all initial areas using the existing flood fill | |
| 566 | + | std::vector<Position> tiles_on_floor; | |
| 567 | + | for (MapIterator mit = begin(); mit != end(); ++mit) { | |
| 568 | + | if ((*mit)->get() == nullptr || (*mit)->empty() || (*mit)->getZ() != floor) { | |
| 569 | + | continue; | |
| 570 | + | } | |
| 571 | + | tiles_on_floor.push_back((*mit)->getPosition()); | |
| 572 | + | } | |
| 573 | + | ||
| 574 | + | // Sort tiles for efficient processing | |
| 575 | + | std::sort(tiles_on_floor.begin(), tiles_on_floor.end(), | |
| 576 | + | [](const Position& a, const Position& b) { | |
| 577 | + | return a.x < b.x || (a.x == b.x && a.y < b.y); | |
| 578 | + | }); | |
| 579 | + | ||
| 580 | + | // Collect initial areas using flood fill | |
| 581 | + | for (const Position& pos : tiles_on_floor) { | |
| 582 | + | uint32_t tile_key = getTileKey(pos.x, pos.y); | |
| 583 | + | if (processed_tiles[tile_key]) { | |
| 584 | + | continue; | |
| 585 | + | } | |
| 586 | + | ||
| 587 | + | Position area_start = pos; | |
| 588 | + | Position area_end = pos; | |
| 589 | + | std::queue<Position> to_process; | |
| 590 | + | to_process.push(pos); | |
| 591 | + | processed_tiles[tile_key] = true; | |
| 592 | + | ||
| 593 | + | while (!to_process.empty()) { | |
| 594 | + | Position current = to_process.front(); | |
| 595 | + | to_process.pop(); | |
| 596 | + | ||
| 597 | + | if (area_end.x - area_start.x >= MAX_AREA_SIZE || | |
| 598 | + | area_end.y - area_start.y >= MAX_AREA_SIZE) { | |
| 599 | + | continue; | |
| 600 | + | } | |
| 601 | + | ||
| 602 | + | area_start.x = std::min(area_start.x, current.x); | |
| 603 | + | area_start.y = std::min(area_start.y, current.y); | |
| 604 | + | area_end.x = std::max(area_end.x, current.x); | |
| 605 | + | area_end.y = std::max(area_end.y, current.y); | |
| 606 | + | ||
| 607 | + | for (int dx = -1; dx <= 1; dx++) { | |
| 608 | + | for (int dy = -1; dy <= 1; dy++) { | |
| 609 | + | if (dx == 0 && dy == 0) continue; | |
| 610 | + | ||
| 611 | + | Position next(current.x + dx, current.y + dy, floor); | |
| 612 | + | uint32_t next_key = getTileKey(next.x, next.y); | |
| 613 | + | ||
| 614 | + | if (!processed_tiles[next_key]) { | |
| 615 | + | Tile* next_tile = getTile(next); | |
| 616 | + | if (next_tile && !next_tile->empty()) { | |
| 617 | + | to_process.push(next); | |
| 618 | + | processed_tiles[next_key] = true; | |
| 619 | + | } | |
| 620 | + | } | |
| 621 | + | } | |
| 622 | + | } | |
| 623 | + | } | |
| 624 | + | ||
| 625 | + | // Add the area if it contains content | |
| 626 | + | bool has_content = false; | |
| 627 | + | for (int y = area_start.y; y <= area_end.y && !has_content; y++) { | |
| 628 | + | for (int x = area_start.x; x <= area_end.x && !has_content; x++) { | |
| 629 | + | Tile* tile = getTile(x, y, floor); | |
| 630 | + | if (tile && !tile->empty()) { | |
| 631 | + | has_content = true; | |
| 632 | + | } | |
| 633 | + | } | |
| 634 | + | } | |
| 635 | + | if (has_content) { | |
| 636 | + | initial_areas.push_back(std::make_pair(area_start, area_end)); | |
| 637 | + | } | |
| 638 | + | } | |
| 639 | + | ||
| 640 | + | // Second pass - merge nearby areas into larger areas while respecting size limits | |
| 641 | + | std::vector<std::pair<Position, Position>> merged_areas; | |
| 642 | + | std::vector<bool> area_processed(initial_areas.size(), false); | |
| 643 | + | ||
| 644 | + | for (size_t i = 0; i < initial_areas.size(); i++) { | |
| 645 | + | if (area_processed[i]) continue; | |
| 646 | + | ||
| 647 | + | Position current_min = initial_areas[i].first; | |
| 648 | + | Position current_max = initial_areas[i].second; | |
| 649 | + | area_processed[i] = true; | |
| 650 | + | ||
| 651 | + | bool merged; | |
| 652 | + | do { | |
| 653 | + | merged = false; | |
| 654 | + | for (size_t j = 0; j < initial_areas.size(); j++) { | |
| 655 | + | if (area_processed[j]) continue; | |
| 656 | + | ||
| 657 | + | const auto& area2 = initial_areas[j]; | |
| 658 | + | if (canMergeAreas(current_min, current_max, area2.first, area2.second) && | |
| 659 | + | areAreasNearby(current_max, area2.first, current_min, area2.second)) { | |
| 660 | + | ||
| 661 | + | // Merge the areas | |
| 662 | + | current_min.x = std::min(current_min.x, area2.first.x); | |
| 663 | + | current_min.y = std::min(current_min.y, area2.first.y); | |
| 664 | + | current_max.x = std::max(current_max.x, area2.second.x); | |
| 665 | + | current_max.y = std::max(current_max.y, area2.second.y); | |
| 666 | + | ||
| 667 | + | area_processed[j] = true; | |
| 668 | + | merged = true; | |
| 669 | + | } | |
| 670 | + | } | |
| 671 | + | } while (merged); | |
| 672 | + | ||
| 673 | + | merged_areas.push_back(std::make_pair(current_min, current_max)); | |
| 674 | + | } | |
| 675 | + | ||
| 676 | + | // No areas found | |
| 677 | + | if (merged_areas.empty()) { | |
| 678 | + | return true; | |
| 679 | + | } | |
| 680 | + | ||
| 681 | + | // Export each merged area | |
| 682 | + | int area_count = 0; | |
| 683 | + | for (const auto& area : merged_areas) { | |
| 684 | + | Position min_pos = area.first; | |
| 685 | + | Position max_pos = area.second; | |
| 686 | + | ||
| 687 | + | // Add small padding but respect MAX_AREA_SIZE | |
| 688 | + | min_pos.x = std::max(0, min_pos.x - 5); | |
| 689 | + | min_pos.y = std::max(0, min_pos.y - 5); | |
| 690 | + | max_pos.x = std::min(65535, max_pos.x + 5); | |
| 691 | + | max_pos.y = std::min(65535, max_pos.y + 5); | |
| 692 | + | ||
| 693 | + | // Ensure we don't exceed MAX_AREA_SIZE | |
| 694 | + | if (max_pos.x - min_pos.x + 1 > MAX_AREA_SIZE) { | |
| 695 | + | max_pos.x = min_pos.x + MAX_AREA_SIZE - 1; | |
| 696 | + | } | |
| 697 | + | if (max_pos.y - min_pos.y + 1 > MAX_AREA_SIZE) { | |
| 698 | + | max_pos.y = min_pos.y + MAX_AREA_SIZE - 1; | |
| 699 | + | } | |
| 700 | + | ||
| 701 | + | // Calculate dimensions | |
| 702 | + | int minimap_width = max_pos.x - min_pos.x + 1; | |
| 703 | + | int minimap_height = max_pos.y - min_pos.y + 1; | |
| 704 | + | ||
| 705 | + | // Allocate memory for the bitmap | |
| 706 | + | pic = newd uint8_t[minimap_width * minimap_height]; | |
| 707 | + | memset(pic, 0, minimap_width * minimap_height); | |
| 708 | + | ||
| 709 | + | // Fill the bitmap | |
| 710 | + | for (int y = min_pos.y; y <= max_pos.y; y++) { | |
| 711 | + | for (int x = min_pos.x; x <= max_pos.x; x++) { | |
| 712 | + | Tile* tile = getTile(x, y, floor); | |
| 713 | + | if (!tile || tile->empty()) { | |
| 714 | + | continue; | |
| 715 | + | } | |
| 716 | + | ||
| 717 | + | uint32_t pixelpos = (y - min_pos.y) * minimap_width + (x - min_pos.x); | |
| 718 | + | uint8_t& pixel = pic[pixelpos]; | |
| 719 | + | ||
| 720 | + | // Get color from items | |
| 721 | + | for (ItemVector::const_reverse_iterator item_iter = tile->items.rbegin(); | |
| 722 | + | item_iter != tile->items.rend(); ++item_iter) { | |
| 723 | + | if ((*item_iter)->getMiniMapColor()) { | |
| 724 | + | pixel = (*item_iter)->getMiniMapColor(); | |
| 725 | + | break; | |
| 726 | + | } | |
| 727 | + | } | |
| 728 | + | ||
| 729 | + | // If no item color, check ground | |
| 730 | + | if (pixel == 0 && tile->hasGround()) { | |
| 731 | + | pixel = tile->ground->getMiniMapColor(); | |
| 732 | + | } | |
| 733 | + | } | |
| 734 | + | } | |
| 735 | + | ||
| 736 | + | // Generate filename for this area | |
| 737 | + | wxString base_name = filename.GetFullPath(); | |
| 738 | + | base_name = base_name.BeforeLast('.'); | |
| 739 | + | wxString area_filename = wxString::Format("%s_area%d.bmp", base_name, area_count++); | |
| 740 | + | ||
| 741 | + | // Write to file | |
| 742 | + | FileWriteHandle fh(nstr(area_filename)); | |
| 743 | + | if (!fh.isOpen()) { | |
| 744 | + | delete[] pic; | |
| 745 | + | return false; | |
| 746 | + | } | |
| 747 | + | ||
| 748 | + | // Store the magic number | |
| 749 | + | fh.addRAW("BM"); | |
| 750 | + | ||
| 751 | + | // Store the file size | |
| 752 | + | uint32_t file_size = 14 // header | |
| 753 | + | + 40 // image data header | |
| 754 | + | + 256 * 4 // color palette | |
| 755 | + | + ((minimap_width + 3) / 4 * 4) * minimap_height; // pixels | |
| 756 | + | fh.addU32(file_size); | |
| 757 | + | ||
| 758 | + | // Two values reserved, must always be 0. | |
| 759 | + | fh.addU16(0); | |
| 760 | + | fh.addU16(0); | |
| 761 | + | ||
| 762 | + | // Bitmapdata offset | |
| 763 | + | fh.addU32(14 + 40 + 256 * 4); | |
| 764 | + | ||
| 765 | + | // Header size | |
| 766 | + | fh.addU32(40); | |
| 767 | + | ||
| 768 | + | // Header width/height | |
| 769 | + | fh.addU32(minimap_width); | |
| 770 | + | fh.addU32(minimap_height); | |
| 771 | + | ||
| 772 | + | // Color planes | |
| 773 | + | fh.addU16(1); | |
| 774 | + | ||
| 775 | + | // bits per pixel, OT map format is 8 | |
| 776 | + | fh.addU16(8); | |
| 777 | + | ||
| 778 | + | // compression type, 0 is no compression | |
| 779 | + | fh.addU32(0); | |
| 780 | + | ||
| 781 | + | // image size, 0 is valid if we use no compression | |
| 782 | + | fh.addU32(0); | |
| 783 | + | ||
| 784 | + | // horizontal/vertical resolution in pixels / meter | |
| 785 | + | fh.addU32(4000); | |
| 786 | + | fh.addU32(4000); | |
| 787 | + | ||
| 788 | + | // Number of colors | |
| 789 | + | fh.addU32(256); | |
| 790 | + | // Important colors, 0 is all | |
| 791 | + | fh.addU32(0); | |
| 792 | + | ||
| 793 | + | // Write the color palette | |
| 794 | + | for (int i = 0; i < 256; ++i) { | |
| 795 | + | fh.addU32(uint32_t(minimap_color[i])); | |
| 796 | + | } | |
| 797 | + | ||
| 798 | + | // Bitmap width must be divisible by four, calculate how much padding we need | |
| 799 | + | int padding = ((minimap_width & 3) != 0 ? 4 - (minimap_width & 3) : 0); | |
| 800 | + | // Bitmap rows are saved in reverse order | |
| 801 | + | for (int y = minimap_height - 1; y >= 0; --y) { | |
| 802 | + | fh.addRAW(pic + y * minimap_width, minimap_width); | |
| 803 | + | for (int i = 0; i < padding; ++i) { | |
| 804 | + | fh.addU8(0); | |
| 805 | + | } | |
| 806 | + | if (displaydialog && y % 100 == 0) { | |
| 807 | + | g_gui.SetLoadDone(90 + int((minimap_height - y) / double(minimap_height) * 10.0)); | |
| 808 | + | } | |
| 809 | + | } | |
| 810 | + | ||
| 811 | + | delete[] pic; | |
| 812 | + | pic = nullptr; | |
| 813 | + | } | |
| 814 | + | ||
| 815 | + | return true; | |
| 816 | + | } catch (...) { | |
| 817 | + | delete[] pic; | |
| 818 | + | throw; | |
| 819 | + | } | |
| 820 | + | } | |
| 821 | + | ||
| 822 | + | uint32_t Map::cleanDuplicateItems(const std::vector<std::pair<uint16_t, uint16_t>>& ranges, const PropertyFlags& flags) { | |
| 823 | + | uint32_t duplicates_removed = 0; | |
| 824 | + | uint32_t tiles_affected = 0; | |
| 825 | + | ||
| 826 | + | // Helper function to check if item is in ranges | |
| 827 | + | auto isInRanges = [&ranges](uint16_t id) -> bool { | |
| 828 | + | if (ranges.empty()) return true; // If no ranges, check all items | |
| 829 | + | for (const auto& range : ranges) { | |
| 830 | + | if (id >= range.first && id <= range.second) return true; | |
| 831 | + | } | |
| 832 | + | return false; | |
| 833 | + | }; | |
| 834 | + | ||
| 835 | + | // Helper function to compare items considering property flags | |
| 836 | + | auto compareItems = [&flags](Item* item1, Item* item2) -> bool { | |
| 837 | + | if (item1->getID() != item2->getID()) return false; | |
| 838 | + | ||
| 839 | + | const ItemType& type1 = g_items[item1->getID()]; | |
| 840 | + | const ItemType& type2 = g_items[item2->getID()]; | |
| 841 | + | ||
| 842 | + | // If a flag is true (checked), we treat items with that property as different | |
| 843 | + | // even if they have the same value for that property | |
| 844 | + | if (flags.ignore_unpassable && (type1.unpassable || type2.unpassable)) return false; | |
| 845 | + | if (flags.ignore_unmovable && (type1.moveable || type2.moveable)) return false; | |
| 846 | + | if (flags.ignore_block_missiles && (type1.blockMissiles || type2.blockMissiles)) return false; | |
| 847 | + | if (flags.ignore_block_pathfinder && (type1.blockPathfinder || type2.blockPathfinder)) return false; | |
| 848 | + | if (flags.ignore_readable && (type1.canReadText || type2.canReadText)) return false; | |
| 849 | + | if (flags.ignore_writeable && (type1.canWriteText || type2.canWriteText)) return false; | |
| 850 | + | if (flags.ignore_pickupable && (type1.pickupable || type2.pickupable)) return false; | |
| 851 | + | if (flags.ignore_stackable && (type1.stackable || type2.stackable)) return false; | |
| 852 | + | if (flags.ignore_rotatable && (type1.rotable || type2.rotable)) return false; | |
| 853 | + | if (flags.ignore_hangable && (type1.isHangable || type2.isHangable)) return false; | |
| 854 | + | if (flags.ignore_hook_east && (type1.hookEast || type2.hookEast)) return false; | |
| 855 | + | if (flags.ignore_hook_south && (type1.hookSouth || type2.hookSouth)) return false; | |
| 856 | + | if (flags.ignore_elevation && (type1.hasElevation || type2.hasElevation)) return false; | |
| 857 | + | ||
| 858 | + | return true; | |
| 859 | + | }; | |
| 860 | + | ||
| 861 | + | for (MapIterator mit = begin(); mit != end(); ++mit) { | |
| 862 | + | Tile* tile = (*mit)->get(); | |
| 863 | + | if (!tile) continue; | |
| 864 | + | ||
| 865 | + | bool tile_modified = false; | |
| 866 | + | std::set<Item*> kept_items; // Track first instances | |
| 867 | + | ||
| 868 | + | // First pass: identify items to keep | |
| 869 | + | for (Item* item : tile->items) { | |
| 870 | + | if (!isInRanges(item->getID())) continue; | |
| 871 | + | ||
| 872 | + | bool is_duplicate = false; | |
| 873 | + | for (Item* kept : kept_items) { | |
| 874 | + | if (compareItems(item, kept)) { | |
| 875 | + | is_duplicate = true; | |
| 876 | + | break; | |
| 877 | + | } | |
| 878 | + | } | |
| 879 | + | ||
| 880 | + | if (!is_duplicate) { | |
| 881 | + | kept_items.insert(item); | |
| 882 | + | } | |
| 883 | + | } | |
| 884 | + | ||
| 885 | + | // Second pass: remove duplicates | |
| 886 | + | auto iit = tile->items.begin(); | |
| 887 | + | while (iit != tile->items.end()) { | |
| 888 | + | Item* item = *iit; | |
| 889 | + | if (!isInRanges(item->getID())) { | |
| 890 | + | ++iit; | |
| 891 | + | continue; | |
| 892 | + | } | |
| 893 | + | ||
| 894 | + | bool should_remove = true; | |
| 895 | + | for (Item* kept : kept_items) { | |
| 896 | + | if (item == kept) { | |
| 897 | + | should_remove = false; | |
| 898 | + | break; | |
| 899 | + | } | |
| 900 | + | } | |
| 901 | + | ||
| 902 | + | if (should_remove) { | |
| 903 | + | delete item; | |
| 904 | + | iit = tile->items.erase(iit); | |
| 905 | + | duplicates_removed++; | |
| 906 | + | tile_modified = true; | |
| 907 | + | } else { | |
| 908 | + | ++iit; | |
| 909 | + | } | |
| 910 | + | } | |
| 911 | + | ||
| 912 | + | if (tile_modified) { | |
| 913 | + | tiles_affected++; | |
| 914 | + | } | |
| 915 | + | } | |
| 916 | + | ||
| 917 | + | return duplicates_removed; | |
| 918 | + | } |
| @@ -0,0 +1,342 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #ifndef RME_MAP_H_ | |
| 19 | + | #define RME_MAP_H_ | |
| 20 | + | ||
| 21 | + | #include "basemap.h" | |
| 22 | + | #include "tile.h" | |
| 23 | + | #include "town.h" | |
| 24 | + | #include "house.h" | |
| 25 | + | #include "spawn.h" | |
| 26 | + | #include "complexitem.h" | |
| 27 | + | #include "waypoints.h" | |
| 28 | + | #include "templates.h" | |
| 29 | + | ||
| 30 | + | // Add this struct before the Map class definition | |
| 31 | + | struct PropertyFlags { | |
| 32 | + | bool ignore_unpassable; | |
| 33 | + | bool ignore_unmovable; | |
| 34 | + | bool ignore_block_missiles; | |
| 35 | + | bool ignore_block_pathfinder; | |
| 36 | + | bool ignore_readable; | |
| 37 | + | bool ignore_writeable; | |
| 38 | + | bool ignore_pickupable; | |
| 39 | + | bool ignore_stackable; | |
| 40 | + | bool ignore_rotatable; | |
| 41 | + | bool ignore_hangable; | |
| 42 | + | bool ignore_hook_east; | |
| 43 | + | bool ignore_hook_south; | |
| 44 | + | bool ignore_elevation; | |
| 45 | + | ||
| 46 | + | // Constructor with default values | |
| 47 | + | PropertyFlags( | |
| 48 | + | bool unpassable = false, | |
| 49 | + | bool unmovable = false, | |
| 50 | + | bool block_missiles = false, | |
| 51 | + | bool block_pathfinder = false, | |
| 52 | + | bool readable = false, | |
| 53 | + | bool writeable = false, | |
| 54 | + | bool pickupable = false, | |
| 55 | + | bool stackable = false, | |
| 56 | + | bool rotatable = false, | |
| 57 | + | bool hangable = false, | |
| 58 | + | bool hook_east = false, | |
| 59 | + | bool hook_south = false, | |
| 60 | + | bool elevation = false | |
| 61 | + | ) : | |
| 62 | + | ignore_unpassable(unpassable), | |
| 63 | + | ignore_unmovable(unmovable), | |
| 64 | + | ignore_block_missiles(block_missiles), | |
| 65 | + | ignore_block_pathfinder(block_pathfinder), | |
| 66 | + | ignore_readable(readable), | |
| 67 | + | ignore_writeable(writeable), | |
| 68 | + | ignore_pickupable(pickupable), | |
| 69 | + | ignore_stackable(stackable), | |
| 70 | + | ignore_rotatable(rotatable), | |
| 71 | + | ignore_hangable(hangable), | |
| 72 | + | ignore_hook_east(hook_east), | |
| 73 | + | ignore_hook_south(hook_south), | |
| 74 | + | ignore_elevation(elevation) | |
| 75 | + | {} | |
| 76 | + | }; | |
| 77 | + | ||
| 78 | + | class Map : public BaseMap { | |
| 79 | + | public: | |
| 80 | + | // ctor and dtor | |
| 81 | + | Map(); | |
| 82 | + | virtual ~Map(); | |
| 83 | + | ||
| 84 | + | // Operations on the entire map | |
| 85 | + | void cleanInvalidTiles(bool showdialog = false); | |
| 86 | + | void convertHouseTiles(uint32_t fromId, uint32_t toId); | |
| 87 | + | ||
| 88 | + | // Save a bmp image of the minimap | |
| 89 | + | bool exportMinimap(FileName filename, int floor = GROUND_LAYER, bool showdialog = false); | |
| 90 | + | // | |
| 91 | + | bool convert(MapVersion to, bool showdialog = false); | |
| 92 | + | bool convert(const ConversionMap& cm, bool showdialog = false); | |
| 93 | + | ||
| 94 | + | // Query information about the map | |
| 95 | + | ||
| 96 | + | MapVersion getVersion() const; | |
| 97 | + | // Returns true if any change has been done since last save | |
| 98 | + | bool hasChanged() const; | |
| 99 | + | // Makes a change, doesn't matter what. Just so that it asks when saving (Also adds a * to the window title) | |
| 100 | + | bool doChange(); | |
| 101 | + | // Clears any changes | |
| 102 | + | bool clearChanges(); | |
| 103 | + | ||
| 104 | + | // Errors/warnings | |
| 105 | + | bool hasWarnings() const { | |
| 106 | + | return warnings.size() != 0; | |
| 107 | + | } | |
| 108 | + | const wxArrayString& getWarnings() const { | |
| 109 | + | return warnings; | |
| 110 | + | } | |
| 111 | + | bool hasError() const { | |
| 112 | + | return error.size() != 0; | |
| 113 | + | } | |
| 114 | + | wxString getError() const { | |
| 115 | + | return error; | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // Mess with spawns | |
| 119 | + | bool addSpawn(Tile* spawn); | |
| 120 | + | void removeSpawn(Tile* tile); | |
| 121 | + | void removeSpawn(const Position& position) { | |
| 122 | + | removeSpawn(getTile(position)); | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // Returns all possible spawns on the target tile | |
| 126 | + | SpawnList getSpawnList(Tile* t); | |
| 127 | + | SpawnList getSpawnList(const Position& position) { | |
| 128 | + | return getSpawnList(getTile(position)); | |
| 129 | + | } | |
| 130 | + | SpawnList getSpawnList(int32_t x, int32_t y, int32_t z) { | |
| 131 | + | return getSpawnList(getTile(x, y, z)); | |
| 132 | + | } | |
| 133 | + | ||
| 134 | + | // Returns true if the map has been saved | |
| 135 | + | // ie. it knows which file it should be saved to | |
| 136 | + | bool hasFile() const; | |
| 137 | + | std::string getFilename() const { | |
| 138 | + | return filename; | |
| 139 | + | } | |
| 140 | + | std::string getName() const { | |
| 141 | + | return name; | |
| 142 | + | } | |
| 143 | + | void setName(const std::string& n) { | |
| 144 | + | name = n; | |
| 145 | + | } | |
| 146 | + | ||
| 147 | + | // Get map data | |
| 148 | + | int getWidth() const { | |
| 149 | + | return width; | |
| 150 | + | } | |
| 151 | + | int getHeight() const { | |
| 152 | + | return height; | |
| 153 | + | } | |
| 154 | + | std::string getMapDescription() const { | |
| 155 | + | return description; | |
| 156 | + | } | |
| 157 | + | std::string getHouseFilename() const { | |
| 158 | + | return housefile; | |
| 159 | + | } | |
| 160 | + | std::string getSpawnFilename() const { | |
| 161 | + | return spawnfile; | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | // Set some map data | |
| 165 | + | void setWidth(int new_width); | |
| 166 | + | void setHeight(int new_height); | |
| 167 | + | void setMapDescription(const std::string& new_description); | |
| 168 | + | void setHouseFilename(const std::string& new_housefile); | |
| 169 | + | void setSpawnFilename(const std::string& new_spawnfile); | |
| 170 | + | ||
| 171 | + | void flagAsNamed() { | |
| 172 | + | unnamed = false; | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | // Removes duplicate items from the map, optionally within specified ID ranges | |
| 176 | + | // Returns number of items removed | |
| 177 | + | uint32_t cleanDuplicateItems( | |
| 178 | + | const std::vector<std::pair<uint16_t, uint16_t>>& ranges, | |
| 179 | + | const PropertyFlags& flags | |
| 180 | + | ); | |
| 181 | + | ||
| 182 | + | protected: | |
| 183 | + | // Loads a map | |
| 184 | + | bool open(const std::string identifier); | |
| 185 | + | ||
| 186 | + | protected: | |
| 187 | + | void removeSpawnInternal(Tile* tile); | |
| 188 | + | ||
| 189 | + | wxArrayString warnings; | |
| 190 | + | wxString error; | |
| 191 | + | ||
| 192 | + | std::string name; // The map name, NOT the same as filename | |
| 193 | + | std::string filename; // the maps filename | |
| 194 | + | std::string description; // The description of the map | |
| 195 | + | ||
| 196 | + | MapVersion mapVersion; | |
| 197 | + | ||
| 198 | + | // Map Width and Height - for info purposes | |
| 199 | + | uint16_t width, height; | |
| 200 | + | ||
| 201 | + | std::string spawnfile; // The maps spawnfile | |
| 202 | + | std::string housefile; // The housefile | |
| 203 | + | std::string waypointfile; // The waypoints file (stores extended waypoint information such as id, preferred icon and matching town) | |
| 204 | + | ||
| 205 | + | public: | |
| 206 | + | Towns towns; | |
| 207 | + | Houses houses; | |
| 208 | + | Spawns spawns; | |
| 209 | + | ||
| 210 | + | protected: | |
| 211 | + | bool has_changed; // If the map has changed | |
| 212 | + | bool unnamed; // If the map has yet to receive a name | |
| 213 | + | ||
| 214 | + | friend class IOMapOTBM; | |
| 215 | + | friend class IOMapOTMM; | |
| 216 | + | friend class Editor; | |
| 217 | + | ||
| 218 | + | public: | |
| 219 | + | Waypoints waypoints; | |
| 220 | + | }; | |
| 221 | + | ||
| 222 | + | template <typename ForeachType> | |
| 223 | + | inline void foreach_ItemOnMap(Map& map, ForeachType& foreach, bool selectedTiles) { | |
| 224 | + | MapIterator tileiter = map.begin(); | |
| 225 | + | MapIterator end = map.end(); | |
| 226 | + | long long done = 0; | |
| 227 | + | ||
| 228 | + | while (tileiter != end) { | |
| 229 | + | ++done; | |
| 230 | + | Tile* tile = (*tileiter)->get(); | |
| 231 | + | if (selectedTiles && !tile->isSelected()) { | |
| 232 | + | ++tileiter; | |
| 233 | + | continue; | |
| 234 | + | } | |
| 235 | + | ||
| 236 | + | if (tile->ground) { | |
| 237 | + | foreach (map, tile, tile->ground, done) | |
| 238 | + | ; | |
| 239 | + | } | |
| 240 | + | ||
| 241 | + | std::queue<Container*> containers; | |
| 242 | + | for (ItemVector::iterator itemiter = tile->items.begin(); itemiter != tile->items.end(); ++itemiter) { | |
| 243 | + | Item* item = *itemiter; | |
| 244 | + | Container* container = dynamic_cast<Container*>(item); | |
| 245 | + | foreach (map, tile, item, done) | |
| 246 | + | ; | |
| 247 | + | if (container) { | |
| 248 | + | containers.push(container); | |
| 249 | + | ||
| 250 | + | do { | |
| 251 | + | container = containers.front(); | |
| 252 | + | ItemVector& v = container->getVector(); | |
| 253 | + | for (ItemVector::iterator containeriter = v.begin(); containeriter != v.end(); ++containeriter) { | |
| 254 | + | Item* i = *containeriter; | |
| 255 | + | Container* c = dynamic_cast<Container*>(i); | |
| 256 | + | foreach (map, tile, i, done) | |
| 257 | + | ; | |
| 258 | + | if (c) { | |
| 259 | + | containers.push(c); | |
| 260 | + | } | |
| 261 | + | } | |
| 262 | + | containers.pop(); | |
| 263 | + | } while (containers.size()); | |
| 264 | + | } | |
| 265 | + | } | |
| 266 | + | ++tileiter; | |
| 267 | + | } | |
| 268 | + | } | |
| 269 | + | ||
| 270 | + | template <typename ForeachType> | |
| 271 | + | inline void foreach_TileOnMap(Map& map, ForeachType& foreach) { | |
| 272 | + | MapIterator tileiter = map.begin(); | |
| 273 | + | MapIterator end = map.end(); | |
| 274 | + | long long done = 0; | |
| 275 | + | ||
| 276 | + | while (tileiter != end) { | |
| 277 | + | foreach (map, (*tileiter++)->get(), ++done) | |
| 278 | + | ; | |
| 279 | + | } | |
| 280 | + | } | |
| 281 | + | ||
| 282 | + | template <typename RemoveIfType> | |
| 283 | + | inline long long remove_if_TileOnMap(Map& map, RemoveIfType& remove_if) { | |
| 284 | + | MapIterator tileiter = map.begin(); | |
| 285 | + | MapIterator end = map.end(); | |
| 286 | + | long long done = 0; | |
| 287 | + | long long removed = 0; | |
| 288 | + | long long total = map.getTileCount(); | |
| 289 | + | ||
| 290 | + | while (tileiter != end) { | |
| 291 | + | Tile* tile = (*tileiter)->get(); | |
| 292 | + | if (remove_if(map, tile, removed, done, total)) { | |
| 293 | + | map.setTile(tile->getPosition(), nullptr, true); | |
| 294 | + | ++removed; | |
| 295 | + | } | |
| 296 | + | ++tileiter; | |
| 297 | + | ++done; | |
| 298 | + | } | |
| 299 | + | ||
| 300 | + | return removed; | |
| 301 | + | } | |
| 302 | + | ||
| 303 | + | template <typename RemoveIfType> | |
| 304 | + | inline int64_t RemoveItemOnMap(Map& map, RemoveIfType& condition, bool selectedOnly) { | |
| 305 | + | int64_t done = 0; | |
| 306 | + | int64_t removed = 0; | |
| 307 | + | ||
| 308 | + | MapIterator it = map.begin(); | |
| 309 | + | MapIterator end = map.end(); | |
| 310 | + | ||
| 311 | + | while (it != end) { | |
| 312 | + | ++done; | |
| 313 | + | Tile* tile = (*it)->get(); | |
| 314 | + | if (selectedOnly && !tile->isSelected()) { | |
| 315 | + | ++it; | |
| 316 | + | continue; | |
| 317 | + | } | |
| 318 | + | ||
| 319 | + | if (tile->ground) { | |
| 320 | + | if (condition(map, tile->ground, removed, done)) { | |
| 321 | + | delete tile->ground; | |
| 322 | + | tile->ground = nullptr; | |
| 323 | + | ++removed; | |
| 324 | + | } | |
| 325 | + | } | |
| 326 | + | ||
| 327 | + | for (auto iit = tile->items.begin(); iit != tile->items.end();) { | |
| 328 | + | Item* item = *iit; | |
| 329 | + | if (condition(map, item, removed, done)) { | |
| 330 | + | iit = tile->items.erase(iit); | |
| 331 | + | delete item; | |
| 332 | + | ++removed; | |
| 333 | + | } else { | |
| 334 | + | ++iit; | |
| 335 | + | } | |
| 336 | + | } | |
| 337 | + | ++it; | |
| 338 | + | } | |
| 339 | + | return removed; | |
| 340 | + | } | |
| 341 | + | ||
| 342 | + | #endif |
| @@ -0,0 +1,66 @@ | |||
| 1 | + | ////////////////////////////////////////////////////////////////////// | |
| 2 | + | // This file is part of Remere's Map Editor | |
| 3 | + | ////////////////////////////////////////////////////////////////////// | |
| 4 | + | // Remere's Map Editor is free software: you can redistribute it and/or modify | |
| 5 | + | // it under the terms of the GNU General Public License as published by | |
| 6 | + | // the Free Software Foundation, either version 3 of the License, or | |
| 7 | + | // (at your option) any later version. | |
| 8 | + | // | |
| 9 | + | // Remere's Map Editor is distributed in the hope that it will be useful, | |
| 10 | + | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + | // GNU General Public License for more details. | |
| 13 | + | // | |
| 14 | + | // You should have received a copy of the GNU General Public License | |
| 15 | + | // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + | ////////////////////////////////////////////////////////////////////// | |
| 17 | + | ||
| 18 | + | #ifndef RME_MAP_ALLOCATOR_H | |
| 19 | + | #define RME_MAP_ALLOCATOR_H | |
| 20 | + | ||
| 21 | + | #include "tile.h" | |
| 22 | + | #include "map_region.h" | |
| 23 | + | ||
| 24 | + | class BaseMap; | |
| 25 | + | ||
| 26 | + | class MapAllocator { | |
| 27 | + | ||
| 28 | + | public: | |
| 29 | + | MapAllocator() { } | |
| 30 | + | ~MapAllocator() { } | |
| 31 | + | ||
| 32 | + | // shorthands for tiles | |
| 33 | + | Tile* operator()(TileLocation* location) { | |
| 34 | + | return allocateTile(location); | |
| 35 | + | } | |
| 36 | + | // free | |
| 37 | + | void operator()(Tile* t) { | |
| 38 | + | freeTile(t); | |
| 39 | + | } | |
| 40 | + | ||
| 41 | + | // | |
| 42 | + | Tile* allocateTile(TileLocation* location) { | |
| 43 | + | return newd Tile(*location); | |
| 44 | + | } | |
| 45 | + | void freeTile(Tile* t) { | |
| 46 | + | delete t; | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | // | |
| 50 | + | Floor* allocateFloor(int x, int y, int z) { | |
| 51 | + | return newd Floor(x, y, z); | |
| 52 | + | } | |
| 53 | + | void freeFloor(Floor* f) { | |
| 54 | + | delete f; | |
| 55 | + | } | |
| 56 | + | ||
| 57 | + | // | |
| 58 | + | QTreeNode* allocateNode(BaseMap& map) { | |
| 59 | + | return newd QTreeNode(map); | |
| 60 | + | } | |
| 61 | + | void freeNode(QTreeNode* qt) { | |
| 62 | + | delete qt; | |
| 63 | + | } | |
| 64 | + | }; | |
| 65 | + | ||
| 66 | + | #endif |