From d2c0b5a49a4ce2341bc295651c250558fe21d36f Mon Sep 17 00:00:00 2001 From: thicco-catto Date: Fri, 12 Dec 2025 22:00:32 +0100 Subject: [PATCH 1/2] Added custom map icon support --- libzhl/functions/Game.zhl | 3 + repentogon/LuaInterfaces/HUD/LuaMinimap.cpp | 278 ++++++++++++++++++++ repentogon/Patches/CustomModManager.cpp | 13 +- repentogon/Patches/CustomModManager.h | 10 +- repentogon/resources/scripts/enums_ex.lua | 7 + 5 files changed, 303 insertions(+), 8 deletions(-) diff --git a/libzhl/functions/Game.zhl b/libzhl/functions/Game.zhl index b246c1f99..7332d32f0 100644 --- a/libzhl/functions/Game.zhl +++ b/libzhl/functions/Game.zhl @@ -155,6 +155,9 @@ static Entity_Effect* Game::ChainLightning(Vector* position, float damage, "558bec83ec0c568bb1": __thiscall bool Game::HasSeedEffect(int SeedEffect); +"a1????????56578bb0????????0b71??e8????????8bf80bfee8????????f7d023c75f5e": +__thiscall int Game::GetCurses(); + "a1(????????)c3????????????????????558bec6a00": reference Game *g_Game; diff --git a/repentogon/LuaInterfaces/HUD/LuaMinimap.cpp b/repentogon/LuaInterfaces/HUD/LuaMinimap.cpp index 36189f052..58fb95866 100644 --- a/repentogon/LuaInterfaces/HUD/LuaMinimap.cpp +++ b/repentogon/LuaInterfaces/HUD/LuaMinimap.cpp @@ -1,6 +1,8 @@ #include "IsaacRepentance.h" #include "LuaCore.h" #include "HookSystem.h" +#include +#include "../../Patches/CustomModManager.h" /*LUA_FUNCTION(Lua_GameGetMinimap) { @@ -12,6 +14,280 @@ } */ +enum MinimapIconPosition { + ICON_POSITION_BEFORE_MAP_ICONS = 0, + ICON_POSITION_AFTER_MAP_ICONS = 1, + ICON_POSITION_BEFORE_CURSE_ICONS = 2, + ICON_POSITION_AFTER_CURSE_ICONS = 3, +}; + +struct MinimapIcon { + ANM2* sprite; + std_string anim; + int frame; + // Used for deleting icons + int id; +}; + +static std::vector> BeforeMapIcons; +static std::vector> AfterMapIcons; +static std::vector> BeforeCurseIcons; +static std::vector> AfterCurseIcons; +static std::map TakenIds; + +#pragma region Helper functions +void TryAddIcon(MinimapIcon icons[], unsigned int& num_icons, ANM2* sprite, std_string& anim, int frame) { + if (num_icons < 7) { + icons[num_icons].sprite = sprite; + icons[num_icons].anim = anim; + icons[num_icons].frame = frame; + + num_icons++; + } +} + +void TryAddAllIcons(MinimapIcon icons[], unsigned int& num_icons, std::vector>& toAdd) { + for (auto& icon : toAdd) { + if (num_icons >= 7) { + break; + } + + TryAddIcon(icons, num_icons, icon->sprite, icon->anim, icon->frame); + } +} + +int GetFreeId(std::vector>& icons) { + int free_id = 1; + bool found = false; + + while (TakenIds.count(free_id) > 0) { + free_id++; + } + + TakenIds[free_id] = true; + + return free_id; +} + +void RemoveIcon(std::vector>& icons, int& id) { + int idx_to_delete = 0; + bool found = false; + + for (size_t i = 0; i < icons.size(); i++) + { + if (icons[i]->id == id) { + idx_to_delete = i; + found = true; + + TakenIds.erase(TakenIds.find(icons[i]->id)); + delete icons[i]->sprite; + + break; + } + } + + if (!found) { + return; + } + + icons.erase(icons.begin() + idx_to_delete); +} + +void RemoveAllIcons(std::vector>& icons) { + for (auto& icon : icons) { + delete icon->sprite; + } + + icons.clear(); +} + +bool ValidateSprite(ANM2* sprite, const char* anim, int& frame) { + if (!sprite->_loaded) { + return false; + } + + sprite->SetAnimation(anim, true); + AnimationData* anim_data = sprite->_animData; + if (anim_data == nullptr) { + return false; + } + + if (frame >= anim_data->GetLength()) { + return false; + } + + return true; +} +#pragma endregion + +HOOK_METHOD(Game, Exit, (bool shouldSave) -> void) { + RemoveAllIcons(BeforeMapIcons); + RemoveAllIcons(AfterMapIcons); + RemoveAllIcons(BeforeCurseIcons); + RemoveAllIcons(AfterCurseIcons); + + TakenIds.clear(); + + super(shouldSave); +} + +HOOK_METHOD(Minimap, RenderIcons, (Vector* position, float alpha) -> void) { + // Check if we actually need to do the custom logic. + if (BeforeMapIcons.size() == 0 && AfterMapIcons.size() == 0 + && BeforeCurseIcons.size() == 0 && AfterCurseIcons.size() == 0) { + super(position, alpha); + } + + PlayerManager* player_manager = g_Game->GetPlayerManager(); + RNG* rng = &player_manager->_rng; + Vector vector_zero(0, 0); + + unsigned int num_icons = 0; + MinimapIcon icons_to_render[7]; + Vector render_position(position->x, position->y); + + std_string icons_anim = "icons"; + std_string curses_anim = "curses"; + +#pragma region Item icons + TryAddAllIcons(icons_to_render, num_icons, BeforeMapIcons); + + if (player_manager->FirstCollectibleOwner(COLLECTIBLE_MIND, &rng, true)) { + TryAddIcon(icons_to_render, num_icons, &this->_itemIconsSprite, icons_anim, 5); + } else { + if (player_manager->FirstCollectibleOwner(COLLECTIBLE_COMPASS, &rng, true)) { + TryAddIcon(icons_to_render, num_icons, &this->_itemIconsSprite, icons_anim, 0); + } + + if (player_manager->FirstCollectibleOwner(COLLECTIBLE_BLUE_MAP, &rng, true)) { + TryAddIcon(icons_to_render, num_icons, &this->_itemIconsSprite, icons_anim, 1); + } + + if (player_manager->FirstCollectibleOwner(COLLECTIBLE_TREASURE_MAP, &rng, true)) { + TryAddIcon(icons_to_render, num_icons, &this->_itemIconsSprite, icons_anim, 2); + } + } + + TryAddAllIcons(icons_to_render, num_icons, AfterMapIcons); + + if (player_manager->FirstCollectibleOwner(COLLECTIBLE_RESTOCK, &rng, true)) { + TryAddIcon(icons_to_render, num_icons, &this->_itemIconsSprite, icons_anim, 4); + } +#pragma endregion + +#pragma region Curse icons + TryAddAllIcons(icons_to_render, num_icons, BeforeCurseIcons); + + unsigned int curses = g_Game->GetCurses(); + + for (size_t i = 0; i < 8; i++) { + if ((curses & 1 << i) != 0) { + TryAddIcon(icons_to_render, num_icons, &this->_itemIconsSprite, curses_anim, i); + } + } + + std::map curseSpriteMap = GetCurseSpriteMap(); + + if (!curseSpriteMap.empty() && num_icons < 7) { + for (const auto& entry : curseSpriteMap) { + int adjustedCurseId = (int)entry.first; + ANM2* curseSprite = entry.second.customANM2; + + if (adjustedCurseId >= 9 && curseSprite->_loaded && (curses & (1U << (adjustedCurseId - 1)))) { + TryAddIcon(icons_to_render, num_icons, curseSprite, curses_anim, entry.second.frameNum); + + if (num_icons >= 7) break; + } + } + } + + + TryAddAllIcons(icons_to_render, num_icons, AfterCurseIcons); +#pragma endregion + +#pragma region Rendering + Vector offset(-16, 0); + if (num_icons >= 4) { + offset += Vector(num_icons - 3.0f, 0); + } + + for (size_t i = 0; i < num_icons; i++) { + MinimapIcon icon = icons_to_render[i]; + + icon.sprite->SetFrame(&icon.anim, icon.frame); + + icon.sprite->_color._tint[3] = alpha; + icon.sprite->Render(&render_position, &vector_zero, &vector_zero); + + render_position += offset; + } +#pragma endregion +} + +LUA_FUNCTION(Lua_MinimapAddIcon) +{ + Minimap* minimap = g_Game->GetMinimap(); + int position = (int)luaL_checkinteger(L, 1); + const char* anm2 = luaL_checkstring(L, 2); + std_string anm2_string(anm2); + const char* anim = luaL_checkstring(L, 3); + std_string anim_string(anim); + int frame = (int)luaL_checkinteger(L, 4); + + ANM2* sprite = new ANM2; + sprite->Load(anm2_string, true); + + if (!ValidateSprite(sprite, anim, frame)) { + lua_pushnil(L); + return 1; + } + + MinimapIcon* icon = new MinimapIcon; + icon->sprite = sprite; + icon->anim = anim_string; + icon->frame = frame; + + if (position == ICON_POSITION_BEFORE_MAP_ICONS) { + icon->id = GetFreeId(BeforeMapIcons); + BeforeMapIcons.push_back(std::unique_ptr(icon)); + } else if (position == ICON_POSITION_AFTER_MAP_ICONS) { + icon->id = GetFreeId(AfterMapIcons); + AfterMapIcons.push_back(std::unique_ptr(icon)); + } else if (position == ICON_POSITION_BEFORE_CURSE_ICONS) { + icon->id = GetFreeId(BeforeCurseIcons); + BeforeCurseIcons.push_back(std::unique_ptr(icon)); + } else if (position == ICON_POSITION_AFTER_CURSE_ICONS) { + icon->id = GetFreeId(AfterCurseIcons); + AfterCurseIcons.push_back(std::unique_ptr(icon)); + } + + lua_pushinteger(L, icon->id); + + return 1; +} + +LUA_FUNCTION(Lua_MinimapRemoveIcon) +{ + Minimap* minimap = g_Game->GetMinimap(); + int priority = (int)luaL_checkinteger(L, 1); + int id = (int)luaL_checkinteger(L, 2); + + if (priority == ICON_POSITION_BEFORE_MAP_ICONS) { + RemoveIcon(BeforeMapIcons, id); + } + else if (priority == ICON_POSITION_AFTER_MAP_ICONS) { + RemoveIcon(AfterMapIcons, id); + } + else if (priority == ICON_POSITION_BEFORE_CURSE_ICONS) { + RemoveIcon(BeforeCurseIcons, id); + } + else if (priority == ICON_POSITION_AFTER_CURSE_ICONS) { + RemoveIcon(AfterCurseIcons, id); + } + + return 0; +} + LUA_FUNCTION(Lua_MinimapGetState) { Minimap* minimap = g_Game->GetMinimap(); @@ -115,6 +391,8 @@ static void RegisterMinimap(lua_State* L) { lua::TableAssoc(L, "GetShakeOffset", Lua_MinimapGetShakeOffset); lua::TableAssoc(L, "SetShakeOffset", Lua_MinimapSetShakeOffset); lua::TableAssoc(L, "Refresh", Lua_MinimapRefresh); + lua::TableAssoc(L, "AddIcon", Lua_MinimapAddIcon); + lua::TableAssoc(L, "RemoveIcon", Lua_MinimapRemoveIcon); //}; lua_setglobal(L, "Minimap"); //lua::RegisterNewClass(L, lua::metatables::MinimapMT, lua::metatables::MinimapMT, functions); diff --git a/repentogon/Patches/CustomModManager.cpp b/repentogon/Patches/CustomModManager.cpp index afc8e1c23..ef9694434 100644 --- a/repentogon/Patches/CustomModManager.cpp +++ b/repentogon/Patches/CustomModManager.cpp @@ -5,12 +5,6 @@ #include "CustomModManager.h" -struct CurseSpriteData { - ModEntryEx* modEx; - ANM2* customANM2; - uint32_t frameNum; -}; - static std::map curseSpriteMap; static ModEntry* lastModEntry = nullptr; static uint32_t currentFrameNum = 0; @@ -196,4 +190,9 @@ void ASMPatchesForCustomModManager() { ASMPatchRegisterCurseSprite(); ASMPatchAssignCustomFrame(); ASMPatchRenderCustomCurses(); -} \ No newline at end of file +} + +std::map GetCurseSpriteMap() +{ + return curseSpriteMap; +} diff --git a/repentogon/Patches/CustomModManager.h b/repentogon/Patches/CustomModManager.h index 8c919aa77..ded62bea3 100644 --- a/repentogon/Patches/CustomModManager.h +++ b/repentogon/Patches/CustomModManager.h @@ -33,4 +33,12 @@ class CustomModManager CustomModManager& operator=(const CustomModManager&) = delete; }; -void ASMPatchesForCustomModManager(); \ No newline at end of file +struct CurseSpriteData { + ModEntryEx* modEx; + ANM2* customANM2; + uint32_t frameNum; +}; + +void ASMPatchesForCustomModManager(); + +std::map GetCurseSpriteMap(); \ No newline at end of file diff --git a/repentogon/resources/scripts/enums_ex.lua b/repentogon/resources/scripts/enums_ex.lua index de4873ea1..63f541b3d 100644 --- a/repentogon/resources/scripts/enums_ex.lua +++ b/repentogon/resources/scripts/enums_ex.lua @@ -3114,6 +3114,13 @@ RoomDisplayFlags = { SHOW_ICON = 1 << 2, } +MinimapIconPosition = { + BEFORE_MAP_ICONS = 0, + AFTER_MAP_ICONS = 1, + BEFORE_CURSE_ICONS = 2, + AFTER_CURSE_ICONS = 3 +} + --deprecated enums Achievement.REVERSED_THE_HEIROPHANT = 529 From 28a3d85d1d4d223a9f2c14b6f5b01084d85e56a3 Mon Sep 17 00:00:00 2001 From: thicco-catto Date: Sun, 14 Dec 2025 19:57:49 +0100 Subject: [PATCH 2/2] Changed to icon registration --- repentogon/LuaInterfaces/HUD/LuaMinimap.cpp | 216 +++++++++----------- 1 file changed, 97 insertions(+), 119 deletions(-) diff --git a/repentogon/LuaInterfaces/HUD/LuaMinimap.cpp b/repentogon/LuaInterfaces/HUD/LuaMinimap.cpp index 58fb95866..1199ce60f 100644 --- a/repentogon/LuaInterfaces/HUD/LuaMinimap.cpp +++ b/repentogon/LuaInterfaces/HUD/LuaMinimap.cpp @@ -21,23 +21,30 @@ enum MinimapIconPosition { ICON_POSITION_AFTER_CURSE_ICONS = 3, }; +const int MAX_MINIMAP_ICONS = 7; +const int BASE_ICON_X_OFFSET = 16; +const int MAX_CURSES = 8; + struct MinimapIcon { ANM2* sprite; std_string anim; int frame; - // Used for deleting icons +}; + +struct RegisteredMinimapIcon { + ANM2 sprite; + int position; + // Unique id that's passed to the lua side int id; }; -static std::vector> BeforeMapIcons; -static std::vector> AfterMapIcons; -static std::vector> BeforeCurseIcons; -static std::vector> AfterCurseIcons; -static std::map TakenIds; +static std::vector RegisteredCustomIcons; +// Set containing the indexes in RegisteredCustomIcons containing active icons +static std::set ActiveCustomIcons; #pragma region Helper functions void TryAddIcon(MinimapIcon icons[], unsigned int& num_icons, ANM2* sprite, std_string& anim, int frame) { - if (num_icons < 7) { + if (num_icons < MAX_MINIMAP_ICONS) { icons[num_icons].sprite = sprite; icons[num_icons].anim = anim; icons[num_icons].frame = frame; @@ -46,68 +53,34 @@ void TryAddIcon(MinimapIcon icons[], unsigned int& num_icons, ANM2* sprite, std_ } } -void TryAddAllIcons(MinimapIcon icons[], unsigned int& num_icons, std::vector>& toAdd) { - for (auto& icon : toAdd) { - if (num_icons >= 7) { - break; - } - - TryAddIcon(icons, num_icons, icon->sprite, icon->anim, icon->frame); - } -} - -int GetFreeId(std::vector>& icons) { - int free_id = 1; - bool found = false; - - while (TakenIds.count(free_id) > 0) { - free_id++; +void TryAddAllIcons(MinimapIcon icons[], unsigned int& num_icons, std::set::iterator& it, int position) { + if (num_icons >= MAX_MINIMAP_ICONS) { + return; } - TakenIds[free_id] = true; - - return free_id; -} - -void RemoveIcon(std::vector>& icons, int& id) { - int idx_to_delete = 0; - bool found = false; - - for (size_t i = 0; i < icons.size(); i++) - { - if (icons[i]->id == id) { - idx_to_delete = i; - found = true; - - TakenIds.erase(TakenIds.find(icons[i]->id)); - delete icons[i]->sprite; + for (it; it != ActiveCustomIcons.end(); ++it) { + int icon_idx = *it; + RegisteredMinimapIcon* icon = RegisteredCustomIcons.at(icon_idx); + if (icon->position <= position) { + TryAddIcon(icons, num_icons, &icon->sprite, icon->sprite._animData->_name, icon->sprite.GetFrame()); + } else { break; } - } - - if (!found) { - return; - } - icons.erase(icons.begin() + idx_to_delete); -} - -void RemoveAllIcons(std::vector>& icons) { - for (auto& icon : icons) { - delete icon->sprite; + if (num_icons >= MAX_MINIMAP_ICONS) { + break; + } } - - icons.clear(); } -bool ValidateSprite(ANM2* sprite, const char* anim, int& frame) { - if (!sprite->_loaded) { +bool ValidateSprite(ANM2& sprite, const char* anim, int& frame) { + if (!sprite._loaded) { return false; } - sprite->SetAnimation(anim, true); - AnimationData* anim_data = sprite->_animData; + sprite.SetAnimation(anim, true); + AnimationData* anim_data = sprite._animData; if (anim_data == nullptr) { return false; } @@ -118,24 +91,23 @@ bool ValidateSprite(ANM2* sprite, const char* anim, int& frame) { return true; } + +bool CompareIcons(RegisteredMinimapIcon* a, RegisteredMinimapIcon* b) { + return a->position < b->position; +} #pragma endregion HOOK_METHOD(Game, Exit, (bool shouldSave) -> void) { - RemoveAllIcons(BeforeMapIcons); - RemoveAllIcons(AfterMapIcons); - RemoveAllIcons(BeforeCurseIcons); - RemoveAllIcons(AfterCurseIcons); - - TakenIds.clear(); + ActiveCustomIcons.clear(); super(shouldSave); } HOOK_METHOD(Minimap, RenderIcons, (Vector* position, float alpha) -> void) { // Check if we actually need to do the custom logic. - if (BeforeMapIcons.size() == 0 && AfterMapIcons.size() == 0 - && BeforeCurseIcons.size() == 0 && AfterCurseIcons.size() == 0) { + if (ActiveCustomIcons.size() <= 0) { super(position, alpha); + return; } PlayerManager* player_manager = g_Game->GetPlayerManager(); @@ -143,14 +115,16 @@ HOOK_METHOD(Minimap, RenderIcons, (Vector* position, float alpha) -> void) { Vector vector_zero(0, 0); unsigned int num_icons = 0; - MinimapIcon icons_to_render[7]; + MinimapIcon icons_to_render[MAX_MINIMAP_ICONS]; Vector render_position(position->x, position->y); std_string icons_anim = "icons"; std_string curses_anim = "curses"; + std::set::iterator active_custom_icons_it = ActiveCustomIcons.begin(); + #pragma region Item icons - TryAddAllIcons(icons_to_render, num_icons, BeforeMapIcons); + TryAddAllIcons(icons_to_render, num_icons, active_custom_icons_it, ICON_POSITION_BEFORE_MAP_ICONS); if (player_manager->FirstCollectibleOwner(COLLECTIBLE_MIND, &rng, true)) { TryAddIcon(icons_to_render, num_icons, &this->_itemIconsSprite, icons_anim, 5); @@ -168,7 +142,7 @@ HOOK_METHOD(Minimap, RenderIcons, (Vector* position, float alpha) -> void) { } } - TryAddAllIcons(icons_to_render, num_icons, AfterMapIcons); + TryAddAllIcons(icons_to_render, num_icons, active_custom_icons_it, ICON_POSITION_AFTER_MAP_ICONS); if (player_manager->FirstCollectibleOwner(COLLECTIBLE_RESTOCK, &rng, true)) { TryAddIcon(icons_to_render, num_icons, &this->_itemIconsSprite, icons_anim, 4); @@ -176,11 +150,11 @@ HOOK_METHOD(Minimap, RenderIcons, (Vector* position, float alpha) -> void) { #pragma endregion #pragma region Curse icons - TryAddAllIcons(icons_to_render, num_icons, BeforeCurseIcons); + TryAddAllIcons(icons_to_render, num_icons, active_custom_icons_it, ICON_POSITION_BEFORE_CURSE_ICONS); unsigned int curses = g_Game->GetCurses(); - for (size_t i = 0; i < 8; i++) { + for (size_t i = 0; i < MAX_CURSES; i++) { if ((curses & 1 << i) != 0) { TryAddIcon(icons_to_render, num_icons, &this->_itemIconsSprite, curses_anim, i); } @@ -188,25 +162,24 @@ HOOK_METHOD(Minimap, RenderIcons, (Vector* position, float alpha) -> void) { std::map curseSpriteMap = GetCurseSpriteMap(); - if (!curseSpriteMap.empty() && num_icons < 7) { + if (!curseSpriteMap.empty() && num_icons < MAX_MINIMAP_ICONS) { for (const auto& entry : curseSpriteMap) { int adjustedCurseId = (int)entry.first; ANM2* curseSprite = entry.second.customANM2; - if (adjustedCurseId >= 9 && curseSprite->_loaded && (curses & (1U << (adjustedCurseId - 1)))) { + if (adjustedCurseId >= (MAX_CURSES + 1) && curseSprite->_loaded && (curses & (1U << (adjustedCurseId - 1)))) { TryAddIcon(icons_to_render, num_icons, curseSprite, curses_anim, entry.second.frameNum); - if (num_icons >= 7) break; + if (num_icons >= MAX_MINIMAP_ICONS) break; } } } - - TryAddAllIcons(icons_to_render, num_icons, AfterCurseIcons); + TryAddAllIcons(icons_to_render, num_icons, active_custom_icons_it, ICON_POSITION_AFTER_CURSE_ICONS); #pragma endregion #pragma region Rendering - Vector offset(-16, 0); + Vector offset(-BASE_ICON_X_OFFSET, 0); if (num_icons >= 4) { offset += Vector(num_icons - 3.0f, 0); } @@ -224,9 +197,7 @@ HOOK_METHOD(Minimap, RenderIcons, (Vector* position, float alpha) -> void) { #pragma endregion } -LUA_FUNCTION(Lua_MinimapAddIcon) -{ - Minimap* minimap = g_Game->GetMinimap(); +LUA_FUNCTION(Lua_MinimapRegisterCustomIcon) { int position = (int)luaL_checkinteger(L, 1); const char* anm2 = luaL_checkstring(L, 2); std_string anm2_string(anm2); @@ -234,55 +205,61 @@ LUA_FUNCTION(Lua_MinimapAddIcon) std_string anim_string(anim); int frame = (int)luaL_checkinteger(L, 4); - ANM2* sprite = new ANM2; - sprite->Load(anm2_string, true); + RegisteredMinimapIcon* minimapIcon = new RegisteredMinimapIcon; + minimapIcon->position = position; - if (!ValidateSprite(sprite, anim, frame)) { + minimapIcon->sprite.Load(anm2_string, true); + + if (!ValidateSprite(minimapIcon->sprite, anim, frame)) { lua_pushnil(L); - return 1; - } + } else { + minimapIcon->sprite.SetFrame(&anim_string, frame); - MinimapIcon* icon = new MinimapIcon; - icon->sprite = sprite; - icon->anim = anim_string; - icon->frame = frame; - - if (position == ICON_POSITION_BEFORE_MAP_ICONS) { - icon->id = GetFreeId(BeforeMapIcons); - BeforeMapIcons.push_back(std::unique_ptr(icon)); - } else if (position == ICON_POSITION_AFTER_MAP_ICONS) { - icon->id = GetFreeId(AfterMapIcons); - AfterMapIcons.push_back(std::unique_ptr(icon)); - } else if (position == ICON_POSITION_BEFORE_CURSE_ICONS) { - icon->id = GetFreeId(BeforeCurseIcons); - BeforeCurseIcons.push_back(std::unique_ptr(icon)); - } else if (position == ICON_POSITION_AFTER_CURSE_ICONS) { - icon->id = GetFreeId(AfterCurseIcons); - AfterCurseIcons.push_back(std::unique_ptr(icon)); - } + minimapIcon->id = RegisteredCustomIcons.size(); + int index_to_place_at = 0; - lua_pushinteger(L, icon->id); + auto lb = std::lower_bound(RegisteredCustomIcons.begin(), RegisteredCustomIcons.end(), minimapIcon, CompareIcons); + RegisteredCustomIcons.insert(lb, minimapIcon); + + lua_pushinteger(L, minimapIcon->id); + } return 1; } -LUA_FUNCTION(Lua_MinimapRemoveIcon) -{ - Minimap* minimap = g_Game->GetMinimap(); - int priority = (int)luaL_checkinteger(L, 1); - int id = (int)luaL_checkinteger(L, 2); - - if (priority == ICON_POSITION_BEFORE_MAP_ICONS) { - RemoveIcon(BeforeMapIcons, id); +LUA_FUNCTION(Lua_MinimapActivateCustomIcon) { + int id = (int)luaL_checkinteger(L, 1); + + if (id < 0 || id >= RegisteredCustomIcons.size()) { + return 0; } - else if (priority == ICON_POSITION_AFTER_MAP_ICONS) { - RemoveIcon(AfterMapIcons, id); + + for (size_t i = 0; i < RegisteredCustomIcons.size(); i++) + { + RegisteredMinimapIcon* icon = RegisteredCustomIcons.at(i); + if (icon->id == id) { + ActiveCustomIcons.insert(i); + return 0; + } } - else if (priority == ICON_POSITION_BEFORE_CURSE_ICONS) { - RemoveIcon(BeforeCurseIcons, id); + + return 0; +} + +LUA_FUNCTION(Lua_MinimapDeactivateCustomIcon) { + int id = (int)luaL_checkinteger(L, 1); + + if (id < 0 || id >= RegisteredCustomIcons.size()) { + return 0; } - else if (priority == ICON_POSITION_AFTER_CURSE_ICONS) { - RemoveIcon(AfterCurseIcons, id); + + for (size_t i = 0; i < RegisteredCustomIcons.size(); i++) + { + RegisteredMinimapIcon* icon = RegisteredCustomIcons.at(i); + if (icon->id == id) { + ActiveCustomIcons.erase(i); + return 0; + } } return 0; @@ -391,8 +368,9 @@ static void RegisterMinimap(lua_State* L) { lua::TableAssoc(L, "GetShakeOffset", Lua_MinimapGetShakeOffset); lua::TableAssoc(L, "SetShakeOffset", Lua_MinimapSetShakeOffset); lua::TableAssoc(L, "Refresh", Lua_MinimapRefresh); - lua::TableAssoc(L, "AddIcon", Lua_MinimapAddIcon); - lua::TableAssoc(L, "RemoveIcon", Lua_MinimapRemoveIcon); + lua::TableAssoc(L, "RegisterIcon", Lua_MinimapRegisterCustomIcon); + lua::TableAssoc(L, "ActivateIcon", Lua_MinimapActivateCustomIcon); + lua::TableAssoc(L, "DeactivateIcon", Lua_MinimapDeactivateCustomIcon); //}; lua_setglobal(L, "Minimap"); //lua::RegisterNewClass(L, lua::metatables::MinimapMT, lua::metatables::MinimapMT, functions);