Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: option remove duplicate items #62

Merged
merged 8 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion data/menubar.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@
<item name="Find $Action" action="SEARCH_ON_MAP_ACTION" help="Find all items with an action ID on map."/>
<item name="Find $Container" action="SEARCH_ON_MAP_CONTAINER" help="Find all containers on map."/>
<item name="Find $Writeable" action="SEARCH_ON_MAP_WRITEABLE" help="Find all writeable items on map."/>
<item name="Find $Duplicate Items" action="SEARCH_ON_MAP_DUPLICATE" help="Find all positions where there are duplicate items on the map."/>
</menu>
<separator/>
<menu name="$Border Options">
<item name="Border $Automagic" hotkey="A" action="AUTOMAGIC" help="Turns on all automatic border functions."/>
<separator/>
<separator/>
<item name="$Borderize Selection" hotkey="Ctrl+B" action="BORDERIZE_SELECTION" help="Creates automatic borders in the entire selected area."/>
<item name="Borderize $Map" action="BORDERIZE_MAP" help="Reborders the entire map."/>
<item name="Ra$ndomize Selection" action="RANDOMIZE_SELECTION" help="Randomizes the ground tiles of the selected area."/>
Expand All @@ -52,6 +53,7 @@
<item name="$Remove Items by ID..." action="MAP_REMOVE_ITEMS" help="Removes all items with the selected ID from the map."/>
<item name="Remove $all corpses..." action="MAP_REMOVE_CORPSES" help="Removes all corpses from the map."/>
<item name="Remove all $unreachable tiles..." action="MAP_REMOVE_UNREACHABLE_TILES" help="Removes all tiles that cannot be reached (or seen) by the player from the map."/>
<item name="Remove all $duplicates items..." action="REMOVE_ON_MAP_DUPLICATE_ITEMS" help="Removes all items duplicates on map."/>
<item name="Remove empty monsters spawns" action="MAP_REMOVE_EMPTY_MONSTERS_SPAWNS" help="Removes all empty monsters spawns from the map."/>
<item name="Remove empty npcs spawns" action="MAP_REMOVE_EMPTY_NPCS_SPAWNS" help="Removes all empty npcs spawns from the map."/>
<item name="$Clear Invalid Houses" action="CLEAR_INVALID_HOUSES" help="Clears house tiles not belonging to any house."/>
Expand Down Expand Up @@ -81,6 +83,7 @@
<item name="Find Item on Selection" action="SEARCH_ON_SELECTION_ITEM" help="Find items on selected area."/>
<item name="Remove Item on Selection" action="REMOVE_ON_SELECTION_ITEM" help="Remove item on selected area."/>
<item name="Remove Monsters on Selection" action="REMOVE_ON_SELECTION_MONSTER" help="Remove monsters on selected area."/>
<item name="Remove Duplicates Items on Selection" action="REMOVE_ON_SELECTION_DUPLICATE_ITEMS" help="Removes all items duplicates selected area."/>
<separator/>
<menu name="$Find on Selection">
<item name="Find $Everything" action="SEARCH_ON_SELECTION_EVERYTHING" help="Find all unique/action/text/container items."/>
Expand All @@ -89,6 +92,7 @@
<item name="Find $Action" action="SEARCH_ON_SELECTION_ACTION" help="Find all items with an action ID on selected area."/>
<item name="Find $Container" action="SEARCH_ON_SELECTION_CONTAINER" help="Find all containers on selected area."/>
<item name="Find $Writeable" action="SEARCH_ON_SELECTION_WRITEABLE" help="Find all writeable items on selected area."/>
<item name="Find $Duplicate Items" action="SEARCH_ON_SELECTION_DUPLICATE" help="Find all positions where there are duplicate items on selected area."/>
</menu>
<separator/>
<menu name="$Selection Mode">
Expand Down
3 changes: 3 additions & 0 deletions source/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
165 changes: 165 additions & 0 deletions source/main_menubar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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<Tile*> 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<int> 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<Tile*>& 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<int> 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();
}
}
11 changes: 10 additions & 1 deletion source/main_menubar.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
}

Expand Down Expand Up @@ -294,14 +298,19 @@ 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
wxObject* LoadItem(pugi::xml_node node, wxMenu* parent, wxArrayString &warnings, wxString &error);
// 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;
Expand Down
39 changes: 39 additions & 0 deletions source/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,4 +323,43 @@ inline int64_t RemoveItemOnMap(Map &map, RemoveIfType &condition, bool selectedO

int64_t RemoveMonstersOnMap(Map &map, bool selectedOnly);

template <typename RemoveIfType>
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
Loading