From 242757777c5c241e17b38aface01ff1845e91fe8 Mon Sep 17 00:00:00 2001 From: Ralphie Morell Date: Sun, 9 Oct 2022 02:37:22 -0400 Subject: [PATCH] Rando: Randomize Starting Age (#1685) --- .../randomizer/3drando/settings.cpp | 3 +- .../randomizer/3drando/settings.hpp | 2 +- .../Enhancements/randomizer/randomizer.cpp | 37 +++++++++++++++++++ .../Enhancements/randomizer/randomizerTypes.h | 1 + soh/src/code/z_parameter.c | 18 +++++++++ soh/src/code/z_sram.c | 12 ++++++ 6 files changed, 71 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index ddc5b315c..293a33273 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -85,7 +85,7 @@ namespace Settings { //World Settings Option RandomizeWorld = Option::Bool("Randomize Settings", {"No","Yes"}, {worldRandomize}, OptionCategory::Toggle); - Option StartingAge = Option::U8 ("Starting Age", {"Adult", "Child", "Random"}, {ageDesc}, OptionCategory::Setting, AGE_CHILD); + Option StartingAge = Option::U8 ("Starting Age", {"Child", "Adult", "Random"}, {ageDesc}, OptionCategory::Setting, AGE_CHILD); uint8_t ResolvedStartingAge; Option ShuffleEntrances = Option::Bool("Shuffle Entrances", {"Off", "On"}, {shuffleEntrancesDesc}); Option ShuffleDungeonEntrances = Option::U8 ("Dungeon Entrances", {"Off", "On", "On + Ganon"}, {dungeonEntrancesDesc}); @@ -2517,6 +2517,7 @@ namespace Settings { OpenKakariko.SetSelectedIndex(cvarSettings[RSK_KAK_GATE]); ZorasFountain.SetSelectedIndex(cvarSettings[RSK_ZORAS_FOUNTAIN]); OpenDoorOfTime.SetSelectedIndex(cvarSettings[RSK_DOOR_OF_TIME]); + StartingAge.SetSelectedIndex(cvarSettings[RSK_STARTING_AGE]); GerudoFortress.SetSelectedIndex(cvarSettings[RSK_GERUDO_FORTRESS]); Bridge.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE]); BridgeStoneCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_STONE_COUNT]); diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.hpp b/soh/soh/Enhancements/randomizer/3drando/settings.hpp index 244cd2568..96c4a9e7c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.hpp @@ -81,8 +81,8 @@ typedef enum { } LACSConditionSetting; typedef enum { - AGE_ADULT, AGE_CHILD, + AGE_ADULT, AGE_RANDOM, } AgeSetting; diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 1f576c4f8..bdb216374 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -193,6 +193,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:Starting Age", RSK_STARTING_AGE }, { "World Settings:Ammo Drops", RSK_ENABLE_BOMBCHU_DROPS }, { "World Settings:Bombchus in Logic", RSK_BOMBCHUS_IN_LOGIC }, { "Misc Settings:Gossip Stone Hints", RSK_GOSSIP_STONE_HINTS }, @@ -553,6 +554,13 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { gSaveContext.randoSettings[index].value = 2; } break; + case RSK_STARTING_AGE: + if(it.value() == "Child") { + gSaveContext.randoSettings[index].value = 0; + } else if (it.value() == "Adult") { + gSaveContext.randoSettings[index].value = 1; + } + break; case RSK_GERUDO_FORTRESS: if(it.value() == "Normal") { gSaveContext.randoSettings[index].value = 0; @@ -3650,6 +3658,9 @@ void GenerateRandomizerImgui() { cvarSettings[RSK_KAK_GATE] = CVar_GetS32("gRandomizeKakarikoGate", 0); cvarSettings[RSK_DOOR_OF_TIME] = CVar_GetS32("gRandomizeDoorOfTime", 0); cvarSettings[RSK_ZORAS_FOUNTAIN] = CVar_GetS32("gRandomizeZorasFountain", 0); + //Starting Age is forced to child if forest setting is set to closed. (0 = Child, 1 = Adult) + cvarSettings[RSK_STARTING_AGE] = ((CVar_GetS32("gRandomizeForest", 0)) && + (CVar_GetS32("gRandomizeStartingAge", 0))); cvarSettings[RSK_GERUDO_FORTRESS] = CVar_GetS32("gRandomizeGerudoFortress", 0); cvarSettings[RSK_RAINBOW_BRIDGE] = CVar_GetS32("gRandomizeRainbowBridge", 0); cvarSettings[RSK_RAINBOW_BRIDGE_STONE_COUNT] = CVar_GetS32("gRandomizeStoneCount", 3); @@ -3935,6 +3946,32 @@ void DrawRandoEditor(bool& open) { ImGui::BeginChild("ChildMiscWorldSettings", ImVec2(0,-8)); ImGui::PushItemWidth(-FLT_MIN); + //Starting Age + //Disabled when Forest is set to Closed + bool disableRandoStartingAge = !CVar_GetS32("gRandomizeForest", 0); + const char* disableRandoStartingAgeText = "This option is disabled because \"Forest\" is set to \"Closed\"."; + ImGui::Text(Settings::StartingAge.GetName().c_str()); + UIWidgets::InsertHelpHoverText( + "Choose which age Link will start as.\n\n" + "Starting as adult means you start with the Master Sword in your inventory.\n" + "Only the child option is compatible with Closed Forest." + ); + if (disableRandoStartingAge) { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + UIWidgets::EnhancementCombobox("gRandomizeStartingAge", randoStartingAge, 3, 0); + if (disableRandoStartingAge) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { + ImGui::SetTooltip("%s", disableRandoStartingAgeText); + } + CVar_SetS32("gRandomizeStartingAge", 0); + ImGui::PopStyleVar(1); + ImGui::PopItemFlag(); + } + + UIWidgets::PaddedSeparator(); + // Gerudo Fortress ImGui::Text("Gerudo Fortress Carpenters"); UIWidgets::InsertHelpHoverText( diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index fc77fa75d..8d52d4cd9 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -979,6 +979,7 @@ typedef enum { RSK_KAK_GATE, RSK_DOOR_OF_TIME, RSK_ZORAS_FOUNTAIN, + RSK_STARTING_AGE, RSK_GERUDO_FORTRESS, RSK_RAINBOW_BRIDGE, RSK_RAINBOW_BRIDGE_STONE_COUNT, diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 56864d1c4..c7766502b 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1493,6 +1493,24 @@ void Inventory_SwapAgeEquipment(void) { gSaveContext.equips.equipment = gSaveContext.childEquips.equipment; gSaveContext.equips.equipment &= 0xFFF0; gSaveContext.equips.equipment |= 0x0001; + } else if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_STARTING_AGE)) { + /*If in rando and starting age is adult, childEquips is not initialized and buttonItems[0] + will be ITEM_NONE. When changing age from adult -> child, reset equips to "default" + (only kokiri tunic/boots equipped, no sword, no C-button items, no D-Pad items). + When becoming child, set swordless flag if player doesn't have kokiri sword + Only in rando to keep swordless link bugs in vanilla*/ + if (1 << 0 & gSaveContext.inventory.equipment == 0) { + gSaveContext.infTable[29] |= 1; + } + + //zero out items + for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { + gSaveContext.equips.buttonItems[i] = ITEM_NONE; + if (i != 0) { + gSaveContext.equips.cButtonSlots[i-1] = ITEM_NONE; + } + } + gSaveContext.equips.equipment = 0x1111; } } diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 16cbcdd33..469e6bfc5 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -368,6 +368,18 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { break; } + int startingAge = Randomizer_GetSettingValue(RSK_STARTING_AGE); + switch (startingAge) { + case 1: //Adult + gSaveContext.linkAge = 0; + gSaveContext.entranceIndex = 0x5F4; + gSaveContext.savedSceneNum = SCENE_SPOT20; //Set scene num manually to ToT + break; + default: //Child + gSaveContext.linkAge = 1; + break; + } + int doorOfTime = Randomizer_GetSettingValue(RSK_DOOR_OF_TIME); switch (doorOfTime) { case 0: // open