#include "randomizer_item_tracker.h" #include "../../util.h" #include "../../OTRGlobals.h" #include "../../UIWidgets.hpp" #include "randomizerTypes.h" #include #include #include #include #include "soh/Enhancements/game-interactor/GameInteractor.h" #include extern "C" { #include #include "variables.h" #include "functions.h" #include "macros.h" extern PlayState* gPlayState; #include "textures/icon_item_static/icon_item_static.h" #include "textures/icon_item_24_static/icon_item_24_static.h" } extern "C" uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum); void DrawEquip(ItemTrackerItem item); void DrawItem(ItemTrackerItem item); void DrawDungeonItem(ItemTrackerItem item); void DrawBottle(ItemTrackerItem item); void DrawQuest(ItemTrackerItem item); void DrawSong(ItemTrackerItem item); int itemTrackerSectionId; bool shouldUpdateVectors = true; std::vector mainWindowItems = {}; std::vector inventoryItems = { ITEM_TRACKER_ITEM(ITEM_STICK, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_NUT, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_BOMB, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_BOW, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_ARROW_FIRE, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_DINS_FIRE, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_SLINGSHOT, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_OCARINA_FAIRY, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_BOMBCHU, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_HOOKSHOT, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_ARROW_ICE, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_FARORES_WIND, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_BOOMERANG, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_LENS, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_BEAN, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_HAMMER, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_ARROW_LIGHT, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_NAYRUS_LOVE, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_BOTTLE, 0, DrawBottle), ITEM_TRACKER_ITEM(ITEM_BOTTLE, 1, DrawBottle), ITEM_TRACKER_ITEM(ITEM_BOTTLE, 2, DrawBottle), ITEM_TRACKER_ITEM(ITEM_BOTTLE, 3, DrawBottle), ITEM_TRACKER_ITEM(ITEM_POCKET_EGG, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_MASK_KEATON, 0, DrawItem), }; std::vector equipmentItems = { ITEM_TRACKER_ITEM(ITEM_SWORD_KOKIRI, 1 << 0, DrawEquip), ITEM_TRACKER_ITEM(ITEM_SWORD_MASTER, 1 << 1, DrawEquip), ITEM_TRACKER_ITEM(ITEM_SWORD_BGS, 1 << 2, DrawEquip), ITEM_TRACKER_ITEM(ITEM_TUNIC_KOKIRI, 1 << 8, DrawEquip), ITEM_TRACKER_ITEM(ITEM_TUNIC_GORON, 1 << 9, DrawEquip), ITEM_TRACKER_ITEM(ITEM_TUNIC_ZORA, 1 << 10, DrawEquip), ITEM_TRACKER_ITEM(ITEM_SHIELD_DEKU, 1 << 4, DrawEquip), ITEM_TRACKER_ITEM(ITEM_SHIELD_HYLIAN, 1 << 5, DrawEquip), ITEM_TRACKER_ITEM(ITEM_SHIELD_MIRROR, 1 << 6, DrawEquip), ITEM_TRACKER_ITEM(ITEM_BOOTS_KOKIRI, 1 << 12, DrawEquip), ITEM_TRACKER_ITEM(ITEM_BOOTS_IRON, 1 << 13, DrawEquip), ITEM_TRACKER_ITEM(ITEM_BOOTS_HOVER, 1 << 14, DrawEquip), }; std::vector miscItems = { ITEM_TRACKER_ITEM(ITEM_BRACELET, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_SCALE_SILVER, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_WALLET_ADULT, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_HEART_CONTAINER, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_HEART_PIECE, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_MAGIC_SMALL, 0, DrawItem), ITEM_TRACKER_ITEM(QUEST_GERUDO_CARD, 1 << 22, DrawQuest), ITEM_TRACKER_ITEM(QUEST_SKULL_TOKEN, 1 << 23, DrawQuest), ITEM_TRACKER_ITEM(QUEST_STONE_OF_AGONY, 1 << 21, DrawQuest), }; std::vector dungeonRewardStones = { ITEM_TRACKER_ITEM(QUEST_KOKIRI_EMERALD, 1 << 18, DrawQuest), ITEM_TRACKER_ITEM(QUEST_GORON_RUBY, 1 << 19, DrawQuest), ITEM_TRACKER_ITEM(QUEST_ZORA_SAPPHIRE, 1 << 20, DrawQuest), }; std::vector dungeonRewardMedallions = { ITEM_TRACKER_ITEM(QUEST_MEDALLION_FOREST, 1 << 0, DrawQuest), ITEM_TRACKER_ITEM(QUEST_MEDALLION_FIRE, 1 << 1, DrawQuest), ITEM_TRACKER_ITEM(QUEST_MEDALLION_WATER, 1 << 2, DrawQuest), ITEM_TRACKER_ITEM(QUEST_MEDALLION_SPIRIT, 1 << 3, DrawQuest), ITEM_TRACKER_ITEM(QUEST_MEDALLION_SHADOW, 1 << 4, DrawQuest), ITEM_TRACKER_ITEM(QUEST_MEDALLION_LIGHT, 1 << 5, DrawQuest), }; std::vector dungeonRewards = {}; std::vector songItems = { ITEM_TRACKER_ITEM(QUEST_SONG_LULLABY, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_EPONA, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_SARIA, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_SUN, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_TIME, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_STORMS, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_MINUET, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_BOLERO, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_SERENADE, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_REQUIEM, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_NOCTURNE, 0, DrawSong), ITEM_TRACKER_ITEM(QUEST_SONG_PRELUDE, 0, DrawSong), }; std::vector gregItems = { ITEM_TRACKER_ITEM(ITEM_RUPEE_GREEN, 0, DrawItem), }; std::vector triforcePieces = { ITEM_TRACKER_ITEM(RG_TRIFORCE_PIECE, 0, DrawItem), }; std::vector itemTrackerDungeonsWithMapsHorizontal = { { SCENE_DEKU_TREE, { ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_DODONGOS_CAVERN, { ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_JABU_JABU, { ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_FOREST_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_FIRE_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_WATER_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_SPIRIT_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_SHADOW_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_INSIDE_GANONS_CASTLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_BOTTOM_OF_THE_WELL, { ITEM_KEY_SMALL, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_ICE_CAVERN, { ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_GERUDO_TRAINING_GROUND, { ITEM_KEY_SMALL } }, }; std::vector itemTrackerDungeonsHorizontal = { { SCENE_FOREST_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_FIRE_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_WATER_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_SPIRIT_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_SHADOW_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_INSIDE_GANONS_CASTLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_BOTTOM_OF_THE_WELL, { ITEM_KEY_SMALL } }, { SCENE_GERUDO_TRAINING_GROUND, { ITEM_KEY_SMALL } }, }; std::vector itemTrackerDungeonsWithMapsCompact = { { SCENE_FOREST_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_FIRE_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_WATER_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_SPIRIT_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_SHADOW_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_BOTTOM_OF_THE_WELL, { ITEM_KEY_SMALL, ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_DEKU_TREE, { ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_DODONGOS_CAVERN, { ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_JABU_JABU, { ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_ICE_CAVERN, { ITEM_DUNGEON_MAP, ITEM_COMPASS } }, { SCENE_INSIDE_GANONS_CASTLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_GERUDO_TRAINING_GROUND, { ITEM_KEY_SMALL } }, }; std::vector itemTrackerDungeonsCompact = { { SCENE_FOREST_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_FIRE_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_WATER_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_SPIRIT_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_SHADOW_TEMPLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_INSIDE_GANONS_CASTLE, { ITEM_KEY_SMALL, ITEM_KEY_BOSS } }, { SCENE_BOTTOM_OF_THE_WELL, { ITEM_KEY_SMALL } }, { SCENE_GERUDO_TRAINING_GROUND, { ITEM_KEY_SMALL } }, { SCENE_THIEVES_HIDEOUT, { ITEM_KEY_SMALL } }, }; std::map itemTrackerDungeonShortNames = { { SCENE_FOREST_TEMPLE, "FRST" }, { SCENE_FIRE_TEMPLE, "FIRE" }, { SCENE_WATER_TEMPLE, "WATR" }, { SCENE_SPIRIT_TEMPLE, "SPRT" }, { SCENE_SHADOW_TEMPLE, "SHDW" }, { SCENE_BOTTOM_OF_THE_WELL, "BOTW" }, { SCENE_DEKU_TREE, "DEKU" }, { SCENE_DODONGOS_CAVERN, "DCVN" }, { SCENE_JABU_JABU, "JABU" }, { SCENE_ICE_CAVERN, "ICE" }, { SCENE_INSIDE_GANONS_CASTLE, "GANON" }, { SCENE_GERUDO_TRAINING_GROUND, "GTG" }, { SCENE_THIEVES_HIDEOUT, "HIDE" }, }; std::vector dungeonItems = {}; std::unordered_map actualItemTrackerItemMap = { { ITEM_BOTTLE, ITEM_TRACKER_ITEM(ITEM_BOTTLE, 0, DrawItem) }, { ITEM_BIG_POE, ITEM_TRACKER_ITEM(ITEM_BIG_POE, 0, DrawItem) }, { ITEM_BLUE_FIRE, ITEM_TRACKER_ITEM(ITEM_BLUE_FIRE, 0, DrawItem) }, { ITEM_BUG, ITEM_TRACKER_ITEM(ITEM_BUG, 0, DrawItem) }, { ITEM_FAIRY, ITEM_TRACKER_ITEM(ITEM_FAIRY, 0, DrawItem) }, { ITEM_FISH, ITEM_TRACKER_ITEM(ITEM_FISH, 0, DrawItem) }, { ITEM_POTION_GREEN, ITEM_TRACKER_ITEM(ITEM_POTION_GREEN, 0, DrawItem) }, { ITEM_POE, ITEM_TRACKER_ITEM(ITEM_POE, 0, DrawItem) }, { ITEM_POTION_RED, ITEM_TRACKER_ITEM(ITEM_POTION_RED, 0, DrawItem) }, { ITEM_POTION_BLUE, ITEM_TRACKER_ITEM(ITEM_POTION_BLUE, 0, DrawItem) }, { ITEM_MILK_BOTTLE, ITEM_TRACKER_ITEM(ITEM_MILK_BOTTLE, 0, DrawItem) }, { ITEM_MILK_HALF, ITEM_TRACKER_ITEM(ITEM_MILK_HALF, 0, DrawItem) }, { ITEM_LETTER_RUTO, ITEM_TRACKER_ITEM(ITEM_LETTER_RUTO, 0, DrawItem) }, { ITEM_HOOKSHOT, ITEM_TRACKER_ITEM(ITEM_HOOKSHOT, 0, DrawItem) }, { ITEM_LONGSHOT, ITEM_TRACKER_ITEM(ITEM_LONGSHOT, 0, DrawItem) }, { ITEM_OCARINA_FAIRY, ITEM_TRACKER_ITEM(ITEM_OCARINA_FAIRY, 0, DrawItem) }, { ITEM_OCARINA_TIME, ITEM_TRACKER_ITEM(ITEM_OCARINA_TIME, 0, DrawItem) }, { ITEM_MAGIC_SMALL, ITEM_TRACKER_ITEM(ITEM_MAGIC_SMALL, 0, DrawItem) }, { ITEM_MAGIC_LARGE, ITEM_TRACKER_ITEM(ITEM_MAGIC_LARGE, 0, DrawItem) }, { ITEM_WALLET_ADULT, ITEM_TRACKER_ITEM(ITEM_WALLET_ADULT, 0, DrawItem) }, { ITEM_WALLET_GIANT, ITEM_TRACKER_ITEM(ITEM_WALLET_GIANT, 0, DrawItem) }, { ITEM_BRACELET, ITEM_TRACKER_ITEM(ITEM_BRACELET, 0, DrawItem) }, { ITEM_GAUNTLETS_SILVER, ITEM_TRACKER_ITEM(ITEM_GAUNTLETS_SILVER, 0, DrawItem) }, { ITEM_GAUNTLETS_GOLD, ITEM_TRACKER_ITEM(ITEM_GAUNTLETS_GOLD, 0, DrawItem) }, { ITEM_SCALE_SILVER, ITEM_TRACKER_ITEM(ITEM_SCALE_SILVER, 0, DrawItem) }, { ITEM_SCALE_GOLDEN, ITEM_TRACKER_ITEM(ITEM_SCALE_GOLDEN, 0, DrawItem) }, { ITEM_WEIRD_EGG, ITEM_TRACKER_ITEM(ITEM_WEIRD_EGG, 0, DrawItem) }, { ITEM_CHICKEN, ITEM_TRACKER_ITEM(ITEM_CHICKEN, 0, DrawItem) }, { ITEM_LETTER_ZELDA, ITEM_TRACKER_ITEM(ITEM_LETTER_ZELDA, 0, DrawItem) }, { ITEM_MASK_KEATON, ITEM_TRACKER_ITEM(ITEM_MASK_KEATON, 0, DrawItem) }, { ITEM_MASK_SKULL, ITEM_TRACKER_ITEM(ITEM_MASK_SKULL, 0, DrawItem) }, { ITEM_MASK_SPOOKY, ITEM_TRACKER_ITEM(ITEM_MASK_SPOOKY, 0, DrawItem) }, { ITEM_MASK_BUNNY, ITEM_TRACKER_ITEM(ITEM_MASK_BUNNY, 0, DrawItem) }, { ITEM_MASK_GORON, ITEM_TRACKER_ITEM(ITEM_MASK_GORON, 0, DrawItem) }, { ITEM_MASK_ZORA, ITEM_TRACKER_ITEM(ITEM_MASK_ZORA, 0, DrawItem) }, { ITEM_MASK_GERUDO, ITEM_TRACKER_ITEM(ITEM_MASK_GERUDO, 0, DrawItem) }, { ITEM_MASK_TRUTH, ITEM_TRACKER_ITEM(ITEM_MASK_TRUTH, 0, DrawItem) }, { ITEM_SOLD_OUT, ITEM_TRACKER_ITEM(ITEM_SOLD_OUT, 0, DrawItem) }, { ITEM_POCKET_EGG, ITEM_TRACKER_ITEM(ITEM_POCKET_EGG, 0, DrawItem) }, { ITEM_POCKET_CUCCO, ITEM_TRACKER_ITEM(ITEM_POCKET_CUCCO, 0, DrawItem) }, { ITEM_COJIRO, ITEM_TRACKER_ITEM(ITEM_COJIRO, 0, DrawItem) }, { ITEM_ODD_MUSHROOM, ITEM_TRACKER_ITEM(ITEM_ODD_MUSHROOM, 0, DrawItem) }, { ITEM_ODD_POTION, ITEM_TRACKER_ITEM(ITEM_ODD_POTION, 0, DrawItem) }, { ITEM_SAW, ITEM_TRACKER_ITEM(ITEM_SAW, 0, DrawItem) }, { ITEM_SWORD_BROKEN, ITEM_TRACKER_ITEM(ITEM_SWORD_BROKEN, 0, DrawItem) }, { ITEM_PRESCRIPTION, ITEM_TRACKER_ITEM(ITEM_PRESCRIPTION, 0, DrawItem) }, { ITEM_FROG, ITEM_TRACKER_ITEM(ITEM_FROG, 0, DrawItem) }, { ITEM_EYEDROPS, ITEM_TRACKER_ITEM(ITEM_EYEDROPS, 0, DrawItem) }, { ITEM_CLAIM_CHECK, ITEM_TRACKER_ITEM(ITEM_CLAIM_CHECK, 0, DrawItem) }, }; std::vector buttonMap = { BTN_A, BTN_B, BTN_CUP, BTN_CDOWN, BTN_CLEFT, BTN_CRIGHT, BTN_L, BTN_Z, BTN_R, BTN_START, BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT }; typedef enum { ITEM_TRACKER_NUMBER_NONE, ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY, ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY, ITEM_TRACKER_NUMBER_CAPACITY, ITEM_TRACKER_NUMBER_AMMO, } ItemTrackerNumberOption; typedef enum { KEYS_COLLECTED_MAX, KEYS_CURRENT_COLLECTED_MAX, KEYS_CURRENT_MAX } ItemTrackerKeysNumberOption; typedef enum { TRIFORCE_PIECE_COLLECTED_REQUIRED, TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX } ItemTrackerTriforcePieceNumberOption; typedef enum { SECTION_DISPLAY_HIDDEN, SECTION_DISPLAY_MAIN_WINDOW, SECTION_DISPLAY_SEPARATE } ItemTrackerDisplayType; typedef enum { SECTION_DISPLAY_EXTENDED_HIDDEN, SECTION_DISPLAY_EXTENDED_MAIN_WINDOW, SECTION_DISPLAY_EXTENDED_MISC_WINDOW, SECTION_DISPLAY_EXTENDED_SEPARATE } ItemTrackerExtendedDisplayType; struct ItemTrackerNumbers { int currentCapacity; int maxCapacity; int currentAmmo; }; static ImVector itemTrackerNotes; uint32_t notesIdleFrames = 0; bool notesNeedSave = false; const uint32_t notesMaxIdleFrames = 40; // two seconds of game time, since OnGameFrameUpdate is used to tick void ItemTrackerOnFrame() { if (notesNeedSave && notesIdleFrames <= notesMaxIdleFrames) { notesIdleFrames++; } } bool IsValidSaveFile() { bool validSave = gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2; return validSave; } bool HasSong(ItemTrackerItem item) { return (1 << item.id) & gSaveContext.inventory.questItems; } bool HasQuestItem(ItemTrackerItem item) { return (item.data & gSaveContext.inventory.questItems) != 0; } bool HasEquipment(ItemTrackerItem item) { return (item.data & gSaveContext.inventory.equipment) != 0; } ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) { ItemTrackerNumbers result; result.currentCapacity = 0; result.maxCapacity = 0; result.currentAmmo = 0; switch (item.id) { case ITEM_STICK: result.currentCapacity = CUR_CAPACITY(UPG_STICKS); result.maxCapacity = 30; result.currentAmmo = AMMO(ITEM_STICK); break; case ITEM_NUT: result.currentCapacity = CUR_CAPACITY(UPG_NUTS); result.maxCapacity = 40; result.currentAmmo = AMMO(ITEM_NUT); break; case ITEM_BOMB: result.currentCapacity = CUR_CAPACITY(UPG_BOMB_BAG); result.maxCapacity = 40; result.currentAmmo = AMMO(ITEM_BOMB); break; case ITEM_BOW: result.currentCapacity = CUR_CAPACITY(UPG_QUIVER); result.maxCapacity = 50; result.currentAmmo = AMMO(ITEM_BOW); break; case ITEM_SLINGSHOT: result.currentCapacity = CUR_CAPACITY(UPG_BULLET_BAG); result.maxCapacity = 50; result.currentAmmo = AMMO(ITEM_SLINGSHOT); break; case ITEM_WALLET_ADULT: case ITEM_WALLET_GIANT: result.currentCapacity = CUR_CAPACITY(UPG_WALLET); result.maxCapacity = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY) > RO_SHOPSANITY_ZERO_ITEMS ? 999 : 500; result.currentAmmo = gSaveContext.rupees; break; case ITEM_BOMBCHU: result.currentCapacity = INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU ? 50 : 0; result.maxCapacity = 50; result.currentAmmo = AMMO(ITEM_BOMBCHU); break; case ITEM_BEAN: result.currentCapacity = INV_CONTENT(ITEM_BEAN) == ITEM_BEAN ? 10 : 0; result.maxCapacity = 10; result.currentAmmo = AMMO(ITEM_BEAN); break; case QUEST_SKULL_TOKEN: result.maxCapacity = result.currentCapacity = 100; result.currentAmmo = gSaveContext.inventory.gsTokens; break; case ITEM_HEART_CONTAINER: result.maxCapacity = result.currentCapacity = 8; result.currentAmmo = gSaveContext.sohStats.heartContainers; break; case ITEM_HEART_PIECE: result.maxCapacity = result.currentCapacity = 36; result.currentAmmo = gSaveContext.sohStats.heartPieces; break; case ITEM_KEY_SMALL: // Though the ammo/capacity naming doesn't really make sense for keys, we are // hijacking the same system to display key counts as there are enough similarities result.currentAmmo = MAX(gSaveContext.inventory.dungeonKeys[item.data], 0); result.currentCapacity = gSaveContext.sohStats.dungeonKeys[item.data]; switch (item.data) { case SCENE_FOREST_TEMPLE: result.maxCapacity = FOREST_TEMPLE_SMALL_KEY_MAX; break; case SCENE_FIRE_TEMPLE: result.maxCapacity = FIRE_TEMPLE_SMALL_KEY_MAX; break; case SCENE_WATER_TEMPLE: result.maxCapacity = WATER_TEMPLE_SMALL_KEY_MAX; break; case SCENE_SPIRIT_TEMPLE: result.maxCapacity = SPIRIT_TEMPLE_SMALL_KEY_MAX; break; case SCENE_SHADOW_TEMPLE: result.maxCapacity = SHADOW_TEMPLE_SMALL_KEY_MAX; break; case SCENE_BOTTOM_OF_THE_WELL: result.maxCapacity = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; break; case SCENE_GERUDO_TRAINING_GROUND: result.maxCapacity = GERUDO_TRAINING_GROUNDS_SMALL_KEY_MAX; break; case SCENE_THIEVES_HIDEOUT: result.maxCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX; break; case SCENE_INSIDE_GANONS_CASTLE: result.maxCapacity = GANONS_CASTLE_SMALL_KEY_MAX; break; } break; } return result; } #define IM_COL_WHITE IM_COL32(255, 255, 255, 255) #define IM_COL_RED IM_COL32(255, 0, 0, 255) #define IM_COL_GREEN IM_COL32(0, 255, 0, 255) #define IM_COL_GRAY IM_COL32(155, 155, 155, 255) #define IM_COL_PURPLE IM_COL32(180, 90, 200, 255) void DrawItemCount(ItemTrackerItem item) { int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); int textSize = CVarGetInteger("gTrackers.ItemTracker.ItemTrackerTextSize", 13); ItemTrackerNumbers currentAndMax = GetItemCurrentAndMax(item); ImVec2 p = ImGui::GetCursorScreenPos(); int32_t trackerNumberDisplayMode = CVarGetInteger("gItemTrackerCapacityTrack", ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY); int32_t trackerKeyNumberDisplayMode = CVarGetInteger("gItemTrackerKeyTrack", KEYS_COLLECTED_MAX); float textScalingFactor = static_cast(iconSize) / 36.0f; uint32_t actualItemId = INV_CONTENT(item.id); bool hasItem = actualItemId != ITEM_NONE; if (CVarGetInteger("gTrackers.ItemTracker.HookshotIdentifier", 0)) { if ((actualItemId == ITEM_HOOKSHOT || actualItemId == ITEM_LONGSHOT) && hasItem) { // Calculate the scaled position for the text ImVec2 textPos = ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize(item.id == ITEM_HOOKSHOT ? "H" : "L").x * textScalingFactor / 2) + 8 * textScalingFactor, p.y - 22 * textScalingFactor); ImGui::SetCursorScreenPos(textPos); ImGui::SetWindowFontScale(textScalingFactor); ImGui::Text(item.id == ITEM_HOOKSHOT ? "H" : "L"); ImGui::SetWindowFontScale(1.0f); // Reset font scale to the original state } } ImGui::SetWindowFontScale(textSize / 13.0f); if (item.id == ITEM_KEY_SMALL && IsValidSaveFile()) { std::string currentString = ""; std::string maxString = std::to_string(currentAndMax.maxCapacity); ImU32 currentColor = IM_COL_WHITE; ImU32 maxColor = IM_COL_GREEN; // "Collected / Max", "Current / Collected / Max", "Current / Max" if (trackerKeyNumberDisplayMode == KEYS_CURRENT_COLLECTED_MAX || trackerKeyNumberDisplayMode == KEYS_CURRENT_MAX) { currentString+= std::to_string(currentAndMax.currentAmmo); currentString+= "/"; } if (trackerKeyNumberDisplayMode == KEYS_COLLECTED_MAX || trackerKeyNumberDisplayMode == KEYS_CURRENT_COLLECTED_MAX) { currentString+= std::to_string(currentAndMax.currentCapacity); currentString+= "/"; } ImGui::SetCursorScreenPos(ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize((currentString + maxString).c_str()).x / 2), p.y - 14)); ImGui::PushStyleColor(ImGuiCol_Text, currentColor); ImGui::Text("%s", currentString.c_str()); ImGui::PopStyleColor(); ImGui::SameLine(0, 0.0f); ImGui::PushStyleColor(ImGuiCol_Text, maxColor); ImGui::Text("%s", maxString.c_str()); ImGui::PopStyleColor(); } else if (currentAndMax.currentCapacity > 0 && trackerNumberDisplayMode != ITEM_TRACKER_NUMBER_NONE && IsValidSaveFile()) { std::string currentString = ""; std::string maxString = ""; ImU32 currentColor = IM_COL_WHITE; ImU32 maxColor = item.id == QUEST_SKULL_TOKEN ? IM_COL_RED : IM_COL_GREEN; bool shouldAlignToLeft = CVarGetInteger("gItemTrackerCurrentOnLeft", 0) && trackerNumberDisplayMode != ITEM_TRACKER_NUMBER_CAPACITY && trackerNumberDisplayMode != ITEM_TRACKER_NUMBER_AMMO; bool shouldDisplayAmmo = trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_AMMO || trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY || // These items have a static capacity, so display ammo instead item.id == ITEM_BOMBCHU || item.id == ITEM_BEAN || item.id == QUEST_SKULL_TOKEN || item.id == ITEM_HEART_CONTAINER || item.id == ITEM_HEART_PIECE; bool shouldDisplayMax = !(trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY || trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY); if (shouldDisplayAmmo) { currentString = std::to_string(currentAndMax.currentAmmo); if (currentAndMax.currentAmmo >= currentAndMax.currentCapacity) { if (item.id == QUEST_SKULL_TOKEN) { currentColor = IM_COL_RED; } else { currentColor = IM_COL_GREEN; } } if (shouldDisplayMax) { currentString += "/"; maxString = std::to_string(currentAndMax.currentCapacity); } if (currentAndMax.currentAmmo <= 0) { currentColor = IM_COL_GRAY; } } else { currentString = std::to_string(currentAndMax.currentCapacity); if (currentAndMax.currentCapacity >= currentAndMax.maxCapacity) { currentColor = IM_COL_GREEN; } else if (shouldDisplayMax) { currentString += "/"; maxString = std::to_string(currentAndMax.maxCapacity); } } float x = shouldAlignToLeft ? p.x : p.x + (iconSize / 2) - (ImGui::CalcTextSize((currentString + maxString).c_str()).x / 2); ImGui::SetCursorScreenPos(ImVec2(x, p.y - 14)); ImGui::PushStyleColor(ImGuiCol_Text, currentColor); ImGui::Text("%s", currentString.c_str()); ImGui::PopStyleColor(); ImGui::SameLine(0, 0.0f); ImGui::PushStyleColor(ImGuiCol_Text, maxColor); ImGui::Text("%s", maxString.c_str()); ImGui::PopStyleColor(); } else if (item.id == RG_TRIFORCE_PIECE && IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT) && IsValidSaveFile()) { std::string currentString = ""; std::string requiredString = ""; std::string maxString = ""; uint8_t piecesRequired = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED); uint8_t piecesTotal = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_TOTAL); ImU32 currentColor = gSaveContext.triforcePiecesCollected >= piecesRequired ? IM_COL_GREEN : IM_COL_WHITE; ImU32 maxColor = IM_COL_GREEN; int32_t trackerTriforcePieceNumberDisplayMode = CVarGetInteger("gItemTrackerTriforcePieceTrack", TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX); currentString += std::to_string(gSaveContext.triforcePiecesCollected); currentString += "/"; // gItemTrackerTriforcePieceTrack if (trackerTriforcePieceNumberDisplayMode == TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX) { currentString += std::to_string(piecesRequired); currentString += "/"; maxString += std::to_string(piecesTotal); } else if (trackerTriforcePieceNumberDisplayMode == TRIFORCE_PIECE_COLLECTED_REQUIRED) { maxString += std::to_string(piecesRequired); } ImGui::SetCursorScreenPos( ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize((currentString + maxString).c_str()).x / 2), p.y - 14)); ImGui::PushStyleColor(ImGuiCol_Text, currentColor); ImGui::Text(currentString.c_str()); ImGui::PopStyleColor(); ImGui::SameLine(0, 0.0f); ImGui::PushStyleColor(ImGuiCol_Text, maxColor); ImGui::Text(maxString.c_str()); ImGui::PopStyleColor(); } else { ImGui::SetCursorScreenPos(ImVec2(p.x, p.y - 14)); ImGui::Text(""); } } void DrawEquip(ItemTrackerItem item) { bool hasEquip = HasEquipment(item); int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasEquip && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(item.id)); } void DrawQuest(ItemTrackerItem item) { bool hasQuestItem = HasQuestItem(item); int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); ImGui::BeginGroup(); ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasQuestItem && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); if (item.id == QUEST_SKULL_TOKEN) { DrawItemCount(item); } ImGui::EndGroup(); UIWidgets::SetLastItemHoverText(SohUtils::GetQuestItemName(item.id)); }; void DrawItem(ItemTrackerItem item) { uint32_t actualItemId = INV_CONTENT(item.id); int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); bool hasItem = actualItemId != ITEM_NONE; std::string itemName = ""; if (item.id == ITEM_NONE) { return; } switch (item.id) { case ITEM_HEART_CONTAINER: actualItemId = item.id; hasItem = gSaveContext.sohStats.heartContainers > 0; break; case ITEM_HEART_PIECE: actualItemId = item.id; hasItem = gSaveContext.sohStats.heartPieces > 0; break; case ITEM_MAGIC_SMALL: case ITEM_MAGIC_LARGE: actualItemId = gSaveContext.magicLevel == 2 ? ITEM_MAGIC_LARGE : ITEM_MAGIC_SMALL; hasItem = gSaveContext.magicLevel > 0; break; case ITEM_WALLET_ADULT: case ITEM_WALLET_GIANT: actualItemId = CUR_UPG_VALUE(UPG_WALLET) == 2 ? ITEM_WALLET_GIANT : ITEM_WALLET_ADULT; hasItem = true; break; case ITEM_BRACELET: case ITEM_GAUNTLETS_SILVER: case ITEM_GAUNTLETS_GOLD: actualItemId = CUR_UPG_VALUE(UPG_STRENGTH) == 3 ? ITEM_GAUNTLETS_GOLD : CUR_UPG_VALUE(UPG_STRENGTH) == 2 ? ITEM_GAUNTLETS_SILVER : ITEM_BRACELET; hasItem = CUR_UPG_VALUE(UPG_STRENGTH) > 0; break; case ITEM_SCALE_SILVER: case ITEM_SCALE_GOLDEN: actualItemId = CUR_UPG_VALUE(UPG_SCALE) == 2 ? ITEM_SCALE_GOLDEN : ITEM_SCALE_SILVER; hasItem = CUR_UPG_VALUE(UPG_SCALE) > 0; break; case ITEM_RUPEE_GREEN: actualItemId = item.id; hasItem = Flags_GetRandomizerInf(RAND_INF_GREG_FOUND); break; case RG_TRIFORCE_PIECE: actualItemId = item.id; hasItem = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT); itemName = "Triforce Piece"; break; } if (GameInteractor::IsSaveLoaded() && (hasItem && item.id != actualItemId && actualItemTrackerItemMap.find(actualItemId) != actualItemTrackerItemMap.end())) { item = actualItemTrackerItemMap[actualItemId]; } ImGui::BeginGroup(); ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasItem && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); DrawItemCount(item); ImGui::EndGroup(); if (itemName == "") { itemName = SohUtils::GetItemName(item.id); } UIWidgets::SetLastItemHoverText(itemName); } void DrawBottle(ItemTrackerItem item) { uint32_t actualItemId = gSaveContext.inventory.items[SLOT(item.id) + item.data]; bool hasItem = actualItemId != ITEM_NONE; if (GameInteractor::IsSaveLoaded() && (hasItem && item.id != actualItemId && actualItemTrackerItemMap.find(actualItemId) != actualItemTrackerItemMap.end())) { item = actualItemTrackerItemMap[actualItemId]; } int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasItem && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(item.id)); }; void DrawDungeonItem(ItemTrackerItem item) { uint32_t itemId = item.id; ImU32 dungeonColor = IM_COL_WHITE; uint32_t bitMask = 1 << (item.id - ITEM_KEY_BOSS); // Bitset starts at ITEM_KEY_BOSS == 0. the rest are sequential int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); bool hasItem = (bitMask & gSaveContext.inventory.dungeonItems[item.data]) != 0; bool hasSmallKey = (gSaveContext.inventory.dungeonKeys[item.data]) >= 0; ImGui::BeginGroup(); if (itemId == ITEM_KEY_SMALL) { ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasSmallKey && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); } else { ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasItem && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); } if (ResourceMgr_IsSceneMasterQuest(item.data) && (CHECK_DUNGEON_ITEM(DUNGEON_MAP, item.data) || item.data == SCENE_GERUDO_TRAINING_GROUND || item.data == SCENE_INSIDE_GANONS_CASTLE)) { dungeonColor = IM_COL_PURPLE; } if (itemId == ITEM_KEY_SMALL) { DrawItemCount(item); ImVec2 p = ImGui::GetCursorScreenPos(); std::string dungeonName = itemTrackerDungeonShortNames[item.data]; ImGui::SetCursorScreenPos(ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize(dungeonName.c_str()).x / 2), p.y - (iconSize + CVarGetInteger("gTrackers.ItemTracker.ItemTrackerTextSize", 13) + 3))); ImGui::PushStyleColor(ImGuiCol_Text, dungeonColor); ImGui::Text("%s", dungeonName.c_str()); ImGui::PopStyleColor(); } if (itemId == ITEM_DUNGEON_MAP && (item.data == SCENE_DEKU_TREE || item.data == SCENE_DODONGOS_CAVERN || item.data == SCENE_JABU_JABU || item.data == SCENE_ICE_CAVERN) ) { ImVec2 p = ImGui::GetCursorScreenPos(); std::string dungeonName = itemTrackerDungeonShortNames[item.data]; ImGui::SetCursorScreenPos(ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize(dungeonName.c_str()).x / 2), p.y - (iconSize + 13))); ImGui::PushStyleColor(ImGuiCol_Text, dungeonColor); ImGui::Text("%s", dungeonName.c_str()); ImGui::PopStyleColor(); } ImGui::EndGroup(); UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(item.id)); } void DrawSong(ItemTrackerItem item) { int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); ImVec2 p = ImGui::GetCursorScreenPos(); bool hasSong = HasSong(item); ImGui::SetCursorScreenPos(ImVec2(p.x + 6, p.y)); ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasSong && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize / 1.5, iconSize), ImVec2(0, 0), ImVec2(1, 1)); UIWidgets::SetLastItemHoverText(SohUtils::GetQuestItemName(item.id)); } void DrawNotes(bool resizeable = false) { ImGui::BeginGroup(); int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); int iconSpacing = CVarGetInteger("gItemTrackerIconSpacing", 12); struct ItemTrackerNotes { static int TrackerNotesResizeCallback(ImGuiInputTextCallbackData* data) { if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) { ImVector* itemTrackerNotes = (ImVector*)data->UserData; IM_ASSERT(itemTrackerNotes->begin() == data->Buf); itemTrackerNotes->resize( data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 data->Buf = itemTrackerNotes->begin(); } return 0; } static bool TrackerNotesInputTextMultiline(const char* label, ImVector* itemTrackerNotes, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) { IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); return ImGui::InputTextMultiline(label, itemTrackerNotes->begin(), (size_t)itemTrackerNotes->size(), size, flags | ImGuiInputTextFlags_CallbackResize, ItemTrackerNotes::TrackerNotesResizeCallback, (void*)itemTrackerNotes); } }; ImVec2 size = resizeable ? ImVec2(-FLT_MIN, ImGui::GetContentRegionAvail().y) : ImVec2(((iconSize + iconSpacing) * 6) - 8, 200); if (ItemTrackerNotes::TrackerNotesInputTextMultiline("##ItemTrackerNotes", &itemTrackerNotes, size, ImGuiInputTextFlags_AllowTabInput)) { notesNeedSave = true; notesIdleFrames = 0; } if ((ImGui::IsItemDeactivatedAfterEdit() || (notesNeedSave && notesIdleFrames > notesMaxIdleFrames)) && IsValidSaveFile()) { notesNeedSave = false; SaveManager::Instance->SaveSection(gSaveContext.fileNum, itemTrackerSectionId, true); } ImGui::EndGroup(); } // Windowing stuff ImVec4 ChromaKeyBackground = { 0, 0, 0, 0 }; // Float value, 1 = 255 in rgb value. void BeginFloatingWindows(std::string UniqueName, ImGuiWindowFlags flags = 0) { ImGuiWindowFlags windowFlags = flags; if (windowFlags == 0) { windowFlags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize; } if (CVarGetInteger("gItemTrackerWindowType", TRACKER_WINDOW_FLOATING) == TRACKER_WINDOW_FLOATING) { ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID); windowFlags |= ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar; if (!CVarGetInteger("gItemTrackerHudEditMode", 0)) { windowFlags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove; } } ImGui::PushStyleColor(ImGuiCol_WindowBg, ChromaKeyBackground); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f); ImGui::Begin(UniqueName.c_str(), nullptr, windowFlags); } void EndFloatingWindows() { ImGui::PopStyleVar(); ImGui::PopStyleColor(); ImGui::PopStyleColor(); ImGui::End(); } /** * DrawItemsInRows * Takes in a vector of ItemTrackerItem and draws them in rows of N items */ void DrawItemsInRows(std::vector items, int columns = 6) { int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); int iconSpacing = CVarGetInteger("gItemTrackerIconSpacing", 12); int topPadding = (CVarGetInteger("gItemTrackerWindowType", TRACKER_WINDOW_FLOATING) == TRACKER_WINDOW_WINDOW) ? 20 : 0; for (int i = 0; i < items.size(); i++) { int row = i / columns; int column = i % columns; ImGui::SetCursorPos(ImVec2((column * (iconSize + iconSpacing) + 8), (row * (iconSize + iconSpacing)) + 8 + topPadding)); items[i].drawFunc(items[i]); } } /** * DrawItemsInACircle * Takes in a vector of ItemTrackerItem and draws them evenly spread across a circle */ void DrawItemsInACircle(std::vector items) { int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); int iconSpacing = CVarGetInteger("gItemTrackerIconSpacing", 12); ImVec2 max = ImGui::GetWindowContentRegionMax(); float radius = (iconSize + iconSpacing) * 2; for (int i = 0; i < items.size(); i++) { float angle = (float)i / items.size() * 2.0f * M_PI; float x = (radius / 2.0f) * cos(angle) + max.x / 2.0f; float y = (radius / 2.0f) * sin(angle) + max.y / 2.0f; ImGui::SetCursorPos(ImVec2(x - (CVarGetInteger("gItemTrackerIconSize", 36) - 8) / 2.0f, y + 4)); items[i].drawFunc(items[i]); } } /** * GetDungeonItemsVector * Loops over dungeons and creates vectors of items in the correct order * to then call DrawItemsInRows */ std::vector GetDungeonItemsVector(std::vector dungeons, int columns = 6) { int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); int iconSpacing = CVarGetInteger("gItemTrackerIconSpacing", 12); std::vector dungeonItems = {}; int rowCount = 0; for (int i = 0; i < dungeons.size(); i++) { if (dungeons[i].items.size() > rowCount) rowCount = dungeons[i].items.size(); } for (int i = 0; i < rowCount; i++) { for (int j = 0; j < MIN(dungeons.size(), columns); j++) { if (dungeons[j].items.size() > i) { switch (dungeons[j].items[i]) { case ITEM_KEY_SMALL: dungeonItems.push_back(ITEM_TRACKER_ITEM(ITEM_KEY_SMALL, dungeons[j].id, DrawDungeonItem)); break; case ITEM_KEY_BOSS: // Swap Ganon's Castle boss key to the right scene ID manually if (dungeons[j].id == SCENE_INSIDE_GANONS_CASTLE) { dungeonItems.push_back(ITEM_TRACKER_ITEM(ITEM_KEY_BOSS, SCENE_GANONS_TOWER, DrawDungeonItem)); } else { dungeonItems.push_back(ITEM_TRACKER_ITEM(ITEM_KEY_BOSS, dungeons[j].id, DrawDungeonItem)); } break; case ITEM_DUNGEON_MAP: dungeonItems.push_back(ITEM_TRACKER_ITEM(ITEM_DUNGEON_MAP, dungeons[j].id, DrawDungeonItem)); break; case ITEM_COMPASS: dungeonItems.push_back(ITEM_TRACKER_ITEM(ITEM_COMPASS, dungeons[j].id, DrawDungeonItem)); break; } } else { dungeonItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem)); } } } if (dungeons.size() > columns) { std::vector nextDungeonItems = GetDungeonItemsVector(std::vector(dungeons.begin() + columns, dungeons.end()), columns); dungeonItems.insert(dungeonItems.end(), nextDungeonItems.begin(), nextDungeonItems.end()); } return dungeonItems; } /* ****************************************************** */ void UpdateVectors() { if (!shouldUpdateVectors) { return; } dungeonRewards.clear(); dungeonRewards.insert(dungeonRewards.end(), dungeonRewardStones.begin(), dungeonRewardStones.end()); dungeonRewards.insert(dungeonRewards.end(), dungeonRewardMedallions.begin(), dungeonRewardMedallions.end()); dungeonItems.clear(); if (CVarGetInteger("gItemTrackerDisplayDungeonItemsHorizontal", 1) && CVarGetInteger("gItemTrackerDungeonItemsDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_SEPARATE) { if (CVarGetInteger("gItemTrackerDisplayDungeonItemsMaps", 1)) { dungeonItems = GetDungeonItemsVector(itemTrackerDungeonsWithMapsHorizontal, 12); // Manually adding Thieves Hideout to an open spot so we don't get an additional row for one item dungeonItems[23] = ITEM_TRACKER_ITEM(ITEM_KEY_SMALL, SCENE_THIEVES_HIDEOUT, DrawDungeonItem); } else { // Manually adding Thieves Hideout to an open spot so we don't get an additional row for one item dungeonItems = GetDungeonItemsVector(itemTrackerDungeonsHorizontal, 8); dungeonItems[15] = ITEM_TRACKER_ITEM(ITEM_KEY_SMALL, SCENE_THIEVES_HIDEOUT, DrawDungeonItem); } } else { if (CVarGetInteger("gItemTrackerDisplayDungeonItemsMaps", 1)) { dungeonItems = GetDungeonItemsVector(itemTrackerDungeonsWithMapsCompact); // Manually adding Thieves Hideout to an open spot so we don't get an additional row for one item dungeonItems[35] = ITEM_TRACKER_ITEM(ITEM_KEY_SMALL, SCENE_THIEVES_HIDEOUT, DrawDungeonItem); } else { dungeonItems = GetDungeonItemsVector(itemTrackerDungeonsCompact); } } mainWindowItems.clear(); if (CVarGetInteger("gItemTrackerInventoryItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW) { mainWindowItems.insert(mainWindowItems.end(), inventoryItems.begin(), inventoryItems.end()); } if (CVarGetInteger("gItemTrackerEquipmentItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW) { mainWindowItems.insert(mainWindowItems.end(), equipmentItems.begin(), equipmentItems.end()); } if (CVarGetInteger("gItemTrackerMiscItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW) { mainWindowItems.insert(mainWindowItems.end(), miscItems.begin(), miscItems.end()); } if (CVarGetInteger("gItemTrackerDungeonRewardsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW) { mainWindowItems.insert(mainWindowItems.end(), dungeonRewardStones.begin(), dungeonRewardStones.end()); mainWindowItems.insert(mainWindowItems.end(), dungeonRewardMedallions.begin(), dungeonRewardMedallions.end()); } if (CVarGetInteger("gItemTrackerSongsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW) { if (CVarGetInteger("gItemTrackerMiscItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW && CVarGetInteger("gItemTrackerDungeonRewardsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) != SECTION_DISPLAY_MAIN_WINDOW) { mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem)); mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem)); mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem)); } mainWindowItems.insert(mainWindowItems.end(), songItems.begin(), songItems.end()); } if (CVarGetInteger("gItemTrackerDungeonItemsDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_MAIN_WINDOW) { mainWindowItems.insert(mainWindowItems.end(), dungeonItems.begin(), dungeonItems.end()); } // if we're adding greg to the misc window, // and misc isn't on the main window, // and it doesn't already have greg, add him if (CVarGetInteger("gItemTrackerGregDisplayType", SECTION_DISPLAY_EXTENDED_HIDDEN) == SECTION_DISPLAY_EXTENDED_MISC_WINDOW && CVarGetInteger("gItemTrackerMiscItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) != SECTION_DISPLAY_MAIN_WINDOW && std::none_of(miscItems.begin(), miscItems.end(), [](ItemTrackerItem item){return item.id == ITEM_RUPEE_GREEN;})) { miscItems.insert(miscItems.end(), gregItems.begin(), gregItems.end()); } else { for (auto it = miscItems.begin(); it != miscItems.end();) { if (it->id == ITEM_RUPEE_GREEN) { miscItems.erase(it); } else { it++; } } } // if we're adding greg to the main window if (CVarGetInteger("gItemTrackerGregDisplayType", SECTION_DISPLAY_EXTENDED_HIDDEN) == SECTION_DISPLAY_EXTENDED_MAIN_WINDOW) { // insert empty items until we're on a new row for greg while (mainWindowItems.size() % 6) { mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem)); } // add greg mainWindowItems.insert(mainWindowItems.end(), gregItems.begin(), gregItems.end()); } // If we're adding triforce pieces to the main window if (CVarGetInteger("gItemTrackerTriforcePiecesDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_MAIN_WINDOW) { // If Greg isn't on the main window, add empty items to place the triforce pieces on a new row. if (CVarGetInteger("gItemTrackerGregDisplayType", SECTION_DISPLAY_EXTENDED_HIDDEN) != SECTION_DISPLAY_EXTENDED_MAIN_WINDOW) { while (mainWindowItems.size() % 6) { mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem)); } } // Add triforce pieces mainWindowItems.insert(mainWindowItems.end(), triforcePieces.begin(), triforcePieces.end()); } shouldUpdateVectors = false; } void ItemTrackerInitFile(bool isDebug) { itemTrackerNotes.clear(); itemTrackerNotes.push_back(0); } void ItemTrackerSaveFile(SaveContext* saveContext, int sectionID, bool fullSave) { SaveManager::Instance->SaveData("personalNotes", std::string(std::begin(itemTrackerNotes), std::end(itemTrackerNotes)).c_str()); } void ItemTrackerLoadFile() { std::string initialTrackerNotes = ""; SaveManager::Instance->LoadData("personalNotes", initialTrackerNotes); itemTrackerNotes.resize(initialTrackerNotes.length() + 1); if (initialTrackerNotes != "") { SohUtils::CopyStringToCharArray(itemTrackerNotes.Data, initialTrackerNotes.c_str(), itemTrackerNotes.size()); } else { itemTrackerNotes.push_back(0); } } void ItemTrackerWindow::DrawElement() { UpdateVectors(); int iconSize = CVarGetInteger("gItemTrackerIconSize", 36); int iconSpacing = CVarGetInteger("gItemTrackerIconSpacing", 12); int comboButton1Mask = buttonMap[CVarGetInteger("gItemTrackerComboButton1", TRACKER_COMBO_BUTTON_L)]; int comboButton2Mask = buttonMap[CVarGetInteger("gItemTrackerComboButton2", TRACKER_COMBO_BUTTON_R)]; OSContPad* buttonsPressed = LUS::Context::GetInstance()->GetControlDeck()->GetPads(); bool comboButtonsHeld = buttonsPressed != nullptr && buttonsPressed[0].button & comboButton1Mask && buttonsPressed[0].button & comboButton2Mask; bool isPaused = CVarGetInteger("gItemTrackerShowOnlyPaused", 0) == 0 || gPlayState != nullptr && gPlayState->pauseCtx.state > 0; if (CVarGetInteger("gItemTrackerWindowType", TRACKER_WINDOW_FLOATING) == TRACKER_WINDOW_WINDOW || isPaused && (CVarGetInteger("gItemTrackerDisplayType", TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_ALWAYS ? CVarGetInteger("gItemTrackerEnabled", 0) : comboButtonsHeld)) { if ( (CVarGetInteger("gItemTrackerInventoryItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW) || (CVarGetInteger("gItemTrackerEquipmentItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW) || (CVarGetInteger("gItemTrackerMiscItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW) || (CVarGetInteger("gItemTrackerDungeonRewardsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW) || (CVarGetInteger("gItemTrackerSongsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_MAIN_WINDOW) || (CVarGetInteger("gItemTrackerDungeonItemsDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_MAIN_WINDOW) || (CVarGetInteger("gItemTrackerGregDisplayType", SECTION_DISPLAY_EXTENDED_HIDDEN) == SECTION_DISPLAY_EXTENDED_MAIN_WINDOW) || (CVarGetInteger("gItemTrackerTriforcePiecesDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_MAIN_WINDOW) || (CVarGetInteger("gItemTrackerNotesDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_MAIN_WINDOW) ) { BeginFloatingWindows("Item Tracker##main window"); DrawItemsInRows(mainWindowItems, 6); if (CVarGetInteger("gItemTrackerNotesDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_MAIN_WINDOW && CVarGetInteger("gItemTrackerDisplayType", TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_ALWAYS) { DrawNotes(); } EndFloatingWindows(); } if (CVarGetInteger("gItemTrackerInventoryItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_SEPARATE) { BeginFloatingWindows("Inventory Items Tracker"); DrawItemsInRows(inventoryItems); EndFloatingWindows(); } if (CVarGetInteger("gItemTrackerEquipmentItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_SEPARATE) { BeginFloatingWindows("Equipment Items Tracker"); DrawItemsInRows(equipmentItems, 3); EndFloatingWindows(); } if (CVarGetInteger("gItemTrackerMiscItemsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_SEPARATE) { BeginFloatingWindows("Misc Items Tracker"); DrawItemsInRows(miscItems, 4); EndFloatingWindows(); } if (CVarGetInteger("gItemTrackerDungeonRewardsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_SEPARATE) { BeginFloatingWindows("Dungeon Rewards Tracker"); if (CVarGetInteger("gItemTrackerDungeonRewardsCircle", 0)) { ImGui::BeginGroup(); DrawItemsInACircle(dungeonRewardMedallions); ImGui::EndGroup(); ImGui::BeginGroup(); DrawItemsInRows(dungeonRewardStones); ImGui::EndGroup(); } else { DrawItemsInRows(dungeonRewards, 3); } EndFloatingWindows(); } if (CVarGetInteger("gItemTrackerSongsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_SEPARATE) { BeginFloatingWindows("Songs Tracker"); DrawItemsInRows(songItems); EndFloatingWindows(); } if (CVarGetInteger("gItemTrackerDungeonItemsDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_SEPARATE) { BeginFloatingWindows("Dungeon Items Tracker"); if (CVarGetInteger("gItemTrackerDisplayDungeonItemsHorizontal", 1)) { if (CVarGetInteger("gItemTrackerDisplayDungeonItemsMaps", 1)) { DrawItemsInRows(dungeonItems, 12); } else { DrawItemsInRows(dungeonItems, 8); } } else { DrawItemsInRows(dungeonItems); } EndFloatingWindows(); } if (CVarGetInteger("gItemTrackerGregDisplayType", SECTION_DISPLAY_EXTENDED_HIDDEN) == SECTION_DISPLAY_EXTENDED_SEPARATE) { BeginFloatingWindows("Greg Tracker"); DrawItemsInRows(gregItems); EndFloatingWindows(); } if (CVarGetInteger("gItemTrackerTriforcePiecesDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_SEPARATE) { BeginFloatingWindows("Triforce Piece Tracker"); DrawItemsInRows(triforcePieces); EndFloatingWindows(); } if (CVarGetInteger("gItemTrackerNotesDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_SEPARATE && CVarGetInteger("gItemTrackerDisplayType", TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_ALWAYS) { ImGui::SetNextWindowSize(ImVec2(400,300), ImGuiCond_FirstUseEver); BeginFloatingWindows("Personal Notes", ImGuiWindowFlags_NoFocusOnAppearing); DrawNotes(true); EndFloatingWindows(); } } } static const char* itemTrackerCapacityTrackOptions[5] = { "No Numbers", "Current Capacity", "Current Ammo", "Current Capacity / Max Capacity", "Current Ammo / Current Capacity" }; static const char* itemTrackerKeyTrackOptions[3] = { "Collected / Max", "Current / Collected / Max", "Current / Max" }; static const char* itemTrackerTriforcePieceTrackOptions[2] = { "Collected / Required", "Collected / Required / Max" }; static const char* windowTypes[2] = { "Floating", "Window" }; static const char* displayModes[2] = { "Always", "Combo Button Hold" }; static const char* buttons[14] = { "A", "B", "C-Up", "C-Down", "C-Left", "C-Right", "L", "Z", "R", "Start", "D-Up", "D-Down", "D-Left", "D-Right" }; static const char* displayTypes[3] = { "Hidden", "Main Window", "Separate" }; static const char* extendedDisplayTypes[4] = { "Hidden", "Main Window", "Misc Window", "Separate" }; void ItemTrackerSettingsWindow::DrawElement() { ImGui::SetNextWindowSize(ImVec2(733, 472), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Item Tracker Settings", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) { ImGui::End(); return; } ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 8.0f, 8.0f }); ImGui::BeginTable("itemTrackerSettingsTable", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV); ImGui::TableSetupColumn("General settings", ImGuiTableColumnFlags_WidthStretch, 200.0f); ImGui::TableSetupColumn("Section settings", ImGuiTableColumnFlags_WidthStretch, 200.0f); ImGui::TableHeadersRow(); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("BG Color"); ImGui::SameLine(); ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::ColorEdit4("BG Color##gItemTrackerBgColor", (float*)&ChromaKeyBackground, ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_NoLabel)) { CVarSetFloat("gItemTrackerBgColorR", ChromaKeyBackground.x); CVarSetFloat("gItemTrackerBgColorG", ChromaKeyBackground.y); CVarSetFloat("gItemTrackerBgColorB", ChromaKeyBackground.z); CVarSetFloat("gItemTrackerBgColorA", ChromaKeyBackground.w); LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } ImGui::PopItemWidth(); if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Window Type", "gItemTrackerWindowType", windowTypes, TRACKER_WINDOW_FLOATING)) { shouldUpdateVectors = true; } if (CVarGetInteger("gItemTrackerWindowType", TRACKER_WINDOW_FLOATING) == TRACKER_WINDOW_FLOATING) { if (UIWidgets::PaddedEnhancementCheckbox("Enable Dragging", "gItemTrackerHudEditMode")) { shouldUpdateVectors = true; } if (UIWidgets::PaddedEnhancementCheckbox("Only enable while paused", "gItemTrackerShowOnlyPaused")) { shouldUpdateVectors = true; } if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Display Mode", "gItemTrackerDisplayType", displayModes, TRACKER_DISPLAY_ALWAYS)) { shouldUpdateVectors = true; } if (CVarGetInteger("gItemTrackerDisplayType", TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_COMBO_BUTTON) { if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Combo Button 1", "gItemTrackerComboButton1", buttons, TRACKER_COMBO_BUTTON_L)) { shouldUpdateVectors = true; } if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Combo Button 2", "gItemTrackerComboButton2", buttons, TRACKER_COMBO_BUTTON_R)) { shouldUpdateVectors = true; } } } UIWidgets::PaddedSeparator(); UIWidgets::EnhancementSliderInt("Icon size : %dpx", "##ITEMTRACKERICONSIZE", "gItemTrackerIconSize", 25, 128, "", 36); UIWidgets::EnhancementSliderInt("Icon margins : %dpx", "##ITEMTRACKERSPACING", "gItemTrackerIconSpacing", -5, 50, "", 12); UIWidgets::EnhancementSliderInt("Text size : %dpx", "##ITEMTRACKERTEXTSIZE", "gTrackers.ItemTracker.ItemTrackerTextSize", 1, 30, "", 13); UIWidgets::Spacer(0); ImGui::Text("Ammo/Capacity Tracking"); UIWidgets::EnhancementCombobox("gItemTrackerCapacityTrack", itemTrackerCapacityTrackOptions, ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY); UIWidgets::InsertHelpHoverText("Customize what the numbers under each item are tracking." "\n\nNote: items without capacity upgrades will track ammo even in capacity mode"); if (CVarGetInteger("gItemTrackerCapacityTrack", ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY) == ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY || CVarGetInteger("gItemTrackerCapacityTrack", ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY) == ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY) { if (UIWidgets::PaddedEnhancementCheckbox("Align count to left side", "gItemTrackerCurrentOnLeft")) { shouldUpdateVectors = true; } } UIWidgets::Spacer(0); ImGui::Text("Key Count Tracking"); UIWidgets::EnhancementCombobox("gItemTrackerKeyTrack", itemTrackerKeyTrackOptions, KEYS_COLLECTED_MAX); UIWidgets::InsertHelpHoverText("Customize what numbers are shown for key tracking."); UIWidgets::Spacer(0); ImGui::Text("Triforce Piece Count Tracking"); UIWidgets::EnhancementCombobox("gItemTrackerTriforcePieceTrack", itemTrackerTriforcePieceTrackOptions, TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX); UIWidgets::InsertHelpHoverText("Customize what numbers are shown for triforce piece tracking."); ImGui::TableNextColumn(); if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Inventory", "gItemTrackerInventoryItemsDisplayType", displayTypes, SECTION_DISPLAY_MAIN_WINDOW)) { shouldUpdateVectors = true; } if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Equipment", "gItemTrackerEquipmentItemsDisplayType", displayTypes, SECTION_DISPLAY_MAIN_WINDOW)) { shouldUpdateVectors = true; } if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Misc", "gItemTrackerMiscItemsDisplayType", displayTypes, SECTION_DISPLAY_MAIN_WINDOW)) { shouldUpdateVectors = true; } if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Dungeon Rewards", "gItemTrackerDungeonRewardsDisplayType", displayTypes, SECTION_DISPLAY_MAIN_WINDOW)) { shouldUpdateVectors = true; } if (CVarGetInteger("gItemTrackerDungeonRewardsDisplayType", SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_SEPARATE) { if (UIWidgets::PaddedEnhancementCheckbox("Circle display", "gItemTrackerDungeonRewardsCircle", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, false)) { shouldUpdateVectors = true; } } if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Songs", "gItemTrackerSongsDisplayType", displayTypes, SECTION_DISPLAY_MAIN_WINDOW)) { shouldUpdateVectors = true; } if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Dungeon Items", "gItemTrackerDungeonItemsDisplayType", displayTypes, SECTION_DISPLAY_HIDDEN)) { shouldUpdateVectors = true; } if (CVarGetInteger("gItemTrackerDungeonItemsDisplayType", SECTION_DISPLAY_HIDDEN) != SECTION_DISPLAY_HIDDEN) { if (CVarGetInteger("gItemTrackerDungeonItemsDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_SEPARATE) { if (UIWidgets::PaddedEnhancementCheckbox("Horizontal display", "gItemTrackerDisplayDungeonItemsHorizontal", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true)) { shouldUpdateVectors = true; } } if (UIWidgets::PaddedEnhancementCheckbox("Maps and compasses", "gItemTrackerDisplayDungeonItemsMaps", true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true)) { shouldUpdateVectors = true; } } if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Greg", "gItemTrackerGregDisplayType", extendedDisplayTypes, SECTION_DISPLAY_EXTENDED_HIDDEN)) { shouldUpdateVectors = true; } if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Triforce Pieces", "gItemTrackerTriforcePiecesDisplayType", displayTypes, SECTION_DISPLAY_HIDDEN)) { shouldUpdateVectors = true; } if (CVarGetInteger("gItemTrackerDisplayType", TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_ALWAYS) { if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Personal notes", "gItemTrackerNotesDisplayType", displayTypes, SECTION_DISPLAY_HIDDEN)) { shouldUpdateVectors = true; } } UIWidgets::EnhancementCheckbox("Show Hookshot Identifiers", "gTrackers.ItemTracker.HookshotIdentifier"); UIWidgets::InsertHelpHoverText("Shows an 'H' or an 'L' to more easiely distinguish between Hookshot and Longshot."); UIWidgets::Spacer(0); ImGui::PopStyleVar(1); ImGui::EndTable(); ImGui::End(); } void ItemTrackerWindow::InitElement() { float trackerBgR = CVarGetFloat("gItemTrackerBgColorR", 0); float trackerBgG = CVarGetFloat("gItemTrackerBgColorG", 0); float trackerBgB = CVarGetFloat("gItemTrackerBgColorB", 0); float trackerBgA = CVarGetFloat("gItemTrackerBgColorA", 1); ChromaKeyBackground = { trackerBgR, trackerBgG, trackerBgB, trackerBgA }; // Float value, 1 = 255 in rgb value. // Crashes when the itemTrackerNotes is empty, so add an empty character to it if (itemTrackerNotes.empty()) { itemTrackerNotes.push_back(0); } SaveManager::Instance->AddInitFunction(ItemTrackerInitFile); itemTrackerSectionId = SaveManager::Instance->AddSaveFunction("itemTrackerData", 1, ItemTrackerSaveFile, true, -1); SaveManager::Instance->AddLoadFunction("itemTrackerData", 1, ItemTrackerLoadFile); GameInteractor::Instance->RegisterGameHook(ItemTrackerOnFrame); }