diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index 13e8ac078..4883f5a0e 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -329,6 +329,7 @@ namespace SohImGui { statsWindowOpen = CVar_GetS32("gStatsEnabled", 0); CVar_RegisterS32("gRandomizeRupeeNames", 1); CVar_RegisterS32("gRandoRelevantNavi", 1); + CVar_RegisterS32("gRandoMatchKeyColors", 1); #ifdef __SWITCH__ Ship::Switch::SetupFont(io->Fonts); #endif diff --git a/soh/include/macros.h b/soh/include/macros.h index 5c441dad9..6360e7970 100644 --- a/soh/include/macros.h +++ b/soh/include/macros.h @@ -261,5 +261,6 @@ extern GraphicsContext* __gfxCtx; #define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1) #define NUM_TRIALS 6 +#define NUM_SCRUBS 35 #endif diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 5410c8f77..4b7936d60 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -110,7 +110,7 @@ Sprite* Randomizer::GetSeedTexture(uint8_t index) { Randomizer::~Randomizer() { this->randoSettings.clear(); this->itemLocations.clear(); - this->randomizerMerchantPrices.clear(); + this->merchantPrices.clear(); } std::unordered_map spoilerFileTrialToEnum = { @@ -911,6 +911,7 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { } else if (it.value() == "Anywhere") { gSaveContext.randoSettings[index].value = 3; } + break; case RSK_KEYSANITY: if(it.value() == "Start With") { gSaveContext.randoSettings[index].value = 0; @@ -1209,7 +1210,7 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent gSaveContext.itemLocations[index].check = SpoilerfileCheckNameToEnum[it.key()]; gSaveContext.itemLocations[index].get = SpoilerfileGetNameToEnum[itemit.value()]; } else if (itemit.key() == "price") { - randomizerMerchantPrices[gSaveContext.itemLocations[index].check] = itemit.value(); + merchantPrices[gSaveContext.itemLocations[index].check] = itemit.value(); } } } else { @@ -2420,8 +2421,8 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa break; } - if (randomizerMerchantPrices.find(scrubIdentity.randomizerCheck) != randomizerMerchantPrices.end()) { - scrubIdentity.itemPrice = randomizerMerchantPrices[scrubIdentity.randomizerCheck]; + if (merchantPrices.find(scrubIdentity.randomizerCheck) != merchantPrices.end()) { + scrubIdentity.itemPrice = merchantPrices[scrubIdentity.randomizerCheck]; } return scrubIdentity; diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 0ebb8d694..c91b28b1d 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -14,13 +14,11 @@ class Randomizer { private: std::unordered_map itemLocations; std::unordered_map hintLocations; - std::unordered_map trialsRequired; std::string childAltarText; std::string adultAltarText; std::string ganonHintText; std::string ganonText; std::unordered_map randoSettings; - std::unordered_map randomizerMerchantPrices; void ParseRandomizerSettingsFile(const char* spoilerFileName); void ParseHintLocationsFile(const char* spoilerFileName); void ParseRequiredTrialsFile(const char* spoilerFileName); @@ -38,6 +36,10 @@ class Randomizer { static const std::string rupeeMessageTableID; static const std::string NaviRandoMessageTableID; + // Public for now to be accessed by SaveManager, will be made private again soon :tm: + std::unordered_map trialsRequired; + std::unordered_map merchantPrices; + static Sprite* GetSeedTexture(uint8_t index); s16 GetItemModelFromId(s16 itemId); s32 GetItemIDFromGetItemID(s32 getItemId); diff --git a/soh/soh/GameMenuBar.cpp b/soh/soh/GameMenuBar.cpp index 197c86bc4..661d385ac 100644 --- a/soh/soh/GameMenuBar.cpp +++ b/soh/soh/GameMenuBar.cpp @@ -1415,7 +1415,24 @@ namespace GameMenuBar { UIWidgets::Tooltip( "When obtaining rupees, randomize what the rupee is called in the textbox." ); - UIWidgets::PaddedEnhancementCheckbox("Key Colors Match Dungeon", "gRandoMatchKeyColors", true, false); + + // Only disable the key colors checkbox when none of the keysanity settings are set to "Any Dungeon", "Overworld" or "Anywhere" + bool disableKeyColors = true; + + if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_KEYSANITY) > 2 || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_KEYS) > 0 || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BOSS_KEYSANITY) > 2 || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) > 2 || + !gSaveContext.n64ddFlag) { + disableKeyColors = false; + } + + const char* disableKeyColorsText = + "This setting is disabled because a savefile is loaded without any key\n" + "shuffle settings set to \"Any Dungeon\", \"Overworld\" or \"Anywhere\""; + + UIWidgets::PaddedEnhancementCheckbox("Key Colors Match Dungeon", "gRandoMatchKeyColors", true, false, + disableKeyColors, disableKeyColorsText); UIWidgets::Tooltip( "Matches the color of small keys and boss keys to the dungeon they belong to. " "This helps identify keys from afar and adds a little bit of flair.\n\nThis only " diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 3305f1d70..1fea00767 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -91,6 +91,18 @@ void SaveManager::LoadRandomizerVersion1() { } SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems); + + std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; + + SaveManager::Instance->LoadArray("merchantPrices", NUM_SCRUBS, [&](size_t i) { + SaveManager::Instance->LoadStruct("", [&]() { + RandomizerCheck rc; + SaveManager::Instance->LoadData("check", rc); + uint32_t price; + SaveManager::Instance->LoadData("price", price); + randomizer->merchantPrices[rc] = price; + }); + }); } void SaveManager::SaveRandomizer() { @@ -135,6 +147,20 @@ void SaveManager::SaveRandomizer() { } SaveManager::Instance->SaveData("adultTradeItems", gSaveContext.adultTradeItems); + + std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; + + std::vector> merchantPrices; + for (const auto & [ check, price ] : randomizer->merchantPrices) { + merchantPrices.push_back(std::make_pair(check, price)); + } + + SaveManager::Instance->SaveArray("merchantPrices", NUM_SCRUBS, [&](size_t i) { + SaveManager::Instance->SaveStruct("", [&]() { + SaveManager::Instance->SaveData("check", merchantPrices[i].first); + SaveManager::Instance->SaveData("price", merchantPrices[i].second); + }); + }); } void SaveManager::Init() { diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 9a9407277..2fdaff7c8 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -8,7 +8,6 @@ #define NUM_DUNGEONS 8 #define NUM_COWS 10 -#define NUM_SCRUBS 35 /** * Initialize new save. @@ -521,6 +520,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { // complete mask quest if (Randomizer_GetSettingValue(RSK_COMPLETE_MASK_QUEST)) { + gSaveContext.infTable[7] |= 0x80; // Soldier Wears Keaton Mask gSaveContext.itemGetInf[3] |= 0x100; // Sold Keaton Mask gSaveContext.itemGetInf[3] |= 0x200; // Sold Skull Mask gSaveContext.itemGetInf[3] |= 0x400; // Sold Spooky Mask diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index 2fc3e3e15..8e776e407 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -381,7 +381,11 @@ void KaleidoScope_DrawItemSelect(GlobalContext* globalCtx) { --INV_CONTENT(ITEM_TRADE_CHILD); } else if ((pauseCtx->stickRelX < -30 || pauseCtx->stickRelX > 30 || pauseCtx->stickRelY < -30 || pauseCtx->stickRelY > 30) || dpad && CHECK_BTN_ANY(input->press.button, BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT)) { - INV_CONTENT(ITEM_TRADE_CHILD) ^= ITEM_MASK_KEATON ^ ITEM_MASK_TRUTH; + if (INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_LETTER_ZELDA) { + INV_CONTENT(ITEM_TRADE_CHILD) = ITEM_MASK_KEATON; + } else { + INV_CONTENT(ITEM_TRADE_CHILD) ^= ITEM_MASK_KEATON ^ ITEM_MASK_TRUTH; + } Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); } for (uint16_t cSlotIndex = 0; cSlotIndex < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); cSlotIndex++) {