summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett Cox <garrettjcox@gmail.com>2026-01-16 15:39:27 -0600
committerGitHub <noreply@github.com>2026-01-16 15:39:27 -0600
commit4430281d1aab4076c40e62e5bb5be1383361afe3 (patch)
tree4702727949eecd6b0576508e6d5b896a2f889ada
parent254cc60e1d718fb73d40610d8ca51455ce54bfef (diff)
UX pass on item tracker overhaul (#1460)
-rw-r--r--mm/2s2h/BenGui/UIWidgets.cpp2
-rw-r--r--mm/2s2h/DeveloperTools/SaveEditor.h2
-rw-r--r--mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTracker.cpp798
-rw-r--r--mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTracker.h63
-rw-r--r--mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTrackerSettings.cpp1041
-rw-r--r--mm/2s2h/Rando/ConvertItem.cpp17
-rw-r--r--mm/2s2h/Rando/StaticData/Items.cpp17
-rw-r--r--mm/2s2h/Rando/StaticData/StaticData.h1
-rw-r--r--mm/2s2h/ShipUtils.cpp157
-rw-r--r--mm/2s2h/ShipUtils.h6
10 files changed, 918 insertions, 1186 deletions
diff --git a/mm/2s2h/BenGui/UIWidgets.cpp b/mm/2s2h/BenGui/UIWidgets.cpp
index 80c8dbdbe..61efce012 100644
--- a/mm/2s2h/BenGui/UIWidgets.cpp
+++ b/mm/2s2h/BenGui/UIWidgets.cpp
@@ -138,7 +138,7 @@ void PushStyleInput(const ImVec4& color) {
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(color.x, color.y, color.z, 0.6f));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.3f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
- ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 6.0f));
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 5.0f);
}
diff --git a/mm/2s2h/DeveloperTools/SaveEditor.h b/mm/2s2h/DeveloperTools/SaveEditor.h
index dcf458d91..ffc85cda9 100644
--- a/mm/2s2h/DeveloperTools/SaveEditor.h
+++ b/mm/2s2h/DeveloperTools/SaveEditor.h
@@ -36,6 +36,8 @@ typedef struct {
std::vector<FlagEntry> entries;
} FlagTable;
+extern std::vector<ItemId> safeItemsForInventorySlot[SLOT_MASK_FIERCE_DEITY + 1];
+
// Reference https://tcrf.net/Proto:The_Legend_of_Zelda:_Majora's_Mask/Debug_Version/Event_Editor
// The source was last referenced on 2025-08-05 and had a last updated value of 2024-06-29
// clang-format off
diff --git a/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTracker.cpp b/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTracker.cpp
index c8c4852f2..c0e7eebcc 100644
--- a/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTracker.cpp
+++ b/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTracker.cpp
@@ -15,6 +15,7 @@ extern "C" {
#include <macros.h>
#include <functions.h>
#include "2s2h_assets.h"
+#include "assets/archives/icon_item_static/icon_item_static_yar.h"
#include "overlays/actors/ovl_En_Si/z_en_si.h"
}
@@ -24,403 +25,227 @@ extern std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
#define FORMAT_COUNT "{}/{}"
-ImVec4 trackerWindowOpacity = ImVec4(0, 0, 0, 0.5f);
+std::vector<TrackerGroup> itemTrackerGroups;
-std::vector<ImVec4> dungeonKeyColors = {
- { 0.9f, 0.33f, 0.56f, 0.4f },
- { 0.1f, 0.54f, 0.16f, 0.4f },
- { 0.61f, 0.04f, 0.86f, 0.4f },
- { 0.58f, 0.65f, 0.15f, 0.4f },
-};
-
-extern TrackerImageObject GetTextureObject(int16_t itemId, bool isRandoItem) {
- int16_t currentItemId = ITEM_NONE;
- int16_t bottleId = 0;
+TrackerImageObject GetImageObject(TrackerItemType itemType, u32 itemId) {
bool itemObtained = false;
+ TrackerImageObject trackerImageObject = {
+ .textureColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f),
+ .textureDimensions = ImVec2(ITEM_TEXTURE_SIZE, ITEM_TEXTURE_SIZE),
+ };
- if (isRandoItem) {
- TrackerImageObject randoImageObject;
- randoImageObject.textureColor = Ship_GetRandoItemColorTint(itemId);
-
- switch (itemId) {
- case RI_FROG_BLUE:
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_33_01);
- break;
- case RI_FROG_CYAN:
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_32_40);
- break;
- case RI_FROG_PINK:
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_32_80);
- break;
- case RI_FROG_WHITE:
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_33_02);
- break;
- case RI_OWL_CLOCK_TOWN_SOUTH:
- itemObtained = GET_OWL_STATUE_ACTIVATED(OWL_WARP_CLOCK_TOWN);
- break;
- case RI_OWL_GREAT_BAY_COAST:
- itemObtained = GET_OWL_STATUE_ACTIVATED(OWL_WARP_GREAT_BAY_COAST);
- break;
- case RI_OWL_IKANA_CANYON:
- itemObtained = GET_OWL_STATUE_ACTIVATED(OWL_WARP_IKANA_CANYON);
- break;
- case RI_OWL_MILK_ROAD:
- itemObtained = GET_OWL_STATUE_ACTIVATED(OWL_WARP_MILK_ROAD);
- break;
- case RI_OWL_MOUNTAIN_VILLAGE:
- itemObtained = GET_OWL_STATUE_ACTIVATED(OWL_WARP_MOUNTAIN_VILLAGE);
- break;
- case RI_OWL_SNOWHEAD:
- itemObtained = GET_OWL_STATUE_ACTIVATED(OWL_WARP_SNOWHEAD);
- break;
- case RI_OWL_SOUTHERN_SWAMP:
- itemObtained = GET_OWL_STATUE_ACTIVATED(OWL_WARP_SOUTHERN_SWAMP);
- break;
- case RI_OWL_STONE_TOWER:
- itemObtained = GET_OWL_STATUE_ACTIVATED(OWL_WARP_STONE_TOWER);
- break;
- case RI_OWL_WOODFALL:
- itemObtained = GET_OWL_STATUE_ACTIVATED(OWL_WARP_WOODFALL);
- break;
- case RI_OWL_ZORA_CAPE:
- itemObtained = GET_OWL_STATUE_ACTIVATED(OWL_WARP_ZORA_CAPE);
- break;
- case RI_SOUL_BOSS_GOHT:
- case RI_SOUL_BOSS_GYORG:
- case RI_SOUL_BOSS_MAJORA:
- case RI_SOUL_BOSS_ODOLWA:
- case RI_SOUL_BOSS_TWINMOLD:
- case RI_SOUL_ENEMY_ALIEN:
- case RI_SOUL_ENEMY_ARMOS:
- case RI_SOUL_ENEMY_BAD_BAT:
- case RI_SOUL_ENEMY_BEAMOS:
- case RI_SOUL_ENEMY_BOE:
- case RI_SOUL_ENEMY_BUBBLE:
- case RI_SOUL_ENEMY_CAPTAIN_KEETA:
- case RI_SOUL_ENEMY_CHUCHU:
- case RI_SOUL_ENEMY_DEATH_ARMOS:
- case RI_SOUL_ENEMY_DEEP_PYTHON:
- case RI_SOUL_ENEMY_DEKU_BABA:
- case RI_SOUL_ENEMY_DEXIHAND:
- case RI_SOUL_ENEMY_DINOLFOS:
- case RI_SOUL_ENEMY_DODONGO:
- case RI_SOUL_ENEMY_DRAGONFLY:
- case RI_SOUL_ENEMY_EENO:
- case RI_SOUL_ENEMY_EYEGORE:
- case RI_SOUL_ENEMY_FREEZARD:
- case RI_SOUL_ENEMY_GARO:
- case RI_SOUL_ENEMY_GEKKO:
- case RI_SOUL_ENEMY_GIANT_BEE:
- case RI_SOUL_ENEMY_GOMESS:
- case RI_SOUL_ENEMY_GUAY:
- case RI_SOUL_ENEMY_HIPLOOP:
- case RI_SOUL_ENEMY_IGOS_DU_IKANA:
- case RI_SOUL_ENEMY_IRON_KNUCKLE:
- case RI_SOUL_ENEMY_KEESE:
- case RI_SOUL_ENEMY_LEEVER:
- case RI_SOUL_ENEMY_LIKE_LIKE:
- case RI_SOUL_ENEMY_MAD_SCRUB:
- case RI_SOUL_ENEMY_NEJIRON:
- case RI_SOUL_ENEMY_OCTOROK:
- case RI_SOUL_ENEMY_PEAHAT:
- case RI_SOUL_ENEMY_PIRATE:
- case RI_SOUL_ENEMY_POE:
- case RI_SOUL_ENEMY_REDEAD:
- case RI_SOUL_ENEMY_SHELLBLADE:
- case RI_SOUL_ENEMY_SKULLFISH:
- case RI_SOUL_ENEMY_SKULLTULA:
- case RI_SOUL_ENEMY_SNAPPER:
- case RI_SOUL_ENEMY_STALCHILD:
- case RI_SOUL_ENEMY_TAKKURI:
- case RI_SOUL_ENEMY_TEKTITE:
- case RI_SOUL_ENEMY_WALLMASTER:
- case RI_SOUL_ENEMY_WART:
- case RI_SOUL_ENEMY_WIZROBE:
- case RI_SOUL_ENEMY_WOLFOS:
- itemObtained = Flags_GetRandoInf(SOUL_RI_TO_RANDO_INF(itemId));
- break;
- case RI_TINGLE_MAP_CLOCK_TOWN:
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_CLOCK_TOWN);
- break;
- case RI_TINGLE_MAP_WOODFALL:
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_WOODFALL);
- break;
- case RI_TINGLE_MAP_SNOWHEAD:
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_SNOWHEAD);
- break;
- case RI_TINGLE_MAP_ROMANI_RANCH:
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_ROMANI_RANCH);
- break;
- case RI_TINGLE_MAP_GREAT_BAY:
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_GREAT_BAY);
- break;
- case RI_TINGLE_MAP_STONE_TOWER:
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_TINGLE_MAP_BOUGHT_STONE_TOWER);
- break;
- case RI_TIME_DAY_1:
- case RI_TIME_DAY_2:
- case RI_TIME_DAY_3:
- randoImageObject.textureColor = ImVec4(1.0f, 0.9f, 0.3f, 1.0f); // Yellow/gold for sun
- itemObtained = Flags_GetRandoInf(
- static_cast<RandoInf>(RANDO_INF_OBTAINED_CLOCK_DAY_1 +
- Rando::ClockItems::GetHalfDayIndexFromClockItem((RandoItemId)itemId)));
- break;
- case RI_TIME_NIGHT_1:
- case RI_TIME_NIGHT_2:
- case RI_TIME_NIGHT_3:
- randoImageObject.textureColor = ImVec4(0.5f, 0.7f, 1.0f, 1.0f); // Light blue for moon
- itemObtained = Flags_GetRandoInf(
- static_cast<RandoInf>(RANDO_INF_OBTAINED_CLOCK_DAY_1 +
- Rando::ClockItems::GetHalfDayIndexFromClockItem((RandoItemId)itemId)));
- break;
- case RI_TRIFORCE_PIECE:
- itemObtained = gSaveContext.save.shipSaveInfo.rando.foundTriforcePieces > 0;
- break;
- case RI_OCARINA_BUTTON_A:
- case RI_OCARINA_BUTTON_C_DOWN:
- case RI_OCARINA_BUTTON_C_LEFT:
- case RI_OCARINA_BUTTON_C_RIGHT:
- case RI_OCARINA_BUTTON_C_UP:
- itemObtained = Flags_GetRandoInf(RANDO_INF_OBTAINED_OCARINA_BUTTON_A + (itemId - RI_OCARINA_BUTTON_A));
- break;
- default:
- break;
- }
- randoImageObject.textureColor.w = itemObtained ? 1.0f : 0.4f;
+ switch (itemType) {
+ case TRACKER_ITEM_RANDO: {
+ RandoItemId randoItemId = (RandoItemId)itemId;
+ switch (randoItemId) {
+ case RI_GS_TOKEN_SWAMP: {
+ itemObtained = Inventory_GetSkullTokenCount(SCENE_KINSTA1) > 0;
+ } break;
+ case RI_GS_TOKEN_OCEAN: {
+ itemObtained = Inventory_GetSkullTokenCount(SCENE_KINDAN2) > 0;
+ } break;
+ case RI_WOODFALL_SMALL_KEY: {
+ itemObtained = DUNGEON_KEY_COUNT(DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE) > 0;
+ } break;
+ case RI_SNOWHEAD_SMALL_KEY: {
+ itemObtained = DUNGEON_KEY_COUNT(DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE) > 0;
+ } break;
+ case RI_GREAT_BAY_SMALL_KEY: {
+ itemObtained = DUNGEON_KEY_COUNT(DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE) > 0;
+ } break;
+ case RI_STONE_TOWER_SMALL_KEY: {
+ itemObtained = DUNGEON_KEY_COUNT(DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE) > 0;
+ } break;
+ case RI_WOODFALL_STRAY_FAIRY: {
+ itemObtained =
+ gSaveContext.save.saveInfo.inventory.strayFairies[DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE] > 0;
+ } break;
+ case RI_SNOWHEAD_STRAY_FAIRY: {
+ itemObtained =
+ gSaveContext.save.saveInfo.inventory.strayFairies[DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE] > 0;
+ } break;
+ case RI_GREAT_BAY_STRAY_FAIRY: {
+ itemObtained =
+ gSaveContext.save.saveInfo.inventory.strayFairies[DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE] > 0;
+ } break;
+ case RI_STONE_TOWER_STRAY_FAIRY: {
+ itemObtained =
+ gSaveContext.save.saveInfo.inventory.strayFairies[DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE] > 0;
+ } break;
+ default: {
+ itemObtained = !Rando::IsItemObtainable(randoItemId);
+ } break;
+ }
- randoImageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
- (const char*)Rando::StaticData::GetIconTexturePath((RandoItemId)itemId));
- randoImageObject.textureDimensions =
- ImVec2(ITEM_TEXTURE_SIZE,
- itemId >= RI_OWL_CLOCK_TOWN_SOUTH && itemId <= RI_OWL_ZORA_CAPE ? 32.0f : ITEM_TEXTURE_SIZE);
+ trackerImageObject.textureColor = Ship_GetRandoItemColorTint(randoItemId);
+ trackerImageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
+ Rando::StaticData::GetIconTexturePath(randoItemId));
+ if (randoItemId >= RI_OWL_CLOCK_TOWN_SOUTH && randoItemId <= RI_OWL_ZORA_CAPE) {
+ trackerImageObject.textureDimensions.y = 24.0f;
+ } else if (randoItemId >= RI_SONG_ELEGY && randoItemId <= RI_SONG_TIME) {
+ trackerImageObject.textureDimensions.x = 32.0f;
+ }
+ } break;
+ case TRACKER_ITEM_SLOT: {
+ itemObtained = gSaveContext.save.saveInfo.inventory.items[itemId] != ITEM_NONE;
+ auto vanillaItemId = gSaveContext.save.saveInfo.inventory.items[itemId];
+ if (vanillaItemId == ITEM_NONE) {
+ vanillaItemId = safeItemsForInventorySlot[itemId][0];
+ }
- return randoImageObject;
- } else {
- if (itemId >= ITEM_BOTTLE_1 && itemId <= ITEM_BOTTLE_6) {
- bottleId = SLOT_BOTTLE_1 + (itemId - ITEM_BOTTLE_1);
- currentItemId = ITEM_BOTTLE;
- }
- if (itemId == ITEM_SKULL_TOKEN_SWAMP || itemId == ITEM_SKULL_TOKEN_OCEAN) {
- currentItemId = ITEM_SKULL_TOKEN;
- }
- if (itemId >= ITEM_CLOCK_TOWN_STRAY_FAIRY && itemId <= ITEM_STONE_TOWER_STRAY_FAIRY) {
- currentItemId = ITEM_STRAY_FAIRIES;
- }
- if (itemId >= ITEM_WOODFALL_DUNGEON_MAP && itemId <= ITEM_STONE_TOWER_KEY_BOSS) {
- const int dungeonIndex = (itemId - ITEM_WOODFALL_DUNGEON_MAP) / 4;
- const int itemTypeIndex = (itemId - ITEM_WOODFALL_DUNGEON_MAP) % 4;
+ trackerImageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
+ (const char*)gItemIcons[vanillaItemId]);
+ } break;
+ case TRACKER_ITEM_SWORD: {
+ if (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) > EQUIP_VALUE_SWORD_NONE) {
+ itemObtained = true;
+ }
+ int vanillaItemId = ITEM_SWORD_KOKIRI;
+ if (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) > EQUIP_VALUE_SWORD_KOKIRI) {
+ vanillaItemId = ITEM_SWORD_KOKIRI + GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) - EQUIP_VALUE_SWORD_KOKIRI;
+ }
- switch (itemTypeIndex) {
- case 0:
- currentItemId = ITEM_DUNGEON_MAP;
- break;
- case 1:
- currentItemId = ITEM_COMPASS;
- break;
- case 2:
- currentItemId = ITEM_KEY_SMALL;
- break;
- case 3:
- currentItemId = ITEM_KEY_BOSS;
- break;
+ trackerImageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
+ (const char*)gItemIcons[vanillaItemId]);
+ } break;
+ case TRACKER_ITEM_SHIELD: {
+ if (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) > EQUIP_VALUE_SHIELD_NONE) {
+ itemObtained = true;
+ }
+ int vanillaItemId = ITEM_SHIELD_HERO;
+ if (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) > EQUIP_VALUE_SHIELD_HERO) {
+ vanillaItemId = ITEM_SHIELD_MIRROR;
}
- }
- }
- if (currentItemId == ITEM_NONE) {
- switch (itemId) {
- case ITEM_MOONS_TEAR:
- currentItemId = ITEM_MOONS_TEAR;
- for (int16_t i = ITEM_MOONS_TEAR; i <= ITEM_DEED_OCEAN; i++) {
- if (gSaveContext.save.saveInfo.inventory.items[SLOT_TRADE_DEED] == i) {
- currentItemId = i;
- break;
- }
- }
- break;
- case ITEM_ROOM_KEY:
- currentItemId = ITEM_ROOM_KEY;
- for (int16_t i = ITEM_ROOM_KEY; i <= ITEM_LETTER_MAMA; i++) {
- if (gSaveContext.save.saveInfo.inventory.items[SLOT_TRADE_KEY_MAMA] == i) {
- currentItemId = i;
- break;
- }
- }
- break;
- case ITEM_LETTER_TO_KAFEI:
- currentItemId = ITEM_LETTER_TO_KAFEI;
- for (int16_t i = ITEM_LETTER_TO_KAFEI; i <= ITEM_PENDANT_OF_MEMORIES; i++) {
- if (gSaveContext.save.saveInfo.inventory.items[SLOT_TRADE_COUPLE] == i) {
- currentItemId = i;
- break;
- }
- }
- break;
- case ITEM_SWORD_KOKIRI:
- currentItemId = ITEM_SWORD_KOKIRI + (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) - EQUIP_VALUE_SWORD_KOKIRI);
- if (currentItemId < ITEM_SWORD_KOKIRI) {
- currentItemId = ITEM_SWORD_KOKIRI;
- }
- break;
- case ITEM_SHIELD_HERO:
- currentItemId = ITEM_SHIELD_HERO + (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) - EQUIP_VALUE_SHIELD_HERO);
- if (currentItemId < ITEM_SHIELD_HERO) {
- currentItemId = ITEM_SHIELD_HERO;
- }
- break;
- case ITEM_WALLET_ADULT:
- currentItemId = ITEM_WALLET_ADULT + CUR_UPG_VALUE(UPG_WALLET) - 1;
- if (currentItemId < ITEM_WALLET_ADULT) {
- currentItemId = ITEM_WALLET_ADULT;
- }
- break;
- case ITEM_MAGIC_JAR_SMALL:
- if (gSaveContext.save.saveInfo.playerData.magicLevel <= 1) {
- currentItemId = ITEM_MAGIC_JAR_SMALL;
- } else {
- currentItemId = ITEM_MAGIC_JAR_BIG;
- }
- break;
- default:
- currentItemId = itemId;
- break;
- }
- }
+ trackerImageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
+ (const char*)gItemIcons[vanillaItemId]);
+ } break;
+ case TRACKER_ITEM_WALLET: {
+ if (CUR_UPG_VALUE(UPG_WALLET) >= 1) {
+ itemObtained = true;
+ }
+ auto vanillaItemId = ITEM_WALLET_ADULT;
+ if (CUR_UPG_VALUE(UPG_WALLET) >= 2) {
+ vanillaItemId = ITEM_WALLET_GIANT;
+ }
- TrackerImageObject imageObject = {
- .textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
- (const char*)gItemIcons[currentItemId]),
- .textureColor = Ship_GetItemColorTint(currentItemId),
- .textureDimensions =
- ImVec2(currentItemId >= ITEM_SONG_SONATA && currentItemId <= ITEM_SONG_SUN ? ITEM_TEXTURE_SIZE / 1.5f
- : ITEM_TEXTURE_SIZE,
- ITEM_TEXTURE_SIZE),
- };
+ trackerImageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
+ (const char*)gItemIcons[vanillaItemId]);
+ } break;
+ case TRACKER_ITEM_MAGIC: {
+ if (gSaveContext.save.saveInfo.playerData.isMagicAcquired) {
+ itemObtained = true;
+ }
+ auto vanillaItemId = ITEM_MAGIC_JAR_SMALL;
+ if (gSaveContext.save.saveInfo.playerData.isDoubleMagicAcquired) {
+ vanillaItemId = ITEM_MAGIC_JAR_BIG;
+ }
- if (itemId >= ITEM_REMAINS_ODOLWA && itemId <= ITEM_BOMBERS_NOTEBOOK) {
- itemObtained = CHECK_QUEST_ITEM(Ship_ConvertItemIdToQuest(itemId));
- } else if (itemId >= ITEM_SWORD_KOKIRI && itemId <= ITEM_SWORD_GILDED) {
- itemObtained = GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) >= EQUIP_VALUE_SWORD_KOKIRI;
- } else if (itemId == ITEM_SHIELD_HERO || itemId == ITEM_SHIELD_MIRROR) {
- itemObtained = GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) >= EQUIP_VALUE_SHIELD_HERO;
- } else if (itemId == ITEM_WALLET_ADULT || itemId == ITEM_WALLET_GIANT) {
- itemObtained = CUR_UPG_VALUE(UPG_WALLET) >= 1;
- } else if (itemId == ITEM_MAGIC_JAR_SMALL || itemId == ITEM_MAGIC_JAR_BIG) {
- itemObtained = gSaveContext.save.saveInfo.playerData.magicLevel != 0;
- } else if (itemId == ITEM_HEART_CONTAINER) {
- itemObtained = gSaveContext.save.saveInfo.playerData.doubleDefense;
- } else if (itemId >= ITEM_BOTTLE_1 && itemId <= ITEM_BOTTLE_6) {
- if (gSaveContext.save.saveInfo.inventory.items[bottleId] != ITEM_NONE && gPlayState) {
- imageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
- (const char*)gItemIcons[gSaveContext.save.saveInfo.inventory.items[bottleId]]);
- } else {
- imageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
- (const char*)gItemIcons[ITEM_BOTTLE]);
- }
- itemObtained = gSaveContext.save.saveInfo.inventory.items[bottleId] != ITEM_NONE;
- } else if (itemId == ITEM_SKULL_TOKEN_SWAMP || itemId == ITEM_SKULL_TOKEN_OCEAN) {
- uint32_t tokenCount = 0;
- if (itemId == ITEM_SKULL_TOKEN_SWAMP) {
- tokenCount = Inventory_GetSkullTokenCount(SCENE_KINSTA1);
- } else {
- tokenCount = Inventory_GetSkullTokenCount(SCENE_KINDAN2);
- }
- itemObtained = tokenCount > 0;
- } else if (itemId >= ITEM_CLOCK_TOWN_STRAY_FAIRY && itemId <= ITEM_STONE_TOWER_STRAY_FAIRY) {
- if (itemId == ITEM_CLOCK_TOWN_STRAY_FAIRY) {
- imageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
- (const char*)fairyIconTextures[0]);
- imageObject.textureColor = ImVec4(1.0f, 0.9f, 0.5f, 0.4f);
- itemObtained = CHECK_WEEKEVENTREG(WEEKEVENTREG_08_80);
- } else {
- imageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
- (const char*)fairyIconTextures[itemId - ITEM_WOODFALL_STRAY_FAIRY]);
- itemObtained = gSaveContext.save.saveInfo.inventory.strayFairies[itemId - ITEM_WOODFALL_STRAY_FAIRY] > 0;
- }
- } else if (itemId >= ITEM_WOODFALL_DUNGEON_MAP && itemId <= ITEM_STONE_TOWER_KEY_BOSS) {
- const int dungeonIndex = (itemId - ITEM_WOODFALL_DUNGEON_MAP) / 4;
- const int itemTypeIndex = (itemId - ITEM_WOODFALL_DUNGEON_MAP) % 4;
- switch (itemTypeIndex) {
- case 0:
- itemObtained = CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, dungeonIndex);
- break;
- case 1:
- itemObtained = CHECK_DUNGEON_ITEM(DUNGEON_MAP, dungeonIndex);
- break;
- case 2:
- imageObject.textureColor = dungeonKeyColors[dungeonIndex];
- itemObtained = DUNGEON_KEY_COUNT(dungeonIndex) > 0;
- break;
- case 3:
- imageObject.textureColor = dungeonKeyColors[dungeonIndex];
- itemObtained = CHECK_DUNGEON_ITEM(DUNGEON_BOSS_KEY, dungeonIndex);
- break;
- }
- } else {
- itemObtained = INV_CONTENT(itemId) != ITEM_NONE;
+ trackerImageObject.textureId = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(
+ (const char*)gItemIcons[vanillaItemId]);
+ } break;
+ default:
+ break;
}
- imageObject.textureColor.w = itemObtained ? 1.0f : 0.4f;
- return imageObject;
+ trackerImageObject.textureColor.w = itemObtained ? 1.0f : 0.4f;
+ return trackerImageObject;
}
-std::string GetItemCounts(int16_t itemId, bool isRandoItem) {
+std::string GetItemCounts(TrackerItemType itemType, u32 itemId) {
std::string countStr = "";
- if (isRandoItem) {
- if (itemId == RI_TRIFORCE_PIECE) {
- int16_t maxPieces = gSaveContext.save.shipSaveInfo.rando.randoSaveOptions[RO_TRIFORCE_PIECES_REQUIRED];
- countStr = fmt::format(FORMAT_COUNT, gSaveContext.save.shipSaveInfo.rando.foundTriforcePieces,
- maxPieces == 1000 ? "1k" : std::to_string(maxPieces));
- }
- } else {
- int dungeonIndex = 0;
- switch (itemId) {
- case ITEM_BOW:
- case ITEM_BOMB:
- case ITEM_BOMBCHU:
- case ITEM_DEKU_STICK:
- case ITEM_DEKU_NUT:
- case ITEM_MAGIC_BEANS:
- case ITEM_POWDER_KEG:
- countStr = std::to_string(AMMO(itemId));
- break;
- case ITEM_WALLET_ADULT:
- countStr = std::to_string(gSaveContext.save.saveInfo.playerData.rupees);
- break;
- case ITEM_PICTOGRAPH_BOX:
- countStr = CHECK_QUEST_ITEM(QUEST_PICTOGRAPH) ? "1" : "0";
- break;
- case ITEM_SKULL_TOKEN_SWAMP:
- case ITEM_SKULL_TOKEN_OCEAN:
- countStr = fmt::format(
- FORMAT_COUNT,
- Inventory_GetSkullTokenCount(itemId == ITEM_SKULL_TOKEN_SWAMP ? SCENE_KINSTA1 : SCENE_KINDAN2),
- IS_RANDO ? RANDO_SAVE_OPTIONS[RO_MINIMUM_SKULLTULA_TOKENS] : SPIDER_HOUSE_TOKENS_REQUIRED);
- break;
- case ITEM_WOODFALL_STRAY_FAIRY:
- case ITEM_SNOWHEAD_STRAY_FAIRY:
- case ITEM_GREAT_BAY_STRAY_FAIRY:
- case ITEM_STONE_TOWER_STRAY_FAIRY:
- countStr = fmt::format(
- FORMAT_COUNT, gSaveContext.save.saveInfo.inventory.strayFairies[itemId - ITEM_WOODFALL_STRAY_FAIRY],
- IS_RANDO ? RANDO_SAVE_OPTIONS[RO_MINIMUM_STRAY_FAIRIES] : STRAY_FAIRY_SCATTERED_TOTAL);
- break;
- case ITEM_WOODFALL_KEY_SMALL:
- case ITEM_SNOWHEAD_KEY_SMALL:
- case ITEM_GREAT_BAY_KEY_SMALL:
- case ITEM_STONE_TOWER_KEY_SMALL:
- dungeonIndex = (itemId - ITEM_WOODFALL_DUNGEON_MAP) / 4;
- countStr = DUNGEON_KEY_COUNT(dungeonIndex) < 0 ? "0" : std::to_string(DUNGEON_KEY_COUNT(dungeonIndex));
- break;
- default:
- break;
- }
+
+ switch (itemType) {
+ case TRACKER_ITEM_RANDO: {
+ switch (itemId) {
+ case RI_TRIFORCE_PIECE: {
+ auto max = RANDO_SAVE_OPTIONS[RO_TRIFORCE_PIECES_REQUIRED];
+ countStr = fmt::format(FORMAT_COUNT, gSaveContext.save.shipSaveInfo.rando.foundTriforcePieces,
+ max > 999 ? "1k" : std::to_string(max));
+ } break;
+ case RI_GS_TOKEN_OCEAN:
+ case RI_GS_TOKEN_SWAMP: {
+ auto max =
+ IS_RANDO ? RANDO_SAVE_OPTIONS[RO_MINIMUM_SKULLTULA_TOKENS] : SPIDER_HOUSE_TOKENS_REQUIRED;
+ auto count =
+ Inventory_GetSkullTokenCount(itemId == RI_GS_TOKEN_SWAMP ? SCENE_KINSTA1 : SCENE_KINDAN2);
+ countStr = fmt::format(FORMAT_COUNT, count, max);
+ } break;
+ case RI_WOODFALL_STRAY_FAIRY: {
+ auto max = IS_RANDO ? RANDO_SAVE_OPTIONS[RO_MINIMUM_STRAY_FAIRIES] : STRAY_FAIRY_SCATTERED_TOTAL;
+ auto count = gSaveContext.save.saveInfo.inventory.strayFairies[DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE];
+ countStr = fmt::format(FORMAT_COUNT, count, max);
+ } break;
+ case RI_SNOWHEAD_STRAY_FAIRY: {
+ auto max = IS_RANDO ? RANDO_SAVE_OPTIONS[RO_MINIMUM_STRAY_FAIRIES] : STRAY_FAIRY_SCATTERED_TOTAL;
+ auto count = gSaveContext.save.saveInfo.inventory.strayFairies[DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE];
+ countStr = fmt::format(FORMAT_COUNT, count, max);
+ } break;
+ case RI_GREAT_BAY_STRAY_FAIRY: {
+ auto max = IS_RANDO ? RANDO_SAVE_OPTIONS[RO_MINIMUM_STRAY_FAIRIES] : STRAY_FAIRY_SCATTERED_TOTAL;
+ auto count =
+ gSaveContext.save.saveInfo.inventory.strayFairies[DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE];
+ countStr = fmt::format(FORMAT_COUNT, count, max);
+ } break;
+ case RI_STONE_TOWER_STRAY_FAIRY: {
+ auto max = IS_RANDO ? RANDO_SAVE_OPTIONS[RO_MINIMUM_STRAY_FAIRIES] : STRAY_FAIRY_SCATTERED_TOTAL;
+ auto count =
+ gSaveContext.save.saveInfo.inventory.strayFairies[DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE];
+ countStr = fmt::format(FORMAT_COUNT, count, max);
+ } break;
+ case RI_WOODFALL_SMALL_KEY: {
+ auto count = DUNGEON_KEY_COUNT(DUNGEON_SCENE_INDEX_WOODFALL_TEMPLE);
+ if (count > 0)
+ countStr = fmt::format(FORMAT_COUNT, count, 1);
+ } break;
+ case RI_SNOWHEAD_SMALL_KEY: {
+ auto count = DUNGEON_KEY_COUNT(DUNGEON_SCENE_INDEX_SNOWHEAD_TEMPLE);
+ if (count > 0)
+ countStr = fmt::format(FORMAT_COUNT, count, 3);
+ } break;
+ case RI_GREAT_BAY_SMALL_KEY: {
+ auto count = DUNGEON_KEY_COUNT(DUNGEON_SCENE_INDEX_GREAT_BAY_TEMPLE);
+ if (count > 0)
+ countStr = fmt::format(FORMAT_COUNT, count, 1);
+ } break;
+ case RI_STONE_TOWER_SMALL_KEY: {
+ auto count = DUNGEON_KEY_COUNT(DUNGEON_SCENE_INDEX_STONE_TOWER_TEMPLE);
+ if (count > 0)
+ countStr = fmt::format(FORMAT_COUNT, count, 4);
+ } break;
+ default:
+ break;
+ }
+ } break;
+ case TRACKER_ITEM_SLOT: {
+ switch (itemId) {
+ case SLOT_BOW:
+ case SLOT_BOMB:
+ case SLOT_BOMBCHU:
+ case SLOT_DEKU_STICK:
+ case SLOT_DEKU_NUT:
+ case SLOT_MAGIC_BEANS:
+ case SLOT_POWDER_KEG: {
+ auto count = gSaveContext.save.saveInfo.inventory.ammo[itemId];
+ if (count > 0)
+ countStr = std::to_string(count);
+ } break;
+ default:
+ break;
+ }
+ } break;
+ case TRACKER_ITEM_WALLET: {
+ countStr = std::to_string(CUR_CAPACITY(UPG_WALLET));
+ } break;
+ default:
+ break;
}
+
return countStr;
}
-void DrawItemCounts(int16_t itemId, bool isRandoItem, ImVec2 textureSize, float scale, ImVec2 currentPos) {
- std::string itemCount = GetItemCounts(itemId, isRandoItem);
+void DrawItemCounts(TrackerItemType itemType, u32 itemId, ImVec2 textureSize, float scale, ImVec2 currentPos) {
+ std::string itemCount = GetItemCounts(itemType, itemId);
if (itemCount.empty()) {
return;
@@ -434,36 +259,121 @@ void DrawItemCounts(int16_t itemId, bool isRandoItem, ImVec2 textureSize, float
ImGui::Text(itemCount.c_str());
}
-void DrawItemSlot(int16_t itemId, float scale, bool isRandoItem) {
+bool DrawItemTrackerSlot(TrackerItemType itemType, u32 itemId, float scale, bool clickable) {
ImVec2 currentPos = ImGui::GetCursorPos();
- TrackerImageObject imageObject = GetTextureObject(itemId, isRandoItem);
- ImGui::Image(imageObject.textureId,
- ImVec2(imageObject.textureDimensions.x * scale, imageObject.textureDimensions.y * scale), ImVec2(0, 0),
- ImVec2(1, 1), imageObject.textureColor, ImVec4(0, 0, 0, 0));
- UIWidgets::Tooltip(GetItemTrackerItemName(itemId, isRandoItem).c_str());
- if (CVarGetInteger("gSettings.ItemTracker.ItemCounts", 0)) {
- DrawItemCounts(itemId, isRandoItem, imageObject.textureDimensions * scale, scale, currentPos);
+ ImVec2 cellSize(ITEM_TEXTURE_SIZE * scale, ITEM_TEXTURE_SIZE * scale);
+
+ TrackerImageObject imageObject = GetImageObject(itemType, itemId);
+
+ // Create an invisible button for layout + clicks
+ bool clicked = false;
+ if (clickable) {
+ imageObject.textureColor.w = 1.0f; // force full opacity for clickable items
+ clicked = ImGui::InvisibleButton(std::to_string(itemId).c_str(), cellSize);
+ } else {
+ ImGui::Dummy(cellSize);
+ }
+
+ // Draw image centered inside the cell
+ ImVec2 p0 = ImGui::GetItemRectMin();
+ ImVec2 p1 = ImGui::GetItemRectMax();
+
+ if (clickable) {
+ bool hovered = ImGui::IsItemHovered();
+ bool held = ImGui::IsItemActive();
+
+ ImU32 bg;
+ if (held) {
+ bg = IM_COL32(0, 0, 0, 60); // pressed
+ } else if (hovered) {
+ bg = IM_COL32(255, 255, 255, 20); // hover
+ } else {
+ bg = IM_COL32(0, 0, 0, 0); // idle subtle
+ }
+
+ ImGui::GetWindowDrawList()->AddRectFilled(p0, p1, bg, 4.0f); // small rounding
+ }
+
+ float aspect = imageObject.textureDimensions.x / imageObject.textureDimensions.y;
+
+ // fit to height
+ ImVec2 drawSize(cellSize.y * aspect, cellSize.y);
+
+ // clamp if too wide
+ if (drawSize.x > cellSize.x) {
+ drawSize.x = cellSize.x;
+ drawSize.y = cellSize.x / aspect;
+ }
+
+ ImVec2 offset((cellSize.x - drawSize.x) * 0.5f, (cellSize.y - drawSize.y) * 0.5f);
+
+ // Draw a glow behind skulltula tokens
+ if (itemType == TRACKER_ITEM_RANDO && (itemId == RI_GS_TOKEN_SWAMP || itemId == RI_GS_TOKEN_OCEAN)) {
+ ImVec4 tintColor = ImVec4(25.0f / 255.0f, 251.0f / 255.0f, 0.0f, imageObject.textureColor.w); // Swamp tint
+ if (itemId == RI_GS_TOKEN_OCEAN) {
+ tintColor = ImVec4(0.0f, 209.0f / 256.0f, 231.0f / 256.0f, imageObject.textureColor.w); // Ocean tint
+ }
+ auto textureId =
+ Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(gMagicArrowEquipEffectTex);
+
+ // Draw texture behind the actual item icon
+ ImGui::GetWindowDrawList()->AddImage(textureId, p0 + offset - ImVec2(8.0f, 8.0f),
+ p0 + offset + drawSize + ImVec2(8.0f, 8.0f), ImVec2(0, 0), ImVec2(1, 1),
+ ImGui::GetColorU32(tintColor));
+ }
+
+ if (itemType == TRACKER_ITEM_RANDO && itemId >= RI_SOUL_BOSS_GOHT && itemId <= RI_SOUL_BOSS_TWINMOLD) {
+ ImVec4 tintColor =
+ ImVec4(255.0f / 255.0f, 255.0f / 255.0f, 255.0f / 255.0f, imageObject.textureColor.w); // Swamp tint
+ auto textureId =
+ Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(gMagicArrowEquipEffectTex);
+
+ // Draw texture behind the actual item icon
+ ImGui::GetWindowDrawList()->AddImage(textureId, p0 + offset - ImVec2(8.0f, 8.0f),
+ p0 + offset + drawSize + ImVec2(8.0f, 8.0f), ImVec2(0, 0), ImVec2(1, 1),
+ ImGui::GetColorU32(tintColor));
+ }
+
+ ImGui::GetWindowDrawList()->AddImage(imageObject.textureId, p0 + offset, p0 + offset + drawSize, ImVec2(0, 0),
+ ImVec2(1, 1), ImGui::GetColorU32(imageObject.textureColor));
+ auto itemName = GetItemTrackerItemName(itemType, itemId);
+ if (!itemName.empty()) {
+ UIWidgets::Tooltip(itemName.c_str());
}
+
+ // Save last item data before drawing counts (which uses ImGui::Text and changes last item)
+ ImGuiContext& g = *ImGui::GetCurrentContext();
+ ImGuiLastItemData backup = g.LastItemData;
+
+ if (CVarGetInteger("gSettings.ItemTracker.ItemCounts", 1)) {
+ DrawItemCounts(itemType, itemId, cellSize, scale, currentPos);
+ }
+
+ // Restore last item data so drag/drop operations work correctly
+ g.LastItemData = backup;
+
+ return clicked;
}
-void DrawItemWindowList(TrackerItemListObject windowObject, bool isRandoItem) {
- int columns = windowObject.columnLength;
- if (windowObject.itemList.size() < windowObject.columnLength) {
- columns = windowObject.itemList.size();
+void DrawItemTrackerGroup(TrackerGroup& trackerGroup) {
+ int columns = trackerGroup.columns;
+ if (trackerGroup.items.size() < trackerGroup.columns) {
+ columns = trackerGroup.items.size();
}
- if (ImGui::BeginTable(windowObject.windowName.c_str(), columns)) {
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(5, 5));
+ float scale = CVarGetInteger("gSettings.ItemTracker.WindowGroup", 0)
+ ? trackerGroup.scale
+ : CVarGetFloat("gSettings.ItemTracker.Scale", 1.0f);
- for (auto& item : windowObject.itemList) {
+ if (ImGui::BeginTable(trackerGroup.name.c_str(), columns)) {
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
+ for (auto& [itemType, itemId] : trackerGroup.items) {
ImGui::TableNextColumn();
- ImVec2 framePadding = ImVec2(item >= ITEM_SONG_SONATA && item <= ITEM_SONG_SUN ? ITEM_SONG_PADDING : 0, 0);
- ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, framePadding);
- DrawItemSlot(item, windowObject.windowScale, isRandoItem);
- ImGui::PopStyleVar(1);
+ DrawItemTrackerSlot(itemType, itemId, scale, false);
}
- ImGui::PopStyleVar(1);
+ ImGui::PopStyleVar(2);
ImGui::EndTable();
}
}
@@ -484,64 +394,52 @@ void ItemTrackerWindow::Draw() {
if (!CVarGetInteger("gSettings.ItemTracker.WindowType", 0)) {
windowFlags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDocking;
}
- shouldWindowSplit = CVarGetInteger("gSettings.ItemTracker.WindowGroup", 0);
-
- std::vector<std::vector<TrackerItemListObject>*> itemTrackerWindows = {
- &BenGui::mItemTrackerWindow->namedItemWindows,
- &BenGui::mItemTrackerWindow->randoItemWindows,
- };
+ bool shouldWindowSplit = CVarGetInteger("gSettings.ItemTracker.WindowGroup", 0);
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f);
- uint32_t windowIndex = TRACKER_MAIN;
- for (auto* window : itemTrackerWindows) {
- if (!window->empty()) {
- bool singleWindowOpen = false;
- if (!shouldWindowSplit) {
- ImVec4 mainBg = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
- mainBg.w = (*window)[0].windowOpacity;
- ImGui::PushStyleColor(ImGuiCol_WindowBg, mainBg);
- singleWindowOpen =
- ImGui::Begin(windowIndex == TRACKER_MAIN ? "Main Tracker" : "Rando Tracker", nullptr, windowFlags);
- }
+ // Adjust opacity
+ ImVec4 windowBg = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
+ windowBg.w = CVarGetFloat("gSettings.ItemTracker.Opacity", 0.5f);
- uint32_t index = 0;
- for (auto& object : *window) {
- if (object.itemList.empty()) {
- index++;
- continue;
- }
-
- bool isWindowOpen = false;
-
- if (shouldWindowSplit) {
- ImVec4 bg = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
- bg.w = object.windowOpacity;
- ImGui::PushStyleColor(ImGuiCol_WindowBg, bg);
- std::string windowName = std::string(object.windowName) + "##" + std::to_string(index);
- isWindowOpen = ImGui::Begin(windowName.c_str(), nullptr, windowFlags);
- } else {
- isWindowOpen = singleWindowOpen;
- }
-
- if (isWindowOpen) {
- DrawItemWindowList(object, windowIndex == TRACKER_MAIN ? false : true);
- }
-
- if (shouldWindowSplit) {
- ImGui::PopStyleColor(1);
- ImGui::End();
- }
-
- index++;
- }
- if (!shouldWindowSplit) {
- ImGui::PopStyleColor(1);
- ImGui::End();
- }
+ bool singleWindowOpen = false;
+ if (!shouldWindowSplit) {
+ ImGui::PushStyleColor(ImGuiCol_WindowBg, windowBg);
+ singleWindowOpen = ImGui::Begin("Item Tracker", nullptr, windowFlags);
+ }
+
+ uint32_t index = 0;
+ for (auto& group : itemTrackerGroups) {
+ if (group.items.empty()) {
+ index++;
+ continue;
+ }
+
+ bool isWindowOpen = false;
+
+ if (shouldWindowSplit) {
+ ImGui::PushStyleColor(ImGuiCol_WindowBg, windowBg);
+ std::string name = std::string(group.name) + "##" + std::to_string(index);
+ isWindowOpen = ImGui::Begin(name.c_str(), nullptr, windowFlags);
+ } else {
+ isWindowOpen = singleWindowOpen;
}
- windowIndex++;
+
+ if (isWindowOpen) {
+ DrawItemTrackerGroup(group);
+ }
+
+ if (shouldWindowSplit) {
+ ImGui::PopStyleColor(1);
+ ImGui::End();
+ }
+
+ index++;
+ }
+ if (!shouldWindowSplit) {
+ ImGui::PopStyleColor(1);
+ ImGui::End();
}
ImGui::PopStyleColor(1);
diff --git a/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTracker.h b/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTracker.h
index 652b3a22b..2c650bd01 100644
--- a/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTracker.h
+++ b/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTracker.h
@@ -3,44 +3,15 @@
#include "ship/window/gui/GuiWindow.h"
#define ITEM_TEXTURE_SIZE 46.0f
-#define ITEM_SONG_PADDING 8.0f
typedef enum {
- TRACKER_MAIN,
- TRACKER_RANDO,
-} TrackerWindowTypes;
-
-typedef enum {
- ITEM_BOTTLE_1 = 0x100,
- ITEM_BOTTLE_2,
- ITEM_BOTTLE_3,
- ITEM_BOTTLE_4,
- ITEM_BOTTLE_5,
- ITEM_BOTTLE_6,
- ITEM_SKULL_TOKEN_SWAMP,
- ITEM_SKULL_TOKEN_OCEAN,
- ITEM_CLOCK_TOWN_STRAY_FAIRY,
- ITEM_WOODFALL_STRAY_FAIRY,
- ITEM_SNOWHEAD_STRAY_FAIRY,
- ITEM_GREAT_BAY_STRAY_FAIRY,
- ITEM_STONE_TOWER_STRAY_FAIRY,
- ITEM_WOODFALL_DUNGEON_MAP,
- ITEM_WOODFALL_DUNGEON_COMPASS,
- ITEM_WOODFALL_KEY_SMALL,
- ITEM_WOODFALL_KEY_BOSS,
- ITEM_SNOWHEAD_DUNGEON_MAP,
- ITEM_SNOWHEAD_DUNGEON_COMPASS,
- ITEM_SNOWHEAD_KEY_SMALL,
- ITEM_SNOWHEAD_KEY_BOSS,
- ITEM_GREAT_BAY_DUNGEON_MAP,
- ITEM_GREAT_BAY_DUNGEON_COMPASS,
- ITEM_GREAT_BAY_KEY_SMALL,
- ITEM_GREAT_BAY_KEY_BOSS,
- ITEM_STONE_TOWER_DUNGEON_MAP,
- ITEM_STONE_TOWER_DUNGEON_COMPASS,
- ITEM_STONE_TOWER_KEY_SMALL,
- ITEM_STONE_TOWER_KEY_BOSS,
-} TrackerTokenSlots;
+ TRACKER_ITEM_RANDO,
+ TRACKER_ITEM_SLOT,
+ TRACKER_ITEM_SWORD,
+ TRACKER_ITEM_SHIELD,
+ TRACKER_ITEM_WALLET,
+ TRACKER_ITEM_MAGIC,
+} TrackerItemType;
typedef struct {
ImTextureID textureId;
@@ -49,25 +20,21 @@ typedef struct {
} TrackerImageObject;
typedef struct {
- std::string windowName;
- int32_t columnLength;
- float windowScale;
- float windowOpacity;
- std::vector<int16_t> itemList;
-} TrackerItemListObject;
+ std::string name;
+ u8 columns;
+ float scale;
+ std::vector<std::pair<TrackerItemType, u32>> items;
+} TrackerGroup;
-TrackerImageObject GetTextureObject(int16_t itemId, bool isRandoItem = false);
-extern std::string GetItemTrackerItemName(int16_t itemId, bool isRandoItem = false);
-extern bool shouldWindowSplit;
+extern std::vector<TrackerGroup> itemTrackerGroups;
+extern bool DrawItemTrackerSlot(TrackerItemType itemType, u32 itemId, float scale, bool clickable);
+extern std::string GetItemTrackerItemName(TrackerItemType itemType, u32 itemId);
class ItemTrackerWindow : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void Draw() override;
- std::vector<TrackerItemListObject> namedItemWindows;
- std::vector<TrackerItemListObject> randoItemWindows;
-
protected:
void InitElement() override;
void DrawElement() override;
diff --git a/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTrackerSettings.cpp b/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTrackerSettings.cpp
index e02be5b4e..a17d1815c 100644
--- a/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTrackerSettings.cpp
+++ b/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTrackerSettings.cpp
@@ -3,6 +3,7 @@
#include "2s2h/BenGui/UIWidgets.hpp"
#include "ShipUtils.h"
#include "ship/config/Config.h"
+#include "2s2h/ShipInit.hpp"
namespace BenGui {
extern std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
@@ -15,358 +16,206 @@ void ItemTrackerSettingsWindow::UpdateElement() {
static const char* windowTypes[2] = { "Floating", "Window" };
-bool shouldWindowSplit = false;
-int16_t popupSlot = SLOT_OCARINA;
-int16_t indexToRemove = ITEM_OCARINA_OF_TIME;
-static std::string trackerInputName;
-bool shouldTrackerPopUpOpen = false;
-bool shouldRemove = false;
+std::vector<TrackerGroup> itemTrackerGroupsAvailable;
+void SaveItemTrackerLayout();
-std::vector<std::string> listOrder = {
- "Inventory", "Bottles", "Masks", "Songs", "Quest", "Tokens", "Stray Fairies", "Dungeon",
-};
-
-std::vector<std::string> randoListOrder = {
- "Frogs", "Ocarina Buttons", "Boss Souls", "Enemy Souls", "Owl Statues", "Time", "Tingle Maps", "Misc",
-};
-
-std::map<std::string, std::tuple<int16_t, int16_t, int16_t>> defaultItemLists = {
- { "Inventory", { ITEM_OCARINA_OF_TIME, ITEM_LETTER_TO_KAFEI, 6 } },
- { "Bottles", { ITEM_BOTTLE_1, ITEM_BOTTLE_6, 6 } },
- { "Masks", { ITEM_MASK_POSTMAN, ITEM_MASK_FIERCE_DEITY, 6 } },
- { "Songs", { ITEM_SONG_TIME, ITEM_SONG_OATH, 5 } },
- { "Quest", { ITEM_REMAINS_ODOLWA, ITEM_BOMBERS_NOTEBOOK, 4 } },
- { "Tokens", { ITEM_SKULL_TOKEN_SWAMP, ITEM_SKULL_TOKEN_OCEAN, 2 } },
- { "Stray Fairies", { ITEM_CLOCK_TOWN_STRAY_FAIRY, ITEM_STONE_TOWER_STRAY_FAIRY, 5 } },
- { "Dungeon", { ITEM_WOODFALL_DUNGEON_MAP, ITEM_STONE_TOWER_KEY_BOSS, 4 } },
-};
-
-std::map<std::string, std::tuple<int16_t, int16_t, int16_t>> randoItemLists = {
- { "Frogs", { RI_FROG_BLUE, RI_FROG_WHITE, 4 } },
- { "Ocarina Buttons", { RI_OCARINA_BUTTON_A, RI_OCARINA_BUTTON_C_UP, 5 } },
- { "Boss Souls", { RI_SOUL_BOSS_GOHT, RI_SOUL_BOSS_TWINMOLD, 5 } },
- { "Enemy Souls", { RI_SOUL_ENEMY_ALIEN, RI_SOUL_ENEMY_WOLFOS, 6 } },
- { "Owl Statues", { RI_OWL_CLOCK_TOWN_SOUTH, RI_OWL_ZORA_CAPE, 5 } },
- { "Tingle Maps", { RI_TINGLE_MAP_CLOCK_TOWN, RI_TINGLE_MAP_WOODFALL, 6 } },
- { "Time", { RI_TIME_DAY_1, RI_TIME_NIGHT_3, 6 } },
- { "Misc", { RI_TRIFORCE_PIECE, RI_TRIFORCE_PIECE, 1 } },
-};
-
-std::vector<std::string> dungeonPrefix = {
- "Woodfall",
- "Snowhead",
- "Great Bay",
- "Stone Tower",
-};
-
-std::pair<uint32_t, uint32_t> GetItemMapRange(uint32_t start, uint32_t end) {
- std::pair<uint32_t, uint32_t> indexRange;
-
- for (size_t i = 0; i < itemIdToItemNameMap.size(); i++) {
- if (itemIdToItemNameMap[i].first == start) {
- indexRange.first = static_cast<int>(i);
- }
- if (itemIdToItemNameMap[i].first == end) {
- indexRange.second = static_cast<int>(i);
- }
+std::vector<std::pair<TrackerItemType, u32>> GetItemsFromRange(TrackerItemType itemType, u32 start, u32 end) {
+ std::vector<std::pair<TrackerItemType, u32>> items;
+ for (u32 itemId = start; itemId <= end; itemId++) {
+ items.push_back({ itemType, itemId });
}
-
- return indexRange;
+ return items;
}
-std::string GetItemTrackerItemName(int16_t itemId, bool isRandoItem) {
- std::string itemName = "";
- uint16_t fallBackCheck = 0;
- if (isRandoItem) {
- itemName = Rando::StaticData::Items[(RandoItemId)itemId].name;
- } else {
- if (itemId >= ITEM_BOTTLE_1 && itemId <= ITEM_BOTTLE_6) {
- itemName = "Bottle";
- } else if (itemId == ITEM_SKULL_TOKEN_SWAMP) {
- itemName = "Swamp Token";
- } else if (itemId == ITEM_SKULL_TOKEN_OCEAN) {
- itemName = "Ocean Token";
- } else if (itemId == ITEM_CLOCK_TOWN_STRAY_FAIRY) {
- itemName = "Clock Town Stray Fairy";
- } else if (itemId >= ITEM_WOODFALL_STRAY_FAIRY && itemId <= ITEM_STONE_TOWER_STRAY_FAIRY) {
- itemName = dungeonPrefix[itemId - ITEM_WOODFALL_STRAY_FAIRY] + " Stray Fairy";
- } else if (itemId >= ITEM_WOODFALL_DUNGEON_MAP && itemId <= ITEM_STONE_TOWER_KEY_BOSS) {
- switch (itemId) {
- case ITEM_WOODFALL_DUNGEON_MAP:
- case ITEM_SNOWHEAD_DUNGEON_MAP:
- case ITEM_GREAT_BAY_DUNGEON_MAP:
- case ITEM_STONE_TOWER_DUNGEON_MAP:
- // Note the Map and Compass are swapped in vanilla code, this is correcting that.
- itemName = dungeonPrefix[(itemId - ITEM_WOODFALL_DUNGEON_MAP) / 4] + " Compass";
- break;
- case ITEM_WOODFALL_DUNGEON_COMPASS:
- case ITEM_SNOWHEAD_DUNGEON_COMPASS:
- case ITEM_GREAT_BAY_DUNGEON_COMPASS:
- case ITEM_STONE_TOWER_DUNGEON_COMPASS:
- itemName = dungeonPrefix[(itemId - ITEM_WOODFALL_DUNGEON_COMPASS) / 4] + " Map";
- break;
- case ITEM_WOODFALL_KEY_SMALL:
- case ITEM_SNOWHEAD_KEY_SMALL:
- case ITEM_GREAT_BAY_KEY_SMALL:
- case ITEM_STONE_TOWER_KEY_SMALL:
- itemName = dungeonPrefix[(itemId - ITEM_WOODFALL_KEY_SMALL) / 4] + " Small Key";
- break;
- case ITEM_WOODFALL_KEY_BOSS:
- case ITEM_SNOWHEAD_KEY_BOSS:
- case ITEM_GREAT_BAY_KEY_BOSS:
- case ITEM_STONE_TOWER_KEY_BOSS:
- itemName = dungeonPrefix[(itemId - ITEM_WOODFALL_KEY_BOSS) / 4] + " Boss Key";
- break;
- default:
- break;
+std::string GetItemTrackerItemName(TrackerItemType itemType, u32 itemId) {
+ switch (itemType) {
+ case TRACKER_ITEM_RANDO: {
+ return Rando::StaticData::Items[(RandoItemId)itemId].name;
+ } break;
+ case TRACKER_ITEM_SLOT: {
+ auto vanillaItemId = gSaveContext.save.saveInfo.inventory.items[itemId];
+ if (vanillaItemId == ITEM_NONE) {
+ vanillaItemId = safeItemsForInventorySlot[itemId][0];
}
- } else if (itemId == ITEM_MAGIC_JAR_SMALL || itemId == ITEM_MAGIC_JAR_BIG) {
- itemName = gSaveContext.save.saveInfo.playerData.magicLevel > 1 ? "Double Magic" : "Single Magic";
- } else if (itemId == ITEM_HEART_CONTAINER) {
- itemName = "Double Defense";
- } else if (itemId >= ITEM_MOONS_TEAR && itemId <= ITEM_PENDANT_OF_MEMORIES) {
- itemName = Ship_GetItemNameById(gSaveContext.save.saveInfo.inventory.items[gItemSlots[itemId]]);
- } else if (itemId == ITEM_SWORD_KOKIRI) {
- fallBackCheck = ITEM_SWORD_KOKIRI + (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) - EQUIP_VALUE_SWORD_KOKIRI);
- itemName = Ship_GetItemNameById(fallBackCheck <= ITEM_SWORD_KOKIRI ? ITEM_SWORD_KOKIRI : fallBackCheck);
- } else if (itemId == ITEM_SHIELD_HERO) {
- fallBackCheck = ITEM_SHIELD_HERO + (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) - EQUIP_VALUE_SHIELD_HERO);
- itemName = Ship_GetItemNameById(fallBackCheck <= ITEM_SHIELD_HERO ? ITEM_SHIELD_HERO : fallBackCheck);
- } else if (itemId == ITEM_WALLET_ADULT) {
- fallBackCheck = ITEM_WALLET_ADULT + CUR_UPG_VALUE(UPG_WALLET) - 1;
- itemName = Ship_GetItemNameById(fallBackCheck <= ITEM_WALLET_ADULT ? ITEM_WALLET_ADULT : fallBackCheck);
- }
- }
-
- if (itemName == "") {
- itemName = Ship_GetItemNameById(itemId);
- }
-
- return itemName;
-}
-
-TrackerItemListObject CreateTrackerObject() {
- std::vector<int16_t> itemTrackerList;
- TrackerItemListObject trackerObject = {
- .windowName = trackerInputName.c_str(),
- .columnLength = 6,
- .windowScale = 1.0f,
- .windowOpacity = 0.5f,
- .itemList = itemTrackerList,
- };
- return trackerObject;
-}
-
-void ItemTrackerPopUpContext(int16_t itemId, bool isRandoItem) {
- bool shouldClose = false;
- uint32_t availableSlots = 0;
- uint32_t windowIndex = 0;
- std::vector<TrackerItemListObject>* window =
- isRandoItem ? &BenGui::mItemTrackerWindow->randoItemWindows : &BenGui::mItemTrackerWindow->namedItemWindows;
- if (shouldTrackerPopUpOpen && ImGui::BeginPopup("ItemWindowSubMenu")) {
- for (auto& object : *window) {
- ImGui::PushID(windowIndex);
- auto findInObject = std::find(object.itemList.begin(), object.itemList.end(), itemId);
- if (findInObject == object.itemList.end()) {
- std::string windowStr = "Add to ";
- windowStr += object.windowName;
- if (UIWidgets::Button(windowStr.c_str(), { .size = ImVec2(0, 0), .color = WIDGET_COLOR })) {
- object.itemList.push_back(itemId);
- shouldClose = true;
- }
- availableSlots++;
+ RandoItemId randoItemId = Rando::StaticData::GetItemIdFromVanillaItemId(vanillaItemId);
+ return Rando::StaticData::Items[randoItemId].name;
+ } break;
+ case TRACKER_ITEM_SWORD: {
+ if (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) == EQUIP_VALUE_SWORD_KOKIRI) {
+ return Rando::StaticData::Items[RI_SWORD_KOKIRI].name;
}
- ImGui::PopID();
- windowIndex++;
- }
- if (availableSlots == 0) {
- ImGui::Text("No Slot Available");
- }
- if (shouldClose) {
- ImGui::CloseCurrentPopup();
- shouldTrackerPopUpOpen = false;
- }
-
- ImGui::EndPopup();
- }
-}
-
-void ItemTrackerDragAndDrop(std::vector<int16_t>& itemWindow, size_t i, TrackerImageObject itemObject) {
- if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
- ImGui::SetDragDropPayload("TRACKER_DRAG", &i, sizeof(size_t));
- ImGui::ImageButton(std::to_string(itemWindow[i]).c_str(), itemObject.textureId, itemObject.textureDimensions,
- ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), itemObject.textureColor);
- ImGui::EndDragDropSource();
- }
-
- if (ImGui::BeginDragDropTarget()) {
- if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("TRACKER_DRAG")) {
- size_t srcIndex = *(const size_t*)payload->Data;
- if (srcIndex != i && srcIndex < itemWindow.size()) {
- auto item = itemWindow[srcIndex];
- itemWindow.erase(itemWindow.begin() + srcIndex);
-
- if (srcIndex < i) {
- i--;
- }
-
- itemWindow.insert(itemWindow.begin() + i, item);
+ if (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) == EQUIP_VALUE_SWORD_RAZOR) {
+ return Rando::StaticData::Items[RI_SWORD_RAZOR].name;
}
- }
- ImGui::EndDragDropTarget();
- }
-}
-
-void DrawItemTrackerSlot(std::vector<int16_t>& itemList, int16_t itemId, bool shouldAdd, bool isRandoItem) {
- TrackerImageObject imageObject = GetTextureObject(itemId, isRandoItem);
- imageObject.textureColor.w = 1.0f;
- if (ImGui::ImageButton(std::to_string(itemId).c_str(), imageObject.textureId, imageObject.textureDimensions,
- ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), imageObject.textureColor)) {
- if (shouldAdd) {
- shouldTrackerPopUpOpen = true;
- popupSlot = itemId;
- ImGui::OpenPopup("ItemWindowSubMenu");
- } else {
- shouldRemove = false;
- for (int i = 0; i < itemList.size(); i++) {
- if (itemList[i] == itemId) {
- indexToRemove = i;
- shouldRemove = true;
- break;
- }
+ if (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SWORD) == EQUIP_VALUE_SWORD_GILDED) {
+ return Rando::StaticData::Items[RI_SWORD_GILDED].name;
}
- }
+ return "Sword (None)";
+ } break;
+ case TRACKER_ITEM_SHIELD: {
+ if (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) == EQUIP_VALUE_SHIELD_HERO) {
+ return Rando::StaticData::Items[RI_SHIELD_HERO].name;
+ }
+ if (GET_CUR_EQUIP_VALUE(EQUIP_TYPE_SHIELD) == EQUIP_VALUE_SHIELD_MIRROR) {
+ return Rando::StaticData::Items[RI_SHIELD_MIRROR].name;
+ }
+ return "Shield (None)";
+ } break;
+ case TRACKER_ITEM_WALLET: {
+ if (CUR_UPG_VALUE(UPG_WALLET) >= 2) {
+ return Rando::StaticData::Items[RI_WALLET_GIANT].name;
+ }
+ if (CUR_UPG_VALUE(UPG_WALLET) >= 1) {
+ return Rando::StaticData::Items[RI_WALLET_ADULT].name;
+ }
+ return "Wallet (None)";
+ } break;
+ case TRACKER_ITEM_MAGIC: {
+ if (gSaveContext.save.saveInfo.playerData.isDoubleMagicAcquired) {
+ return Rando::StaticData::Items[RI_DOUBLE_MAGIC].name;
+ }
+ if (gSaveContext.save.saveInfo.playerData.isMagicAcquired) {
+ return Rando::StaticData::Items[RI_SINGLE_MAGIC].name;
+ }
+ return "Magic (None)";
+ } break;
+ default:
+ break;
}
- UIWidgets::Tooltip(GetItemTrackerItemName(itemId, isRandoItem).c_str());
+
+ return "";
}
-void DrawItemList(std::string listName, int columns) {
- bool isRandoItem = false;
- if (ImGui::BeginChild(listName.c_str(), ImVec2(0, 0),
+struct DragDropPayload {
+ TrackerItemType itemType;
+ u32 itemId;
+ int sourceGroupIndex;
+ int sourceItemIndex;
+ bool fromAddMode;
+};
+
+void DrawItemTrackerGroupPreview(TrackerGroup& group, bool addMode, int groupIndex) {
+ static std::pair<TrackerItemType, u32> selectedItem = { TRACKER_ITEM_RANDO, 0 };
+
+ if (ImGui::BeginChild(group.name.c_str(), ImVec2(0, 0),
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX |
ImGuiChildFlags_AutoResizeY)) {
- if (ImGui::BeginTable(listName.c_str(), columns)) {
- ImVec2 framePadding = ImVec2(listName == "Songs" ? ITEM_SONG_PADDING : 0, 0);
- ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, framePadding);
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(5, 5));
- std::vector<int16_t> emptyList;
-
- if (listName == "Frogs" || listName == "Ocarina Buttons" || listName == "Boss Souls" ||
- listName == "Enemy Souls" || listName == "Owl Statues" || listName == "Tingle Maps" ||
- listName == "Time" || listName == "Misc") {
- for (int j = std::get<0>(randoItemLists.at(listName)); j <= std::get<1>(randoItemLists.at(listName));
- j++) {
- ImGui::TableNextColumn();
- isRandoItem = true;
- DrawItemTrackerSlot(emptyList, j, true, true);
- }
- } else if (listName == "Bottles" || listName == "Tokens" || listName == "Stray Fairies" ||
- listName == "Dungeon") {
- for (int j = std::get<0>(defaultItemLists.at(listName));
- j <= std::get<1>(defaultItemLists.at(listName)); j++) {
- ImGui::TableNextColumn();
- isRandoItem = false;
- DrawItemTrackerSlot(emptyList, j, true, false);
- }
- } else {
- std::pair<uint32_t, uint32_t> range = GetItemMapRange(std::get<0>(defaultItemLists.at(listName)),
- std::get<1>(defaultItemLists.at(listName)));
- for (int i = range.first; i <= range.second; i++) {
-
- if (itemIdToItemNameMap[i].first == ITEM_WALLET_ADULT) {
- ImGui::TableNextColumn();
- DrawItemTrackerSlot(emptyList, ITEM_MAGIC_JAR_SMALL, true, false);
- ImGui::TableNextColumn();
- DrawItemTrackerSlot(emptyList, ITEM_HEART_CONTAINER, true, false);
+ if (ImGui::BeginTable(group.name.c_str(), group.columns)) {
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
+
+ // Use index-based loop to avoid iterator invalidation
+ for (size_t itemIndex = 0; itemIndex < group.items.size(); itemIndex++) {
+ auto& [itemType, itemId] = group.items[itemIndex];
+ ImGui::TableNextColumn();
+ ImGui::PushID((int)itemIndex);
+ if (DrawItemTrackerSlot(itemType, itemId, 1.0f, true)) {
+ if (addMode) {
+ selectedItem = { itemType, itemId };
+ ImGui::OpenPopup("AddToGroup");
+ } else {
+ group.items.erase(
+ std::remove(group.items.begin(), group.items.end(), std::make_pair(itemType, itemId)),
+ group.items.end());
+ SaveItemTrackerLayout();
}
- ImGui::TableNextColumn();
- DrawItemTrackerSlot(emptyList, itemIdToItemNameMap[i].first, true, isRandoItem);
}
- }
- ImGui::PopStyleVar(2);
- ItemTrackerPopUpContext(popupSlot, isRandoItem);
- ImGui::EndTable();
- }
- }
- ImGui::EndChild();
-}
-void DrawPreviewPane() {
- bool isRandoItem = false;
- uint32_t imguiId = 0;
- uint32_t listIndex = 0;
- uint32_t windowListIndex = TRACKER_MAIN;
- if (ImGui::BeginChild("List Previews")) {
- std::vector<std::vector<TrackerItemListObject>*> windowList = {
- &BenGui::mItemTrackerWindow->namedItemWindows,
- &BenGui::mItemTrackerWindow->randoItemWindows,
- };
-
- for (auto* window : windowList) {
- ImGui::SeparatorText(windowListIndex == TRACKER_MAIN ? "Vanilla Tracker Windows" : "Rando Tracker Windows");
- listIndex = 0;
- for (auto& object : *window) {
- ImGui::PushID(imguiId);
- ImGui::SeparatorText(object.windowName.c_str());
- ImGui::SameLine(ImGui::GetContentRegionMax().x - (ImGui::CalcTextSize("Clear Main").x * 1.5f));
- if (UIWidgets::Button("Clear", { .size = ImVec2(0, 0), .color = UIWidgets::Colors::Red })) {
- object.itemList.clear();
- }
- ImGui::SameLine();
- if (UIWidgets::Button("x", { .size = ImVec2(0, 0), .color = UIWidgets::Colors::Red })) {
- auto& currentWindow = *windowList[windowListIndex];
- currentWindow.erase(currentWindow.begin() + listIndex);
+ // Drag and drop functionality
+ if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
+ DragDropPayload payload;
+ payload.itemType = itemType;
+ payload.itemId = itemId;
+ payload.sourceGroupIndex = groupIndex;
+ payload.sourceItemIndex = (int)itemIndex;
+ payload.fromAddMode = addMode;
+ ImGui::SetDragDropPayload("TRACKER_ITEM", &payload, sizeof(DragDropPayload));
+
+ // Display preview while dragging
+ DrawItemTrackerSlot(itemType, itemId, 0.5f, true);
+ ImGui::EndDragDropSource();
}
- ImGui::PopID();
- if (object.itemList.size() == 0) {
- listIndex++;
- imguiId++;
- continue;
- }
- if (ImGui::BeginTable(std::to_string(listIndex).c_str(), object.columnLength)) {
- ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(5, 5));
- for (int i = 0; i < object.itemList.size(); i++) {
- ImGui::TableNextColumn();
- if (windowListIndex == TRACKER_RANDO) {
- DrawItemTrackerSlot(object.itemList, object.itemList[i], false, true);
- isRandoItem = true;
+
+ // Only allow dropping on removeMode slots
+ if (!addMode && ImGui::BeginDragDropTarget()) {
+ if (const ImGuiPayload* imguiPayload = ImGui::AcceptDragDropPayload("TRACKER_ITEM")) {
+ DragDropPayload* payload = (DragDropPayload*)imguiPayload->Data;
+
+ if (payload->fromAddMode) {
+ // Dragging from addMode to removeMode: insert at this position
+ group.items.insert(group.items.begin() + itemIndex,
+ std::make_pair(payload->itemType, payload->itemId));
+ SaveItemTrackerLayout();
} else {
- DrawItemTrackerSlot(object.itemList, (int16_t)object.itemList[i], false, false);
+ // Dragging from removeMode to removeMode: move item
+ if (payload->sourceGroupIndex == groupIndex) {
+ // Moving within same group
+ if (payload->sourceItemIndex != (int)itemIndex) {
+ auto item = group.items[payload->sourceItemIndex];
+ group.items.erase(group.items.begin() + payload->sourceItemIndex);
+
+ // Adjust target index if we removed an item before it
+ int targetIndex = (int)itemIndex;
+ if (payload->sourceItemIndex < (int)itemIndex) {
+ targetIndex--;
+ }
+ group.items.insert(group.items.begin() + targetIndex, item);
+ SaveItemTrackerLayout();
+ }
+ } else {
+ // Moving between different groups
+ auto item = std::make_pair(payload->itemType, payload->itemId);
+ itemTrackerGroups[payload->sourceGroupIndex].items.erase(
+ itemTrackerGroups[payload->sourceGroupIndex].items.begin() +
+ payload->sourceItemIndex);
+ group.items.insert(group.items.begin() + itemIndex, item);
+ SaveItemTrackerLayout();
+ }
}
- ItemTrackerDragAndDrop(object.itemList, i, GetTextureObject(object.itemList[i], isRandoItem));
}
- if (shouldRemove) {
- object.itemList.erase(object.itemList.begin() + indexToRemove);
- shouldRemove = false;
- indexToRemove = ITEM_OCARINA_OF_TIME;
+ ImGui::EndDragDropTarget();
+ }
+
+ // Check for popup in the same ID scope
+ if (addMode && ImGui::BeginPopup("AddToGroup")) {
+ UIWidgets::PushStyleMenuItem(WIDGET_COLOR);
+ ImGui::SeparatorText("Select group to add item to");
+ for (size_t i = 0; i < itemTrackerGroups.size(); i++) {
+ if (ImGui::Selectable(itemTrackerGroups[i].name.c_str(), false)) {
+ itemTrackerGroups[i].items.push_back(selectedItem);
+ SaveItemTrackerLayout();
+ ImGui::CloseCurrentPopup();
+ }
}
- ImGui::PopStyleVar(2);
- ImGui::EndTable();
+ UIWidgets::PopStyleMenuItem();
+ ImGui::EndPopup();
}
- listIndex++;
- imguiId++;
+
+ ImGui::PopID();
}
- windowListIndex++;
+ ImGui::PopStyleVar(2);
+ ImGui::EndTable();
}
}
ImGui::EndChild();
}
-void DrawTrackerWindowOptions(int32_t windowIndex, TrackerItemListObject& windowObject) {
+bool DrawTrackerWindowOptions(int32_t windowIndex, TrackerGroup& group) {
ImGui::PushID(windowIndex);
- int32_t columns = windowObject.columnLength;
- float scale = windowObject.windowScale;
- float opacity = windowObject.windowOpacity;
+ int32_t columns = group.columns;
+ float scale = group.scale;
std::string trackerInputRename;
if (windowIndex >= 0) {
- if (UIWidgets::InputString("##windowname", &trackerInputRename,
+ if (UIWidgets::InputString("##name", &trackerInputRename,
UIWidgets::InputOptions()
.LabelPosition(UIWidgets::LabelPosition::None)
.Color(WIDGET_COLOR)
- .PlaceholderText(windowObject.windowName)
- .DefaultValue(windowObject.windowName))) {
- windowObject.windowName = trackerInputRename;
+ .PlaceholderText(group.name)
+ .DefaultValue(group.name))) {
+ if (!trackerInputRename.empty() && trackerInputRename != group.name) {
+ group.name = trackerInputRename;
+ SaveItemTrackerLayout();
+ }
}
}
if (UIWidgets::SliderInt("Columns", &columns,
@@ -376,239 +225,377 @@ void DrawTrackerWindowOptions(int32_t windowIndex, TrackerItemListObject& window
.DefaultValue(6)
.LabelPosition(UIWidgets::LabelPosition::None)
.Format("Columns: %i")
- .Color(WIDGET_COLOR)
- .Size(ImVec2(ImGui::GetContentRegionAvail().x / 2, 0)))) {
- windowObject.columnLength = columns;
+ .Color(WIDGET_COLOR))) {
+ group.columns = columns;
+ SaveItemTrackerLayout();
}
- ImGui::SameLine();
- if (UIWidgets::SliderFloat("Scale", &scale,
- UIWidgets::FloatSliderOptions()
- .Min(0.5f)
- .Max(5.0f)
- .DefaultValue(1.0f)
- .LabelPosition(UIWidgets::LabelPosition::None)
- .Format("Scale: %.1f")
- .Step(0.5f)
- .Color(WIDGET_COLOR)
- .Size(ImVec2(ImGui::GetContentRegionAvail().x, 0)))) {
- windowObject.windowScale = scale;
+ if (CVarGetInteger("gSettings.ItemTracker.WindowGroup", 0)) {
+ if (UIWidgets::SliderFloat("Scale", &scale,
+ UIWidgets::FloatSliderOptions()
+ .Min(0.2f)
+ .Max(3.0f)
+ .DefaultValue(1.0f)
+ .LabelPosition(UIWidgets::LabelPosition::None)
+ .Format("Scale: %.1f")
+ .Step(0.5f)
+ .Color(WIDGET_COLOR))) {
+ group.scale = scale;
+ SaveItemTrackerLayout();
+ }
}
- if (UIWidgets::SliderFloat("Opacity", &opacity,
- UIWidgets::FloatSliderOptions()
- .Min(0)
- .Max(1.0f)
- .DefaultValue(0.5f)
- .LabelPosition(UIWidgets::LabelPosition::None)
- .Format("Opacity: %.1f")
- .Step(0.1f)
- .Color(WIDGET_COLOR)
- .Size(ImVec2(ImGui::GetContentRegionAvail().x, 0)))) {
- windowObject.windowOpacity = opacity;
+ if (UIWidgets::Button("Remove Group", { .color = UIWidgets::Colors::Red })) {
+ itemTrackerGroups.erase(itemTrackerGroups.begin() + windowIndex);
+ SaveItemTrackerLayout();
+ ImGui::PopID();
+ return true;
}
ImGui::PopID();
- UIWidgets::Separator();
+ return false;
}
-void ApplyRandoItemGroup(std::string listName) {
- std::tuple<int16_t, int16_t, int16_t> list = randoItemLists.at(listName);
- TrackerItemListObject itemObject = {
- .windowName = listName,
- .columnLength = std::get<2>(list),
- .windowScale = 1.0f,
- .windowOpacity = 0.5f,
- };
- for (int i = std::get<0>(list); i <= std::get<1>(list); i++) {
- itemObject.itemList.push_back(i);
- }
-
- BenGui::mItemTrackerWindow->randoItemWindows.push_back(itemObject);
-}
-
-void ApplyDefaultItemGroup(std::string listName) {
- std::tuple<int16_t, int16_t, int16_t> list = defaultItemLists.at(listName);
- TrackerItemListObject itemObject = {
- .windowName = listName,
- .columnLength = std::get<2>(list),
- .windowScale = 1.0f,
- .windowOpacity = 0.5f,
- };
-
- if (listName == "Bottles" || listName == "Tokens" || listName == "Stray Fairies" || listName == "Dungeon") {
- int16_t baseValue = std::get<0>(list);
- int16_t maxValue = std::get<1>(list);
- for (int j = baseValue; j <= maxValue; j++) {
- itemObject.itemList.push_back(j);
- }
- } else {
- std::pair<uint32_t, uint32_t> range = GetItemMapRange(std::get<0>(list), std::get<1>(list));
- for (int i = range.first; i <= range.second; i++) {
- if (itemIdToItemNameMap[i].first == ITEM_WALLET_ADULT) {
- itemObject.itemList.push_back(ITEM_MAGIC_JAR_SMALL);
- itemObject.itemList.push_back(ITEM_HEART_CONTAINER);
- }
- itemObject.itemList.push_back(itemIdToItemNameMap[i].first);
- }
- }
- BenGui::mItemTrackerWindow->namedItemWindows.push_back(itemObject);
+void LoadAvailableWindows() {
+ itemTrackerGroupsAvailable.clear();
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Inventory",
+ .columns = 6,
+ .scale = 1.0f,
+ .items = GetItemsFromRange(TRACKER_ITEM_SLOT, SLOT_OCARINA, SLOT_BOTTLE_6),
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Masks",
+ .columns = 6,
+ .scale = 1.0f,
+ .items = GetItemsFromRange(TRACKER_ITEM_SLOT, SLOT_MASK_POSTMAN, SLOT_MASK_FIERCE_DEITY),
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Songs",
+ .columns = 5,
+ .scale = 1.0f,
+ .items = {
+ { TRACKER_ITEM_RANDO, RI_SONG_TIME },
+ { TRACKER_ITEM_RANDO, RI_SONG_HEALING },
+ { TRACKER_ITEM_RANDO, RI_SONG_EPONA },
+ { TRACKER_ITEM_RANDO, RI_SONG_SOARING },
+ { TRACKER_ITEM_RANDO, RI_SONG_STORMS },
+ { TRACKER_ITEM_RANDO, RI_SONG_SONATA },
+ { TRACKER_ITEM_RANDO, RI_SONG_LULLABY },
+ { TRACKER_ITEM_RANDO, RI_SONG_NOVA },
+ { TRACKER_ITEM_RANDO, RI_SONG_ELEGY },
+ { TRACKER_ITEM_RANDO, RI_SONG_OATH },
+ },
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Quest",
+ .columns = 5,
+ .scale = 1.0f,
+ .items = {
+ { TRACKER_ITEM_RANDO, RI_REMAINS_ODOLWA },
+ { TRACKER_ITEM_RANDO, RI_REMAINS_GOHT },
+ { TRACKER_ITEM_RANDO, RI_REMAINS_GYORG },
+ { TRACKER_ITEM_RANDO, RI_REMAINS_TWINMOLD },
+ { TRACKER_ITEM_RANDO, RI_BOMBERS_NOTEBOOK },
+ { TRACKER_ITEM_SWORD, RI_PROGRESSIVE_SWORD },
+ { TRACKER_ITEM_SHIELD, RI_SHIELD_HERO },
+ { TRACKER_ITEM_MAGIC, RI_PROGRESSIVE_MAGIC },
+ { TRACKER_ITEM_RANDO, RI_DOUBLE_DEFENSE },
+ { TRACKER_ITEM_WALLET, RI_PROGRESSIVE_WALLET },
+ },
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Tokens",
+ .columns = 2,
+ .scale = 1.0f,
+ .items = {
+ { TRACKER_ITEM_RANDO, RI_GS_TOKEN_SWAMP },
+ { TRACKER_ITEM_RANDO, RI_GS_TOKEN_OCEAN },
+ },
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Stray Fairies",
+ .columns = 5,
+ .scale = 1.0f,
+ .items = {
+ { TRACKER_ITEM_RANDO, RI_CLOCK_TOWN_STRAY_FAIRY },
+ { TRACKER_ITEM_RANDO, RI_WOODFALL_STRAY_FAIRY },
+ { TRACKER_ITEM_RANDO, RI_SNOWHEAD_STRAY_FAIRY },
+ { TRACKER_ITEM_RANDO, RI_GREAT_BAY_STRAY_FAIRY },
+ { TRACKER_ITEM_RANDO, RI_STONE_TOWER_STRAY_FAIRY },
+ },
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Dungeon",
+ .columns = 4,
+ .scale = 1.0f,
+ .items = {
+ { TRACKER_ITEM_RANDO, RI_WOODFALL_BOSS_KEY },
+ { TRACKER_ITEM_RANDO, RI_SNOWHEAD_BOSS_KEY },
+ { TRACKER_ITEM_RANDO, RI_GREAT_BAY_BOSS_KEY },
+ { TRACKER_ITEM_RANDO, RI_STONE_TOWER_BOSS_KEY },
+ { TRACKER_ITEM_RANDO, RI_WOODFALL_SMALL_KEY },
+ { TRACKER_ITEM_RANDO, RI_SNOWHEAD_SMALL_KEY },
+ { TRACKER_ITEM_RANDO, RI_GREAT_BAY_SMALL_KEY },
+ { TRACKER_ITEM_RANDO, RI_STONE_TOWER_SMALL_KEY },
+ },
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Frogs",
+ .columns = 4,
+ .scale = 1.0f,
+ .items = GetItemsFromRange(TRACKER_ITEM_RANDO, RI_FROG_BLUE, RI_FROG_WHITE),
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Ocarina Buttons",
+ .columns = 5,
+ .scale = 1.0f,
+ .items = GetItemsFromRange(TRACKER_ITEM_RANDO, RI_OCARINA_BUTTON_A, RI_OCARINA_BUTTON_C_UP),
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{ .name = "Boss Souls",
+ .columns = 5,
+ .scale = 1.0f,
+ .items = {
+ { TRACKER_ITEM_RANDO, RI_SOUL_BOSS_ODOLWA },
+ { TRACKER_ITEM_RANDO, RI_SOUL_BOSS_GOHT },
+ { TRACKER_ITEM_RANDO, RI_SOUL_BOSS_GYORG },
+ { TRACKER_ITEM_RANDO, RI_SOUL_BOSS_TWINMOLD },
+ { TRACKER_ITEM_RANDO, RI_SOUL_BOSS_MAJORA },
+ } });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Enemy Souls",
+ .columns = 6,
+ .scale = 1.0f,
+ .items = GetItemsFromRange(TRACKER_ITEM_RANDO, RI_SOUL_ENEMY_ALIEN, RI_SOUL_ENEMY_WOLFOS),
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{ .name = "Owl Statues",
+ .columns = 5,
+ .scale = 1.0f,
+ .items = {
+ { TRACKER_ITEM_RANDO, RI_OWL_CLOCK_TOWN_SOUTH },
+ { TRACKER_ITEM_RANDO, RI_OWL_MILK_ROAD },
+ { TRACKER_ITEM_RANDO, RI_OWL_SOUTHERN_SWAMP },
+ { TRACKER_ITEM_RANDO, RI_OWL_WOODFALL },
+ { TRACKER_ITEM_RANDO, RI_OWL_MOUNTAIN_VILLAGE },
+ { TRACKER_ITEM_RANDO, RI_OWL_SNOWHEAD },
+ { TRACKER_ITEM_RANDO, RI_OWL_GREAT_BAY_COAST },
+ { TRACKER_ITEM_RANDO, RI_OWL_ZORA_CAPE },
+ { TRACKER_ITEM_RANDO, RI_OWL_IKANA_CANYON },
+ { TRACKER_ITEM_RANDO, RI_OWL_STONE_TOWER },
+ } });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Time",
+ .columns = 6,
+ .scale = 1.0f,
+ .items = GetItemsFromRange(TRACKER_ITEM_RANDO, RI_TIME_DAY_1, RI_TIME_NIGHT_3),
+ });
+
+ itemTrackerGroupsAvailable.push_back(TrackerGroup{
+ .name = "Misc",
+ .columns = 6,
+ .scale = 1.0f,
+ .items = {
+ { TRACKER_ITEM_RANDO, RI_TRIFORCE_PIECE },
+ { TRACKER_ITEM_RANDO, RI_ABILITY_SWIM },
+ },
+ });
}
void ApplyDefaultItemPreset() {
- BenGui::mItemTrackerWindow->namedItemWindows.clear();
+ itemTrackerGroups.clear();
- for (int key = 0; key < defaultItemLists.size(); key++) {
- if (listOrder[key] == "Rando") {
- continue;
+ std::set<std::string> defaultGroups = {
+ "Inventory", "Masks", "Songs", "Quest", "Tokens", "Stray Fairies", "Dungeon",
+ };
+
+ for (auto& group : itemTrackerGroupsAvailable) {
+ if (defaultGroups.count(group.name)) {
+ itemTrackerGroups.push_back(group);
}
- ApplyDefaultItemGroup(listOrder[key]);
}
}
void SaveItemTrackerLayout() {
- std::vector<std::vector<TrackerItemListObject>*> trackerWindows = {
- &BenGui::mItemTrackerWindow->namedItemWindows,
- &BenGui::mItemTrackerWindow->randoItemWindows,
- };
-
- auto itemTrackerConfig = nlohmann::json::object();
-
- uint16_t windowType = 0;
-
- for (auto* window : trackerWindows) {
- if (window->empty()) {
- windowType++;
- continue;
- }
-
- std::string windowName = windowType == TRACKER_MAIN ? "Main" : "Rando";
- nlohmann::json trackerSaveObject = nlohmann::json::object();
-
- for (auto& object : *window) {
- trackerSaveObject[object.windowName] = nlohmann::json::object();
- trackerSaveObject[object.windowName]["Name"] = object.windowName;
- trackerSaveObject[object.windowName]["Columns"] = object.columnLength;
- trackerSaveObject[object.windowName]["Scale"] = object.windowScale;
- trackerSaveObject[object.windowName]["Opacity"] = object.windowOpacity;
- trackerSaveObject[object.windowName]["ItemList"] = nlohmann::json::array();
-
- for (auto& item : object.itemList) {
- trackerSaveObject[object.windowName]["ItemList"].push_back(item);
- }
- }
- itemTrackerConfig[windowName] = trackerSaveObject;
- windowType++;
+ auto itemTrackerLayout = nlohmann::json::array();
+ for (auto& group : itemTrackerGroups) {
+ auto groupJson = nlohmann::json::object({
+ { "name", group.name },
+ { "columns", group.columns },
+ { "scale", group.scale },
+ { "items", group.items },
+ });
+ itemTrackerLayout.push_back(groupJson);
}
-
- Ship::Context::GetInstance()->GetConfig()->SetBlock("ItemTrackerLayout", itemTrackerConfig);
+ Ship::Context::GetInstance()->GetConfig()->SetBlock("CVars.ItemTrackerLayout", itemTrackerLayout);
Ship::Context::GetInstance()->GetConfig()->Save();
}
-void LoadItemTrackerLayout() {
+void LoadItemTrackerConfig() {
auto allConfig = Ship::Context::GetInstance()->GetConfig()->GetNestedJson();
- if (allConfig.find("ItemTrackerLayout") == allConfig.end()) {
- return;
- }
- auto& itemTrackerConfig = allConfig["ItemTrackerLayout"];
-
- for (auto& [windowKey, windowData] : itemTrackerConfig.items()) {
- std::vector<TrackerItemListObject>* window = windowKey == "Main"
- ? &BenGui::mItemTrackerWindow->namedItemWindows
- : &BenGui::mItemTrackerWindow->randoItemWindows;
- for (auto& [dataKey, dataInfo] : windowData.items()) {
- TrackerItemListObject windowObj = { .windowName = dataInfo["Name"].get<std::string>(),
- .columnLength = dataInfo["Columns"],
- .windowScale = dataInfo["Scale"],
- .windowOpacity = dataInfo["Opacity"],
- .itemList = dataInfo["ItemList"] };
- window->push_back(windowObj);
- }
- }
-}
+ // Verify that the config has CVars.ItemTrackerLayout and its an array
+ if (allConfig.find("CVars") != allConfig.end() && allConfig["CVars"].is_object() &&
+ allConfig["CVars"].find("ItemTrackerLayout") != allConfig["CVars"].end() &&
+ allConfig["CVars"]["ItemTrackerLayout"].is_array()) {
+
+ itemTrackerGroups.clear();
+ auto& itemTrackerLayout = allConfig["CVars"]["ItemTrackerLayout"];
+ for (auto& group : itemTrackerLayout) {
+ std::vector<std::pair<TrackerItemType, u32>> items;
+
+ // Manually parse items array
+ if (group.contains("items") && group["items"].is_array()) {
+ for (auto& item : group["items"]) {
+ if (item.is_array() && item.size() >= 2) {
+ items.push_back({ static_cast<TrackerItemType>(item[0].get<int>()), item[1].get<u32>() });
+ }
+ }
+ }
-void DrawTrackerSaveLoadOptions() {
- if (UIWidgets::Button("Save Layout", { .color = WIDGET_COLOR })) {
- SaveItemTrackerLayout();
- }
- if (UIWidgets::Button("Load Layout", { .color = WIDGET_COLOR })) {
- BenGui::mItemTrackerWindow->namedItemWindows.clear();
- BenGui::mItemTrackerWindow->randoItemWindows.clear();
- LoadItemTrackerLayout();
+ itemTrackerGroups.push_back(TrackerGroup{
+ .name = group.value("name", std::string("")),
+ .columns = group.value("columns", (u8)6),
+ .scale = group.value("scale", 1.0f),
+ .items = items,
+ });
+ }
}
}
void DrawTrackerOptions() {
- int32_t windowIndex = 0;
- ImGui::SeparatorText("Presets");
- if (UIWidgets::Button("Default Preset", { .color = WIDGET_COLOR })) {
- ApplyDefaultItemPreset();
- }
- UIWidgets::Tooltip("Places all Vanilla items in the tracker.");
-
- ImGui::SeparatorText("Custom Windows");
- if (ImGui::BeginTable("OptionsList", 2)) {
+ if (ImGui::BeginTable("OptionsTable", 2)) {
ImGui::TableNextColumn();
+ if (CVarGetInteger("gWindows.ItemTracker", 0)) {
+ UIWidgets::WindowButton("Disable Item Tracker", "gWindows.ItemTracker", BenGui::mItemTrackerWindow,
+ { .size = UIWidgets::Sizes::Inline, .color = WIDGET_COLOR });
+ } else {
+ UIWidgets::WindowButton("Enable Item Tracker", "gWindows.ItemTracker", BenGui::mItemTrackerWindow,
+ { .size = UIWidgets::Sizes::Inline, .color = WIDGET_COLOR });
+ }
+
UIWidgets::CVarCombobox("Window Type", "gSettings.ItemTracker.WindowType", windowTypes,
{ .alignment = UIWidgets::ComponentAlignment::Right,
.labelPosition = UIWidgets::LabelPosition::Near,
.color = WIDGET_COLOR });
- ImGui::TableNextColumn();
UIWidgets::CVarCheckbox("Split Window Groups", "gSettings.ItemTracker.WindowGroup");
- UIWidgets::CVarCheckbox("Show Item Counts", "gSettings.ItemTracker.ItemCounts");
- ImGui::EndTable();
- }
- UIWidgets::InputString("Window Name", &trackerInputName,
- {
- .labelPosition = UIWidgets::LabelPosition::None,
- .color = WIDGET_COLOR,
- .placeholder = "Enter new window name",
- });
- if (ImGui::BeginTable("WindowCreation", 2)) {
+ UIWidgets::CVarCheckbox("Show Item Counts", "gSettings.ItemTracker.ItemCounts",
+ UIWidgets::CheckboxOptions().DefaultValue(true));
ImGui::TableNextColumn();
- if (UIWidgets::Button("Create Vanilla Window", { .color = WIDGET_COLOR })) {
- BenGui::mItemTrackerWindow->namedItemWindows.push_back(CreateTrackerObject());
- trackerInputName.clear();
+
+ if (UIWidgets::Button("Restore Default Groups", { .color = UIWidgets::Colors::Gray })) {
+ ApplyDefaultItemPreset();
+ SaveItemTrackerLayout();
}
- ImGui::TableNextColumn();
- if (UIWidgets::Button("Create Rando Window", { .color = WIDGET_COLOR })) {
- BenGui::mItemTrackerWindow->randoItemWindows.push_back(CreateTrackerObject());
+
+ if (!CVarGetInteger("gSettings.ItemTracker.WindowGroup", 0)) {
+ UIWidgets::CVarSliderFloat("Scale", "gSettings.ItemTracker.Scale",
+ UIWidgets::FloatSliderOptions()
+ .Min(0.2f)
+ .Max(3.0f)
+ .DefaultValue(1.0f)
+ .LabelPosition(UIWidgets::LabelPosition::None)
+ .Format("Scale: %.1f")
+ .Step(0.5f)
+ .Color(WIDGET_COLOR));
+ }
+
+ UIWidgets::CVarSliderFloat("Opacity", "gSettings.ItemTracker.Opacity",
+ UIWidgets::FloatSliderOptions()
+ .Min(0.0f)
+ .Max(1.0f)
+ .DefaultValue(0.5f)
+ .Format("Opacity: %.1f")
+ .LabelPosition(UIWidgets::LabelPosition::None)
+ .Step(0.1f)
+ .Color(WIDGET_COLOR));
+ static std::string trackerInputName;
+ UIWidgets::InputString("##Group Name", &trackerInputName,
+ UIWidgets::InputOptions()
+ .LabelPosition(UIWidgets::LabelPosition::None)
+ .Color(WIDGET_COLOR)
+ .PlaceholderText("Enter new group name")
+ .Size({ ImGui::GetContentRegionAvail().x - 45.0f, 0 }));
+ ImGui::SameLine();
+ if (UIWidgets::Button(ICON_FA_PLUS, { .color = UIWidgets::Colors::Green })) {
+ itemTrackerGroups.push_back(TrackerGroup{
+ .name = trackerInputName.c_str(),
+ .columns = 6,
+ .scale = 1.0f,
+ });
+ SaveItemTrackerLayout();
trackerInputName.clear();
}
+
ImGui::EndTable();
}
- ImGui::SeparatorText("Window Options");
- for (auto& window : BenGui::mItemTrackerWindow->namedItemWindows) {
- DrawTrackerWindowOptions(windowIndex, window);
- windowIndex++;
- }
- for (auto& window : BenGui::mItemTrackerWindow->randoItemWindows) {
- DrawTrackerWindowOptions(windowIndex, window);
- windowIndex++;
- }
}
-void DrawTrackerCustomizationOptions() {
- if (ImGui::BeginChild("Item Lists")) {
- for (int key = 0; key < defaultItemLists.size(); key++) {
- ImGui::PushID(key);
- std::tuple<int16_t, int16_t, int16_t> list = defaultItemLists.at(listOrder[key]);
- ImGui::SeparatorText(listOrder[key].c_str());
- ImGui::SameLine(ImGui::GetContentRegionMax().x - (ImGui::CalcTextSize("Set All").x * 1.5f));
- if (UIWidgets::Button("Set All", { .size = ImVec2(0, 0), .color = UIWidgets::Colors::Green })) {
- ApplyDefaultItemGroup(listOrder[key]);
+void DrawTrackerAvailableGroups() {
+ if (ImGui::BeginChild("Available Groups")) {
+ int groupIndex = 0;
+ for (auto& group : itemTrackerGroupsAvailable) {
+ ImGui::PushID(groupIndex);
+ ImGui::SeparatorText(group.name.c_str());
+ ImGui::SameLine(ImGui::GetContentRegionMax().x - (ImGui::CalcTextSize("aaa").x * 1.5f));
+ if (UIWidgets::Button(ICON_FA_PLUS, { .size = ImVec2(0, 0), .color = UIWidgets::Colors::Green })) {
+ itemTrackerGroups.push_back(group);
+ SaveItemTrackerLayout();
}
- DrawItemList(listOrder[key], std::get<2>(list));
+ DrawItemTrackerGroupPreview(group, true, groupIndex);
ImGui::PopID();
+ groupIndex++;
}
- for (int rkey = 0; rkey < randoItemLists.size(); rkey++) {
- ImGui::PushID(rkey + RI_MAX);
- std::tuple<int16_t, int16_t, int16_t> list = randoItemLists.at(randoListOrder[rkey]);
- ImGui::SeparatorText(randoListOrder[rkey].c_str());
- ImGui::SameLine(ImGui::GetContentRegionMax().x - (ImGui::CalcTextSize("Set All").x * 1.5f));
- if (UIWidgets::Button("Set All", { .size = ImVec2(0, 0), .color = UIWidgets::Colors::Green })) {
- ApplyRandoItemGroup(randoListOrder[rkey]);
+ }
+ ImGui::EndChild();
+}
+
+void DrawTrackerActiveGroups() {
+ if (ImGui::BeginChild("Active Groups")) {
+ int groupIndex = 0;
+ for (auto& group : itemTrackerGroups) {
+ ImGui::PushID(groupIndex);
+ ImGui::SeparatorText(group.name.c_str());
+
+ ImGui::SameLine(ImGui::GetContentRegionMax().x - (ImGui::CalcTextSize("aaaaaaaaa").x * 1.5f));
+ if (UIWidgets::Button(ICON_FA_CHEVRON_UP, { .size = ImVec2(0, 0), .color = WIDGET_COLOR })) {
+ if (groupIndex > 0) {
+ std::swap(itemTrackerGroups[groupIndex], itemTrackerGroups[groupIndex - 1]);
+ SaveItemTrackerLayout();
+ }
+ }
+ ImGui::SameLine();
+ if (UIWidgets::Button(ICON_FA_CHEVRON_DOWN, { .size = ImVec2(0, 0), .color = WIDGET_COLOR })) {
+ if (groupIndex < static_cast<int>(itemTrackerGroups.size()) - 1) {
+ std::swap(itemTrackerGroups[groupIndex], itemTrackerGroups[groupIndex + 1]);
+ SaveItemTrackerLayout();
+ }
+ }
+ ImGui::SameLine();
+ if (UIWidgets::Button(ICON_FA_ELLIPSIS_H, { .size = ImVec2(0, 0), .color = UIWidgets::Colors::Gray })) {
+ ImGui::OpenPopup("GroupOptions");
}
- DrawItemList(randoListOrder[rkey], std::get<2>(list));
+ ImGui::SetNextWindowSize(ImVec2(400, 0), ImGuiCond_Always);
+ ImGui::SetNextWindowPos(ImVec2(ImGui::GetItemRectMin().x - 400, ImGui::GetItemRectMin().y),
+ ImGuiCond_Always);
+ if (ImGui::BeginPopup("GroupOptions")) {
+ if (DrawTrackerWindowOptions(groupIndex, group)) {
+ ImGui::CloseCurrentPopup();
+ }
+ ImGui::EndPopup();
+ }
+ DrawItemTrackerGroupPreview(group, false, groupIndex);
ImGui::PopID();
+ groupIndex++;
}
}
ImGui::EndChild();
@@ -617,42 +604,15 @@ void DrawTrackerCustomizationOptions() {
void ItemTrackerSettingsWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(733, 472), ImGuiCond_FirstUseEver);
if (ImGui::BeginChild("Item Tracker Settings")) {
- ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f));
- ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 1.0f, 1.0f, 0.2f));
- ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 0.1f));
+ DrawTrackerOptions();
- if (CVarGetInteger("gWindows.ItemTracker", 0)) {
- UIWidgets::WindowButton("Hide Item Tracker", "gWindows.ItemTracker", BenGui::mItemTrackerWindow,
- { .size = UIWidgets::Sizes::Inline, .color = WIDGET_COLOR });
- } else {
- UIWidgets::WindowButton("Show Item Tracker", "gWindows.ItemTracker", BenGui::mItemTrackerWindow,
- { .size = UIWidgets::Sizes::Inline, .color = WIDGET_COLOR });
- }
- UIWidgets::Separator();
UIWidgets::PushStyleTabs(WIDGET_COLOR);
if (ImGui::BeginTable("TrackerTabs", 2)) {
ImGui::TableNextColumn();
if (ImGui::BeginChild("TrackerChild")) {
if (ImGui::BeginTabBar("TrackerTabs")) {
- if (ImGui::BeginTabItem("Customization")) {
- if (ImGui::BeginChild("CustomizationChild")) {
- DrawTrackerCustomizationOptions();
- }
- ImGui::EndChild();
- ImGui::EndTabItem();
- }
- if (ImGui::BeginTabItem("Options")) {
- if (ImGui::BeginChild("OptionsChild")) {
- DrawTrackerOptions();
- }
- ImGui::EndChild();
- ImGui::EndTabItem();
- }
- if (ImGui::BeginTabItem("Save/Load")) {
- if (ImGui::BeginChild("SaveChild")) {
- DrawTrackerSaveLoadOptions();
- }
- ImGui::EndChild();
+ if (ImGui::BeginTabItem("Available Groups")) {
+ DrawTrackerAvailableGroups();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
@@ -663,8 +623,8 @@ void ItemTrackerSettingsWindow::DrawElement() {
ImGui::TableNextColumn();
if (ImGui::BeginChild("WindowChild")) {
if (ImGui::BeginTabBar("WindowTab")) {
- if (ImGui::BeginTabItem("Window Layouts")) {
- DrawPreviewPane();
+ if (ImGui::BeginTabItem("Active Groups")) {
+ DrawTrackerActiveGroups();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
@@ -674,11 +634,12 @@ void ItemTrackerSettingsWindow::DrawElement() {
ImGui::EndTable();
}
UIWidgets::PopStyleTabs();
-
- ImGui::PopStyleColor(3);
}
ImGui::EndChild();
}
void ItemTrackerSettingsWindow::InitElement() {
+ LoadAvailableWindows();
+ ApplyDefaultItemPreset();
+ LoadItemTrackerConfig();
}
diff --git a/mm/2s2h/Rando/ConvertItem.cpp b/mm/2s2h/Rando/ConvertItem.cpp
index e8815a58f..fd3232a66 100644
--- a/mm/2s2h/Rando/ConvertItem.cpp
+++ b/mm/2s2h/Rando/ConvertItem.cpp
@@ -307,11 +307,6 @@ bool Rando::IsItemObtainable(RandoItemId randoItemId, RandoCheckId randoCheckId)
case RI_STONE_TOWER_STRAY_FAIRY:
case RI_GS_TOKEN_SWAMP:
case RI_GS_TOKEN_OCEAN:
- case RI_FROG_BLUE:
- case RI_FROG_CYAN:
- case RI_FROG_PINK:
- case RI_FROG_WHITE:
- case RI_ABILITY_SWIM:
case RI_TRIFORCE_PIECE:
if (hasObtainedCheck) {
return false;
@@ -448,6 +443,8 @@ bool Rando::IsItemObtainable(RandoItemId randoItemId, RandoCheckId randoCheckId)
// These items are technically fine to receive again because they don't do anything, but we'll convert them to
// ensure it's clear to the player something didn't go wrong.
// Quest Items
+ case RI_BOMBERS_NOTEBOOK:
+ return !CHECK_QUEST_ITEM(QUEST_BOMBERS_NOTEBOOK);
case RI_REMAINS_ODOLWA:
return !CHECK_QUEST_ITEM(QUEST_REMAINS_ODOLWA);
case RI_REMAINS_GOHT:
@@ -547,6 +544,16 @@ bool Rando::IsItemObtainable(RandoItemId randoItemId, RandoCheckId randoCheckId)
case RI_SOUL_ENEMY_WIZROBE:
case RI_SOUL_ENEMY_WOLFOS:
return !Flags_GetRandoInf(SOUL_RI_TO_RANDO_INF(randoItemId));
+ case RI_ABILITY_SWIM:
+ return !Flags_GetRandoInf(RANDO_INF_OBTAINED_SWIM);
+ case RI_FROG_BLUE:
+ return !CHECK_WEEKEVENTREG(WEEKEVENTREG_33_01);
+ case RI_FROG_CYAN:
+ return !CHECK_WEEKEVENTREG(WEEKEVENTREG_32_40);
+ case RI_FROG_PINK:
+ return !CHECK_WEEKEVENTREG(WEEKEVENTREG_32_80);
+ case RI_FROG_WHITE:
+ return !CHECK_WEEKEVENTREG(WEEKEVENTREG_33_02);
case RI_TIME_DAY_1:
case RI_TIME_NIGHT_1:
case RI_TIME_DAY_2:
diff --git a/mm/2s2h/Rando/StaticData/Items.cpp b/mm/2s2h/Rando/StaticData/Items.cpp
index 946578558..adb53840f 100644
--- a/mm/2s2h/Rando/StaticData/Items.cpp
+++ b/mm/2s2h/Rando/StaticData/Items.cpp
@@ -308,6 +308,15 @@ RandoItemId GetItemIdFromName(const char* name) {
return RI_UNKNOWN;
}
+RandoItemId GetItemIdFromVanillaItemId(u32 itemId) {
+ for (auto& [randoItemId, randoStaticItem] : Items) {
+ if (randoStaticItem.itemId == itemId) {
+ return randoItemId;
+ }
+ }
+ return RI_UNKNOWN;
+}
+
// This exists because of nintendo being nintendo
u8 GetIconForZMessage(RandoItemId randoItemId) {
switch (randoItemId) {
@@ -392,10 +401,14 @@ const char* GetIconTexturePath(RandoItemId randoItemId) {
case RI_PROGRESSIVE_MAGIC:
return (const char*)gItemIcons[ITEM_MAGIC_JAR_SMALL];
case RI_SOUL_BOSS_GOHT:
+ return (const char*)gItemIcons[ITEM_REMAINS_GOHT];
case RI_SOUL_BOSS_GYORG:
- case RI_SOUL_BOSS_MAJORA:
+ return (const char*)gItemIcons[ITEM_REMAINS_GYORG];
case RI_SOUL_BOSS_ODOLWA:
+ return (const char*)gItemIcons[ITEM_REMAINS_ODOLWA];
case RI_SOUL_BOSS_TWINMOLD:
+ return (const char*)gItemIcons[ITEM_REMAINS_TWINMOLD];
+ case RI_SOUL_BOSS_MAJORA:
case RI_SOUL_ENEMY_ALIEN:
case RI_SOUL_ENEMY_ARMOS:
case RI_SOUL_ENEMY_BAD_BAT:
@@ -489,6 +502,8 @@ const char* GetIconTexturePath(RandoItemId randoItemId) {
return (const char*)gThreeDayClockMoonHourTex;
case RI_TIME_PROGRESSIVE:
return (const char*)gThreeDayClockSunHourTex;
+ case RI_ABILITY_SWIM:
+ return (const char*)gItemIcons[ITEM_MASK_ZORA];
default:
break;
}
diff --git a/mm/2s2h/Rando/StaticData/StaticData.h b/mm/2s2h/Rando/StaticData/StaticData.h
index 81ed12b52..6e3641cdc 100644
--- a/mm/2s2h/Rando/StaticData/StaticData.h
+++ b/mm/2s2h/Rando/StaticData/StaticData.h
@@ -50,6 +50,7 @@ extern std::map<StartingItemCategory, std::vector<RandoItemId>> StartingItemsMap
extern std::map<RandoItemId, u8> MaxStartingItemsMap;
RandoItemId GetItemIdFromName(const char* name);
+RandoItemId GetItemIdFromVanillaItemId(u32 itemId);
u8 GetIconForZMessage(RandoItemId itemId);
const char* GetIconTexturePath(RandoItemId itemId);
bool ShouldShowGetItemCutscene(RandoItemId itemId);
diff --git a/mm/2s2h/ShipUtils.cpp b/mm/2s2h/ShipUtils.cpp
index 2e8e70fce..fce0a3828 100644
--- a/mm/2s2h/ShipUtils.cpp
+++ b/mm/2s2h/ShipUtils.cpp
@@ -127,105 +127,6 @@ std::array<const char*, 11> digitList = { gCounterDigit0Tex, gCounterDigit1Tex,
gCounterDigit4Tex, gCounterDigit5Tex, gCounterDigit6Tex, gCounterDigit7Tex,
gCounterDigit8Tex, gCounterDigit9Tex, gCounterColonTex };
-const char* fairyIconTextures[] = { gDungeonStrayFairyWoodfallIconTex, gDungeonStrayFairySnowheadIconTex,
- gDungeonStrayFairyGreatBayIconTex, gDungeonStrayFairyStoneTowerIconTex };
-
-std::vector<std::pair<int16_t, std::string>> itemIdToItemNameMap = {
- // Inventory
- { ITEM_OCARINA_OF_TIME, "Ocarina of Time" },
- { ITEM_BOW, "Bow" },
- { ITEM_ARROW_FIRE, "Fire Arrow" },
- { ITEM_ARROW_ICE, "Ice Arrow" },
- { ITEM_ARROW_LIGHT, "Light Arrow" },
- { ITEM_MOONS_TEAR, "Moon's Tear" },
- { ITEM_BOMB, "Bomb" },
- { ITEM_BOMBCHU, "Bombchu" },
- { ITEM_DEKU_STICK, "Deku Stick" },
- { ITEM_DEKU_NUT, "Deku Nut" },
- { ITEM_MAGIC_BEANS, "Magic Bean" },
- { ITEM_ROOM_KEY, "Room Key" },
- { ITEM_POWDER_KEG, "Powder Keg" },
- { ITEM_PICTOGRAPH_BOX, "Pictograph" },
- { ITEM_LENS_OF_TRUTH, "Lens of Truth" },
- { ITEM_HOOKSHOT, "Hookshot" },
- { ITEM_SWORD_GREAT_FAIRY, "Great Fairy Sword" },
- { ITEM_LETTER_TO_KAFEI, "Letter to Kafei" },
- { ITEM_BOTTLE, "Empty Bottle" },
-
- // Masks
- { ITEM_MASK_POSTMAN, "Postman's Hat" },
- { ITEM_MASK_ALL_NIGHT, "All-Night Mask" },
- { ITEM_MASK_BLAST, "Blast Mask" },
- { ITEM_MASK_STONE, "Stone Mask" },
- { ITEM_MASK_GREAT_FAIRY, "Great Fairy's Mask" },
- { ITEM_MASK_DEKU, "Deku Mask" },
- { ITEM_MASK_KEATON, "Keaton Mask" },
- { ITEM_MASK_BREMEN, "Bremen Mask" },
- { ITEM_MASK_BUNNY, "Bunny Hood" },
- { ITEM_MASK_DON_GERO, "Don Gero's Mask" },
- { ITEM_MASK_SCENTS, "Mask of Scents" },
- { ITEM_MASK_GORON, "Goron Mask" },
- { ITEM_MASK_ROMANI, "Romani's Mask" },
- { ITEM_MASK_CIRCUS_LEADER, "Circus Leader's Mask" },
- { ITEM_MASK_KAFEIS_MASK, "Kafei's Mask" },
- { ITEM_MASK_COUPLE, "Couple's Mask" },
- { ITEM_MASK_TRUTH, "Mask of Truth" },
- { ITEM_MASK_ZORA, "Zora Mask" },
- { ITEM_MASK_KAMARO, "Kamaro's Mask" },
- { ITEM_MASK_GIBDO, "Gibdo Mask" },
- { ITEM_MASK_GARO, "Garo's Mask" },
- { ITEM_MASK_CAPTAIN, "Captain's Hat" },
- { ITEM_MASK_GIANT, "Giant's Mask" },
- { ITEM_MASK_FIERCE_DEITY, "Fierce Deity's Mask" },
-
- // Songs
- { ITEM_SONG_TIME, "Song of Time" },
- { ITEM_SONG_HEALING, "Song of Healing" },
- { ITEM_SONG_EPONA, "Epona's Song" },
- { ITEM_SONG_SOARING, "Song of Soaring" },
- { ITEM_SONG_STORMS, "Song of Storms" },
- { ITEM_SONG_SONATA, "Sonata of Awakening" },
- { ITEM_SONG_LULLABY, "Goron Lullaby" },
- { ITEM_SONG_NOVA, "New Wave Bossa Nova" },
- { ITEM_SONG_ELEGY, "Elegy of Emptiness" },
- { ITEM_SONG_OATH, "Oath to Order" },
-
- // Quest
- { ITEM_REMAINS_ODOLWA, "Odolwa's Remains" },
- { ITEM_REMAINS_GOHT, "Goht's Remains" },
- { ITEM_REMAINS_GYORG, "Gyorg's Remains" },
- { ITEM_REMAINS_TWINMOLD, "Twinmold's Remains" },
- { ITEM_SWORD_KOKIRI, "Kokiri Sword" },
- { ITEM_SHIELD_HERO, "Hero's Shield" },
- { ITEM_WALLET_ADULT, "Adult Wallet" },
- { ITEM_BOMBERS_NOTEBOOK, "Bombers' Notebook" },
-
- // Upgrade Items
- { ITEM_SWORD_RAZOR, "Razor Sword" },
- { ITEM_SWORD_GILDED, "Gilded Sword" },
- { ITEM_SHIELD_MIRROR, "Mirror Shield" },
- { ITEM_WALLET_GIANT, "Giant Wallet" },
-
- // Trade Items
- { ITEM_DEED_LAND, "Land Title Deed" },
- { ITEM_DEED_SWAMP, "Swamp Title Deed" },
- { ITEM_DEED_MOUNTAIN, "Mountain Title Deed" },
- { ITEM_DEED_OCEAN, "Ocean Title Deed" },
- { ITEM_LETTER_MAMA, "Letter to Mama" },
- { ITEM_PENDANT_OF_MEMORIES, "Pendant of Memories" },
-};
-
-std::string Ship_GetItemNameById(int16_t itemId) {
- std::string itemName = "";
- for (auto& [id, name] : itemIdToItemNameMap) {
- if (id == itemId) {
- itemName = name;
- break;
- }
- }
- return itemName;
-};
-
std::map<uint32_t, ImVec4> itemColorMap = {
{ ITEM_SONG_SONATA, ImVec4(0.588f, 1.0f, 0.392f, 1.0f) },
{ ITEM_SONG_LULLABY, ImVec4(1.0f, 0.313f, 0.156f, 1.0f) },
@@ -244,12 +145,33 @@ ImVec4 Ship_GetItemColorTint(uint32_t itemId) {
}
}
-std::map<uint32_t, ImVec4> randoItemColorMap = {
+std::unordered_map<uint32_t, ImVec4> randoItemColorMap = {
{ RI_OCARINA_BUTTON_A, ImVec4(0.085f, 0.494f, 0.796f, 1) },
{ RI_OCARINA_BUTTON_C_DOWN, ImVec4(0.84f, 0.768f, 0.089f, 1) },
{ RI_OCARINA_BUTTON_C_LEFT, ImVec4(0.84f, 0.768f, 0.089f, 1) },
{ RI_OCARINA_BUTTON_C_RIGHT, ImVec4(0.84f, 0.768f, 0.089f, 1) },
{ RI_OCARINA_BUTTON_C_UP, ImVec4(0.84f, 0.768f, 0.089f, 1) },
+ { RI_CLOCK_TOWN_STRAY_FAIRY, ImVec4(1.0f, 0.9f, 0.5f, 0.4f) },
+ { RI_WOODFALL_SMALL_KEY, ImVec4(0.9f, 0.33f, 0.56f, 0.4f) },
+ { RI_SNOWHEAD_SMALL_KEY, ImVec4(0.1f, 0.54f, 0.16f, 0.4f) },
+ { RI_GREAT_BAY_SMALL_KEY, ImVec4(0.61f, 0.04f, 0.86f, 0.4f) },
+ { RI_STONE_TOWER_SMALL_KEY, ImVec4(0.58f, 0.65f, 0.15f, 0.4f) },
+ { RI_WOODFALL_BOSS_KEY, ImVec4(0.9f, 0.33f, 0.56f, 0.4f) },
+ { RI_SNOWHEAD_BOSS_KEY, ImVec4(0.1f, 0.54f, 0.16f, 0.4f) },
+ { RI_GREAT_BAY_BOSS_KEY, ImVec4(0.61f, 0.04f, 0.86f, 0.4f) },
+ { RI_STONE_TOWER_BOSS_KEY, ImVec4(0.58f, 0.65f, 0.15f, 0.4f) },
+ { RI_TIME_DAY_1, ImVec4(1.0f, 0.9f, 0.3f, 1.0f) },
+ { RI_TIME_DAY_2, ImVec4(1.0f, 0.9f, 0.3f, 1.0f) },
+ { RI_TIME_DAY_3, ImVec4(1.0f, 0.9f, 0.3f, 1.0f) },
+ { RI_TIME_NIGHT_1, ImVec4(0.5f, 0.7f, 1.0f, 1.0f) },
+ { RI_TIME_NIGHT_2, ImVec4(0.5f, 0.7f, 1.0f, 1.0f) },
+ { RI_TIME_NIGHT_3, ImVec4(0.5f, 0.7f, 1.0f, 1.0f) },
+ { RI_SONG_SONATA, ImVec4(0.588f, 1.0f, 0.392f, 1.0f) },
+ { RI_SONG_LULLABY, ImVec4(1.0f, 0.313f, 0.156f, 1.0f) },
+ { RI_SONG_NOVA, ImVec4(0.392f, 0.588f, 1.0f, 1.0f) },
+ { RI_SONG_ELEGY, ImVec4(1.0f, 0.627f, 0.0f, 1.0f) },
+ { RI_SONG_OATH, ImVec4(1.0f, 0.392f, 1.0f, 1.0f) },
+ { RI_SONG_LULLABY_INTRO, ImVec4(1.0f, 0.313f, 0.156f, 1.0f) },
};
ImVec4 Ship_GetRandoItemColorTint(uint32_t randoItemId) {
@@ -261,41 +183,6 @@ ImVec4 Ship_GetRandoItemColorTint(uint32_t randoItemId) {
}
}
-std::map<QuestItem, ItemId> questIdToItemMap = {
- { QUEST_REMAINS_ODOLWA, ITEM_REMAINS_ODOLWA },
- { QUEST_REMAINS_GOHT, ITEM_REMAINS_GOHT },
- { QUEST_REMAINS_GYORG, ITEM_REMAINS_GYORG },
- { QUEST_REMAINS_TWINMOLD, ITEM_REMAINS_TWINMOLD },
- { QUEST_SONG_SONATA, ITEM_SONG_SONATA },
- { QUEST_SONG_LULLABY, ITEM_SONG_LULLABY },
- { QUEST_SONG_BOSSA_NOVA, ITEM_SONG_NOVA },
- { QUEST_SONG_ELEGY, ITEM_SONG_ELEGY },
- { QUEST_SONG_OATH, ITEM_SONG_OATH },
- { QUEST_SONG_SARIA, ITEM_SONG_SARIA },
- { QUEST_SONG_TIME, ITEM_SONG_TIME },
- { QUEST_SONG_HEALING, ITEM_SONG_HEALING },
- { QUEST_SONG_EPONA, ITEM_SONG_EPONA },
- { QUEST_SONG_SOARING, ITEM_SONG_SOARING },
- { QUEST_SONG_STORMS, ITEM_SONG_STORMS },
- { QUEST_SONG_SUN, ITEM_SONG_SUN },
- { QUEST_BOMBERS_NOTEBOOK, ITEM_BOMBERS_NOTEBOOK },
-};
-
-uint32_t Ship_ConvertQuestIdToItem(uint32_t itemId) {
- auto findQuest = questIdToItemMap.find((QuestItem)itemId);
- if (findQuest != questIdToItemMap.end()) {
- return findQuest->second;
- }
-}
-
-uint32_t Ship_ConvertItemIdToQuest(uint32_t itemId) {
- for (auto& quest : questIdToItemMap) {
- if (quest.second == itemId) {
- return quest.first;
- }
- }
-}
-
extern "C" const char* Ship_GetSceneName(s16 sceneId) {
if (sceneNames.contains(sceneId)) {
return sceneNames[sceneId];
diff --git a/mm/2s2h/ShipUtils.h b/mm/2s2h/ShipUtils.h
index 24b9eaa5a..4d1f5b1d1 100644
--- a/mm/2s2h/ShipUtils.h
+++ b/mm/2s2h/ShipUtils.h
@@ -24,15 +24,9 @@ std::string convertEnumToReadableName(const std::string& input);
std::string Ship_RemoveSpecialCharacters(const std::string& str);
extern u16 sOwlWarpEntrancesForMods[];
extern std::array<const char*, 11> digitList;
-extern const char* fairyIconTextures[];
extern std::string Ship_FormatTimeDisplay(uint32_t value);
-extern std::vector<std::pair<int16_t, std::string>> itemIdToItemNameMap;
-extern std::string Ship_GetItemNameById(int16_t itemId);
-extern std::map<uint32_t, ImVec4> itemColorMap;
extern ImVec4 Ship_GetItemColorTint(uint32_t itemId);
extern ImVec4 Ship_GetRandoItemColorTint(uint32_t randoItemId);
-uint32_t Ship_ConvertQuestIdToItem(uint32_t itemId);
-uint32_t Ship_ConvertItemIdToQuest(uint32_t itemId);
extern uint32_t Ship_Hash(std::string str);
extern std::string GetActorDescription(u16 actorNum);
extern std::string GetActorDebugName(u16 actorNum);