From f431f7df724bcd3eddb6882589b2772f480b1ff3 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Sun, 14 Aug 2022 12:29:56 -0500 Subject: [PATCH 01/45] Add Bombchus in Logic rando setting and implement progressive chus --- .../Enhancements/randomizer/randomizer.cpp | 25 ++++++++++++++++++- .../Enhancements/randomizer/randomizerTypes.h | 3 ++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index ca86793cc1..100d36c173 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1452,6 +1452,7 @@ std::unordered_map SpoilerfileSettingNameToEn { "Shuffle Dungeon Items:Gerudo Fortress Keys", RSK_GERUDO_KEYS }, { "Shuffle Dungeon Items:Boss Keys", RSK_BOSS_KEYSANITY }, { "Shuffle Dungeon Items:Ganon's Boss Key", RSK_GANONS_BOSS_KEY }, + { "World Settings:Bombchus in Logic", RSK_BOMBCHUS_IN_LOGIC }, { "Misc Settings:Gossip Stone Hints", RSK_GOSSIP_STONE_HINTS }, { "Misc Settings:Hint Clarity", RSK_HINT_CLARITY }, { "Misc Settings:Hint Distribution", RSK_HINT_DISTRIBUTION }, @@ -2229,7 +2230,13 @@ GetItemID Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) return GI_RUPEE_BLUE; case RG_PROGRESSIVE_BOMBCHUS: - return GI_BOMBCHUS_20; //todo progressive? + if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_NONE) { + return GI_BOMBCHUS_20; + } + if (AMMO(ITEM_BOMBCHU) < 5) { + return GI_BOMBCHUS_10; + } + return GI_BOMBCHUS_5; case RG_PROGRESSIVE_MAGIC_METER: switch (gSaveContext.magicLevel) { @@ -3540,6 +3547,7 @@ void GenerateRandomizerImgui() { cvarSettings[RSK_SHUFFLE_TOKENS] = CVar_GetS32("gRandomizeShuffleTokens", 0); cvarSettings[RSK_SHUFFLE_COWS] = CVar_GetS32("gRandomizeShuffleCows", 0); cvarSettings[RSK_SHUFFLE_ADULT_TRADE] = CVar_GetS32("gRandomizeShuffleAdultTrade", 0); + cvarSettings[RSK_BOMBCHUS_IN_LOGIC] = CVar_GetS32("gRandomizeBombchusInLogic", 0); cvarSettings[RSK_SKIP_CHILD_ZELDA] = CVar_GetS32("gRandomizeSkipChildZelda", 0); // if we skip child zelda, we start with zelda's letter, and malon starts @@ -4153,6 +4161,21 @@ void DrawRandoEditor(bool& open) { "This setting does not effect the item earned from playing\n" "the Song of Storms and the frog song minigame." ); + PaddedSeparator(); + + // Bombchus in Logic + // TODO: add to world settings after entrance rando gets merged + SohImGui::EnhancementCheckbox(Settings::BombchusInLogic.GetName().c_str(), "gRandomizeBombchusInLogic"); + InsertHelpHoverText( + "Bombchus are properly considered in logic.\n" + "\n" + "The first Bombchu pack will always be 20, and subsequent packs will be" + "5 or 10 based on how many you have.\n" + "Once found, they can be replenished at the Kokiri shop, Bazaar, or Bombchu" + "shop.\n" + "\n" + "Bombchu Bowling is opened by obtaining Bombchus." + ); } ImGui::PopItemWidth(); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index b09b9dab24..4209766155 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1008,5 +1008,6 @@ typedef enum { RSK_COMPLETE_MASK_QUEST, RSK_ENABLE_GLITCH_CUTSCENES, RSK_SKULLS_SUNS_SONG, - RSK_SHUFFLE_ADULT_TRADE + RSK_SHUFFLE_ADULT_TRADE, + RSK_BOMBCHUS_IN_LOGIC } RandomizerSettingKey; From 8cb50a2ee16ff205e4fcd8fd58b98e8eb88fefc1 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Sun, 14 Aug 2022 12:30:22 -0500 Subject: [PATCH 02/45] Open Bombchu Bowling with chus --- .../randomizer/3drando/settings.cpp | 2 ++ .../Enhancements/randomizer/randomizer.cpp | 5 ++-- .../ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c | 26 ++++++++++++------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 71aa70b323..1482a5cdb2 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2551,6 +2551,8 @@ namespace Settings { MapsAndCompasses.SetSelectedIndex(cvarSettings[RSK_STARTING_MAPS_COMPASSES]); + BombchusInLogic.SetSelectedIndex(cvarSettings[RSK_BOMBCHUS_IN_LOGIC]); + StartingConsumables.SetSelectedIndex(cvarSettings[RSK_STARTING_CONSUMABLES]); StartingMaxRupees.SetSelectedIndex(cvarSettings[RSK_FULL_WALLETS]); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 100d36c173..95401a34ef 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1688,6 +1688,7 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { case RSK_STARTING_KOKIRI_SWORD: case RSK_COMPLETE_MASK_QUEST: case RSK_ENABLE_GLITCH_CUTSCENES: + case RSK_BOMBCHUS_IN_LOGIC: if(it.value() == "Off") { gSaveContext.randoSettings[index].value = 0; } else if(it.value() == "On") { @@ -4169,9 +4170,9 @@ void DrawRandoEditor(bool& open) { InsertHelpHoverText( "Bombchus are properly considered in logic.\n" "\n" - "The first Bombchu pack will always be 20, and subsequent packs will be" + "The first Bombchu pack will always be 20, and subsequent packs will be " "5 or 10 based on how many you have.\n" - "Once found, they can be replenished at the Kokiri shop, Bazaar, or Bombchu" + "Once found, they can be replenished at the Kokiri shop, Bazaar, or Bombchu " "shop.\n" "\n" "Bombchu Bowling is opened by obtaining Bombchus." diff --git a/soh/src/overlays/actors/ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c b/soh/src/overlays/actors/ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c index dc22f9dab6..28a63bbf62 100644 --- a/soh/src/overlays/actors/ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c +++ b/soh/src/overlays/actors/ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c @@ -143,13 +143,14 @@ void EnBomBowMan_BlinkAwake(EnBomBowlMan* this, GlobalContext* globalCtx) { } } - // Check for Bomb Bag if Rando is enabled - // RANDOTODO: Check for bombchu pack instead of bomb bag if bombchus are in logic + // Check for Bomb Bag or Bombchus if Rando is enabled, depending on whether bombchus are considered in logic if (gSaveContext.n64ddFlag) { - if (INV_CONTENT(ITEM_BOMB) != ITEM_NONE) { - this->actor.textId = 0xBF; - } else { + u8 bombchusInLogic = Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC); + if ((!bombchusInLogic && INV_CONTENT(ITEM_BOMB) == ITEM_NONE) || + (bombchusInLogic && INV_CONTENT(ITEM_BOMBCHU) == ITEM_NONE)) { this->actor.textId = 0x7058; + } else { + this->actor.textId = 0xBF; } } } @@ -177,11 +178,16 @@ void EnBomBowMan_CheckBeatenDC(EnBomBowlMan* this, GlobalContext* globalCtx) { this->eyeMode = CHU_GIRL_EYES_AWAKE; this->blinkTimer = (s16)Rand_ZeroFloat(60.0f) + 20; - // Check for beaten Dodongo's Cavern if not rando'd - // check for bomb bag if rando'd - if ((!gSaveContext.n64ddFlag && - !((gSaveContext.eventChkInf[2] & 0x20) || BREG(2))) || - (gSaveContext.n64ddFlag && (INV_CONTENT(ITEM_BOMB) == ITEM_NONE))) { + // Check if beaten Dodongo's Cavern if not rando'd + // check for bomb bag or bombchus if rando'd depending on whether chus are in logic + bool bombchuBowlingClosed; + if (gSaveContext.n64ddFlag) { + u8 explosive = Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) ? ITEM_BOMBCHU : ITEM_BOMB; + bombchuBowlingClosed = (INV_CONTENT(explosive) == ITEM_NONE); + } else { + bombchuBowlingClosed = !((gSaveContext.eventChkInf[2] & 0x20) || BREG(2)); + } + if (bombchuBowlingClosed) { this->actionFunc = EnBomBowMan_WaitNotBeatenDC; } else { this->actor.textId = 0x18; From e8df2f2e470719b5d2efd9e83eca0d73605fa456 Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Wed, 17 Aug 2022 11:36:41 -0500 Subject: [PATCH 03/45] Open bombchu shop with chus --- .../overlays/actors/ovl_En_GirlA/z_en_girla.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c index 5a1a36be7a..f32404cc11 100644 --- a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c +++ b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c @@ -633,8 +633,16 @@ s32 EnGirlA_CanBuy_Unk20(GlobalContext* globalCtx, EnGirlA* this) { } s32 EnGirlA_CanBuy_Bombchus(GlobalContext* globalCtx, EnGirlA* this) { - // When in rando, don't allow buying bombchus when the player doesn't have a bomb bag - if (AMMO(ITEM_BOMBCHU) >= 50 || (gSaveContext.n64ddFlag && CUR_CAPACITY(UPG_BOMB_BAG) == 0)) { + // When in rando, don't allow buying bombchus when the player doesn't have required explosives + // If bombchus are in logic, the player needs to have bombchus; otherwise they need a bomb bag + if (gSaveContext.n64ddFlag) { + u8 bombchusInLogic = Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC); + if ((!bombchusInLogic && CUR_CAPACITY(UPG_BOMB_BAG) == 0) || + (bombchusInLogic && INV_CONTENT(ITEM_BOMBCHU) == ITEM_NONE)) { + return CANBUY_RESULT_CANT_GET_NOW; + } + } + if (AMMO(ITEM_BOMBCHU) >= 50) { return CANBUY_RESULT_CANT_GET_NOW; } if (gSaveContext.rupees < this->basePrice) { @@ -861,6 +869,11 @@ void EnGirlA_BuyEvent_ZoraTunic(GlobalContext* globalCtx, EnGirlA* this) { } void EnGirlA_BuyEvent_ObtainBombchuPack(GlobalContext* globalCtx, EnGirlA* this) { + Rupees_ChangeBy(-this->basePrice); + + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC)) { + return; + } switch (this->actor.params) { case SI_BOMBCHU_10_2: gSaveContext.itemGetInf[0] |= 0x40; @@ -887,7 +900,6 @@ void EnGirlA_BuyEvent_ObtainBombchuPack(GlobalContext* globalCtx, EnGirlA* this) gSaveContext.itemGetInf[0] |= 0x20; break; } - Rupees_ChangeBy(-this->basePrice); } void EnGirlA_Noop(EnGirlA* this, GlobalContext* globalCtx) { From 170b7595725936692bc429518de2c999ea46ffe7 Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Thu, 18 Aug 2022 10:38:49 -0500 Subject: [PATCH 04/45] Make Bombchus buyable without a wallet --- .../custom-message/CustomMessageTypes.h | 2 ++ soh/soh/OTRGlobals.cpp | 3 +++ soh/soh/z_message_OTR.cpp | 22 ++++++++++++++++++- .../overlays/actors/ovl_En_GirlA/z_en_girla.c | 7 +++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index 1859e83a52..f9a4f7936e 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -1,6 +1,8 @@ #pragma once typedef enum { + TEXT_BUY_BOMBCHU_10_PROMPT = 0x8C, + TEXT_BUY_BOMBCHU_10_DESC = 0xBC, TEXT_GS_NO_FREEZE = 0xB4, TEXT_GS_FREEZE = 0xB5, TEXT_RANDOMIZER_CUSTOM_ITEM = 0xF8, diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 3611c97de2..699c3f103c 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1540,6 +1540,9 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { } } else if (textId == TEXT_SCRUB_POH || textId == TEXT_SCRUB_STICK_UPGRADE || textId == TEXT_SCRUB_NUT_UPGRADE) { messageEntry = Randomizer_GetScrubMessage(textId); + } else if (Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) && + (textId == TEXT_BUY_BOMBCHU_10_DESC || textId == TEXT_BUY_BOMBCHU_10_PROMPT)) { + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId); } } if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) { diff --git a/soh/soh/z_message_OTR.cpp b/soh/soh/z_message_OTR.cpp index c6be439644..5cfc99395c 100644 --- a/soh/soh/z_message_OTR.cpp +++ b/soh/soh/z_message_OTR.cpp @@ -111,5 +111,25 @@ extern "C" void OTRMessage_Init() TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM, "You got a %rGold Skulltula Token%w!&You've collected %r\x19%w tokens&in total!", "Du erhälst ein %rGoldene&Skulltula-Symbol%w! Du hast&insgesamt %r\x19%w symbol gesammelt!", - "Vous obtenez un %rSymbole de&Skulltula d'or%w! Vous avez&collecté %r\x19\%w symboles en tout!" }); + "Vous obtenez un %rSymbole de&Skulltula d'or%w! Vous avez&collecté %r\x19\%w symboles en tout!" + } + ); + CustomMessageManager::Instance->CreateMessage( + customMessageTableID, TEXT_BUY_BOMBCHU_10_DESC, + { + TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, + "\x08%rBombchu (10 pieces) 99 Rupees&%wThis looks like a toy mouse, but&it's actually a self-propelled time&bomb!\x09\x0A", + "\x08%rKrabbelmine 10 Stück 99 Rubine&%wDas ist eine praktische Zeitbombe,&die Du als Distanzwaffe&einsetzen kannst!\x09\x0A", + "\x08%rMissile 10 unités 99 Rubis&%wProfilée comme une souris&mécanique, cette arme est &destructrice!!!\x09\x0A", + } + ); + CustomMessageManager::Instance->CreateMessage( + customMessageTableID, TEXT_BUY_BOMBCHU_10_PROMPT, + { + TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, + "\x08\Bombchu 10 pieces 99 Rupees\x09&&\x1B%gBuy&Don't buy%w", + "\x08Krabbelmine 10 Stück 99 Rubine\x09&&\x1B%gKaufen!&Nicht kaufen!%w", + "\x08Missiles 10 unités 99 Rubis\x09&&\x1B%gAcheter&Ne pas acheter%w", + } + ); } diff --git a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c index f32404cc11..54af786a64 100644 --- a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c +++ b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c @@ -1065,7 +1065,12 @@ void EnGirlA_InitializeItemAction(EnGirlA* this, GlobalContext* globalCtx) { this->canBuyFunc = itemEntry->canBuyFunc; this->itemGiveFunc = itemEntry->itemGiveFunc; this->buyEventFunc = itemEntry->buyEventFunc; - this->basePrice = itemEntry->price; + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) && + this->getItemId == GI_BOMBCHUS_10) { + this->basePrice = 99; + } else { + this->basePrice = itemEntry->price; + } this->itemCount = itemEntry->count; this->hiliteFunc = itemEntry->hiliteFunc; this->giDrawId = itemEntry->giDrawId; From 58aed3dc07fef3a98a208ac377529fa13f83ea99 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Mon, 22 Aug 2022 10:41:59 -0500 Subject: [PATCH 05/45] Correct bombchus in logic description to only include chu shop --- soh/soh/Enhancements/randomizer/randomizer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 95401a34ef..8616208d3f 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -4172,8 +4172,7 @@ void DrawRandoEditor(bool& open) { "\n" "The first Bombchu pack will always be 20, and subsequent packs will be " "5 or 10 based on how many you have.\n" - "Once found, they can be replenished at the Kokiri shop, Bazaar, or Bombchu " - "shop.\n" + "Once found, they can be replenished at the Bombchu shop.\n" "\n" "Bombchu Bowling is opened by obtaining Bombchus." ); From 6a900022c07c470b7d5471e2993181b5b6d91b0f Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Tue, 23 Aug 2022 07:47:21 -0500 Subject: [PATCH 06/45] Pass vanilla ammo drops to logic --- soh/soh/Enhancements/randomizer/3drando/settings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 1482a5cdb2..9bff10b1ce 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2552,6 +2552,7 @@ namespace Settings { MapsAndCompasses.SetSelectedIndex(cvarSettings[RSK_STARTING_MAPS_COMPASSES]); BombchusInLogic.SetSelectedIndex(cvarSettings[RSK_BOMBCHUS_IN_LOGIC]); + AmmoDrops.SetSelectedIndex(AMMODROPS_VANILLA); // Ensure logic knows bombchu drops aren't implemented yet StartingConsumables.SetSelectedIndex(cvarSettings[RSK_STARTING_CONSUMABLES]); StartingMaxRupees.SetSelectedIndex(cvarSettings[RSK_FULL_WALLETS]); From 05136c13b7cc9e4a0431e5b8adf33d38cf198902 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Fri, 26 Aug 2022 20:46:19 -0400 Subject: [PATCH 07/45] Fixes Link getting Song as pocket item (#1326) --- soh/src/code/z_sram.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 952ce8e3ce..c71bb4defd 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -703,6 +703,8 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { if (getItem.modIndex == MOD_NONE) { if (getItem.itemId >= ITEM_MEDALLION_FOREST && getItem.itemId <= ITEM_ZORA_SAPPHIRE) { GiveLinkDungeonReward(getItem.getItemId); + } else if (getItem.itemId >= ITEM_SONG_MINUET && getItem.itemId <= ITEM_SONG_STORMS) { + GiveLinkSong(getItem.getItemId); } else if (giid == GI_RUPEE_GREEN || giid == GI_RUPEE_BLUE || giid == GI_RUPEE_RED || giid == GI_RUPEE_PURPLE || giid == GI_RUPEE_GOLD) { GiveLinkRupeesByGetItemId(giid); From 62aeac51b9b9d86be0ab5cae1510cecadd0d92ff Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Fri, 26 Aug 2022 22:14:49 -0400 Subject: [PATCH 08/45] ACTUALLY fixes adult trade items on save init this time. --- soh/src/code/z_sram.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index d53055c932..4bbbe726a4 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -558,7 +558,7 @@ void GiveLinkAdultTradeItem(GetItemID giid) { if (item >= ITEM_POCKET_EGG) { gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(item); } - INV_CONTENT(item) = item; + INV_CONTENT(ITEM_TRADE_ADULT) = item; } void GiveLinksPocketMedallion() { @@ -788,6 +788,11 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.eventChkInf[3] |= 0x800; gSaveContext.eventChkInf[12] |= 1; + // shuffle adult trade quest + if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { + gSaveContext.adultTradeItems = 0; + } + // Give Link's pocket item GiveLinksPocketMedallion(); @@ -904,7 +909,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { GiveLinkDekuNutUpgrade(giid); } else if (giid == GI_SKULL_TOKEN) { GiveLinkSkullToken(); - } else if (giid >= GI_POCKET_EGG && giid <= GI_CLAIM_CHECK) { + } else if (giid >= GI_POCKET_EGG && giid <= GI_CLAIM_CHECK || giid == GI_COJIRO) { GiveLinkAdultTradeItem(giid); } else { s32 iid = getItem.itemId; @@ -1022,11 +1027,6 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { } } - // shuffle adult trade quest - if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { - gSaveContext.adultTradeItems = 0; - } - // complete mask quest if (Randomizer_GetSettingValue(RSK_COMPLETE_MASK_QUEST)) { gSaveContext.itemGetInf[3] |= 0x100; // Sold Keaton Mask From 7fbb381db74a0aa2405866b99f7daa31fae431a8 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 02:25:13 -0400 Subject: [PATCH 09/45] Changes Malon's behavior to so she won't leave Hyrule Castle until you've obtained her item. --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index 88c5b07245..5e6b363b5a 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -90,7 +90,16 @@ static void* sEyeTextures[] = { gMalonChildEyeClosedTex, }; +bool Randomizer_ObtainedMalonHCReward() { + return Flags_GetEventChkInf(0x12); +} + u16 EnMa1_GetText(GlobalContext* globalCtx, Actor* thisx) { + // Special case for Malon Hyrule Castle Text. Placing it here at the beginning + // has the added benefit of circumventing mask text if wearing bunny hood. + if (gSaveContext.n64ddFlag && globalCtx->sceneNum == SCENE_SPOT15) { + return Randomizer_ObtainedMalonHCReward() ? 0x2044 : 0x2043; + } u16 faceReaction = Text_GetFaceReaction(globalCtx, 0x17); if (faceReaction != 0) { @@ -195,7 +204,8 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { !(gSaveContext.eventChkInf[1] & 0x10) && !(gSaveContext.infTable[8] & 0x800)) { return 1; } - if ((globalCtx->sceneNum == SCENE_SPOT15) && !(gSaveContext.eventChkInf[1] & 0x10)) { + if ((globalCtx->sceneNum == SCENE_SPOT15) && (!(gSaveContext.eventChkInf[1] & 0x10) || + (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()))) { if (gSaveContext.infTable[8] & 0x800) { return 1; } else { @@ -209,7 +219,7 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { if (globalCtx->sceneNum != SCENE_SPOT20) { return 0; } - if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10)) { + if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10) && ((gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()) || !gSaveContext.n64ddFlag)) { return 1; } return 0; @@ -290,7 +300,7 @@ void EnMa1_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.targetMode = 6; this->unk_1E8.unk_00 = 0; - if (!(gSaveContext.eventChkInf[1] & 0x10) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || + if (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F))) { this->actionFunc = func_80AA0D88; EnMa1_ChangeAnim(this, ENMA1_ANIM_2); @@ -322,9 +332,11 @@ void func_80AA0D88(EnMa1* this, GlobalContext* globalCtx) { } } - if ((globalCtx->sceneNum == SCENE_SPOT15) && (gSaveContext.eventChkInf[1] & 0x10)) { - Actor_Kill(&this->actor); - } else if (!(gSaveContext.eventChkInf[1] & 0x10) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { + if ((globalCtx->sceneNum == SCENE_SPOT15) && (gSaveContext.eventChkInf[1] & 0x10) && (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward())) { + if (!gSaveContext.n64ddFlag) { + Actor_Kill(&this->actor); + } + } else if ((!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward())) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { if (this->unk_1E8.unk_00 == 2) { this->actionFunc = func_80AA0EA0; globalCtx->msgCtx.stateTimer = 4; From bf1b327a955faa356a56e7ae02db13bf386628c5 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 02:50:44 -0400 Subject: [PATCH 10/45] Cleanup and Documentation --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index 5e6b363b5a..d7dbea1f55 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -200,10 +200,14 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { if (!LINK_IS_CHILD) { return 0; } + // Causes Malon to appear in the market if you haven't met her yet. if (((globalCtx->sceneNum == SCENE_MARKET_NIGHT) || (globalCtx->sceneNum == SCENE_MARKET_DAY)) && !(gSaveContext.eventChkInf[1] & 0x10) && !(gSaveContext.infTable[8] & 0x800)) { return 1; } + // Causes Malon to appear at Hyrule Castle if you've met her already and either we're vanilla and Talon hasn't + // left Hyrule Castle, or if we're randomized and haven't obtained her check. If we haven't met Malon yet, this + // sets the flag for meeting her. if ((globalCtx->sceneNum == SCENE_SPOT15) && (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()))) { if (gSaveContext.infTable[8] & 0x800) { @@ -213,13 +217,18 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { return 0; } } + // Malon asleep in her bed if Talon has left Hyrule Castle and it is nighttime. if ((globalCtx->sceneNum == SCENE_SOUKO) && IS_NIGHT && (gSaveContext.eventChkInf[1] & 0x10)) { return 1; } + // Don't spawn Malon if none of the above are true and we are not in Lon Lon Ranch. if (globalCtx->sceneNum != SCENE_SPOT20) { return 0; } - if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10) && ((gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()) || !gSaveContext.n64ddFlag)) { + // If we've gotten this far, we're in Lon Lon Ranch. Spawn Malon if it is daytime, Talon has left Hyrule Castle, and + // either we are not randomized, or we are and we have received Malon's item at Hyrule Castle. + if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10) && + ((gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()) || !gSaveContext.n64ddFlag)) { return 1; } return 0; @@ -300,10 +309,14 @@ void EnMa1_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.targetMode = 6; this->unk_1E8.unk_00 = 0; + // If Talon has not left Hyrule Castle, we are randomized and ahve not obtained Malon's HC Check, we are not randomized + // and have Epona's Song, or we are randomized and have obtained Malon's Epona's Song Check. This sets Malon's idle + // singing animation in such a way that she has dialog but does not give items or respond to the Ocarina. if (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F))) { this->actionFunc = func_80AA0D88; EnMa1_ChangeAnim(this, ENMA1_ANIM_2); + // If none of the above conditions were true, set Malon up to teach Epona's Song. } else { if (gSaveContext.n64ddFlag) { // Skip straight to "let's sing it together" textbox in the ranch gSaveContext.eventChkInf[1] |= 0x40; @@ -332,10 +345,15 @@ void func_80AA0D88(EnMa1* this, GlobalContext* globalCtx) { } } - if ((globalCtx->sceneNum == SCENE_SPOT15) && (gSaveContext.eventChkInf[1] & 0x10) && (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward())) { + // If we're at Hyrule Castle, and either Talon has left or we're randomized and have obtained Malon's HC Check + if ((globalCtx->sceneNum == SCENE_SPOT15) && ((!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()))) { + // Only kill Malon's Actor here in vanilla. If we're in rando and speak to her we don't want her to pop + // out of existence immediately. The init function will properly kill her actor on the next scene load. if (!gSaveContext.n64ddFlag) { Actor_Kill(&this->actor); } + // If Talon has not run away, or we're randomized and have not received Malon's HC Check, or we're + // not randomized and have obtained Epona's Song, put Malon in the state to give Link the HC reward. } else if ((!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward())) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { if (this->unk_1E8.unk_00 == 2) { this->actionFunc = func_80AA0EA0; From a572c11f4f41a011733507296189161b758df7d0 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 03:27:20 -0400 Subject: [PATCH 11/45] Fixes ice trap gidata not getting cleared after trap is sprung. (#1322) --- soh/src/overlays/actors/ovl_player_actor/z_player.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index cd2950d657..e2c823012c 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -6121,6 +6121,8 @@ s32 func_8083E5A8(Player* this, GlobalContext* globalCtx) { this->actor.colChkInfo.damage = 0; func_80837C0C(globalCtx, this, 3, 0.0f, 0.0f, 0, 20); Player_SetPendingFlag(this, globalCtx); + this->getItemId == GI_NONE; + this->getItemEntry = (GetItemEntry)GET_ITEM_NONE; return 1; } @@ -12866,6 +12868,8 @@ void func_8084E6D4(Player* this, GlobalContext* globalCtx) { } else { this->actor.colChkInfo.damage = 0; func_80837C0C(globalCtx, this, 3, 0.0f, 0.0f, 0, 20); + this->getItemId == GI_NONE; + this->getItemEntry = (GetItemEntry)GET_ITEM_NONE; } return; } From 928a39fe9e21f43a2e322a9cdf06bed98c04b6fe Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 09:30:49 -0400 Subject: [PATCH 12/45] More Cleanup --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index d7dbea1f55..eaf4b14192 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -309,9 +309,11 @@ void EnMa1_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.targetMode = 6; this->unk_1E8.unk_00 = 0; - // If Talon has not left Hyrule Castle, we are randomized and ahve not obtained Malon's HC Check, we are not randomized - // and have Epona's Song, or we are randomized and have obtained Malon's Epona's Song Check. This sets Malon's idle - // singing animation in such a way that she has dialog but does not give items or respond to the Ocarina. + // To avoid missing a check, we want Malon to have the actionFunc for singing, but not reacting to Ocarina, if any of + // the following are true. + // 1. Talon has not left Hyrule Castle. + // 2. We are Randomized and have not obtained Malon's Weird Egg Check. + // 3. We are not Randomized and have obtained Epona's Song if (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F))) { this->actionFunc = func_80AA0D88; @@ -345,15 +347,15 @@ void func_80AA0D88(EnMa1* this, GlobalContext* globalCtx) { } } - // If we're at Hyrule Castle, and either Talon has left or we're randomized and have obtained Malon's HC Check - if ((globalCtx->sceneNum == SCENE_SPOT15) && ((!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()))) { - // Only kill Malon's Actor here in vanilla. If we're in rando and speak to her we don't want her to pop - // out of existence immediately. The init function will properly kill her actor on the next scene load. - if (!gSaveContext.n64ddFlag) { - Actor_Kill(&this->actor); - } - // If Talon has not run away, or we're randomized and have not received Malon's HC Check, or we're - // not randomized and have obtained Epona's Song, put Malon in the state to give Link the HC reward. + // We want to Kill Malon's Actor outside of randomizer when Talon is freed. In Randomizer we don't kill Malon's + // Actor here, otherwise if we wake up Talon first and then get her check she will spontaneously + // disappear. + if ((globalCtx->sceneNum == SCENE_SPOT15) && (!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[1] & 0x10)) { + Actor_Kill(&this->actor); + // We want Malon to give the Weird Egg Check (see function below) in the following situations: + // 1. Talon as not left Hyrule Castle (Vanilla) OR + // 2. We haven't obtained Malon's Weird Egg Check (Randomizer only) OR + // 3. We have Epona's Song? (Vanilla only, not sure why it's here but I didn't write that one) } else if ((!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward())) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { if (this->unk_1E8.unk_00 == 2) { this->actionFunc = func_80AA0EA0; From 1bf8423f75bd0b7abe77787831c1863b08105e6b Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 14:19:37 -0400 Subject: [PATCH 13/45] Reimplements selecting different amounts of Ganon's Trials. --- soh/include/functions.h | 1 + soh/include/macros.h | 1 + .../randomizer/3drando/settings.cpp | 18 +++--- .../randomizer/3drando/spoiler_log.cpp | 59 ++++++++++++------- .../Enhancements/randomizer/randomizer.cpp | 56 +++++++++++++++--- soh/soh/Enhancements/randomizer/randomizer.h | 6 +- soh/soh/OTRGlobals.cpp | 8 +++ soh/soh/OTRGlobals.h | 2 + soh/src/code/z_actor.c | 4 ++ soh/src/code/z_sram.c | 10 +++- .../actors/ovl_Demo_Kekkai/z_demo_kekkai.c | 28 ++++++++- .../ovl_Object_Kankyo/z_object_kankyo.c | 21 +++++++ .../ovl_file_choose/z_file_choose.c | 1 + 13 files changed, 174 insertions(+), 41 deletions(-) diff --git a/soh/include/functions.h b/soh/include/functions.h index 9047b6d3f2..7d8b309a58 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -561,6 +561,7 @@ s32 Flags_GetInfTable(s32 flag); void Flags_SetInfTable(s32 flag); s32 Flags_GetRandomizerInf(RandomizerInf flag); void Flags_SetRandomizerInf(RandomizerInf flag); +void Flags_UnsetRandomizerInf(RandomizerInf flag); u16 func_80037C30(GlobalContext* globalCtx, s16 arg1); s32 func_80037D98(GlobalContext* globalCtx, Actor* actor, s16 arg2, s32* arg3); s32 func_80038290(GlobalContext* globalCtx, Actor* actor, Vec3s* arg2, Vec3s* arg3, Vec3f arg4); diff --git a/soh/include/macros.h b/soh/include/macros.h index 1822cb1d69..bcfb3fce5f 100644 --- a/soh/include/macros.h +++ b/soh/include/macros.h @@ -260,5 +260,6 @@ extern GraphicsContext* __gfxCtx; #define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1) +#define NUM_TRIALS 6 #endif diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index fc02dfd6a4..9e496598e0 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2519,15 +2519,15 @@ namespace Settings { BridgeTokenCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_TOKEN_COUNT]); RandomGanonsTrials.SetSelectedIndex(cvarSettings[RSK_RANDOM_TRIALS]); // RANDTODO: Switch this back once Ganon's Trials Count is properly implemented. - //GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); - switch (cvarSettings[RSK_TRIAL_COUNT]) { - case 0: - GanonsTrialsCount.SetSelectedIndex(6); - break; - case 1: - GanonsTrialsCount.SetSelectedIndex(0); - break; - } + GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); + // switch (cvarSettings[RSK_TRIAL_COUNT]) { + // case 0: + // GanonsTrialsCount.SetSelectedIndex(6); + // break; + // case 1: + // GanonsTrialsCount.SetSelectedIndex(0); + // break; + // } ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]); ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]); diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 48ed607d2b..332fbb9e16 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -501,27 +501,46 @@ static void WriteMasterQuestDungeons(tinyxml2::XMLDocument& spoilerLog) { } } -// Writes the required trails to the spoiler log, if there are any. -static void WriteRequiredTrials(tinyxml2::XMLDocument& spoilerLog) { - auto parentNode = spoilerLog.NewElement("required-trials"); - - for (const auto* trial : Trial::trialList) { - if (trial->IsSkipped()) { - continue; +// Writes the required trials to the spoiler log, if there are any. +static void WriteRequiredTrials() { + for (const auto& trial : Trial::trialList) { + if (trial->IsRequired()) { + std::string trialName; + switch (gSaveContext.language) { + case LANGUAGE_FRA: + trialName = trial->GetName().GetFrench(); + break; + case LANGUAGE_ENG: + default: + trialName = trial->GetName().GetEnglish(); + break; + } + jsonData["requiredTrials"].push_back(RemoveLineBreaks(trialName)); + } } - - auto node = parentNode->InsertNewChildElement("trial"); - // PURPLE TODO: LOCALIZATION - std::string name = trial->GetName().GetEnglish(); - name[0] = toupper(name[0]); // Capitalize T in "The" - node->SetAttribute("name", name.c_str()); - } - - if (!parentNode->NoChildren()) { - spoilerLog.RootElement()->InsertEndChild(parentNode); - } } +// Writes the required trails to the spoiler log, if there are any. +// static void WriteRequiredTrials(tinyxml2::XMLDocument& spoilerLog) { +// auto parentNode = spoilerLog.NewElement("required-trials"); + +// for (const auto* trial : Trial::trialList) { +// if (trial->IsSkipped()) { +// continue; +// } + +// auto node = parentNode->InsertNewChildElement("trial"); +// // PURPLE TODO: LOCALIZATION +// std::string name = trial->GetName().GetEnglish(); +// name[0] = toupper(name[0]); // Capitalize T in "The" +// node->SetAttribute("name", name.c_str()); +// } + +// if (!parentNode->NoChildren()) { +// spoilerLog.RootElement()->InsertEndChild(parentNode); +// } +// } + // Writes the intended playthrough to the spoiler log, separated into spheres. static void WritePlaythrough() { // auto playthroughNode = spoilerLog.NewElement("playthrough"); @@ -723,7 +742,7 @@ const char* SpoilerLog_Write(int language) { // WriteEnabledGlitches(spoilerLog); //} //WriteMasterQuestDungeons(spoilerLog); - //WriteRequiredTrials(spoilerLog); + WriteRequiredTrials(); WritePlaythrough(); //WriteWayOfTheHeroLocation(spoilerLog); @@ -773,7 +792,7 @@ bool PlacementLog_Write() { WriteEnabledTricks(placementLog); WriteEnabledGlitches(placementLog); WriteMasterQuestDungeons(placementLog); - WriteRequiredTrials(placementLog); + //WriteRequiredTrials(placementLog); placementtxt = "\n" + placementtxt; diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 2d7798e208..6dff5a627f 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -107,6 +107,21 @@ Randomizer::~Randomizer() { this->randomizerMerchantPrices.clear(); } +std::unordered_map spoilerFileTrialToEnum = { + { "the Forest Trial", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, + { "l'épreuve de la forêt", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, + { "the Fire Trial", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, + { "l'épreuve du feu", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, + { "the Water Trial", RAND_INF_TRIALS_DONE_WATER_TRIAL }, + { "l'épreuve de l'eau", RAND_INF_TRIALS_DONE_WATER_TRIAL }, + { "the Spirit Trial", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, + { "l'épreuve de l'esprit", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, + { "the Shadow Trial", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, + { "l'épreuve de l'ombre", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, + { "the Light Trial", RAND_INF_TRIALS_DONE_LIGHT_TRIAL }, + { "l'épreuve de la lumière", RAND_INF_TRIALS_DONE_LIGHT_TRIAL } +}; + std::unordered_map getItemIdToItemId = { { GI_BOW, ITEM_BOW }, { GI_ARROW_FIRE, ITEM_ARROW_FIRE }, @@ -673,6 +688,12 @@ void Randomizer::LoadItemLocations(const char* spoilerFileName, bool silent) { itemLocations[RC_UNKNOWN_CHECK] = RG_NONE; } +void Randomizer::LoadRequiredTrials(const char* spoilerFileName) { + if (strcmp(spoilerFileName, "") != 0) { + ParseRequiredTrialsFile(spoilerFileName); + } +} + void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { std::ifstream spoilerFileStream(sanitize(spoilerFileName)); if (!spoilerFileStream) @@ -1091,6 +1112,25 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { } } +void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) { + std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + if (!spoilerFileStream) { + return; + } + + try { + json spoilerFileJson; + spoilerFileStream >> spoilerFileJson; + json trialsJson = spoilerFileJson["requiredTrials"]; + + for (auto it = trialsJson.begin(); it != trialsJson.end(); it++) { + this->trialsRequired[spoilerFileTrialToEnum[it.value()]] = true; + } + } catch (const std::exception& e) { + return; + } +} + void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent) { std::ifstream spoilerFileStream(sanitize(spoilerFileName)); if (!spoilerFileStream) @@ -1141,6 +1181,10 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent } } +bool Randomizer::IsTrialRequired(RandomizerInf trial) { + return this->trialsRequired.contains(trial); +} + s16 Randomizer::GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) { s16 itemId = GetItemFromActor(actorId, actorParams, sceneNum, ogId); return itemId; @@ -3355,21 +3399,17 @@ void DrawRandoEditor(bool& open) { PaddedSeparator(); // Random Ganon's Trials - /* ImGui::Text("Random Ganon's Trials"); + SohImGui::EnhancementCheckbox("Random Ganon's Trials", "gRandomizeGanonTrial"); InsertHelpHoverText("Sets a random number or required trials to enter\nGanon's Tower."); - SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 2, 0); if (CVar_GetS32("gRandomizeGanonTrial", 0) == 0) { - ImGui::PopItemWidth(); SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 0, 6, "", 6); InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); - RANDTODO: Switch back to slider when pre-completing some of Ganon's Trials is properly implemnted. } - */ - SohImGui::EnhancementCheckbox("Skip Ganon's Trials", "gRandomizeGanonTrialCount"); - InsertHelpHoverText( - "Sets whether or not Ganon's Castle Trials are required to enter Ganon's Tower."); + // SohImGui::EnhancementCheckbox("Skip Ganon's Trials", "gRandomizeGanonTrialCount"); + // InsertHelpHoverText( + // "Sets whether or not Ganon's Castle Trials are required to enter Ganon's Tower."); } // COLUMN 2 - Shuffle Settings diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 8b467a699e..2c87a5b036 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -14,6 +14,7 @@ class Randomizer { private: std::unordered_map itemLocations; std::unordered_map hintLocations; + std::unordered_map trialsRequired; std::string childAltarText; std::string adultAltarText; std::string ganonHintText; @@ -24,6 +25,7 @@ class Randomizer { s16 GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId); void ParseRandomizerSettingsFile(const char* spoilerFileName); void ParseHintLocationsFile(const char* spoilerFileName); + void ParseRequiredTrialsFile(const char* spoilerFileName); void ParseItemLocationsFile(const char* spoilerFileName, bool silent); bool IsItemVanilla(RandomizerGet randoGet); @@ -44,7 +46,9 @@ class Randomizer { bool SpoilerFileExists(const char* spoilerFileName); void LoadRandomizerSettings(const char* spoilerFileName); void LoadHintLocations(const char* spoilerFileName); - void LoadItemLocations(const char* spoilerFileName, bool silent); + void LoadRequiredTrials(const char* spoilerFileName); + void LoadItemLocations(const char* spoilerFileName,bool silent); + bool IsTrialRequired(RandomizerInf trial); u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey); RandomizerCheck GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams); std::string GetChildAltarText() const; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index d6f20e9a45..7d7a86268f 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1562,10 +1562,18 @@ extern "C" void Randomizer_LoadHintLocations(const char* spoilerFileName) { OTRGlobals::Instance->gRandomizer->LoadHintLocations(spoilerFileName); } +extern "C" void Randomizer_LoadRequiredTrials(const char* spoilerFileName) { + OTRGlobals::Instance->gRandomizer->LoadRequiredTrials(spoilerFileName); +} + extern "C" void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent) { OTRGlobals::Instance->gRandomizer->LoadItemLocations(spoilerFileName, silent); } +extern "C" bool Randomizer_IsTrialRequired(RandomizerInf trial) { + return OTRGlobals::Instance->gRandomizer->IsTrialRequired(trial); +} + extern "C" bool SpoilerFileExists(const char* spoilerFileName) { return OTRGlobals::Instance->gRandomizer->SpoilerFileExists(spoilerFileName); } diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 3266b16ebf..f81afdaeac 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -98,7 +98,9 @@ u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum); ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); void Randomizer_LoadHintLocations(const char* spoilerFileName); +void Randomizer_LoadRequiredTrials(const char* spoilerFileName); void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent); +bool Randomizer_IsTrialRequired(RandomizerInf trial); GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 5d7add53a8..0f4808494c 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -4719,6 +4719,10 @@ void Flags_SetRandomizerInf(RandomizerInf flag) { gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); } +void Flags_UnsetRandomizerInf(RandomizerInf flag) { + gSaveContext.randomizerInf[flag >> 4] &= ~(flag & 0xF); +} + u32 func_80035BFC(GlobalContext* globalCtx, s16 arg1) { u16 retTextId = 0; diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 4bbbe726a4..c8befa586a 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -7,7 +7,6 @@ #include "soh/Enhancements/randomizer/adult_trade_shuffle.h" #define NUM_DUNGEONS 8 -#define NUM_TRIALS 6 #define NUM_COWS 10 #define NUM_SCRUBS 35 @@ -762,6 +761,15 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.randomizerInf[i] = 0; } + // Set all trials to cleared if trial count is random or anything other than 6 + if (Randomizer_GetSettingValue(RSK_RANDOM_TRIALS) || (Randomizer_GetSettingValue(RSK_TRIAL_COUNT) != 6)) { + for (u16 i = RAND_INF_TRIALS_DONE_LIGHT_TRIAL; i <= RAND_INF_TRIALS_DONE_SHADOW_TRIAL; i++) { + if (!Randomizer_IsTrialRequired(i)) { + Flags_SetRandomizerInf(i); + } + } + } + // Set Cutscene flags to skip them gSaveContext.eventChkInf[0xC] |= 0x10; // returned to tot with medallions gSaveContext.eventChkInf[0xC] |= 0x20; //sheik at tot pedestal diff --git a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c index adc534a2d4..dab59262c6 100644 --- a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c +++ b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c @@ -64,12 +64,33 @@ static u8 sEnergyColors[] = { /* Forest prim */ 255, 255, 170, /* env */ 0, 200, 0, }; +// Translates from the barrier's actor params to their corresponding randInf flags. +RandomizerInf trialParamToRandInf(u16 params) { + switch (params) { + case KEKKAI_LIGHT: + return RAND_INF_TRIALS_DONE_LIGHT_TRIAL; + case KEKKAI_FOREST: + return RAND_INF_TRIALS_DONE_FOREST_TRIAL; + case KEKKAI_FIRE: + return RAND_INF_TRIALS_DONE_FIRE_TRIAL; + case KEKKAI_WATER: + return RAND_INF_TRIALS_DONE_WATER_TRIAL; + case KEKKAI_SPIRIT: + return RAND_INF_TRIALS_DONE_SPIRIT_TRIAL; + case KEKKAI_SHADOW: + return RAND_INF_TRIALS_DONE_SHADOW_TRIAL; + } +} + s32 DemoKekkai_CheckEventFlag(s32 params) { static s32 eventFlags[] = { 0xC3, 0xBC, 0xBF, 0xBE, 0xBD, 0xAD, 0xBB }; if ((params < KEKKAI_TOWER) || (params > KEKKAI_FOREST)) { return true; } + if (gSaveContext.n64ddFlag) { + return Flags_GetRandomizerInf(trialParamToRandInf(params)); + } return Flags_GetEventChkInf(eventFlags[params]); } @@ -128,8 +149,7 @@ void DemoKekkai_Init(Actor* thisx, GlobalContext* globalCtx) { this->collider2.dim.yShift = 300; if (gSaveContext.n64ddFlag) { - int trialsToComplete = Randomizer_GetSettingValue(RSK_TRIAL_COUNT); - if (trialsToComplete <= TrialsDoneCount()) { + if (TrialsDoneCount() == NUM_TRIALS) { Actor_Kill(thisx); return; } @@ -141,6 +161,10 @@ void DemoKekkai_Init(Actor* thisx, GlobalContext* globalCtx) { case KEKKAI_SHADOW: case KEKKAI_SPIRIT: case KEKKAI_FOREST: + if (gSaveContext.n64ddFlag && Flags_GetRandomizerInf(trialParamToRandInf(thisx->params))) { + Actor_Kill(thisx); + return; + } this->energyAlpha = 1.0f; this->orbScale = 1.0f; Actor_SetScale(thisx, 0.1f); diff --git a/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c b/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c index 22b7969644..6aff361444 100644 --- a/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c +++ b/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c @@ -135,6 +135,27 @@ void ObjectKankyo_Init(Actor* thisx, GlobalContext* globalCtx) { this->effects[5].size = 0.0f; } + if (gSaveContext.n64ddFlag) { + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_FOREST_TRIAL)) { + this->effects[0].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_WATER_TRIAL)) { + this->effects[1].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_SHADOW_TRIAL)) { + this->effects[2].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_FIRE_TRIAL)) { + this->effects[3].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_LIGHT_TRIAL)) { + this->effects[4].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_SPIRIT_TRIAL)) { + this->effects[5].size = 0.0f; + } + } + if (gSaveContext.cutsceneTrigger != 0) { if (gSaveContext.entranceIndex == 0x0538) { this->effects[0].size = 0.1f; diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 75cc7ca27b..f363751ee2 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -433,6 +433,7 @@ void FileChoose_UpdateMainMenu(GameState* thisx) { const char* fileLoc = CVar_GetString("gSpoilerLog", ""); Randomizer_LoadSettings(fileLoc); Randomizer_LoadHintLocations(fileLoc); + Randomizer_LoadRequiredTrials(fileLoc); Randomizer_LoadItemLocations(fileLoc, silent); fileSelectSpoilerFileLoaded = true; } From ff0ef4a6b472e9e11692b03cb24073826f27fab0 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 14:27:02 -0400 Subject: [PATCH 14/45] ImGui/Commented out code cleanup. --- soh/soh/Enhancements/randomizer/3drando/settings.cpp | 10 ---------- soh/soh/Enhancements/randomizer/randomizer.cpp | 6 +----- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 9e496598e0..cb9820cec0 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2518,17 +2518,7 @@ namespace Settings { BridgeDungeonCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_DUNGEON_COUNT]); BridgeTokenCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_TOKEN_COUNT]); RandomGanonsTrials.SetSelectedIndex(cvarSettings[RSK_RANDOM_TRIALS]); - // RANDTODO: Switch this back once Ganon's Trials Count is properly implemented. GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); - // switch (cvarSettings[RSK_TRIAL_COUNT]) { - // case 0: - // GanonsTrialsCount.SetSelectedIndex(6); - // break; - // case 1: - // GanonsTrialsCount.SetSelectedIndex(0); - // break; - // } - ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]); ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]); Tokensanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_TOKENS]); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 6dff5a627f..11335d2757 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3399,17 +3399,13 @@ void DrawRandoEditor(bool& open) { PaddedSeparator(); // Random Ganon's Trials - ImGui::Text("Random Ganon's Trials"); SohImGui::EnhancementCheckbox("Random Ganon's Trials", "gRandomizeGanonTrial"); - InsertHelpHoverText("Sets a random number or required trials to enter\nGanon's Tower."); + InsertHelpHoverText("Sets a random number or required trials to enter Ganon's Tower."); if (CVar_GetS32("gRandomizeGanonTrial", 0) == 0) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 0, 6, "", 6); InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); } - // SohImGui::EnhancementCheckbox("Skip Ganon's Trials", "gRandomizeGanonTrialCount"); - // InsertHelpHoverText( - // "Sets whether or not Ganon's Castle Trials are required to enter Ganon's Tower."); } // COLUMN 2 - Shuffle Settings From 3d8b8066dadd584de71d17ba017ed6989d00041f Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 14:33:38 -0400 Subject: [PATCH 15/45] More comment cleanup --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index eaf4b14192..c2a19e6217 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -205,16 +205,15 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { !(gSaveContext.eventChkInf[1] & 0x10) && !(gSaveContext.infTable[8] & 0x800)) { return 1; } - // Causes Malon to appear at Hyrule Castle if you've met her already and either we're vanilla and Talon hasn't - // left Hyrule Castle, or if we're randomized and haven't obtained her check. If we haven't met Malon yet, this - // sets the flag for meeting her. - if ((globalCtx->sceneNum == SCENE_SPOT15) && (!(gSaveContext.eventChkInf[1] & 0x10) || - (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()))) { - if (gSaveContext.infTable[8] & 0x800) { - return 1; - } else { - gSaveContext.infTable[8] |= 0x800; - return 0; + if ((globalCtx->sceneNum == SCENE_SPOT15) && // if we're at hyrule castle + (!(gSaveContext.eventChkInf[1] & 0x10) || // and talon hasn't left + (gSaveContext.n64ddFlag && + !Randomizer_ObtainedMalonHCReward()))) { // or we're rando'd and haven't gotten malon's HC check + if (gSaveContext.infTable[8] & 0x800) { // if we've met malon + return 1; // make her appear at the castle + } else { // if we haven't met malon + gSaveContext.infTable[8] |= 0x800; // set the flag for meeting malon + return 0; // don't make her appear at the castle } } // Malon asleep in her bed if Talon has left Hyrule Castle and it is nighttime. From 4d8bfa97c0914d79c0b3e5bc8916aa6ff8656a2e Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 15:51:14 -0400 Subject: [PATCH 16/45] UI Changes (dropdown and slider rather than checkbox and slider) --- .../Enhancements/randomizer/3drando/settings.cpp | 12 ++++++++++-- soh/soh/Enhancements/randomizer/randomizer.cpp | 16 +++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index cb9820cec0..cb91e53341 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2517,8 +2517,16 @@ namespace Settings { BridgeRewardCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_REWARD_COUNT]); BridgeDungeonCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_DUNGEON_COUNT]); BridgeTokenCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_TOKEN_COUNT]); - RandomGanonsTrials.SetSelectedIndex(cvarSettings[RSK_RANDOM_TRIALS]); - GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); + if (cvarSettings[RSK_RANDOM_TRIALS] == 2) { + RandomGanonsTrials.SetSelectedIndex(1); + } else { + RandomGanonsTrials.SetSelectedIndex(0); + } + if (cvarSettings[RSK_RANDOM_TRIALS] == 0) { + GanonsTrialsCount.SetSelectedIndex(0); + } else { + GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); + } ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]); ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]); Tokensanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_TOKENS]); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 11335d2757..af83fe8e4f 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3025,7 +3025,7 @@ void DrawRandoEditor(bool& open) { const char* randoGerudoFortress[3] = { "Normal", "Fast", "Open" }; const char* randoRainbowBridge[7] = { "Vanilla", "Always open", "Stones", "Medallions", "Dungeon rewards", "Dungeons", "Tokens" }; - const char* randoGanonsTrial[2] = { "Off", "On" }; + const char* randoGanonsTrial[3] = { "Skip", "Set Number", "Random Number" }; // World Settings const char* randoStartingAge[3] = { "Child", "Adult", "Random" }; @@ -3399,12 +3399,18 @@ void DrawRandoEditor(bool& open) { PaddedSeparator(); // Random Ganon's Trials - SohImGui::EnhancementCheckbox("Random Ganon's Trials", "gRandomizeGanonTrial"); - InsertHelpHoverText("Sets a random number or required trials to enter Ganon's Tower."); - if (CVar_GetS32("gRandomizeGanonTrial", 0) == 0) { + ImGui::Text("Ganon's Trials"); + InsertHelpHoverText("Sets the number of Ganon's Trials required to dispel the barrier\n\n" + "Skip - No Trials are required and the barrier is already dispelled.\n\n" + "Set Number - Select a number of trials that will be required from the" + "slider below. Which specific trials you need to complete will be random.\n\n" + "Random Number - A Random number and set of trials will be required."); + SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 3, 0); + if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 0, 6, "", 6); - InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); + InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower." + "The specific trials you need to complete will be randomly selected."); } } From dbd8909d2634d73e8da63d0ecb51ec4c3fa8b510 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 15:53:57 -0400 Subject: [PATCH 17/45] Forgot to limit slider from 1-6 rather than 0-6 --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index af83fe8e4f..4dea6642cb 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3408,7 +3408,7 @@ void DrawRandoEditor(bool& open) { SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 3, 0); if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", - "gRandomizeGanonTrialCount", 0, 6, "", 6); + "gRandomizeGanonTrialCount", 1, 6, "", 6); InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower." "The specific trials you need to complete will be randomly selected."); } From 404a637ebd2df655dd0d052ee4f419d23fa3f800 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 15:56:11 -0400 Subject: [PATCH 18/45] Removes added function that went unused. --- soh/include/functions.h | 1 - soh/src/code/z_actor.c | 4 ---- 2 files changed, 5 deletions(-) diff --git a/soh/include/functions.h b/soh/include/functions.h index 7d8b309a58..9047b6d3f2 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -561,7 +561,6 @@ s32 Flags_GetInfTable(s32 flag); void Flags_SetInfTable(s32 flag); s32 Flags_GetRandomizerInf(RandomizerInf flag); void Flags_SetRandomizerInf(RandomizerInf flag); -void Flags_UnsetRandomizerInf(RandomizerInf flag); u16 func_80037C30(GlobalContext* globalCtx, s16 arg1); s32 func_80037D98(GlobalContext* globalCtx, Actor* actor, s16 arg2, s32* arg3); s32 func_80038290(GlobalContext* globalCtx, Actor* actor, Vec3s* arg2, Vec3s* arg3, Vec3f arg4); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 0f4808494c..5d7add53a8 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -4719,10 +4719,6 @@ void Flags_SetRandomizerInf(RandomizerInf flag) { gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); } -void Flags_UnsetRandomizerInf(RandomizerInf flag) { - gSaveContext.randomizerInf[flag >> 4] &= ~(flag & 0xF); -} - u32 func_80035BFC(GlobalContext* globalCtx, s16 arg1) { u16 retTextId = 0; From 6aaef2179bbe26485973ab6552a9b22e514f12c6 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 18:26:25 -0400 Subject: [PATCH 19/45] More Cleanup --- .../randomizer/3drando/spoiler_log.cpp | 21 ------------------- .../Enhancements/randomizer/randomizer.cpp | 3 +-- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 332fbb9e16..63230c2d1d 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -520,27 +520,6 @@ static void WriteRequiredTrials() { } } -// Writes the required trails to the spoiler log, if there are any. -// static void WriteRequiredTrials(tinyxml2::XMLDocument& spoilerLog) { -// auto parentNode = spoilerLog.NewElement("required-trials"); - -// for (const auto* trial : Trial::trialList) { -// if (trial->IsSkipped()) { -// continue; -// } - -// auto node = parentNode->InsertNewChildElement("trial"); -// // PURPLE TODO: LOCALIZATION -// std::string name = trial->GetName().GetEnglish(); -// name[0] = toupper(name[0]); // Capitalize T in "The" -// node->SetAttribute("name", name.c_str()); -// } - -// if (!parentNode->NoChildren()) { -// spoilerLog.RootElement()->InsertEndChild(parentNode); -// } -// } - // Writes the intended playthrough to the spoiler log, separated into spheres. static void WritePlaythrough() { // auto playthroughNode = spoilerLog.NewElement("playthrough"); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 4dea6642cb..a433f0b3cf 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3409,8 +3409,7 @@ void DrawRandoEditor(bool& open) { if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 1, 6, "", 6); - InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower." - "The specific trials you need to complete will be randomly selected."); + InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); } } From fafd90482b37cd54e30fea7f5f38fe44864c5c3b Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 18:42:36 -0400 Subject: [PATCH 20/45] Refactor of some old rando code to use new functions. --- .../actors/ovl_Demo_Kekkai/z_demo_kekkai.c | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c index dab59262c6..6d0b51db23 100644 --- a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c +++ b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c @@ -271,27 +271,10 @@ void DemoKekkai_TrialBarrierDispel(Actor* thisx, GlobalContext* globalCtx) { DemoKekkai* this = (DemoKekkai*)thisx; if (gSaveContext.n64ddFlag) { - switch (thisx->params) { - case KEKKAI_WATER: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_WATER_TRIAL); - break; - case KEKKAI_LIGHT: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_LIGHT_TRIAL); - break; - case KEKKAI_FIRE: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_FIRE_TRIAL); - break; - case KEKKAI_SHADOW: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_SHADOW_TRIAL); - break; - case KEKKAI_SPIRIT: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_SPIRIT_TRIAL); - break; - case KEKKAI_FOREST: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_FOREST_TRIAL); - break; - } - Flags_SetEventChkInf(eventFlags[thisx->params]); + Flags_SetRandomizerInf(trialParamToRandInf(thisx->params)); + // May or may not be needed. Not sure if needed for anything + // that randoInf isn't already covering. Leaving it for safety. + Flags_SetEventChkInf(eventFlags[thisx->params]); } if (globalCtx->csCtx.frames == csFrames[this->actor.params]) { From 9c43f7225b97aa38b14cdfdfdc146f4135980f19 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 18:45:21 -0400 Subject: [PATCH 21/45] Adds captilization to French spoilerfile strings. --- soh/soh/Enhancements/randomizer/3drando/trial.cpp | 12 ++++++------ soh/soh/Enhancements/randomizer/randomizer.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/trial.cpp b/soh/soh/Enhancements/randomizer/3drando/trial.cpp index 1659673c97..e9ee31317b 100644 --- a/soh/soh/Enhancements/randomizer/3drando/trial.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/trial.cpp @@ -7,12 +7,12 @@ TrialInfo::TrialInfo(Text name_) TrialInfo::~TrialInfo() = default; - TrialInfo ForestTrial = TrialInfo(Text{"the Forest Trial", /*french*/"l'épreuve de la forêt", /*spanish*/"la prueba del bosque"}); - TrialInfo FireTrial = TrialInfo(Text{"the Fire Trial", /*french*/"l'épreuve du feu", /*spanish*/"la prueba del fuego"}); - TrialInfo WaterTrial = TrialInfo(Text{"the Water Trial", /*french*/"l'épreuve de l'eau", /*spanish*/"la prueba del agua"}); - TrialInfo SpiritTrial = TrialInfo(Text{"the Spirit Trial", /*french*/"l'épreuve de l'esprit", /*spanish*/"la prueba del espíritu"}); - TrialInfo ShadowTrial = TrialInfo(Text{"the Shadow Trial", /*french*/"l'épreuve de l'ombre", /*spanish*/"la prueba de las sombras"}); - TrialInfo LightTrial = TrialInfo(Text{"the Light Trial", /*french*/"l'épreuve de la lumière", /*spanish*/"la prueba de la luz"}); + TrialInfo ForestTrial = TrialInfo(Text{"the Forest Trial", /*french*/"l'épreuve de la Forêt", /*spanish*/"la prueba del bosque"}); + TrialInfo FireTrial = TrialInfo(Text{"the Fire Trial", /*french*/"l'épreuve du Feu", /*spanish*/"la prueba del fuego"}); + TrialInfo WaterTrial = TrialInfo(Text{"the Water Trial", /*french*/"l'épreuve de l'Eau", /*spanish*/"la prueba del agua"}); + TrialInfo SpiritTrial = TrialInfo(Text{"the Spirit Trial", /*french*/"l'épreuve de l'Esprit", /*spanish*/"la prueba del espíritu"}); + TrialInfo ShadowTrial = TrialInfo(Text{"the Shadow Trial", /*french*/"l'épreuve de l'Ombre", /*spanish*/"la prueba de las sombras"}); + TrialInfo LightTrial = TrialInfo(Text{"the Light Trial", /*french*/"l'épreuve de la Lumière", /*spanish*/"la prueba de la luz"}); const TrialArray trialList = { &ForestTrial, diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index a433f0b3cf..8f4ef7d3b9 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -109,17 +109,17 @@ Randomizer::~Randomizer() { std::unordered_map spoilerFileTrialToEnum = { { "the Forest Trial", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, - { "l'épreuve de la forêt", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, + { "l'épreuve de la Forêt", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, { "the Fire Trial", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, - { "l'épreuve du feu", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, + { "l'épreuve du Feu", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, { "the Water Trial", RAND_INF_TRIALS_DONE_WATER_TRIAL }, - { "l'épreuve de l'eau", RAND_INF_TRIALS_DONE_WATER_TRIAL }, + { "l'épreuve de l'Eau", RAND_INF_TRIALS_DONE_WATER_TRIAL }, { "the Spirit Trial", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, - { "l'épreuve de l'esprit", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, + { "l'épreuve de l'Esprit", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, { "the Shadow Trial", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, - { "l'épreuve de l'ombre", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, + { "l'épreuve de l'Ombre", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, { "the Light Trial", RAND_INF_TRIALS_DONE_LIGHT_TRIAL }, - { "l'épreuve de la lumière", RAND_INF_TRIALS_DONE_LIGHT_TRIAL } + { "l'épreuve de la Lumière", RAND_INF_TRIALS_DONE_LIGHT_TRIAL } }; std::unordered_map getItemIdToItemId = { From 0de1cd96b1f466a8f24a57efbefdeecd5e2db181 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sun, 28 Aug 2022 22:57:41 -0400 Subject: [PATCH 22/45] Fixes keys, maps, and compasses on develop-zhora rando. --- .../Enhancements/randomizer/randomizer.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 8f4ef7d3b9..a6d6b0e4b0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1619,6 +1619,41 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_BUY_BOMBS_535: case RG_BUY_RED_POTION_40: case RG_BUY_RED_POTION_50: + case RG_FOREST_TEMPLE_SMALL_KEY: + case RG_FIRE_TEMPLE_SMALL_KEY: + case RG_WATER_TEMPLE_SMALL_KEY: + case RG_SPIRIT_TEMPLE_SMALL_KEY: + case RG_SHADOW_TEMPLE_SMALL_KEY: + case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: + case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: + case RG_GERUDO_FORTRESS_SMALL_KEY: + case RG_GANONS_CASTLE_SMALL_KEY: + case RG_FOREST_TEMPLE_BOSS_KEY: + case RG_FIRE_TEMPLE_BOSS_KEY: + case RG_WATER_TEMPLE_BOSS_KEY: + case RG_SPIRIT_TEMPLE_BOSS_KEY: + case RG_SHADOW_TEMPLE_BOSS_KEY: + case RG_GANONS_CASTLE_BOSS_KEY: + case RG_DEKU_TREE_COMPASS: + case RG_DODONGOS_CAVERN_COMPASS: + case RG_JABU_JABUS_BELLY_COMPASS: + case RG_FOREST_TEMPLE_COMPASS: + case RG_FIRE_TEMPLE_COMPASS: + case RG_WATER_TEMPLE_COMPASS: + case RG_SPIRIT_TEMPLE_COMPASS: + case RG_SHADOW_TEMPLE_COMPASS: + case RG_BOTTOM_OF_THE_WELL_COMPASS: + case RG_ICE_CAVERN_COMPASS: + case RG_DEKU_TREE_MAP: + case RG_DODONGOS_CAVERN_MAP: + case RG_JABU_JABUS_BELLY_MAP: + case RG_FOREST_TEMPLE_MAP: + case RG_FIRE_TEMPLE_MAP: + case RG_WATER_TEMPLE_MAP: + case RG_SPIRIT_TEMPLE_MAP: + case RG_SHADOW_TEMPLE_MAP: + case RG_BOTTOM_OF_THE_WELL_MAP: + case RG_ICE_CAVERN_MAP: return true; default: return false; From 760eaa4d97de5ebaa38ad9213f4301f73f6dd08d Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sun, 28 Aug 2022 23:01:21 -0400 Subject: [PATCH 23/45] Adds randotodo comment as a note to adapt for the keysanity situation. --- soh/soh/Enhancements/randomizer/randomizer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index a6d6b0e4b0..1bb2a1ab93 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1619,6 +1619,7 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_BUY_BOMBS_535: case RG_BUY_RED_POTION_40: case RG_BUY_RED_POTION_50: + //RANDO TODO: Fix this to return false if keysanity is on. case RG_FOREST_TEMPLE_SMALL_KEY: case RG_FIRE_TEMPLE_SMALL_KEY: case RG_WATER_TEMPLE_SMALL_KEY: From 35d651f06e62149768397a2f53078a0ef01a8293 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sun, 28 Aug 2022 23:54:13 -0400 Subject: [PATCH 24/45] When shuffled to Own Dungeon or below, give vanilla keys, maps, and compasses. --- .../Enhancements/randomizer/randomizer.cpp | 78 ++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 1bb2a1ab93..a9fe62d9a0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1409,7 +1409,66 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { return GI_BOTTLE; case RG_BOTTLE_WITH_MILK: return GI_MILK_BOTTLE; - + + case RG_DEKU_TREE_MAP: + case RG_DODONGOS_CAVERN_MAP: + case RG_JABU_JABUS_BELLY_MAP: + case RG_FOREST_TEMPLE_MAP: + case RG_FIRE_TEMPLE_MAP: + case RG_WATER_TEMPLE_MAP: + case RG_SPIRIT_TEMPLE_MAP: + case RG_SHADOW_TEMPLE_MAP: + case RG_BOTTOM_OF_THE_WELL_MAP: + case RG_ICE_CAVERN_MAP: + if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) < 3) { + return GI_MAP; + } else { + return randoGet; + } + + case RG_DEKU_TREE_COMPASS: + case RG_DODONGOS_CAVERN_COMPASS: + case RG_JABU_JABUS_BELLY_COMPASS: + case RG_FOREST_TEMPLE_COMPASS: + case RG_FIRE_TEMPLE_COMPASS: + case RG_WATER_TEMPLE_COMPASS: + case RG_SPIRIT_TEMPLE_COMPASS: + case RG_SHADOW_TEMPLE_COMPASS: + case RG_BOTTOM_OF_THE_WELL_COMPASS: + case RG_ICE_CAVERN_COMPASS: + if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) < 3) { + return GI_COMPASS; + } else { + return randoGet; + } + + case RG_FOREST_TEMPLE_BOSS_KEY: + case RG_FIRE_TEMPLE_BOSS_KEY: + case RG_WATER_TEMPLE_BOSS_KEY: + case RG_SPIRIT_TEMPLE_BOSS_KEY: + case RG_SHADOW_TEMPLE_BOSS_KEY: + case RG_GANONS_CASTLE_BOSS_KEY: + if (GetRandoSettingValue(RSK_BOSS_KEYSANITY) < 3) { + return GI_KEY_BOSS; + } else { + return randoGet; + } + + case RG_FOREST_TEMPLE_SMALL_KEY: + case RG_FIRE_TEMPLE_SMALL_KEY: + case RG_WATER_TEMPLE_SMALL_KEY: + case RG_SPIRIT_TEMPLE_SMALL_KEY: + case RG_SHADOW_TEMPLE_SMALL_KEY: + case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: + case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: + case RG_GERUDO_FORTRESS_SMALL_KEY: + case RG_GANONS_CASTLE_SMALL_KEY: + if (GetRandoSettingValue(RSK_KEYSANITY) < 3) { + return GI_KEY_SMALL; + } else { + return randoGet; + } + // todo test this with keys in own dungeon case RG_TREASURE_GAME_SMALL_KEY: return GI_DOOR_KEY; @@ -1619,7 +1678,7 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_BUY_BOMBS_535: case RG_BUY_RED_POTION_40: case RG_BUY_RED_POTION_50: - //RANDO TODO: Fix this to return false if keysanity is on. + return true; case RG_FOREST_TEMPLE_SMALL_KEY: case RG_FIRE_TEMPLE_SMALL_KEY: case RG_WATER_TEMPLE_SMALL_KEY: @@ -1629,12 +1688,24 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: case RG_GERUDO_FORTRESS_SMALL_KEY: case RG_GANONS_CASTLE_SMALL_KEY: + if (GetRandoSettingValue(RSK_KEYSANITY) > 2) { + return false; + } + return true; case RG_FOREST_TEMPLE_BOSS_KEY: case RG_FIRE_TEMPLE_BOSS_KEY: case RG_WATER_TEMPLE_BOSS_KEY: case RG_SPIRIT_TEMPLE_BOSS_KEY: case RG_SHADOW_TEMPLE_BOSS_KEY: + if (GetRandoSettingValue(RSK_BOSS_KEYSANITY) > 2) { + return false; + } + return true; case RG_GANONS_CASTLE_BOSS_KEY: + if (GetRandoSettingValue(RSK_GANONS_BOSS_KEY) > 2) { + return false; + } + return true; case RG_DEKU_TREE_COMPASS: case RG_DODONGOS_CAVERN_COMPASS: case RG_JABU_JABUS_BELLY_COMPASS: @@ -1655,6 +1726,9 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_SHADOW_TEMPLE_MAP: case RG_BOTTOM_OF_THE_WELL_MAP: case RG_ICE_CAVERN_MAP: + if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) > 2) { + return false; + } return true; default: return false; From 0a27714b8edb65775d4989e170a472fd3ab348f2 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 00:09:44 -0400 Subject: [PATCH 25/45] Adds missing case for RSK_GERUDO_KEYS from spoilerfile parsing. --- .../Enhancements/randomizer/randomizer.cpp | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index a9fe62d9a0..2ed1888e40 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -875,6 +875,19 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { gSaveContext.randoSettings[index].value = 3; } break; + case RSK_GERUDO_KEYS: + if (it.value() == "Vanilla") { + gSaveContext.randoSettings[index].value = 0; + } + if (it.value() == "Any Dungeon") { + gSaveContext.randoSettings[index].value = 1; + } + if (it.value() == "Overworld") { + gSaveContext.randoSettings[index].value = 2; + } + if (it.value() == "Anywhere") { + gSaveContext.randoSettings[index].value = 3; + } case RSK_KEYSANITY: if(it.value() == "Start With") { gSaveContext.randoSettings[index].value = 0; @@ -1461,13 +1474,18 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case RG_SHADOW_TEMPLE_SMALL_KEY: case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: - case RG_GERUDO_FORTRESS_SMALL_KEY: case RG_GANONS_CASTLE_SMALL_KEY: if (GetRandoSettingValue(RSK_KEYSANITY) < 3) { return GI_KEY_SMALL; } else { return randoGet; } + case RG_GERUDO_FORTRESS_SMALL_KEY: + if (GetRandoSettingValue(RSK_GERUDO_KEYS) == 0) { + return GI_KEY_SMALL; + } else { + return randoGet; + } // todo test this with keys in own dungeon case RG_TREASURE_GAME_SMALL_KEY: @@ -1686,12 +1704,16 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_SHADOW_TEMPLE_SMALL_KEY: case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: - case RG_GERUDO_FORTRESS_SMALL_KEY: case RG_GANONS_CASTLE_SMALL_KEY: if (GetRandoSettingValue(RSK_KEYSANITY) > 2) { return false; } return true; + case RG_GERUDO_FORTRESS_SMALL_KEY: + if (GetRandoSettingValue(RSK_GERUDO_KEYS != 0)) { + return false + } + return true; case RG_FOREST_TEMPLE_BOSS_KEY: case RG_FIRE_TEMPLE_BOSS_KEY: case RG_WATER_TEMPLE_BOSS_KEY: From a84262dbf7a9bd8658bd027e31f13c8a6aac5b43 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 00:11:10 -0400 Subject: [PATCH 26/45] Bit of cleanup --- soh/soh/Enhancements/randomizer/randomizer.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 2ed1888e40..7d552ce900 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -878,14 +878,11 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { case RSK_GERUDO_KEYS: if (it.value() == "Vanilla") { gSaveContext.randoSettings[index].value = 0; - } - if (it.value() == "Any Dungeon") { + } else if (it.value() == "Any Dungeon") { gSaveContext.randoSettings[index].value = 1; - } - if (it.value() == "Overworld") { + } else if (it.value() == "Overworld") { gSaveContext.randoSettings[index].value = 2; - } - if (it.value() == "Anywhere") { + } else if (it.value() == "Anywhere") { gSaveContext.randoSettings[index].value = 3; } case RSK_KEYSANITY: From f44c588a2c24aa3ffc2de533b1553bd6c595d821 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 01:03:21 -0400 Subject: [PATCH 27/45] Oops --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 7d552ce900..01bb061756 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1708,7 +1708,7 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { return true; case RG_GERUDO_FORTRESS_SMALL_KEY: if (GetRandoSettingValue(RSK_GERUDO_KEYS != 0)) { - return false + return false; } return true; case RG_FOREST_TEMPLE_BOSS_KEY: From 51dbee365a6c3efd366a15c79e0814e242756a45 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 01:04:13 -0400 Subject: [PATCH 28/45] Oops part 2 --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 01bb061756..b4129eba14 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1707,7 +1707,7 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { } return true; case RG_GERUDO_FORTRESS_SMALL_KEY: - if (GetRandoSettingValue(RSK_GERUDO_KEYS != 0)) { + if (GetRandoSettingValue(RSK_GERUDO_KEYS) != 0) { return false; } return true; From 11618730442b0a8737e79739e7484932c855922a Mon Sep 17 00:00:00 2001 From: aMannus Date: Mon, 29 Aug 2022 21:51:42 +0200 Subject: [PATCH 29/45] Moar names --- .../Enhancements/randomizer/randomizer.cpp | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 8f4ef7d3b9..fd018ff7b6 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -36,17 +36,23 @@ const std::string Randomizer::merchantMessageTableID = "RandomizerMerchants"; const std::string Randomizer::rupeeMessageTableID = "RandomizerRupees"; const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi"; -static const char* englishRupeeNames[44] = { - "Rupees", "Bitcoin", "Bananas", "Cornflakes", "Gummybears", "Floopies", "Dollars", "Lemmings", - "Emeralds", "Bucks", "Rubles", "Diamonds", "Moons", "Stars", "Mana", "Doll Hairs", - "Dogecoin", "Mushrooms", "Experience", "Friends", "Coins", "Rings", "Gil", "Pokédollars", - "Bells", "Orbs", "Bottle Caps", "Simoleons", "Pokémon", "Toys", "Smackaroos", "Zorkmids", - "Zenny", "Bones", "Souls", "Studs", "Munny", "Rubies", "Gald", "Gold", - "Shillings", "Pounds", "Glimmer", "Potch" +static const char* englishRupeeNames[52] = { + "Rupees", "Bitcoin", "Bananas", "Cornflakes", "Gummybears", "Floopies", "Dollars", "Lemmings", + "Emeralds", "Bucks", "Rubles", "Diamonds", "Moons", "Stars", "Mana", "Doll Hairs", + "Dogecoin", "Mushrooms", "Experience", "Friends", "Coins", "Rings", "Gil", "Pokédollars", + "Bells", "Orbs", "Bottle Caps", "Simoleons", "Pokémon", "Toys", "Smackaroos", "Zorkmids", + "Zenny", "Bones", "Souls", "Studs", "Munny", "Rubies", "Gald", "Gold", + "Shillings", "Pounds", "Glimmer", "Potch", "Robux", "V-Bucks", "Bratwürste", "Mesetas", + "Bath Salts", "Coal", "Euro", "Spoons" }; -static const char* germanRupeeNames[1] = { - "Rubine" +static const char* germanRupeeNames[41] = { + "Rubine", "Mäuse", "Kröten", "Münzen", "Euro", "Mark", "Bananen", + "Gummibären", "Bonbons", "Diamanten", "Bratwürste", "Bitcoin", "Dogecoin", "Monde", + "Sterne", "Brause UFOs", "Taler", "Sternis", "Schillinge", "Freunde", "Seelen", + "Gil", "Zenny", "Pfandflaschen", "Knochen", "Pilze", "Smaragde", "Kronkorken", + "Pokédollar", "Brötchen", "EXP", "Wagenchips", "Moos", "Knete", "Kohle", + "Kies", "Radieschen", "Diridari", "Steine", "Kartoffeln", "Penunze" }; static const char* frenchRupeeNames[36] = { From b9aee7085edda009c07e9876e3ed88994e6b0e20 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 19:12:19 -0400 Subject: [PATCH 30/45] Adds note to key colors enhancement about this change. --- libultraship/libultraship/ImGuiImpl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index d430bc7699..c74d126fb6 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -2011,7 +2011,9 @@ namespace SohImGui { ); PaddedEnhancementCheckbox("Key Colors Match Dungeon", "gRandoMatchKeyColors", true, false); 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."); + "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 " + "applies to seeds with keys and boss keys shuffled to Any Dungeon, Overworld, or Anywhere."); PaddedEnhancementCheckbox("Quest Item Fanfares", "gRandoQuestItemFanfares", true, false); Tooltip( "Play unique fanfares when obtaining quest items " From 99674ff88c0ef9669d3782a7003d533a7d5e2f1b Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 19:19:01 -0400 Subject: [PATCH 31/45] Readds missing workaround for spirit temple and ganon's castle keys. --- soh/src/code/z_parameter.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 73044df27e..265c69aced 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1690,12 +1690,35 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { } return ITEM_NONE; } else if (item == ITEM_KEY_SMALL) { - if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { - gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; - return ITEM_NONE; + // Small key exceptions for rando with keysanity off. + if (gSaveContext.n64ddFlag) { + if (globalCtx->sceneNum == 10) { // ganon's tower -> ganon's castle + if (gSaveContext.inventory.dungeonKeys[13] < 0) { + gSaveContext.inventory.dungeonKeys[13] = 1; + return ITEM_NONE; + } else { + gSaveContext.inventory.dungeonKeys[13]++; + return ITEM_NONE; + } + } + + if (globalCtx->sceneNum == 92) { // Desert Colossus -> Spirit Temple. + if (gSaveContext.inventory.dungeonKeys[6] < 0) { + gSaveContext.inventory.dungeonKeys[6] = 1; + return ITEM_NONE; + } else { + gSaveContext.inventory.dungeonKeys[6]++; + return ITEM_NONE; + } + } } else { - gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]++; - return ITEM_NONE; + if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { + gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; + return ITEM_NONE; + } else { + gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]++; + return ITEM_NONE; + } } } else if ((item == ITEM_QUIVER_30) || (item == ITEM_BOW)) { if (CUR_UPG_VALUE(UPG_QUIVER) == 0) { From 3856d1b0a745aede9f6e1ce409d31ee66cc3bdf3 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Tue, 30 Aug 2022 11:00:47 -0400 Subject: [PATCH 32/45] Fixed small key case that was behind an else and shouldn't have been --- soh/src/code/z_parameter.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 265c69aced..f8df81f342 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1711,14 +1711,12 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { return ITEM_NONE; } } + if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { + gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; + return ITEM_NONE; } else { - if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { - gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; - return ITEM_NONE; - } else { - gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]++; - return ITEM_NONE; - } + gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]++; + return ITEM_NONE; } } else if ((item == ITEM_QUIVER_30) || (item == ITEM_BOW)) { if (CUR_UPG_VALUE(UPG_QUIVER) == 0) { From 60257b98a4ae4e392ef2c049255b367a6ef34ee8 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Tue, 30 Aug 2022 11:21:29 -0400 Subject: [PATCH 33/45] Oops. Missed closing bracket. --- soh/src/code/z_parameter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index f8df81f342..8d26f36586 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1711,6 +1711,7 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { return ITEM_NONE; } } + } if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; return ITEM_NONE; From 776219fb52730541c402c1fd63b7b9bd470cdb22 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 31 Aug 2022 09:25:47 -0400 Subject: [PATCH 34/45] Backports a fix for sheik checks from rando-next (#1340) * Fixes some Sheik checks I had accidentally set the wrong flag for. * Removes duplicate switch case from cherry-pick --- soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c b/soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c index 90e401f06f..30ab5d06ea 100644 --- a/soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c +++ b/soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c @@ -298,7 +298,7 @@ void GivePlayerRandoRewardSheikSong(EnXc* sheik, GlobalContext* globalCtx, Rando } } else if (check != RC_SHEIK_AT_TEMPLE) { if (GiveItemEntryFromActor(&sheik->actor, globalCtx, getItemEntry, 10000.0f, 100.0f)) { - player->pendingFlag.flagID = 0x55; + player->pendingFlag.flagID = (0x5 << 4) | (sheikType & 0xF) >> 1; player->pendingFlag.flagType = FLAG_EVENT_CHECK_INF; } } From bf505dba5cef0aaffb4576c9b4c4f430e9bceb43 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 31 Aug 2022 09:25:58 -0400 Subject: [PATCH 35/45] Fixes keys, maps, and compasses on develop-zhora rando (#1338) * Fixes keys, maps, and compasses on develop-zhora rando. * Adds randotodo comment as a note to adapt for the keysanity situation. --- .../Enhancements/randomizer/randomizer.cpp | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 1fc95a04fc..4958503619 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -2209,6 +2209,42 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_BUY_BOMBS_535: case RG_BUY_RED_POTION_40: case RG_BUY_RED_POTION_50: + //RANDO TODO: Fix this to return false if keysanity is on. + case RG_FOREST_TEMPLE_SMALL_KEY: + case RG_FIRE_TEMPLE_SMALL_KEY: + case RG_WATER_TEMPLE_SMALL_KEY: + case RG_SPIRIT_TEMPLE_SMALL_KEY: + case RG_SHADOW_TEMPLE_SMALL_KEY: + case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: + case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: + case RG_GERUDO_FORTRESS_SMALL_KEY: + case RG_GANONS_CASTLE_SMALL_KEY: + case RG_FOREST_TEMPLE_BOSS_KEY: + case RG_FIRE_TEMPLE_BOSS_KEY: + case RG_WATER_TEMPLE_BOSS_KEY: + case RG_SPIRIT_TEMPLE_BOSS_KEY: + case RG_SHADOW_TEMPLE_BOSS_KEY: + case RG_GANONS_CASTLE_BOSS_KEY: + case RG_DEKU_TREE_COMPASS: + case RG_DODONGOS_CAVERN_COMPASS: + case RG_JABU_JABUS_BELLY_COMPASS: + case RG_FOREST_TEMPLE_COMPASS: + case RG_FIRE_TEMPLE_COMPASS: + case RG_WATER_TEMPLE_COMPASS: + case RG_SPIRIT_TEMPLE_COMPASS: + case RG_SHADOW_TEMPLE_COMPASS: + case RG_BOTTOM_OF_THE_WELL_COMPASS: + case RG_ICE_CAVERN_COMPASS: + case RG_DEKU_TREE_MAP: + case RG_DODONGOS_CAVERN_MAP: + case RG_JABU_JABUS_BELLY_MAP: + case RG_FOREST_TEMPLE_MAP: + case RG_FIRE_TEMPLE_MAP: + case RG_WATER_TEMPLE_MAP: + case RG_SPIRIT_TEMPLE_MAP: + case RG_SHADOW_TEMPLE_MAP: + case RG_BOTTOM_OF_THE_WELL_MAP: + case RG_ICE_CAVERN_MAP: return true; default: return false; From 042d6f3865fd187642eb8aa48f8c01f9d5b6c399 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 31 Aug 2022 10:57:59 -0400 Subject: [PATCH 36/45] Fixes a few bugs related to chests. --- soh/src/overlays/actors/ovl_player_actor/z_player.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 2631e39b99..2ac6e0fc25 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -6108,7 +6108,7 @@ s32 func_8083E5A8(Player* this, GlobalContext* globalCtx) { } GetItemEntry giEntry; - if (this->getItemEntry.objectId == OBJECT_INVALID) { + if (this->getItemEntry.objectId == OBJECT_INVALID || (this->getItemId != this->getItemEntry.getItemId)) { giEntry = ItemTable_Retrieve(this->getItemId); } else { giEntry = this->getItemEntry; @@ -6165,7 +6165,7 @@ s32 func_8083E5A8(Player* this, GlobalContext* globalCtx) { } } else if (CHECK_BTN_ALL(sControlInput->press.button, BTN_A) && !(this->stateFlags1 & PLAYER_STATE1_11) && !(this->stateFlags2 & PLAYER_STATE2_10)) { - if (this->getItemId != GI_NONE && this->getItemEntry.objectId != OBJECT_INVALID) { + if (this->getItemId != GI_NONE) { GetItemEntry giEntry; if (this->getItemEntry.objectId == OBJECT_INVALID) { giEntry = ItemTable_Retrieve(-this->getItemId); @@ -9687,8 +9687,8 @@ void func_808473D4(GlobalContext* globalCtx, Player* this) { else if ((!(this->stateFlags1 & PLAYER_STATE1_11) || (heldActor == NULL)) && (interactRangeActor != NULL) && ((!sp1C && (this->getItemId == GI_NONE)) || - ((this->getItemId < 0 && this->getItemEntry.getItemId < 0) && !(this->stateFlags1 & PLAYER_STATE1_27)))) { - if (this->getItemId < 0 && this->getItemEntry.getItemId < 0) { + (this->getItemId < 0 && !(this->stateFlags1 & PLAYER_STATE1_27)))) { + if (this->getItemId < 0) { doAction = DO_ACTION_OPEN; } else if ((interactRangeActor->id == ACTOR_BG_TOKI_SWD) && LINK_IS_ADULT) { doAction = DO_ACTION_DROP; From 1f12caa5c9e02f108560ffe3f73f624ce42f4422 Mon Sep 17 00:00:00 2001 From: briaguya Date: Wed, 31 Aug 2022 18:15:09 -0400 Subject: [PATCH 37/45] fix oot ice trap check optimization issues --- soh/soh/OTRGlobals.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 7d7a86268f..8867862602 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1652,15 +1652,14 @@ extern "C" GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomi return ItemTable_RetrieveEntry(getItemModIndex, itemID); } -extern "C" bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor) { - return gSaveContext.n64ddFlag && (actor->parent != NULL) && - Randomizer_GetItemFromKnownCheck(randomizerCheck, ogId).getItemId == RG_ICE_TRAP; -} - extern "C" bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId) { return gSaveContext.n64ddFlag && Randomizer_GetItemFromKnownCheck(randomizerCheck, ogId).getItemId == RG_ICE_TRAP; } +extern "C" bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor) { + return Randomizer_ItemIsIceTrap(randomizerCheck, ogId) && actor->parent != NULL; +} + extern "C" CustomMessageEntry Randomizer_GetCustomGetItemMessage(Player* player) { s16 giid; if (player->getItemEntry.objectId != OBJECT_INVALID) { From 584a4ad818df3046c2e13d0ab1c2e6a7f6c67fa6 Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Wed, 31 Aug 2022 22:59:38 -0400 Subject: [PATCH 38/45] Linux crash handler (#1209) * crash handler linux * cleanups * missing underscore * more cleanups * cleanups * 32 bit --- .gitignore | 2 + libultraship/libultraship/CMakeLists.txt | 7 + libultraship/libultraship/CrashHandler.cpp | 172 +++++++++++++++++++++ libultraship/libultraship/CrashHandler.h | 18 +++ soh/include/functions.h | 2 +- soh/include/segment_symbols.h | 12 +- soh/soh/OTRGlobals.h | 2 + soh/src/code/fault.c | 2 +- soh/src/code/main.c | 12 +- 9 files changed, 218 insertions(+), 11 deletions(-) create mode 100644 libultraship/libultraship/CrashHandler.cpp create mode 100644 libultraship/libultraship/CrashHandler.h diff --git a/.gitignore b/.gitignore index 1df76208d2..98fe2b6370 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ __pycache__/ .idea/ cmake-build-debug venv/ +.cache/ # Project-specific ignores build/ @@ -410,6 +411,7 @@ oot.otr *.sav shipofharkinian.ini shipofharkinian.json +imgui.ini # Switch Stuff diff --git a/libultraship/libultraship/CMakeLists.txt b/libultraship/libultraship/CMakeLists.txt index b599936601..aec229bfb9 100644 --- a/libultraship/libultraship/CMakeLists.txt +++ b/libultraship/libultraship/CMakeLists.txt @@ -334,6 +334,12 @@ set(Source_Files__Resources__mpq ) source_group("Source Files\\Resources\\mpq" FILES ${Source_Files__Resources__mpq}) +set(Source_Files__Crash_Handler + "CrashHandler.cpp" + "CrashHandler.h" +) +source_group("Source Files\\Crash Handler" FILES ${Source_Files__Crash_Handler}) + if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(Source_Files__Darwin "OSXFolderManager.mm" @@ -388,6 +394,7 @@ set(ALL_FILES ${Source_Files__Resources__Factories} ${Source_Files__Resources__Files} ${Source_Files__Resources__mpq} + ${Source_Files__Crash_Handler} ${Source_Files__Darwin} ${Source_Files__NintendoSwitch} ${Source_Files__CafeOS} diff --git a/libultraship/libultraship/CrashHandler.cpp b/libultraship/libultraship/CrashHandler.cpp new file mode 100644 index 0000000000..f8d66beab8 --- /dev/null +++ b/libultraship/libultraship/CrashHandler.cpp @@ -0,0 +1,172 @@ +#include "spdlog/spdlog.h" +#include "Utils/StringHelper.h" +#include "CrashHandler.h" + +#if defined(__linux__) +#include +#include +#include // for __cxa_demangle +#include // for dladdr +#include +#include + +extern "C" void DeinitOTR(void); + + +static void PrintRegisters(ucontext_t* ctx) { + char regbuffer[1024]; + SPDLOG_CRITICAL("Registers:"); +#if defined(__x86_64__) + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RAX]); + SPDLOG_CRITICAL("RAX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RDI]); + SPDLOG_CRITICAL("RDI: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RSI]); + SPDLOG_CRITICAL("RSI: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RDX]); + SPDLOG_CRITICAL("RDX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RCX]); + SPDLOG_CRITICAL("RCX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R8]); + SPDLOG_CRITICAL("R8 : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R9]); + SPDLOG_CRITICAL("R9 : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R10]); + SPDLOG_CRITICAL("R10: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R11]); + SPDLOG_CRITICAL("R11: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RSP]); + SPDLOG_CRITICAL("RSP: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RBX]); + SPDLOG_CRITICAL("RBX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RBP]); + SPDLOG_CRITICAL("RBP: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R12]); + SPDLOG_CRITICAL("R12: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R13]); + SPDLOG_CRITICAL("R13: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R14]); + SPDLOG_CRITICAL("R14: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R15]); + SPDLOG_CRITICAL("R15: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RIP]); + SPDLOG_CRITICAL("RIP: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_EFL]); + SPDLOG_CRITICAL("EFLAGS: {} ", regbuffer); +#else + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EDI]); + SPDLOG_CRITICAL("EDI : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ESI]); + SPDLOG_CRITICAL("ESI : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EBP]); + SPDLOG_CRITICAL("EBP : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ESP]); + SPDLOG_CRITICAL("ESP : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EBX]); + SPDLOG_CRITICAL("EBX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EDX]); + SPDLOG_CRITICAL("EDX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ECX]); + SPDLOG_CRITICAL("ECX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EAX]); + SPDLOG_CRITICAL("EAX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EIP]); + SPDLOG_CRITICAL("EIP : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EFL]); + SPDLOG_CRITICAL("EFL : {} ", regbuffer); +#endif +} + +static void ErrorHandler(int sig, siginfo_t* sigInfo, void* data) +{ + std::array arr; + ucontext_t* ctx = static_cast(data); + constexpr size_t nMaxFrames = arr.size(); + size_t size = backtrace(arr.data(), nMaxFrames); + char** symbols = backtrace_symbols(arr.data(), nMaxFrames); + + SPDLOG_CRITICAL("(Signal: {})\n", sig); + + switch (sig) { + case SIGILL: + SPDLOG_CRITICAL("ILLEGAL INSTRUCTION"); + break; + case SIGABRT: + SPDLOG_CRITICAL("ABORT"); + break; + case SIGFPE: + SPDLOG_CRITICAL("ERRONEUS ARITHEMETIC OPERATION"); + break; + case SIGSEGV: + SPDLOG_CRITICAL("INVALID ACCESS TO STORAGE"); + break; + } + + PrintRegisters(ctx); + + SPDLOG_CRITICAL("Traceback:\n"); + for (size_t i = 1; i < size; i++) + { + Dl_info info; + int gotAddress = dladdr(arr[i], &info); + std::string functionName(symbols[i]); + + if (gotAddress != 0 && info.dli_sname != nullptr) + { + FILE* pipe; + int32_t status; + char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); + const char* nameFound = info.dli_sname; + + if (status == 0) + { + nameFound = demangled; + } + #if 0 + char command[256]; + char addrLine[128]; + snprintf(command, sizeof(command), "addr2line -e soh.elf %s + 0x%lX", nameFound, (uintptr_t)arr[i] - (uintptr_t)info.dli_saddr); + pipe = popen(command, "r"); + fgets(addrLine, 128, pipe); + #endif + + functionName = StringHelper::Sprintf("%s (+0x%X)", nameFound, + (char*)arr[i] - (char*)info.dli_saddr); + free(demangled); + } + + SPDLOG_CRITICAL("{} {}", i, functionName.c_str()); + } + + free(symbols); + DeinitOTR(); + exit(1); +} + +static void ShutdownHandler(int sig, siginfo_t* sigInfo, void* data) { + DeinitOTR(); + exit(1); +} + +extern "C" void SetupHandlerLinux() { + struct sigaction action; + struct sigaction shutdownAction; + + action.sa_flags = SA_SIGINFO; + action.sa_sigaction = ErrorHandler; + + sigaction(SIGILL, &action, nullptr); + sigaction(SIGABRT, &action, nullptr); + sigaction(SIGFPE, &action, nullptr); + sigaction(SIGSEGV, &action, nullptr); + + shutdownAction.sa_flags = SA_SIGINFO; + shutdownAction.sa_sigaction = ShutdownHandler; + sigaction(SIGINT, &shutdownAction, nullptr); + sigaction(SIGTERM, &shutdownAction, nullptr); + sigaction(SIGQUIT, &shutdownAction, nullptr); + sigaction(SIGKILL, &shutdownAction, nullptr); + + +} +#endif diff --git a/libultraship/libultraship/CrashHandler.h b/libultraship/libultraship/CrashHandler.h new file mode 100644 index 0000000000..e068a4e389 --- /dev/null +++ b/libultraship/libultraship/CrashHandler.h @@ -0,0 +1,18 @@ +#ifndef CRASH_HANDLER_H +#define CRASH_HANDLER_H + +#ifdef __linux__ + +#ifdef __cplusplus +extern "C" { +#endif + +void SetupHandlerLinux(void); + +#ifdef __cplusplus +} +#endif + +#endif // __linux__ + +#endif // CRASH_HANDLER_H \ No newline at end of file diff --git a/soh/include/functions.h b/soh/include/functions.h index a336cb1efb..6339cff647 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -1656,7 +1656,7 @@ void PadMgr_HandleRetraceMsg(PadMgr* padmgr); void PadMgr_HandlePreNMI(PadMgr* padmgr); // This function must remain commented out, because it is called incorrectly in // fault.c (actual bug in game), and the compiler notices and won't compile it -// void PadMgr_RequestPadData(PadMgr* padmgr, Input* inputs, s32 mode); +void PadMgr_RequestPadData(PadMgr* padmgr, Input* inputs, s32 mode); void PadMgr_Init(PadMgr* padmgr, OSMesgQueue* siIntMsgQ, IrqMgr* irqMgr, OSId id, OSPri priority, void* stack); void Sched_SwapFrameBuffer(CfbInfo* cfbInfo); void func_800C84E4(SchedContext* sc, CfbInfo* cfbInfo); diff --git a/soh/include/segment_symbols.h b/soh/include/segment_symbols.h index 81fe348010..3b50b4eaad 100644 --- a/soh/include/segment_symbols.h +++ b/soh/include/segment_symbols.h @@ -3,20 +3,20 @@ #include "z64.h" -#define DECLARE_SEGMENT(name) \ - //extern u8 _##name##SegmentStart[]; \ +#define DECLARE_SEGMENT(name) + //extern u8 _##name##SegmentStart[]; //extern u8 _##name##SegmentEnd[]; -#define DECLARE_ROM_SEGMENT(name) \ - //extern u8 _##name##SegmentRomStart[]; \ +#define DECLARE_ROM_SEGMENT(name) + //extern u8 _##name##SegmentRomStart[]; //extern u8 _##name##SegmentRomEnd[]; #define DECLARE_BSS_SEGMENT(name) \ extern u8 _##name##SegmentBssStart[]; \ extern u8 _##name##SegmentBssEnd[]; -#define DECLARE_OVERLAY_SEGMENT(name) \ - //DECLARE_SEGMENT(ovl_##name) \ +#define DECLARE_OVERLAY_SEGMENT(name) + //DECLARE_SEGMENT(ovl_##name) //DECLARE_ROM_SEGMENT(ovl_##name) DECLARE_SEGMENT(boot) diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index dc304358db..089394e330 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -32,6 +32,8 @@ private: #endif #ifndef __cplusplus +void InitOTR(void); +void DeinitOTR(void); void VanillaItemTable_Init(); void OTRAudio_Init(); void InitAudio(); diff --git a/soh/src/code/fault.c b/soh/src/code/fault.c index c55a63a001..f7414766a4 100644 --- a/soh/src/code/fault.c +++ b/soh/src/code/fault.c @@ -293,7 +293,7 @@ void Fault_Sleep(u32 duration) { void Fault_PadCallback(Input* input) { //! @bug This function is not called correctly and thus will crash from reading a bad pointer at 0x800C7E4C - PadMgr_RequestPadData(input, 0); + PadMgr_RequestPadData(&gPadMgr, input, 0); } void Fault_UpdatePadImpl() diff --git a/soh/src/code/main.c b/soh/src/code/main.c index ccfdc2019f..8e9fe1776a 100644 --- a/soh/src/code/main.c +++ b/soh/src/code/main.c @@ -3,6 +3,8 @@ #include #include "soh/OTRGlobals.h" +#include "../libultraship/CrashHandler.h" + s32 gScreenWidth = SCREEN_WIDTH; s32 gScreenHeight = SCREEN_HEIGHT; @@ -38,6 +40,10 @@ void Main_LogSystemHeap(void) { int main(int argc, char** argv) { +#ifdef __linux__ + SetupHandlerLinux(); +#endif + GameConsole_Init(); InitOTR(); BootCommands_Init(); @@ -64,14 +70,14 @@ void Main(void* arg) { Fault_Init(); SysCfb_Init(0); Heaps_Alloc(); - sysHeap = gSystemHeap; + sysHeap = (uintptr_t)gSystemHeap; fb = SysCfb_GetFbPtr(0); gSystemHeapSize = 1024 * 1024 * 4; // "System heap initalization" osSyncPrintf("システムヒープ初期化 %08x-%08x %08x\n", sysHeap, fb, gSystemHeapSize); - SystemHeap_Init(sysHeap, gSystemHeapSize); // initializes the system heap + SystemHeap_Init((void*)sysHeap, gSystemHeapSize); // initializes the system heap if (osMemSize >= 0x800000) { - debugHeap = SysCfb_GetFbEnd(); + debugHeap = (void*)SysCfb_GetFbEnd(); debugHeapSize = (0x80600000 - (uintptr_t)debugHeap); } else { debugHeapSize = 0x400; From cfaed3ded0ea32d63b6efe9f6b8eed9f021391e5 Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Wed, 31 Aug 2022 22:07:34 -0500 Subject: [PATCH 39/45] Make Biggoron ignore whether you have BGS in rando --- soh/src/overlays/actors/ovl_En_Go/z_en_go.c | 4 ++-- soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Go/z_en_go.c b/soh/src/overlays/actors/ovl_En_Go/z_en_go.c index 58124ef23a..3cadd6afee 100644 --- a/soh/src/overlays/actors/ovl_En_Go/z_en_go.c +++ b/soh/src/overlays/actors/ovl_En_Go/z_en_go.c @@ -95,7 +95,7 @@ u16 EnGo_GetTextID(GlobalContext* globalCtx, Actor* thisx) { switch (thisx->params & 0xF0) { case 0x90: - if (gSaveContext.bgsFlag) { + if (gSaveContext.bgsFlag && !gSaveContext.n64ddFlag) { return 0x305E; } else if (INV_CONTENT(ITEM_TRADE_ADULT) >= ITEM_CLAIM_CHECK) { if (Environment_GetBgsDayCount() >= CVar_GetS32("gForgeTime", 3)) { @@ -859,7 +859,7 @@ void func_80A405CC(EnGo* this, GlobalContext* globalCtx) { void EnGo_BiggoronActionFunc(EnGo* this, GlobalContext* globalCtx) { if (((this->actor.params & 0xF0) == 0x90) && (this->unk_1E0.unk_00 == 2)) { - if (gSaveContext.bgsFlag) { + if (gSaveContext.bgsFlag && !gSaveContext.n64ddFlag) { this->unk_1E0.unk_00 = 0; } else { if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_EYEDROPS) { diff --git a/soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c b/soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c index 9f6ff147e4..db11549618 100644 --- a/soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c +++ b/soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c @@ -595,7 +595,7 @@ s16 EnGo2_GetStateGoronCityLink(GlobalContext* globalCtx, EnGo2* this) { u16 EnGo2_GetTextIdGoronDmtBiggoron(GlobalContext* globalCtx, EnGo2* this) { Player* player = GET_PLAYER(globalCtx); - if (gSaveContext.bgsFlag) { + if (gSaveContext.bgsFlag && !gSaveContext.n64ddFlag) { player->exchangeItemId = EXCH_ITEM_CLAIM_CHECK; return 0x305E; } else if (INV_CONTENT(ITEM_TRADE_ADULT) >= ITEM_CLAIM_CHECK) { @@ -622,10 +622,6 @@ s16 EnGo2_GetStateGoronDmtBiggoron(GlobalContext* globalCtx, EnGo2* this) { } if(gSaveContext.n64ddFlag) { - if (INV_CONTENT(ITEM_CLAIM_CHECK) != ITEM_CLAIM_CHECK) { - return 0; - } - EnGo2_GetItemEntry(this, globalCtx, Randomizer_GetItemFromKnownCheck(RC_DMT_TRADE_CLAIM_CHECK, GI_SWORD_BGS)); Flags_SetTreasure(globalCtx, 0x1F); } else { @@ -1063,7 +1059,7 @@ void EnGo2_BiggoronSetTextId(EnGo2* this, GlobalContext* globalCtx, Player* play u16 textId; if ((this->actor.params & 0x1F) == GORON_DMT_BIGGORON) { - if (gSaveContext.bgsFlag) { + if ((!gSaveContext.n64ddFlag && gSaveContext.bgsFlag)) { if (func_8002F368(globalCtx) == EXCH_ITEM_CLAIM_CHECK) { this->actor.textId = 0x3003; } else { @@ -1071,16 +1067,20 @@ void EnGo2_BiggoronSetTextId(EnGo2* this, GlobalContext* globalCtx, Player* play } player->actor.textId = this->actor.textId; - } else if (!gSaveContext.bgsFlag && (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_CLAIM_CHECK)) { + } else if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_CLAIM_CHECK) { if (func_8002F368(globalCtx) == EXCH_ITEM_CLAIM_CHECK) { - if (Environment_GetBgsDayCount() >= CVar_GetS32("gForgeTime", 3)) { + if (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F)) { + textId = 0x3003; + } else if (Environment_GetBgsDayCount() >= CVar_GetS32("gForgeTime", 3)) { textId = 0x305E; } else { textId = 0x305D; } this->actor.textId = textId; } else { - if (Environment_GetBgsDayCount() >= CVar_GetS32("gForgeTime", 3)) { + if (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F)) { + textId = 0x305E; + } else if (Environment_GetBgsDayCount() >= CVar_GetS32("gForgeTime", 3)) { textId = 0x3002; } else { textId = 0x305D; From 354905fb7dd6a9a89410f0129429b5ee419ebc39 Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 1 Sep 2022 11:06:05 +0200 Subject: [PATCH 40/45] Added 1 more name --- soh/soh/Enhancements/randomizer/randomizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index fd018ff7b6..b46fbb4d28 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -36,14 +36,14 @@ const std::string Randomizer::merchantMessageTableID = "RandomizerMerchants"; const std::string Randomizer::rupeeMessageTableID = "RandomizerRupees"; const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi"; -static const char* englishRupeeNames[52] = { +static const char* englishRupeeNames[53] = { "Rupees", "Bitcoin", "Bananas", "Cornflakes", "Gummybears", "Floopies", "Dollars", "Lemmings", "Emeralds", "Bucks", "Rubles", "Diamonds", "Moons", "Stars", "Mana", "Doll Hairs", "Dogecoin", "Mushrooms", "Experience", "Friends", "Coins", "Rings", "Gil", "Pokédollars", "Bells", "Orbs", "Bottle Caps", "Simoleons", "Pokémon", "Toys", "Smackaroos", "Zorkmids", "Zenny", "Bones", "Souls", "Studs", "Munny", "Rubies", "Gald", "Gold", "Shillings", "Pounds", "Glimmer", "Potch", "Robux", "V-Bucks", "Bratwürste", "Mesetas", - "Bath Salts", "Coal", "Euro", "Spoons" + "Bath Salts", "Coal", "Euro", "Spoons", "Cucumbers" }; static const char* germanRupeeNames[41] = { From 0a744cde0132dd7ad5de27e1e6d849bba24b4720 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Thu, 1 Sep 2022 08:11:17 -0500 Subject: [PATCH 41/45] Clarify comments --- .../actors/ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c | 8 +++++--- soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c b/soh/src/overlays/actors/ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c index 28a63bbf62..6bb097d896 100644 --- a/soh/src/overlays/actors/ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c +++ b/soh/src/overlays/actors/ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c @@ -143,7 +143,8 @@ void EnBomBowMan_BlinkAwake(EnBomBowlMan* this, GlobalContext* globalCtx) { } } - // Check for Bomb Bag or Bombchus if Rando is enabled, depending on whether bombchus are considered in logic + // In randomizer, only check for bomb bag when bombchus aren't in logic + // and only check for bombchus when bombchus are in logic if (gSaveContext.n64ddFlag) { u8 bombchusInLogic = Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC); if ((!bombchusInLogic && INV_CONTENT(ITEM_BOMB) == ITEM_NONE) || @@ -178,13 +179,14 @@ void EnBomBowMan_CheckBeatenDC(EnBomBowlMan* this, GlobalContext* globalCtx) { this->eyeMode = CHU_GIRL_EYES_AWAKE; this->blinkTimer = (s16)Rand_ZeroFloat(60.0f) + 20; - // Check if beaten Dodongo's Cavern if not rando'd - // check for bomb bag or bombchus if rando'd depending on whether chus are in logic bool bombchuBowlingClosed; if (gSaveContext.n64ddFlag) { + // when rando'd, check if we have bombchus if chus are in logic + // and check if we have a bomb bag if chus aren't in logic u8 explosive = Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) ? ITEM_BOMBCHU : ITEM_BOMB; bombchuBowlingClosed = (INV_CONTENT(explosive) == ITEM_NONE); } else { + // if not rando'd, check if we have beaten Dodongo's Cavern bombchuBowlingClosed = !((gSaveContext.eventChkInf[2] & 0x20) || BREG(2)); } if (bombchuBowlingClosed) { diff --git a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c index 54af786a64..cbc2e97499 100644 --- a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c +++ b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c @@ -871,9 +871,12 @@ void EnGirlA_BuyEvent_ZoraTunic(GlobalContext* globalCtx, EnGirlA* this) { void EnGirlA_BuyEvent_ObtainBombchuPack(GlobalContext* globalCtx, EnGirlA* this) { Rupees_ChangeBy(-this->basePrice); + // Normally, buying a bombchu pack sets a flag indicating the pack is now sold out + // If they're in logic for rando, skip setting that flag so they can be purchased repeatedly if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC)) { return; } + switch (this->actor.params) { case SI_BOMBCHU_10_2: gSaveContext.itemGetInf[0] |= 0x40; @@ -1065,6 +1068,7 @@ void EnGirlA_InitializeItemAction(EnGirlA* this, GlobalContext* globalCtx) { this->canBuyFunc = itemEntry->canBuyFunc; this->itemGiveFunc = itemEntry->itemGiveFunc; this->buyEventFunc = itemEntry->buyEventFunc; + // If chus are in logic, make the 10 pack affordable without a wallet upgrade if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_BOMBCHUS_IN_LOGIC) && this->getItemId == GI_BOMBCHUS_10) { this->basePrice = 99; From c84654b202a84159b028f78a3e64d0a605d5a46a Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Thu, 1 Sep 2022 09:23:08 -0500 Subject: [PATCH 42/45] Always check n64ddFlag before bgsFlag that order is consistent with the existing condition in EnGo2_GetStateGoronDmtBiggoron --- soh/src/overlays/actors/ovl_En_Go/z_en_go.c | 4 ++-- soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Go/z_en_go.c b/soh/src/overlays/actors/ovl_En_Go/z_en_go.c index 3cadd6afee..4e803af0a4 100644 --- a/soh/src/overlays/actors/ovl_En_Go/z_en_go.c +++ b/soh/src/overlays/actors/ovl_En_Go/z_en_go.c @@ -95,7 +95,7 @@ u16 EnGo_GetTextID(GlobalContext* globalCtx, Actor* thisx) { switch (thisx->params & 0xF0) { case 0x90: - if (gSaveContext.bgsFlag && !gSaveContext.n64ddFlag) { + if (!gSaveContext.n64ddFlag && gSaveContext.bgsFlag) { return 0x305E; } else if (INV_CONTENT(ITEM_TRADE_ADULT) >= ITEM_CLAIM_CHECK) { if (Environment_GetBgsDayCount() >= CVar_GetS32("gForgeTime", 3)) { @@ -859,7 +859,7 @@ void func_80A405CC(EnGo* this, GlobalContext* globalCtx) { void EnGo_BiggoronActionFunc(EnGo* this, GlobalContext* globalCtx) { if (((this->actor.params & 0xF0) == 0x90) && (this->unk_1E0.unk_00 == 2)) { - if (gSaveContext.bgsFlag && !gSaveContext.n64ddFlag) { + if (!gSaveContext.n64ddFlag && gSaveContext.bgsFlag) { this->unk_1E0.unk_00 = 0; } else { if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_EYEDROPS) { diff --git a/soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c b/soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c index db11549618..c8b635902a 100644 --- a/soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c +++ b/soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c @@ -595,7 +595,7 @@ s16 EnGo2_GetStateGoronCityLink(GlobalContext* globalCtx, EnGo2* this) { u16 EnGo2_GetTextIdGoronDmtBiggoron(GlobalContext* globalCtx, EnGo2* this) { Player* player = GET_PLAYER(globalCtx); - if (gSaveContext.bgsFlag && !gSaveContext.n64ddFlag) { + if (!gSaveContext.n64ddFlag && gSaveContext.bgsFlag) { player->exchangeItemId = EXCH_ITEM_CLAIM_CHECK; return 0x305E; } else if (INV_CONTENT(ITEM_TRADE_ADULT) >= ITEM_CLAIM_CHECK) { From a55eb572db92b04565d3bb58bad02591bff01f65 Mon Sep 17 00:00:00 2001 From: briaguya Date: Thu, 1 Sep 2022 12:06:41 -0400 Subject: [PATCH 43/45] fix keysanity related build issue --- .../Enhancements/randomizer/randomizer.cpp | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 5af2cb9e7c..d1548ea9b0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1701,43 +1701,6 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_BUY_BOMBS_535: case RG_BUY_RED_POTION_40: case RG_BUY_RED_POTION_50: - //RANDO TODO: Fix this to return false if keysanity is on. - case RG_FOREST_TEMPLE_SMALL_KEY: - case RG_FIRE_TEMPLE_SMALL_KEY: - case RG_WATER_TEMPLE_SMALL_KEY: - case RG_SPIRIT_TEMPLE_SMALL_KEY: - case RG_SHADOW_TEMPLE_SMALL_KEY: - case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: - case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: - case RG_GERUDO_FORTRESS_SMALL_KEY: - case RG_GANONS_CASTLE_SMALL_KEY: - case RG_FOREST_TEMPLE_BOSS_KEY: - case RG_FIRE_TEMPLE_BOSS_KEY: - case RG_WATER_TEMPLE_BOSS_KEY: - case RG_SPIRIT_TEMPLE_BOSS_KEY: - case RG_SHADOW_TEMPLE_BOSS_KEY: - case RG_GANONS_CASTLE_BOSS_KEY: - case RG_DEKU_TREE_COMPASS: - case RG_DODONGOS_CAVERN_COMPASS: - case RG_JABU_JABUS_BELLY_COMPASS: - case RG_FOREST_TEMPLE_COMPASS: - case RG_FIRE_TEMPLE_COMPASS: - case RG_WATER_TEMPLE_COMPASS: - case RG_SPIRIT_TEMPLE_COMPASS: - case RG_SHADOW_TEMPLE_COMPASS: - case RG_BOTTOM_OF_THE_WELL_COMPASS: - case RG_ICE_CAVERN_COMPASS: - case RG_DEKU_TREE_MAP: - case RG_DODONGOS_CAVERN_MAP: - case RG_JABU_JABUS_BELLY_MAP: - case RG_FOREST_TEMPLE_MAP: - case RG_FIRE_TEMPLE_MAP: - case RG_WATER_TEMPLE_MAP: - case RG_SPIRIT_TEMPLE_MAP: - case RG_SHADOW_TEMPLE_MAP: - case RG_BOTTOM_OF_THE_WELL_MAP: - case RG_ICE_CAVERN_MAP: - return true; case RG_FOREST_TEMPLE_SMALL_KEY: case RG_FIRE_TEMPLE_SMALL_KEY: case RG_WATER_TEMPLE_SMALL_KEY: From 1e13879c6b844e38ca2f67a0bec38d350133860a Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 1 Sep 2022 19:43:08 +0200 Subject: [PATCH 44/45] Removed name --- soh/soh/Enhancements/randomizer/randomizer.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index b46fbb4d28..e999c0442c 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -36,14 +36,14 @@ const std::string Randomizer::merchantMessageTableID = "RandomizerMerchants"; const std::string Randomizer::rupeeMessageTableID = "RandomizerRupees"; const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi"; -static const char* englishRupeeNames[53] = { - "Rupees", "Bitcoin", "Bananas", "Cornflakes", "Gummybears", "Floopies", "Dollars", "Lemmings", - "Emeralds", "Bucks", "Rubles", "Diamonds", "Moons", "Stars", "Mana", "Doll Hairs", - "Dogecoin", "Mushrooms", "Experience", "Friends", "Coins", "Rings", "Gil", "Pokédollars", - "Bells", "Orbs", "Bottle Caps", "Simoleons", "Pokémon", "Toys", "Smackaroos", "Zorkmids", - "Zenny", "Bones", "Souls", "Studs", "Munny", "Rubies", "Gald", "Gold", - "Shillings", "Pounds", "Glimmer", "Potch", "Robux", "V-Bucks", "Bratwürste", "Mesetas", - "Bath Salts", "Coal", "Euro", "Spoons", "Cucumbers" +static const char* englishRupeeNames[52] = { + "Rupees", "Bitcoin", "Bananas", "Cornflakes", "Gummybears", "Floopies", "Dollars", "Lemmings", + "Emeralds", "Bucks", "Rubles", "Diamonds", "Moons", "Stars", "Mana", "Doll Hairs", + "Dogecoin", "Mushrooms", "Experience", "Friends", "Coins", "Rings", "Gil", "Pokédollars", + "Bells", "Orbs", "Bottle Caps", "Simoleons", "Pokémon", "Toys", "Smackaroos", "Zorkmids", + "Zenny", "Bones", "Souls", "Studs", "Munny", "Rubies", "Gald", "Gold", + "Shillings", "Pounds", "Glimmer", "Potch", "Robux", "V-Bucks", "Bratwürste", "Mesetas", + "Coal", "Euro", "Spoons", "Cucumbers" }; static const char* germanRupeeNames[41] = { From 812a1e79705d2249d66737148ca1b88de3bd30e8 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 1 Sep 2022 17:50:12 -0400 Subject: [PATCH 45/45] Added return statement in IsVanillaItem before keys. --- soh/soh/Enhancements/randomizer/randomizer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 9a4f9fa1b0..9bf46e430c 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1707,6 +1707,7 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_BUY_BOMBS_535: case RG_BUY_RED_POTION_40: case RG_BUY_RED_POTION_50: + return true; case RG_FOREST_TEMPLE_SMALL_KEY: case RG_FIRE_TEMPLE_SMALL_KEY: case RG_WATER_TEMPLE_SMALL_KEY: