From 51ea7531347b1a2e512432f88082e6761ccff79d Mon Sep 17 00:00:00 2001 From: Luan Luciano Date: Wed, 1 Nov 2023 22:03:48 -0300 Subject: [PATCH] update --- data/menubar.xml | 2 + source/item.h | 3 + source/items.h | 3 + source/main_menubar.cpp | 165 ++++++++++++++++++++++++++++++++++++++++ source/main_menubar.h | 11 ++- source/map.h | 39 ++++++++++ 6 files changed, 222 insertions(+), 1 deletion(-) diff --git a/data/menubar.xml b/data/menubar.xml index 391960ed..a99ff09c 100644 --- a/data/menubar.xml +++ b/data/menubar.xml @@ -38,6 +38,7 @@ + @@ -52,6 +53,7 @@ + diff --git a/source/item.h b/source/item.h index 1072ab8b..9c298c45 100644 --- a/source/item.h +++ b/source/item.h @@ -303,6 +303,9 @@ class Item : public ItemAttributes { bool isMetaItem() const { return getItemType().isMetaItem(); } + bool hasElevation() const { + return getItemType().hasElevation(); + } // Wall alignment (vertical, horizontal, pole, corner) BorderType getWallAlignment() const; diff --git a/source/items.h b/source/items.h index e1417dc0..13288311 100644 --- a/source/items.h +++ b/source/items.h @@ -294,6 +294,9 @@ class ItemType { return is_metaitem; } + bool hasElevation() const noexcept { + return hasElevation; + } bool isFloorChange() const noexcept; float getWeight() const noexcept { diff --git a/source/main_menubar.cpp b/source/main_menubar.cpp index 1e2857b8..20a54b8c 100644 --- a/source/main_menubar.cpp +++ b/source/main_menubar.cpp @@ -201,6 +201,11 @@ MainMenuBar::MainMenuBar(MainFrame* frame) : MAKE_ACTION(GOTO_WEBSITE, wxITEM_NORMAL, OnGotoWebsite); MAKE_ACTION(ABOUT, wxITEM_NORMAL, OnAbout); + MAKE_ACTION(SEARCH_ON_MAP_DUPLICATE, wxITEM_NORMAL, OnSearchForDuplicateItemsOnMap); + MAKE_ACTION(SEARCH_ON_SELECTION_DUPLICATE, wxITEM_NORMAL, OnSearchForDuplicateItemsOnSelection); + MAKE_ACTION(REMOVE_ON_MAP_DUPLICATE_ITEMS, wxITEM_NORMAL, OnRemoveForDuplicateItemsOnMap); + MAKE_ACTION(REMOVE_ON_SELECTION_DUPLICATE_ITEMS, wxITEM_NORMAL, OnRemoveForDuplicateItemsOnSelection); + // A deleter, this way the frame does not need // to bother deleting us. class CustomMenuBar : public wxMenuBar { @@ -409,6 +414,11 @@ void MainMenuBar::Update() { EnableItem(DEBUG_VIEW_DAT, loaded); + EnableItem(SEARCH_ON_MAP_DUPLICATE, is_host); + EnableItem(SEARCH_ON_SELECTION_DUPLICATE, has_selection && is_host); + EnableItem(REMOVE_ON_MAP_DUPLICATE_ITEMS, is_local); + EnableItem(REMOVE_ON_SELECTION_DUPLICATE_ITEMS, is_local && has_selection); + UpdateFloorMenu(); UpdateIndicatorsMenu(); } @@ -2267,3 +2277,158 @@ void MainMenuBar::SearchItems(bool unique, bool action, bool container, bool wri result->AddPosition(searcher.desc(iter->second), iter->first->getPosition()); } } + +void MainMenuBar::OnSearchForDuplicateItemsOnMap(wxCommandEvent &WXUNUSED(event)) { + SearchDuplicatedItems(false); +} + +void MainMenuBar::OnSearchForDuplicateItemsOnSelection(wxCommandEvent &WXUNUSED(event)) { + SearchDuplicatedItems(true); +} + +void MainMenuBar::OnRemoveForDuplicateItemsOnMap(wxCommandEvent &WXUNUSED(event)) { + RemoveDuplicatesItems(false); +} + +void MainMenuBar::OnRemoveForDuplicateItemsOnSelection(wxCommandEvent &WXUNUSED(event)) { + RemoveDuplicatesItems(true); +} + +namespace SearchDuplicatedItems { + struct condition { + std::unordered_set foundTiles; + + void operator()(Map& map, Tile* tile, Item* item, long long done) { + if (done % 0x8000 == 0) { + g_gui.SetLoadDone((unsigned int)(100 * done / map.getTileCount())); + } + + if (!tile) { + return; + } + + if (!item) { + return; + } + + if (item->isGroundTile()) { + return; + } + + if (foundTiles.count(tile) == 0) { + std::unordered_set itemIDs; + for (Item* existingItem : tile->items) { + if (itemIDs.count(existingItem->getID()) > 0) { + foundTiles.insert(tile); + break; + } + itemIDs.insert(existingItem->getID()); + } + } + } + }; +} + +void MainMenuBar::SearchDuplicatedItems(bool onSelection/* = false*/) { + if (!g_gui.IsEditorOpen()) { + return; + } + + if (onSelection) { + g_gui.CreateLoadBar("Searching on selected area..."); + } else { + g_gui.CreateLoadBar("Searching on map..."); + } + + SearchDuplicatedItems::condition finder; + + foreach_ItemOnMap(g_gui.GetCurrentMap(), finder, onSelection); + std::unordered_set& foundTiles = finder.foundTiles; + + g_gui.DestroyLoadBar(); + + size_t setSize = foundTiles.size(); + + wxString msg; + msg << setSize << " duplicate items founded."; + + g_gui.PopupDialog("Search completed", msg, wxOK); + + SearchResultWindow* result = g_gui.ShowSearchWindow(); + result->Clear(); + for (const Tile* tile : foundTiles) { + result->AddPosition("Duplicate items", tile->getPosition()); + } +} + +namespace RemoveDuplicatesItems { + struct condition { + bool operator()(Map& map, Tile* tile, Item* item, long long removed, long long done) { + if (done % 0x8000 == 0) { + g_gui.SetLoadDone((unsigned int)(100 * done / map.getTileCount())); + } + + if (!tile) { + return false; + } + + if (!item) { + return false; + } + + if (item->isGroundTile()) { + return false; + } + + if (item->isMoveable() && item->hasElevation()) { + return false; + } + + std::unordered_set itemIDsDuplicates; + for (Item* itemInTile : tile->items) { + if (itemInTile && itemInTile->getID() == item->getID()) { + if (itemIDsDuplicates.count(itemInTile->getID()) > 0) { + itemIDsDuplicates.clear(); + return true; + } + itemIDsDuplicates.insert(itemInTile->getID()); + } + } + + itemIDsDuplicates.clear(); + return false; + } + }; +} + +void MainMenuBar::RemoveDuplicatesItems(bool onSelection/* = false*/) { + if (!g_gui.IsEditorOpen()) { + return; + } + + int ok = g_gui.PopupDialog("Remove Duplicate Items", "Do you want to remove all duplicates items from the map?", wxYES | wxNO); + + if(ok == wxID_YES) { + g_gui.GetCurrentEditor()->getSelection().clear(); + g_gui.GetCurrentEditor()->clearActions(); + + RemoveDuplicatesItems::condition func; + + if (onSelection) { + g_gui.CreateLoadBar("Searching on selected area for items to remove..."); + } else { + g_gui.CreateLoadBar("Searching on map for items to remove..."); + } + + long long removed = RemoveItemDuplicateOnMap(g_gui.GetCurrentMap(), func, onSelection); + + g_gui.DestroyLoadBar(); + + wxString msg; + msg << removed << " duplicate items deleted."; + + g_gui.PopupDialog("Search completed", msg, wxOK); + + g_gui.GetCurrentMap().doChange(); + } +} diff --git a/source/main_menubar.h b/source/main_menubar.h index 6468498f..788ae74f 100644 --- a/source/main_menubar.h +++ b/source/main_menubar.h @@ -157,6 +157,10 @@ namespace MenuBar { EXTENSIONS, GOTO_WEBSITE, ABOUT, + SEARCH_ON_MAP_DUPLICATE, + SEARCH_ON_SELECTION_DUPLICATE, + REMOVE_ON_MAP_DUPLICATE_ITEMS, + REMOVE_ON_SELECTION_DUPLICATE_ITEMS, }; } @@ -294,6 +298,10 @@ class MainMenuBar : public wxEvtHandler { void OnListExtensions(wxCommandEvent &event); void OnGotoWebsite(wxCommandEvent &event); void OnAbout(wxCommandEvent &event); + void OnSearchForDuplicateItemsOnMap(wxCommandEvent &event); + void OnSearchForDuplicateItemsOnSelection(wxCommandEvent &event); + void OnRemoveForDuplicateItemsOnMap(wxCommandEvent &event); + void OnRemoveForDuplicateItemsOnSelection(wxCommandEvent &event); protected: // Load and returns a menu item, also sets accelerator @@ -301,7 +309,8 @@ class MainMenuBar : public wxEvtHandler { // Checks the items in the menus according to the settings (in config) void LoadValues(); void SearchItems(bool unique, bool action, bool container, bool writable, bool onSelection = false); - + void SearchDuplicatedItems(bool onSelection = false); + void RemoveDuplicatesItems(bool onSelection = false); protected: MainFrame* frame; wxMenuBar* menubar; diff --git a/source/map.h b/source/map.h index c95f7a02..91862ea2 100644 --- a/source/map.h +++ b/source/map.h @@ -323,4 +323,43 @@ inline int64_t RemoveItemOnMap(Map &map, RemoveIfType &condition, bool selectedO int64_t RemoveMonstersOnMap(Map &map, bool selectedOnly); +template +inline int64_t RemoveItemDuplicateOnMap(Map &map, RemoveIfType &condition, bool selectedOnly) { + int64_t done = 0; + int64_t removed = 0; + + MapIterator it = map.begin(); + MapIterator end = map.end(); + + while (it != end) { + ++done; + Tile* tile = (*it)->get(); + if (selectedOnly && !tile->isSelected()) { + ++it; + continue; + } + + if (tile->ground) { + if (condition(map, tile, tile->ground, removed, done)) { + delete tile->ground; + tile->ground = nullptr; + ++removed; + } + } + + for (auto iit = tile->items.begin(); iit != tile->items.end();) { + Item* item = *iit; + if (condition(map, tile, item, removed, done)) { + iit = tile->items.erase(iit); + delete item; + ++removed; + } else { + ++iit; + } + } + ++it; + } + return removed; +} + #endif