From 6470522a0221e20d899331d8d4b9f8cd187e27a5 Mon Sep 17 00:00:00 2001 From: Archez Date: Mon, 9 Dec 2024 21:17:26 -0500 Subject: [PATCH 1/6] Fix temp flags transfering in dungeon chains and various issues with voidouts in mixed entrances (#4637) --- .../game-interactor/GameInteractor.h | 3 ++ .../Enhancements/randomizer/hook_handlers.cpp | 36 +++++++++++++++++++ .../randomizer/randomizer_entrance.c | 7 ---- .../actors/ovl_player_actor/z_player.c | 6 ++-- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index 8aa37a580..f91e3491e 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -281,6 +281,9 @@ typedef enum { VB_SPAWN_BLUE_WARP, // Vanilla condition: this->warpTimer > sWarpTimerTarget && gSaveContext.nextCutsceneIndex == 0xFFEF VB_BLUE_WARP_APPLY_ENTRANCE_AND_CUTSCENE, + // Vanilla condition: SurfaceType_GetSlope(&play->colCtx, poly, bgId) == 2 + // Opt: int (original next entrance index) + VB_SET_VOIDOUT_FROM_SURFACE, // Vanilla condition: this->collider.base.acFlags & 2 VB_BG_BREAKWALL_BREAK, // Vanilla condition: true diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 000081cec..fa313d763 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -1558,6 +1558,40 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l *should = !Flags_GetInfTable(INFTABLE_145) || Flags_GetInfTable(INFTABLE_146); break; } + case VB_SET_VOIDOUT_FROM_SURFACE: { + // ENTRTODO: Move all entrance rando handling to a dedicated file + std::vector entrPersistTempFlags = { + ENTR_DEKU_TREE_BOSS_ENTRANCE, ENTR_DEKU_TREE_BOSS_DOOR, ENTR_DODONGOS_CAVERN_BOSS_ENTRANCE, + ENTR_DODONGOS_CAVERN_BOSS_DOOR, ENTR_JABU_JABU_BOSS_ENTRANCE, ENTR_JABU_JABU_BOSS_DOOR, + ENTR_FOREST_TEMPLE_BOSS_ENTRANCE, ENTR_FOREST_TEMPLE_BOSS_DOOR, ENTR_FIRE_TEMPLE_BOSS_ENTRANCE, + ENTR_FIRE_TEMPLE_BOSS_DOOR, ENTR_WATER_TEMPLE_BOSS_ENTRANCE, ENTR_WATER_TEMPLE_BOSS_DOOR, + ENTR_SPIRIT_TEMPLE_BOSS_ENTRANCE, ENTR_SPIRIT_TEMPLE_BOSS_DOOR, ENTR_SHADOW_TEMPLE_BOSS_ENTRANCE, + ENTR_SHADOW_TEMPLE_BOSS_DOOR, ENTR_SPIRIT_TEMPLE_ENTRANCE, + }; + + s16 originalEntrance = (s16)va_arg(args, int); + + // In Entrance rando, if our respawnFlag is set for a grotto return, we don't want the void out to happen + if (*should == true && RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES)) { + // Check for dungeon special entrances that are randomized to a new location + if (std::find(entrPersistTempFlags.begin(), entrPersistTempFlags.end(), originalEntrance) != + entrPersistTempFlags.end() && originalEntrance != gPlayState->nextEntranceIndex) { + // Normally dungeons use a special voidout between scenes so that entering/exiting a boss room, + // or leaving via Spirit Hands and going back in persist temp flags across scenes. + // For ER, the temp flags should be wiped out so that they aren't transferred to the new location. + gPlayState->actorCtx.flags.tempSwch = 0; + gPlayState->actorCtx.flags.tempCollect = 0; + + // If the respawnFlag is set for a grotto return, we don't want the void out to happen. + // Set the data flag to one to prevent the respawn point from being overriden by dungeon doors. + if (gSaveContext.respawnFlag == 2) { + gSaveContext.respawn[RESPAWN_MODE_DOWN].data = 1; + *should = false; + } + } + } + break; + } case VB_FREEZE_ON_SKULL_TOKEN: case VB_TRADE_TIMER_ODD_MUSHROOM: case VB_TRADE_TIMER_FROG: @@ -1623,6 +1657,7 @@ void RandomizerOnSceneInitHandler(int16_t sceneNum) { CheckTracker::RecalculateAllAreaTotals(); } + // ENTRTODO: Move all entrance rando handling to a dedicated file if (RAND_GET_OPTION(RSK_SHUFFLE_ENTRANCES)) { // In ER, override roomNum to load based on scene and spawn during scene init if (gSaveContext.respawnFlag <= 0) { @@ -2336,6 +2371,7 @@ void RandomizerRegisterHooks() { if (!IS_RANDO) return; + // ENTRTODO: Move all entrance rando handling to a dedicated file // Setup the modified entrance table and entrance shuffle table for rando Entrance_Init(); diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index 8f4a1668c..7a492fe9c 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -267,13 +267,6 @@ s16 Entrance_PeekNextIndexOverride(int16_t nextEntranceIndex) { } s16 Entrance_OverrideNextIndex(s16 nextEntranceIndex) { - // When entering Spirit Temple, clear temp flags so they don't carry over to the randomized dungeon - if (nextEntranceIndex == ENTR_SPIRIT_TEMPLE_ENTRANCE && Entrance_GetOverride(nextEntranceIndex) != nextEntranceIndex && - gPlayState != NULL) { - gPlayState->actorCtx.flags.tempSwch = 0; - gPlayState->actorCtx.flags.tempCollect = 0; - } - // Exiting through the crawl space from Hyrule Castle courtyard is the same exit as leaving Ganon's castle // Don't override the entrance if we came from the Castle courtyard (day and night scenes) if (gPlayState != NULL && (gPlayState->sceneNum == SCENE_CASTLE_COURTYARD_GUARDS_DAY || gPlayState->sceneNum == SCENE_CASTLE_COURTYARD_GUARDS_NIGHT) && 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 16abaf568..ade67d576 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -5145,9 +5145,9 @@ s32 Player_HandleExitsAndVoids(PlayState* play, Player* this, CollisionPoly* pol Scene_SetTransitionForNextEntrance(play); } else { - // In Entrance rando, if our respawnFlag is set for a grotto return, we don't want the void out to happen - if (SurfaceType_GetSlope(&play->colCtx, poly, bgId) == 2 && - (!IS_RANDO || (Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES) && gSaveContext.respawnFlag != 2))) { + if (GameInteractor_Should(VB_SET_VOIDOUT_FROM_SURFACE, + SurfaceType_GetSlope(&play->colCtx, poly, bgId) == 2, + play->setupExitList[exitIndex - 1])) { gSaveContext.respawn[RESPAWN_MODE_DOWN].entranceIndex = play->nextEntranceIndex; Play_TriggerVoidOut(play); gSaveContext.respawnFlag = -2; From ad232985009e8f7de5725bc137e06047f8e2faf2 Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Tue, 10 Dec 2024 02:18:00 +0000 Subject: [PATCH 2/6] Automate settings text to enum conversion and remove OptionGroups from the process (#4636) * Automate settings text to enum conversion * rename fortress setting into carpenters --- .../randomizer/3drando/item_pool.cpp | 4 +- .../location_access/locacc_gerudo_valley.cpp | 4 +- .../randomizer/3drando/spoiler_log.cpp | 13 +- .../randomizer/3drando/starting_inventory.cpp | 2 +- soh/soh/Enhancements/randomizer/logic.cpp | 2 +- soh/soh/Enhancements/randomizer/option.cpp | 37 +- soh/soh/Enhancements/randomizer/option.h | 34 +- .../randomizer/option_descriptions.cpp | 7 +- .../Enhancements/randomizer/randomizerTypes.h | 2 +- .../randomizer/randomizer_check_objects.cpp | 2 +- .../randomizer/randomizer_check_tracker.cpp | 2 +- soh/soh/Enhancements/randomizer/savefile.cpp | 4 +- soh/soh/Enhancements/randomizer/settings.cpp | 1061 ++--------------- soh/soh/Enhancements/randomizer/settings.h | 9 +- .../Enhancements/randomizer/static_data.cpp | 3 +- soh/soh/Enhancements/randomizer/static_data.h | 1 + 16 files changed, 196 insertions(+), 991 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index 5d7a290c0..38ca7c646 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -1026,7 +1026,7 @@ void GenerateItemPool() { } //Gerudo Fortress - if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN)) { + if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FREE)) { ctx->PlaceItemInLocation(RC_GF_NORTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true); ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true); ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true); @@ -1071,7 +1071,7 @@ void GenerateItemPool() { } //Gerudo Membership Card - if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) && ctx->GetOption(RSK_GERUDO_FORTRESS).IsNot(RO_GF_OPEN)) { + if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) && ctx->GetOption(RSK_GERUDO_FORTRESS).IsNot(RO_GF_FREE)) { AddItemToMainPool(RG_GERUDO_MEMBERSHIP_CARD); ctx->possibleIceTrapModels.push_back(RG_GERUDO_MEMBERSHIP_CARD); } else if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) { diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp index db7058f33..529c47fd2 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp @@ -16,7 +16,7 @@ void RegionTable_Init_GerudoValley() { Entrance(RR_GV_UPPER_STREAM, {[]{return true;}}), Entrance(RR_GV_CRATE_LEDGE, {[]{return logic->IsChild || logic->CanUse(RG_LONGSHOT);}}), Entrance(RR_GV_GROTTO_LEDGE, {[]{return true;}}), - Entrance(RR_GV_FORTRESS_SIDE, {[]{return (logic->IsAdult && (logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN) || logic->CarpenterRescue)) || (logic->IsChild && logic->CanUse(RG_HOOKSHOT));}}), + Entrance(RR_GV_FORTRESS_SIDE, {[]{return (logic->IsAdult && (logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FREE) || logic->CarpenterRescue)) || (logic->IsChild && logic->CanUse(RG_HOOKSHOT));}}), }); areaTable[RR_GV_UPPER_STREAM] = Region("GV Upper Stream", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, { @@ -64,7 +64,7 @@ void RegionTable_Init_GerudoValley() { //Exits Entrance(RR_GERUDO_FORTRESS, {[]{return true;}}), Entrance(RR_GV_UPPER_STREAM, {[]{return true;}}), - Entrance(RR_GERUDO_VALLEY, {[]{return logic->IsChild || logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN) || logic->CarpenterRescue;}}), + Entrance(RR_GERUDO_VALLEY, {[]{return logic->IsChild || logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FREE) || logic->CarpenterRescue;}}), Entrance(RR_GV_CARPENTER_TENT, {[]{return logic->IsAdult;}}), Entrance(RR_GV_STORMS_GROTTO, {[]{return logic->IsAdult && logic->CanOpenStormsGrotto();}}), Entrance(RR_GV_CRATE_LEDGE, {[]{return false;}}), diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index a665c4eea..58409d0ec 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -139,14 +139,11 @@ static void WriteShuffledEntrance(std::string sphereString, Entrance* entrance) // Writes the settings (without excluded locations, starting inventory and tricks) to the spoilerLog document. static void WriteSettings() { auto ctx = Rando::Context::GetInstance(); - auto allOptionGroups = ctx->GetSettings()->GetOptionGroups(); - for (const Rando::OptionGroup& optionGroup : allOptionGroups) { - if (optionGroup.GetContainsType() == Rando::OptionGroupType::DEFAULT && optionGroup.PrintInSpoiler()) { - for (Rando::Option* option : optionGroup.GetOptions()) { - std::string settingName = optionGroup.GetName() + ":" + option->GetName(); - jsonData["settings"][settingName] = option->GetSelectedOptionText(); - } - } + std::array options = ctx->GetSettings()->GetAllOptions(); + for (const Rando::Option& option : options) { + if (option.GetName() != ""){ + jsonData["settings"][option.GetName()] = option.GetSelectedOptionText(); + } } } diff --git a/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp b/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp index 035259fdb..dea7042c5 100644 --- a/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp @@ -61,7 +61,7 @@ void GenerateStartingInventory() { AddItemToInventory(RG_GANONS_CASTLE_BOSS_KEY); } - if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN) && !ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) { + if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FREE) && !ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) { AddItemToInventory(RG_GERUDO_MEMBERSHIP_CARD); } diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index da76be1d3..72f493977 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -1124,7 +1124,7 @@ namespace Rando { bool Logic::CanFinishGerudoFortress(){ return (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_NORMAL) && SmallKeys(RR_GERUDO_FORTRESS, 4) && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (HasItem(RG_GERUDO_MEMBERSHIP_CARD) || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN))) || (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FAST) && SmallKeys(RR_GERUDO_FORTRESS, 1) && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD))) || - ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN); + ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FREE); } bool Logic::CanStandingShield(){ diff --git a/soh/soh/Enhancements/randomizer/option.cpp b/soh/soh/Enhancements/randomizer/option.cpp index 08195276d..f5f9d1cba 100644 --- a/soh/soh/Enhancements/randomizer/option.cpp +++ b/soh/soh/Enhancements/randomizer/option.cpp @@ -178,6 +178,15 @@ void Option::RemoveFlag(const int imFlag_) { imFlags &= ~imFlag_; } +void Option::SetContextIndexFromText(const std::string text) { + if (optionsTextToVar.contains(text)){ + SetContextIndex(optionsTextToVar[text]); + } else { + SPDLOG_ERROR("Option {} does not have a var named {}.", name, text); + assert(false); + } +} + Option::Option(uint8_t var_, std::string name_, std::vector options_, OptionCategory category_, std::string cvarName_, std::string description_, WidgetType widgetType_, uint8_t defaultOption_, bool defaultHidden_, int imFlags_) @@ -186,6 +195,7 @@ Option::Option(uint8_t var_, std::string name_, std::vector options defaultOption(defaultOption_), defaultHidden(defaultHidden_), imFlags(imFlags_) { menuSelection = contextSelection = defaultOption; hidden = defaultHidden; + PopulateTextToNum(); SetFromCVar(); } Option::Option(bool var_, std::string name_, std::vector options_, const OptionCategory category_, @@ -196,6 +206,7 @@ Option::Option(bool var_, std::string name_, std::vector options_, defaultOption(defaultOption_), defaultHidden(defaultHidden_), imFlags(imFlags_) { menuSelection = contextSelection = defaultOption; hidden = defaultHidden; + PopulateTextToNum(); SetFromCVar(); } @@ -333,6 +344,12 @@ bool Option::RenderSlider() { return changed; } +void Option::PopulateTextToNum(){ + for (uint8_t count = 0; count < options.size(); count++){ + optionsTextToVar[options[count]] = count; + } +} + TrickOption::TrickOption(const RandomizerCheckQuest quest_, const RandomizerArea area_, std::set tags_, const bool glitch_, const std::string& name_, std::string description_) : Option(false, name_, {"Disabled", "Enabled"}, OptionCategory::Setting, "", std::move(description_), WidgetType::Checkbox, 0, false, IMFLAG_NONE), @@ -363,26 +380,26 @@ const std::set& TrickOption::GetTags() const { } OptionGroup::OptionGroup(std::string name, std::vector options, const OptionGroupType groupType, - const bool printInSpoiler, const WidgetContainerType containerType, std::string description) - : mName(std::move(name)), mOptions(std::move(options)), mGroupType(groupType), mPrintInSpoiler(printInSpoiler), + const WidgetContainerType containerType, std::string description) + : mName(std::move(name)), mOptions(std::move(options)), mGroupType(groupType), mContainerType(containerType), mDescription(std::move(description)) { } OptionGroup::OptionGroup(std::string name, std::vector subGroups, const OptionGroupType groupType, - const bool printInSpoiler, const WidgetContainerType containerType, std::string description) - : mName(std::move(name)), mSubGroups(std::move(subGroups)), mGroupType(groupType), mPrintInSpoiler(printInSpoiler), + const WidgetContainerType containerType, std::string description) + : mName(std::move(name)), mSubGroups(std::move(subGroups)), mGroupType(groupType), mContainsType(OptionGroupType::SUBGROUP), mContainerType(containerType), mDescription(std::move(description)) { } -OptionGroup OptionGroup::SubGroup(std::string name, std::vector options, const bool printInSpoiler, +OptionGroup OptionGroup::SubGroup(std::string name, std::vector options, const WidgetContainerType containerType, std::string description) { - return {std::move(name), std::move(options), OptionGroupType::SUBGROUP, printInSpoiler, containerType, + return {std::move(name), std::move(options), OptionGroupType::SUBGROUP, containerType, std::move(description)}; } -OptionGroup OptionGroup::SubGroup(std::string name, std::vector subGroups, const bool printInSpoiler, +OptionGroup OptionGroup::SubGroup(std::string name, std::vector subGroups, const WidgetContainerType containerType, std::string description) { - return {std::move(name), std::move(subGroups), OptionGroupType::SUBGROUP, printInSpoiler, containerType, + return {std::move(name), std::move(subGroups), OptionGroupType::SUBGROUP, containerType, std::move(description)}; } @@ -398,10 +415,6 @@ const std::vector& OptionGroup::GetSubGroups() const { return mSubGroups; } -bool OptionGroup::PrintInSpoiler() const { - return mPrintInSpoiler; -} - OptionGroupType OptionGroup::GetGroupType() const { return mGroupType; } diff --git a/soh/soh/Enhancements/randomizer/option.h b/soh/soh/Enhancements/randomizer/option.h index 5b7eb5b9d..cc34338d8 100644 --- a/soh/soh/Enhancements/randomizer/option.h +++ b/soh/soh/Enhancements/randomizer/option.h @@ -56,9 +56,9 @@ class Option { * @param options_ A vector of value names for this Option. This vector should have a size of 2. * The name corresponding to the selected index for this option will be printed to the spoiler/patch file. * @param category_ The desired `OptionCategory` for this option. - * @param cvarName_ The name ofthe CVar this option should correspond with. Set as an empty string to not + * @param cvarName_ The name of the CVar this option should correspond with. Set as an empty string to not * link to any Cvar. - * @param description_ A description of what this option affects. Will be rendered in a toolip in ImGui. + * @param description_ A description of what this option affects. Will be rendered in a tooltip in ImGui. * Can be left as an empty string if desired, no tooltip will be rendered. * @param widgetType_ What type of widget should be rendered. Should probably be `Checkbox` but technically * `Combobox` or `Slider` would render and function correctly. @@ -305,6 +305,8 @@ class Option { void SetFlag(int imFlag_); void RemoveFlag(int imFlag_); + void SetContextIndexFromText(std::string text); + protected: Option(uint8_t var_, std::string name_, std::vector options_, OptionCategory category_, std::string cvarName_, std::string description_, WidgetType widgetType_, uint8_t defaultOption_, @@ -318,6 +320,7 @@ protected: bool RenderTristateCheckbox(); bool RenderCombobox(); bool RenderSlider(); + void PopulateTextToNum(); std::variant var; std::string name; std::vector options; @@ -335,6 +338,7 @@ protected: bool disabled = false; UIWidgets::CheckboxGraphics disabledGraphic = UIWidgets::CheckboxGraphics::Cross; std::string disabledText; + std::unordered_map optionsTextToVar = {}; }; class TrickOption : public Option { @@ -416,13 +420,11 @@ class OptionGroup { * @param options A vector of Option pointers * @param groupType `DEFAULT` if this group is not contained within any other groups, `SUBGROUP` if it is a * subgroup of another group. - * @param printInSpoiler Whether or not to print the contents of this group to the spoiler/patch file. * @param containerType Specifies the type of container this widget should render as in ImGui. * @param description A description that can appear in a tooltip in ImGui. */ OptionGroup(std::string name, std::vector options, OptionGroupType groupType = OptionGroupType::DEFAULT, - bool printInSpoiler = true, WidgetContainerType containerType = WidgetContainerType::BASIC, - std::string description = ""); + WidgetContainerType containerType = WidgetContainerType::BASIC, std::string description = ""); /** * @brief Construct a new Option Group containing a list of `OptionGroup` pointers. @@ -431,13 +433,11 @@ class OptionGroup { * @param subGroups A vector of OptionGroup pointers that will be subgroups of this group. * @param groupType `DEFAULT` if this group is not contained within any other groups, `SUBGROUP` if it is a * subgroup of another group. - * @param printInSpoiler Whether or not to print the contents of this group to spoiler/patch file. * @param containerType Specifies the type of container this widget should render as in ImGui. * @param description A description that can appear in a tooltip in ImGui. */ OptionGroup(std::string name, std::vector subGroups, OptionGroupType groupType = OptionGroupType::DEFAULT, - bool printInSpoiler = true, WidgetContainerType containerType = WidgetContainerType::BASIC, - std::string description = ""); + WidgetContainerType containerType = WidgetContainerType::BASIC, std::string description = ""); /** * @brief Convenience function for constructing an OptionGroup of groupType `SUBGROUP` with @@ -445,13 +445,11 @@ class OptionGroup { * * @param name The name of this option group. Appears in the spoiler/patch file. * @param options A vector of Option pointers. - * @param printInSpoiler Whether or not to print the options of this group to the spoiler/patch file. * @param containerType Specifies the type of container this widget should render as in ImGui. * @param description A description that can appear in a tooltip in ImGui. * @return OptionGroup */ - static OptionGroup SubGroup(std::string name, std::vector options, bool printInSpoiler = true, - WidgetContainerType containerType = WidgetContainerType::BASIC, + static OptionGroup SubGroup(std::string name, std::vector options, WidgetContainerType containerType = WidgetContainerType::BASIC, std::string description = ""); /** @@ -460,13 +458,11 @@ class OptionGroup { * * @param name The name of this option group. Appears in the spoiler/patch file. * @param subGroups A vector of OptionGroup pointers. - * @param printInSpoiler Whether or not to print the options of this group to the spoiler/patch file. * @param containerType Specifies the type of container this widget should render as in ImGui. * @param description A description that can appear in a tooltip in ImGui. * @return OptionGroup */ - static OptionGroup SubGroup(std::string name, std::vector subGroups, bool printInSpoiler = true, - WidgetContainerType containerType = WidgetContainerType::BASIC, + static OptionGroup SubGroup(std::string name, std::vector subGroups, WidgetContainerType containerType = WidgetContainerType::BASIC, std::string description = ""); /** @@ -490,15 +486,6 @@ class OptionGroup { */ const std::vector& GetSubGroups() const; - /** - * @brief Returns whether or not this `OptionGroup`'s contents should be printed to the - * spoiler/patch file. - * - * @return true - * @return false - */ - bool PrintInSpoiler() const; - /** * @brief Get the Group Type of this `OptionGroup`. `DEFAULT` means this group is not contained * within any other groups, while `SUBGROUP` means that it is contained within at least one other. @@ -532,7 +519,6 @@ class OptionGroup { std::vector mOptions; std::vector mSubGroups; OptionGroupType mGroupType = OptionGroupType::DEFAULT; - bool mPrintInSpoiler = true; OptionGroupType mContainsType = OptionGroupType::DEFAULT; WidgetContainerType mContainerType = WidgetContainerType::BASIC; std::string mDescription; diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index 405620849..c2abfc72b 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -43,14 +43,15 @@ void Settings::CreateOptionDescriptions() { "Choose which age Link will start as.\n\n" "Starting as adult means you start with the Master Sword in your inventory.\n" "The child option is forcefully set if it would conflict with other options."; - mOptionDescriptions[RSK_GERUDO_FORTRESS] = "Sets the amount of carpenters required to repair the bridge " - "in Gerudo Valley.\n" + mOptionDescriptions[RSK_GERUDO_FORTRESS] = "Sets the state of the carpenters captured by Gerudo " + "in Gerudo Fortress, and with it the number of guards that spawn.\n" "\n" "Normal - All 4 carpenters are required to be saved.\n" "\n" "Fast - Only the bottom left carpenter requires rescuing.\n" "\n" - "Open - The bridge is repaired from the start.\n" + "Free - The bridge is repaired from the start, and Nabooru cannot spawn.\n" + "If the Gerudo Membership Card isn't shuffled, you start with it.\n" "\n" "Only \"Normal\" is compatible with Gerudo Fortress Key Rings."; mOptionDescriptions[RSK_RAINBOW_BRIDGE] = diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 70a8e19d6..e5b6df090 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -4198,7 +4198,7 @@ typedef enum { typedef enum { RO_GF_NORMAL, RO_GF_FAST, - RO_GF_OPEN, + RO_GF_FREE, } RandoOptionGerudoFortress; //Kakariko Gate settings (closed/open) diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp index 5d3a62b86..27d2845fe 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp @@ -206,7 +206,7 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() { CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), RO_GANON_BOSS_KEY_VANILLA) != RO_GANON_BOSS_KEY_KAK_TOKENS) && // 100 skull reward ganon boss key (location.GetRCType() != RCTYPE_GF_KEY && location.GetRandomizerCheck() != RC_GF_GERUDO_MEMBERSHIP_CARD || - (CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoFortress"), RO_GF_NORMAL) == RO_GF_OPEN && + (CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoFortress"), RO_GF_NORMAL) == RO_GF_FREE && location.GetRCType() != RCTYPE_GF_KEY && location.GetRandomizerCheck() != RC_GF_GERUDO_MEMBERSHIP_CARD) || (CVarGetInteger(CVAR_RANDOMIZER_SETTING("GerudoFortress"), RO_GF_NORMAL) == RO_GF_FAST && ((location.GetRandomizerCheck() == RC_GF_GERUDO_MEMBERSHIP_CARD && diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index a9d9e72dc..98a0d4c3f 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -1185,7 +1185,7 @@ void LoadSettings() { fortressFast = false; fortressNormal = false; switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_FORTRESS)) { - case RO_GF_OPEN: + case RO_GF_FREE: showGerudoFortressKeys = false; showGerudoCard = false; break; diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index fd23feb04..4876af321 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -453,7 +453,7 @@ extern "C" void Randomizer_InitSaveFile() { } if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_FAST || - Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_OPEN) { + Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_FREE) { Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(1)); Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(2)); Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(3)); @@ -471,7 +471,7 @@ extern "C" void Randomizer_InitSaveFile() { gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].collect |= (1 << 0x0F); } - if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_OPEN) { + if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_FREE) { Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(0)); gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x01); // heard yell and unlocked door gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x05); diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index e13a32cfa..405af139c 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -110,13 +110,13 @@ void Settings::CreateOptions() { mOptions[RSK_DOOR_OF_TIME] = Option::U8("Door of Time", {"Closed", "Song only", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("DoorOfTime"), mOptionDescriptions[RSK_DOOR_OF_TIME], WidgetType::Combobox); mOptions[RSK_ZORAS_FOUNTAIN] = Option::U8("Zora's Fountain", {"Closed", "Closed as child", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ZorasFountain"), mOptionDescriptions[RSK_ZORAS_FOUNTAIN]); mOptions[RSK_SLEEPING_WATERFALL] = Option::U8("Sleeping Waterfall", {"Closed", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SleepingWaterfall"), mOptionDescriptions[RSK_SLEEPING_WATERFALL]); - mOptions[RSK_GERUDO_FORTRESS] = Option::U8("Gerudo Fortress", {"Normal", "Fast", "Open"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GerudoFortress"), mOptionDescriptions[RSK_GERUDO_FORTRESS]); + mOptions[RSK_GERUDO_FORTRESS] = Option::U8("Fortress Carpenters", {"Normal", "Fast", "Free"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GerudoFortress"), mOptionDescriptions[RSK_GERUDO_FORTRESS]); mOptions[RSK_RAINBOW_BRIDGE] = Option::U8("Rainbow Bridge", {"Vanilla", "Always open", "Stones", "Medallions", "Dungeon rewards", "Dungeons", "Tokens", "Greg"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("RainbowBridge"), mOptionDescriptions[RSK_RAINBOW_BRIDGE], WidgetType::Combobox, RO_BRIDGE_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_RAINBOW_BRIDGE_STONE_COUNT] = Option::U8("Stone Count", {NumOpts(0, 4)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StoneCount"), "", WidgetType::Slider, 3, true); - mOptions[RSK_RAINBOW_BRIDGE_MEDALLION_COUNT] = Option::U8("Medallion Count", {NumOpts(0, 7)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MedallionCount"), "", WidgetType::Slider, 6, true); - mOptions[RSK_RAINBOW_BRIDGE_REWARD_COUNT] = Option::U8("Reward Count", {NumOpts(0, 10)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("RewardCount"), "", WidgetType::Slider, 9, true); - mOptions[RSK_RAINBOW_BRIDGE_DUNGEON_COUNT] = Option::U8("Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("DungeonCount"), "", WidgetType::Slider, 8, true); - mOptions[RSK_RAINBOW_BRIDGE_TOKEN_COUNT] = Option::U8("Token Count", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("TokenCount"), "", WidgetType::Slider, 100, true); + mOptions[RSK_RAINBOW_BRIDGE_STONE_COUNT] = Option::U8("Bridge Stone Count", {NumOpts(0, 4)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StoneCount"), "", WidgetType::Slider, 3, true); + mOptions[RSK_RAINBOW_BRIDGE_MEDALLION_COUNT] = Option::U8("Bridge Medallion Count", {NumOpts(0, 7)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MedallionCount"), "", WidgetType::Slider, 6, true); + mOptions[RSK_RAINBOW_BRIDGE_REWARD_COUNT] = Option::U8("Bridge Reward Count", {NumOpts(0, 10)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("RewardCount"), "", WidgetType::Slider, 9, true); + mOptions[RSK_RAINBOW_BRIDGE_DUNGEON_COUNT] = Option::U8("Bridge Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("DungeonCount"), "", WidgetType::Slider, 8, true); + mOptions[RSK_RAINBOW_BRIDGE_TOKEN_COUNT] = Option::U8("Bridge Token Count", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("TokenCount"), "", WidgetType::Slider, 100, true); mOptions[RSK_BRIDGE_OPTIONS] = Option::U8("Bridge Reward Options", {"Standard Rewards", "Greg as Reward", "Greg as Wildcard"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("BridgeRewardOptions"), mOptionDescriptions[RSK_BRIDGE_OPTIONS], WidgetType::Combobox, RO_BRIDGE_STANDARD_REWARD, false, IMFLAG_NONE); mOptions[RSK_GANONS_TRIALS] = Option::U8("Ganon's Trials", {"Skip", "Set Number", "Random Number"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GanonTrial"), mOptionDescriptions[RSK_GANONS_TRIALS], WidgetType::Combobox, RO_GANONS_TRIALS_SET_NUMBER); mOptions[RSK_TRIAL_COUNT] = Option::U8("Ganon's Trials Count", {NumOpts(0, 6)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GanonTrialCount"), mOptionDescriptions[RSK_TRIAL_COUNT], WidgetType::Slider, 6, true); @@ -146,44 +146,44 @@ void Settings::CreateOptions() { mOptions[RSK_MQ_DUNGEON_RANDOM] = Option::U8("MQ Dungeon Setting", {"None", "Set Number", "Random", "Selection Only"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeons"), mOptionDescriptions[RSK_MQ_DUNGEON_RANDOM], WidgetType::Combobox, RO_MQ_DUNGEONS_NONE, true, IMFLAG_NONE); mOptions[RSK_MQ_DUNGEON_COUNT] = Option::U8("MQ Dungeon Count", {NumOpts(0, 12)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonCount"), "", WidgetType::Slider, 12, true, IMFLAG_NONE); mOptions[RSK_MQ_DUNGEON_SET] = Option::Bool("Set Dungeon Quests", {"Off", "On"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsSelection"), mOptionDescriptions[RSK_MQ_DUNGEON_SET], WidgetType::Checkbox, false, false, IMFLAG_NONE); - mOptions[RSK_MQ_DEKU_TREE] = Option::U8("Deku Tree", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsDekuTree"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_DODONGOS_CAVERN] = Option::U8("Dodongo's Cavern", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsDodongosCavern"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_JABU_JABU] = Option::U8("Jabu-Jabu's Belly", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsJabuJabu"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_FOREST_TEMPLE] = Option::U8("Forest Temple", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsForestTemple"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_FIRE_TEMPLE] = Option::U8("Fire Temple", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsFireTemple"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_WATER_TEMPLE] = Option::U8("Water Temple", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsWaterTemple"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_SPIRIT_TEMPLE] = Option::U8("Spirit Temple", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsSpiritTemple"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_SHADOW_TEMPLE] = Option::U8("Shadow Temple", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsShadowTemple"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_BOTTOM_OF_THE_WELL] = Option::U8("Bottom of the Well", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsBottomOfTheWell"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_ICE_CAVERN] = Option::U8("Ice Cavern", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsIceCavern"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_GTG] = Option::U8("Gerudo Training Grounds", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsGTG"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MQ_GANONS_CASTLE] = Option::U8("Ganon's Castle", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsGanonsCastle"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA); + mOptions[RSK_MQ_DEKU_TREE] = Option::U8("Deku Tree Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsDekuTree"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_DODONGOS_CAVERN] = Option::U8("Dodongo's Cavern Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsDodongosCavern"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_JABU_JABU] = Option::U8("Jabu-Jabu's Belly Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsJabuJabu"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_FOREST_TEMPLE] = Option::U8("Forest Temple Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsForestTemple"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_FIRE_TEMPLE] = Option::U8("Fire Temple Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsFireTemple"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_WATER_TEMPLE] = Option::U8("Water Temple Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsWaterTemple"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_SPIRIT_TEMPLE] = Option::U8("Spirit Temple Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsSpiritTemple"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_SHADOW_TEMPLE] = Option::U8("Shadow Temple Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsShadowTemple"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_BOTTOM_OF_THE_WELL] = Option::U8("Bottom of the Well Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsBottomOfTheWell"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_ICE_CAVERN] = Option::U8("Ice Cavern Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsIceCavern"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_GTG] = Option::U8("Gerudo Training Grounds Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsGTG"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MQ_GANONS_CASTLE] = Option::U8("Ganon's Castle Quest", {"Vanilla", "Master Quest", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeonsGanonsCastle"), "", WidgetType::Combobox, RO_MQ_SET_VANILLA); mOptions[RSK_SHUFFLE_DUNGEON_REWARDS] = Option::U8("Shuffle Dungeon Rewards", {"End of Dungeons", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleDungeonReward"), mOptionDescriptions[RSK_SHUFFLE_DUNGEON_REWARDS], WidgetType::Combobox, RO_DUNGEON_REWARDS_END_OF_DUNGEON); mOptions[RSK_LINKS_POCKET] = Option::U8("Link's Pocket", {"Dungeon Reward", "Advancement", "Anything", "Nothing"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LinksPocket"), "", WidgetType::Combobox, RO_LINKS_POCKET_DUNGEON_REWARD); mOptions[RSK_SHUFFLE_SONGS] = Option::U8("Shuffle Songs", {"Song Locations", "Dungeon Rewards", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleSongs"), mOptionDescriptions[RSK_SHUFFLE_SONGS], WidgetType::Combobox, RO_SONG_SHUFFLE_SONG_LOCATIONS); - mOptions[RSK_SHOPSANITY] = Option::U8("Shopsanity", {"Off", "Specific Count", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Shopsanity"), mOptionDescriptions[RSK_SHOPSANITY], WidgetType::Combobox, RO_SHOPSANITY_OFF); - mOptions[RSK_SHOPSANITY_COUNT] = Option::U8("Shopsanity Item Count", {NumOpts(0, 7/*8*/)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityCount"), mOptionDescriptions[RSK_SHOPSANITY_COUNT], WidgetType::Slider, 0, false, IMFLAG_NONE); - mOptions[RSK_SHOPSANITY_PRICES] = Option::U8("Shopsanity Prices", {"Vanilla", "Cheap Balanced", "Balanced", "Fixed", "Range", "Set By Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), mOptionDescriptions[RSK_SHOPSANITY_PRICES], WidgetType::Combobox, RO_PRICE_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE] = Option::U8("Fixed Price", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityFixedPrice"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE], WidgetType::Slider, 10, true); - mOptions[RSK_SHOPSANITY_PRICES_RANGE_1] = Option::U8("Lower Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPriceRange1"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_RANGE_1], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_SHOPSANITY_PRICES_RANGE_2] = Option::U8("Upper Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPriceRange2"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_RANGE_2], WidgetType::Slider, 100, true, IMFLAG_NONE); - mOptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT] = Option::U8("No Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityNoWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT] = Option::U8("Child Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityChildWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT] = Option::U8("Adult Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityAdultWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT] = Option::U8("Giant Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityGiantWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT] = Option::U8("Tycoon Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityTycoonWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY] = Option::U8("Shop Shuffle", {"Off", "Specific Count", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Shopsanity"), mOptionDescriptions[RSK_SHOPSANITY], WidgetType::Combobox, RO_SHOPSANITY_OFF); + mOptions[RSK_SHOPSANITY_COUNT] = Option::U8("Shops Item Count", {NumOpts(0, 7/*8*/)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityCount"), mOptionDescriptions[RSK_SHOPSANITY_COUNT], WidgetType::Slider, 0, false, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES] = Option::U8("Shops Prices", {"Vanilla", "Cheap Balanced", "Balanced", "Fixed", "Range", "Set By Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), mOptionDescriptions[RSK_SHOPSANITY_PRICES], WidgetType::Combobox, RO_PRICE_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE] = Option::U8("Shops Fixed Price", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityFixedPrice"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE], WidgetType::Slider, 10, true); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_1] = Option::U8("Shops Lower Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPriceRange1"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_RANGE_1], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_2] = Option::U8("Shops Upper Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPriceRange2"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_RANGE_2], WidgetType::Slider, 100, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT] = Option::U8("Shops No Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityNoWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT] = Option::U8("Shops Child Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityChildWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT] = Option::U8("Shops Adult Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityAdultWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT] = Option::U8("Shops Giant Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityGiantWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT] = Option::U8("Shops Tycoon Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityTycoonWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE] = Option::Bool("Shops Affordable Prices", CVAR_RANDOMIZER_SETTING("ShopsanityPricesAffordable"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_AFFORDABLE]); - mOptions[RSK_SHUFFLE_TOKENS] = Option::U8("Tokensanity", {"Off", "Dungeons", "Overworld", "All Tokens"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleTokens"), mOptionDescriptions[RSK_SHUFFLE_TOKENS], WidgetType::Combobox, RO_TOKENSANITY_OFF); - mOptions[RSK_SHUFFLE_SCRUBS] = Option::U8("Scrub Shuffle", {"Off", "One-Time Only", "All"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleScrubs"), mOptionDescriptions[RSK_SHUFFLE_SCRUBS], WidgetType::Combobox, RO_SCRUBS_OFF); - mOptions[RSK_SCRUBS_PRICES] = Option::U8("Scrub Prices", {"Vanilla", "Cheap Balanced", "Balanced", "Fixed", "Range", "Set By Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsPrices"), mOptionDescriptions[RSK_SCRUBS_PRICES], WidgetType::Combobox, RO_PRICE_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE] = Option::U8("Fixed Price", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsFixedPrice"), mOptionDescriptions[RSK_SCRUBS_PRICES_FIXED_PRICE], WidgetType::Slider, 10, true); - mOptions[RSK_SCRUBS_PRICES_RANGE_1] = Option::U8("Lower Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsPriceRange1"), mOptionDescriptions[RSK_SCRUBS_PRICES_RANGE_1], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_SCRUBS_PRICES_RANGE_2] = Option::U8("Upper Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsPriceRange2"), mOptionDescriptions[RSK_SCRUBS_PRICES_RANGE_2], WidgetType::Slider, 100, true, IMFLAG_NONE); - mOptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT] = Option::U8("No Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsNoWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT] = Option::U8("Child Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsChildWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT] = Option::U8("Adult Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsAdultWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT] = Option::U8("Giant Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsGiantWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT] = Option::U8("Tycoon Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsTycoonWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHUFFLE_TOKENS] = Option::U8("Token Shuffle", {"Off", "Dungeons", "Overworld", "All Tokens"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleTokens"), mOptionDescriptions[RSK_SHUFFLE_TOKENS], WidgetType::Combobox, RO_TOKENSANITY_OFF); + mOptions[RSK_SHUFFLE_SCRUBS] = Option::U8("Scrubs Shuffle", {"Off", "One-Time Only", "All"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleScrubs"), mOptionDescriptions[RSK_SHUFFLE_SCRUBS], WidgetType::Combobox, RO_SCRUBS_OFF); + mOptions[RSK_SCRUBS_PRICES] = Option::U8("Scrubs Prices", {"Vanilla", "Cheap Balanced", "Balanced", "Fixed", "Range", "Set By Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsPrices"), mOptionDescriptions[RSK_SCRUBS_PRICES], WidgetType::Combobox, RO_PRICE_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE] = Option::U8("Scrubs Fixed Price", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsFixedPrice"), mOptionDescriptions[RSK_SCRUBS_PRICES_FIXED_PRICE], WidgetType::Slider, 10, true); + mOptions[RSK_SCRUBS_PRICES_RANGE_1] = Option::U8("Scrubs Lower Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsPriceRange1"), mOptionDescriptions[RSK_SCRUBS_PRICES_RANGE_1], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_RANGE_2] = Option::U8("Scrubs Upper Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsPriceRange2"), mOptionDescriptions[RSK_SCRUBS_PRICES_RANGE_2], WidgetType::Slider, 100, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT] = Option::U8("Scrubs No Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsNoWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT] = Option::U8("Scrubs Child Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsChildWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT] = Option::U8("Scrubs Adult Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsAdultWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT] = Option::U8("Scrubs Giant Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsGiantWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT] = Option::U8("Scrubs Tycoon Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsTycoonWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); mOptions[RSK_SCRUBS_PRICES_AFFORDABLE] = Option::Bool("Scrubs Affordable Prices", CVAR_RANDOMIZER_SETTING("ScrubsPricesAffordable"), mOptionDescriptions[RSK_SCRUBS_PRICES_AFFORDABLE]); mOptions[RSK_SHUFFLE_BEEHIVES] = Option::Bool("Shuffle Beehives", CVAR_RANDOMIZER_SETTING("ShuffleBeehives"), mOptionDescriptions[RSK_SHUFFLE_BEEHIVES]); mOptions[RSK_SHUFFLE_COWS] = Option::Bool("Shuffle Cows", CVAR_RANDOMIZER_SETTING("ShuffleCows"), mOptionDescriptions[RSK_SHUFFLE_COWS]); @@ -199,14 +199,14 @@ void Settings::CreateOptions() { mOptions[RSK_SHUFFLE_FISHING_POLE] = Option::Bool("Shuffle Fishing Pole", CVAR_RANDOMIZER_SETTING("ShuffleFishingPole"), mOptionDescriptions[RSK_SHUFFLE_FISHING_POLE]); mOptions[RSK_SHUFFLE_MERCHANTS] = Option::U8("Shuffle Merchants", {"Off", "Bean Merchant Only", "All But Beans", "All"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), mOptionDescriptions[RSK_SHUFFLE_MERCHANTS], WidgetType::Combobox, RO_SHUFFLE_MERCHANTS_OFF, IMFLAG_NONE); mOptions[RSK_MERCHANT_PRICES] = Option::U8("Merchant Prices", {"Vanilla", "Cheap Balanced", "Balanced", "Fixed", "Range", "Set By Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantPrices"), mOptionDescriptions[RSK_MERCHANT_PRICES], WidgetType::Combobox, RO_PRICE_VANILLA, false, IMFLAG_NONE); - mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE] = Option::U8("Fixed Price", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantFixedPrice"), mOptionDescriptions[RSK_MERCHANT_PRICES_FIXED_PRICE], WidgetType::Slider, 10, true); - mOptions[RSK_MERCHANT_PRICES_RANGE_1] = Option::U8("Lower Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantPriceRange1"), mOptionDescriptions[RSK_MERCHANT_PRICES_RANGE_1], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_MERCHANT_PRICES_RANGE_2] = Option::U8("Upper Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantPriceRange2"), mOptionDescriptions[RSK_MERCHANT_PRICES_RANGE_2], WidgetType::Slider, 100, true, IMFLAG_NONE); - mOptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT] = Option::U8("No Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantNoWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT] = Option::U8("Child Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantChildWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT] = Option::U8("Adult Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantAdultWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT] = Option::U8("Giant Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantGiantWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); - mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT] = Option::U8("Tycoon Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantTycoonWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE] = Option::U8("Merchant Fixed Price", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantFixedPrice"), mOptionDescriptions[RSK_MERCHANT_PRICES_FIXED_PRICE], WidgetType::Slider, 10, true); + mOptions[RSK_MERCHANT_PRICES_RANGE_1] = Option::U8("Merchant Lower Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantPriceRange1"), mOptionDescriptions[RSK_MERCHANT_PRICES_RANGE_1], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_RANGE_2] = Option::U8("Merchant Upper Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantPriceRange2"), mOptionDescriptions[RSK_MERCHANT_PRICES_RANGE_2], WidgetType::Slider, 100, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT] = Option::U8("Merchant No Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantNoWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT] = Option::U8("Merchant Child Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantChildWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT] = Option::U8("Merchant Adult Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantAdultWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT] = Option::U8("Merchant Giant Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantGiantWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT] = Option::U8("Merchant Tycoon Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantTycoonWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); mOptions[RSK_MERCHANT_PRICES_AFFORDABLE] = Option::Bool("Merchant Affordable Prices", CVAR_RANDOMIZER_SETTING("MerchantPricesAffordable"), mOptionDescriptions[RSK_MERCHANT_PRICES_AFFORDABLE]); mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES] = Option::Bool("Shuffle Frog Song Rupees", CVAR_RANDOMIZER_SETTING("ShuffleFrogSongRupees"), mOptionDescriptions[RSK_SHUFFLE_FROG_SONG_RUPEES]); mOptions[RSK_SHUFFLE_ADULT_TRADE] = Option::Bool("Shuffle Adult Trade", CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), mOptionDescriptions[RSK_SHUFFLE_ADULT_TRADE]); @@ -219,16 +219,16 @@ void Settings::CreateOptions() { mOptions[RSK_FISHSANITY_POND_COUNT] = Option::U8("Pond Fish Count", {NumOpts(0,17,1)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("FishsanityPondCount"), mOptionDescriptions[RSK_FISHSANITY_POND_COUNT], WidgetType::Slider, 0, true, IMFLAG_NONE); mOptions[RSK_FISHSANITY_AGE_SPLIT] = Option::Bool("Pond Age Split", CVAR_RANDOMIZER_SETTING("FishsanityAgeSplit"), mOptionDescriptions[RSK_FISHSANITY_AGE_SPLIT]); mOptions[RSK_SHUFFLE_MAPANDCOMPASS] = Option::U8("Maps/Compasses", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingMapsCompasses"), mOptionDescriptions[RSK_SHUFFLE_MAPANDCOMPASS], WidgetType::Combobox, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON); - mOptions[RSK_KEYSANITY] = Option::U8("Small Keys", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Keysanity"), mOptionDescriptions[RSK_KEYSANITY], WidgetType::Combobox, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON); + mOptions[RSK_KEYSANITY] = Option::U8("Small Key Shuffle", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Keysanity"), mOptionDescriptions[RSK_KEYSANITY], WidgetType::Combobox, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON); mOptions[RSK_GERUDO_KEYS] = Option::U8("Gerudo Fortress Keys", {"Vanilla", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GerudoKeys"), mOptionDescriptions[RSK_GERUDO_KEYS], WidgetType::Combobox, RO_GERUDO_KEYS_VANILLA); - mOptions[RSK_BOSS_KEYSANITY] = Option::U8("Boss Keys", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("BossKeysanity"), mOptionDescriptions[RSK_BOSS_KEYSANITY], WidgetType::Combobox, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON); + mOptions[RSK_BOSS_KEYSANITY] = Option::U8("Boss Key Shuffle", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("BossKeysanity"), mOptionDescriptions[RSK_BOSS_KEYSANITY], WidgetType::Combobox, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON); mOptions[RSK_GANONS_BOSS_KEY] = Option::U8("Ganon's Boss Key", {"Vanilla", "Own Dungeon", "Start With", "Any Dungeon", "Overworld", "Anywhere", "LACS-Vanilla", "LACS-Stones", "LACS-Medallions", "LACS-Rewards", "LACS-Dungeons", "LACS-Tokens", "100 GS Reward", "Triforce Hunt"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), mOptionDescriptions[RSK_GANONS_BOSS_KEY], WidgetType::Combobox, RO_GANON_BOSS_KEY_VANILLA); - mOptions[RSK_LACS_STONE_COUNT] = Option::U8("Stone Count", {NumOpts(0, 4)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsStoneCount"), "", WidgetType::Slider, 3, true); - mOptions[RSK_LACS_MEDALLION_COUNT] = Option::U8("Medallion Count", {NumOpts(0, 7)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsMedallionCount"), "", WidgetType::Slider, 6, true); - mOptions[RSK_LACS_REWARD_COUNT] = Option::U8("Reward Count", {NumOpts(0, 10)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardCount"), "", WidgetType::Slider, 9, true); - mOptions[RSK_LACS_DUNGEON_COUNT] = Option::U8("Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsDungeonCount"), "", WidgetType::Slider, 8, true); - mOptions[RSK_LACS_TOKEN_COUNT] = Option::U8("Token Count", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsTokenCount"), "", WidgetType::Slider, 100, true); - mOptions[RSK_LACS_OPTIONS] = Option::U8("LACS Reward Options", {"Standard Reward", "Greg as Reward", "Greg as Wildcard"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardOptions"), "", WidgetType::Combobox, RO_LACS_STANDARD_REWARD); + mOptions[RSK_LACS_STONE_COUNT] = Option::U8("GCBK Stone Count", {NumOpts(0, 4)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsStoneCount"), "", WidgetType::Slider, 3, true); + mOptions[RSK_LACS_MEDALLION_COUNT] = Option::U8("GCBK Medallion Count", {NumOpts(0, 7)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsMedallionCount"), "", WidgetType::Slider, 6, true); + mOptions[RSK_LACS_REWARD_COUNT] = Option::U8("GCBK Reward Count", {NumOpts(0, 10)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardCount"), "", WidgetType::Slider, 9, true); + mOptions[RSK_LACS_DUNGEON_COUNT] = Option::U8("GCBK Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsDungeonCount"), "", WidgetType::Slider, 8, true); + mOptions[RSK_LACS_TOKEN_COUNT] = Option::U8("GCBK Token Count", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsTokenCount"), "", WidgetType::Slider, 100, true); + mOptions[RSK_LACS_OPTIONS] = Option::U8("GCBK LACS Reward Options", {"Standard Reward", "Greg as Reward", "Greg as Wildcard"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardOptions"), "", WidgetType::Combobox, RO_LACS_STANDARD_REWARD); mOptions[RSK_KEYRINGS] = Option::U8("Key Rings", {"Off", "Random", "Count", "Selection"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRings"), mOptionDescriptions[RSK_KEYRINGS], WidgetType::Combobox, RO_KEYRINGS_OFF); mOptions[RSK_KEYRINGS_RANDOM_COUNT] = Option::U8("Keyring Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsRandomCount"), "", WidgetType::Slider, 8); mOptions[RSK_KEYRINGS_GERUDO_FORTRESS] = Option::U8("Gerudo Fortress Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGerudoFortress"), "", WidgetType::TristateCheckbox, 0); @@ -304,7 +304,7 @@ void Settings::CreateOptions() { mOptions[RSK_STARTING_NOCTURNE_OF_SHADOW] = Option::Bool("Start with Nocturne of Shadow", CVAR_RANDOMIZER_SETTING("StartingNocturneOfShadow"), "", IMFLAG_NONE); mOptions[RSK_STARTING_PRELUDE_OF_LIGHT] = Option::Bool("Start with Prelude of Light", CVAR_RANDOMIZER_SETTING("StartingPreludeOfLight")); mOptions[RSK_STARTING_SKULLTULA_TOKEN] = Option::U8("Gold Skulltula Tokens", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingSkulltulaToken"), "", WidgetType::Slider); - mOptions[RSK_STARTING_HEARTS] = Option::U8("Hearts", {NumOpts(1, 20)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingHearts"), "", WidgetType::Slider, 2); + mOptions[RSK_STARTING_HEARTS] = Option::U8("Starting Hearts", {NumOpts(1, 20)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingHearts"), "", WidgetType::Slider, 2); // TODO: Remainder of Starting Items mOptions[RSK_LOGIC_RULES] = Option::U8("Logic", {"Glitchless", "Glitched", "No Logic", "Vanilla"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LogicRules"), mOptionDescriptions[RSK_LOGIC_RULES], WidgetType::Combobox, RO_LOGIC_GLITCHLESS); mOptions[RSK_ALL_LOCATIONS_REACHABLE] = Option::Bool("All Locations Reachable", {"Off", "On"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("AllLocationsReachable"), mOptionDescriptions[RSK_ALL_LOCATIONS_REACHABLE], WidgetType::Checkbox, RO_GENERIC_ON); @@ -312,6 +312,8 @@ void Settings::CreateOptions() { mOptions[RSK_DAMAGE_MULTIPLIER] = Option::U8("Damage Multiplier", {"x1/2", "x1", "x2", "x4", "x8", "x16", "OHKO"}, OptionCategory::Setting, "", "", WidgetType::Slider, RO_DAMAGE_MULTIPLIER_DEFAULT); // clang-format on + StaticData::optionNameToEnum = PopulateOptionNameToEnum(); + mExcludeLocationsOptionsAreas.reserve(RCAREA_INVALID); mTrickOptions[RT_ACUTE_ANGLE_CLIP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_NONE, {Tricks::Tag::ADVANCED}, true, "Acute angle clip", "Enables locations requiring jumpslash clips through walls which meet at an acute angle."); @@ -684,7 +686,7 @@ void Settings::CreateOptions() { &mTrickOptions[RT_GANON_MQ_FIRE_TRIAL], &mTrickOptions[RT_GANON_MQ_SHADOW_TRIAL], &mTrickOptions[RT_GANON_MQ_LIGHT_TRIAL], - }, false); + }); for (int i = 0; i < RT_MAX; i++) { auto& trick = mTrickOptions[i]; if (!trick.GetName().empty()) { @@ -699,7 +701,7 @@ void Settings::CreateOptions() { &mOptions[RSK_DOOR_OF_TIME], &mOptions[RSK_ZORAS_FOUNTAIN], &mOptions[RSK_SLEEPING_WATERFALL], - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_WORLD_IMGUI] = OptionGroup::SubGroup("World Settings", { &mOptions[RSK_STARTING_AGE], &mOptions[RSK_GERUDO_FORTRESS], @@ -730,7 +732,7 @@ void Settings::CreateOptions() { &mOptions[RSK_TRIFORCE_HUNT], &mOptions[RSK_TRIFORCE_HUNT_PIECES_TOTAL], &mOptions[RSK_TRIFORCE_HUNT_PIECES_REQUIRED] - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_SHUFFLE_ENTRANCES_IMGUI] = OptionGroup::SubGroup("Shuffle Entrances", { &mOptions[RSK_SHUFFLE_DUNGEON_ENTRANCES], &mOptions[RSK_SHUFFLE_BOSS_ENTRANCES], @@ -747,12 +749,12 @@ void Settings::CreateOptions() { &mOptions[RSK_MIX_OVERWORLD_ENTRANCES], &mOptions[RSK_MIX_INTERIOR_ENTRANCES], &mOptions[RSK_MIX_GROTTO_ENTRANCES] - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_WORLD_IMGUI_TABLE] = OptionGroup::SubGroup("World", { &mOptionGroups[RSG_AREA_ACCESS_IMGUI], &mOptionGroups[RSG_WORLD_IMGUI], &mOptionGroups[RSG_SHUFFLE_ENTRANCES_IMGUI], - }, false, WidgetContainerType::TABLE); + }, WidgetContainerType::TABLE); mOptionGroups[RSG_SHUFFLE_ITEMS_IMGUI] = OptionGroup::SubGroup("Shuffle Items", { &mOptions[RSK_SHUFFLE_SONGS], &mOptions[RSK_SHUFFLE_TOKENS], @@ -769,7 +771,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_FISHING_POLE], &mOptions[RSK_SHUFFLE_DEKU_STICK_BAG], &mOptions[RSK_SHUFFLE_DEKU_NUT_BAG], - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_SHUFFLE_NPCS_IMGUI] = OptionGroup::SubGroup("Shuffle NPCs & Merchants", { &mOptions[RSK_SHOPSANITY], &mOptions[RSK_SHOPSANITY_COUNT], @@ -814,7 +816,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_ADULT_TRADE], &mOptions[RSK_SHUFFLE_100_GS_REWARD], &mOptions[RSK_SHUFFLE_BOSS_SOULS], - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_SHUFFLE_DUNGEON_ITEMS_IMGUI] = OptionGroup::SubGroup("Shuffle Dungeon Items", { &mOptions[RSK_SHUFFLE_DUNGEON_REWARDS], &mOptions[RSK_SHUFFLE_MAPANDCOMPASS], @@ -839,12 +841,12 @@ void Settings::CreateOptions() { &mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL], &mOptions[RSK_KEYRINGS_GTG], &mOptions[RSK_KEYRINGS_GANONS_CASTLE], - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_ITEMS_IMGUI_TABLE] = OptionGroup::SubGroup("Items", { &mOptionGroups[RSG_SHUFFLE_ITEMS_IMGUI], &mOptionGroups[RSG_SHUFFLE_NPCS_IMGUI], &mOptionGroups[RSG_SHUFFLE_DUNGEON_ITEMS_IMGUI], - }, false, WidgetContainerType::TABLE); + }, WidgetContainerType::TABLE); mOptionGroups[RSG_TIMESAVERS_IMGUI] = OptionGroup::SubGroup("Timesavers", { &mOptions[RSK_CUCCO_COUNT], &mOptions[RSK_BIG_POE_COUNT], @@ -853,14 +855,14 @@ void Settings::CreateOptions() { &mOptions[RSK_SKIP_EPONA_RACE], &mOptions[RSK_COMPLETE_MASK_QUEST], &mOptions[RSK_SKIP_SCARECROWS_SONG] - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_ITEM_POOL_HINTS_IMGUI] = OptionGroup::SubGroup("", { &mOptions[RSK_ITEM_POOL], &mOptions[RSK_ICE_TRAPS], &mOptions[RSK_GOSSIP_STONE_HINTS], &mOptions[RSK_HINT_CLARITY], &mOptions[RSK_HINT_DISTRIBUTION], - }, false, WidgetContainerType::SECTION); + }, WidgetContainerType::SECTION); mOptionGroups[RSG_EXTRA_HINTS_IMGUI] = OptionGroup::SubGroup("Extra Hints", { &mOptions[RSK_TOT_ALTAR_HINT], &mOptions[RSK_GANONDORF_HINT], @@ -887,11 +889,11 @@ void Settings::CreateOptions() { &mOptions[RSK_KAK_50_SKULLS_HINT], &mOptions[RSK_KAK_100_SKULLS_HINT], &mOptions[RSK_MASK_SHOP_HINT] - }, false, WidgetContainerType::SECTION, "This setting adds some hints at locations other than Gossip Stones."); + }, WidgetContainerType::SECTION, "This setting adds some hints at locations other than Gossip Stones."); mOptionGroups[RSG_ITEM_POOL_HINTS_IMGUI_COLUMN] = OptionGroup::SubGroup("Item Pool & Hints", std::initializer_list{ &mOptionGroups[RSG_ITEM_POOL_HINTS_IMGUI], &mOptionGroups[RSG_EXTRA_HINTS_IMGUI], - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_ADDITIONAL_FEATURES_IMGUI] = OptionGroup::SubGroup("Additional Features", { &mOptions[RSK_FULL_WALLETS], &mOptions[RSK_BOMBCHUS_IN_LOGIC], @@ -900,25 +902,25 @@ void Settings::CreateOptions() { &mOptions[RSK_SUNLIGHT_ARROWS], &mOptions[RSK_INFINITE_UPGRADES], &mOptions[RSK_SKELETON_KEY], - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_GAMEPLAY_IMGUI_TABLE] = OptionGroup::SubGroup("Gameplay", { &mOptionGroups[RSG_TIMESAVERS_IMGUI], &mOptionGroups[RSG_ITEM_POOL_HINTS_IMGUI_COLUMN], &mOptionGroups[RSG_ADDITIONAL_FEATURES_IMGUI] - }, false, WidgetContainerType::TABLE); + }, WidgetContainerType::TABLE); mOptionGroups[RSG_STARTING_EQUIPMENT_IMGUI] = OptionGroup::SubGroup("Starting Equipment", { &mOptions[RSK_LINKS_POCKET], &mOptions[RSK_STARTING_KOKIRI_SWORD], &mOptions[RSK_STARTING_MASTER_SWORD], &mOptions[RSK_STARTING_DEKU_SHIELD] - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_STARTING_ITEMS_IMGUI] = OptionGroup::SubGroup("Starting Items", { &mOptions[RSK_STARTING_OCARINA], &mOptions[RSK_STARTING_STICKS], &mOptions[RSK_STARTING_NUTS], &mOptions[RSK_STARTING_SKULLTULA_TOKEN], &mOptions[RSK_STARTING_HEARTS], - }, false, WidgetContainerType::COLUMN); + }, WidgetContainerType::COLUMN); mOptionGroups[RSG_STARTING_NORMAL_SONGS_IMGUI] = OptionGroup::SubGroup("Normal Songs", { &mOptions[RSK_STARTING_ZELDAS_LULLABY], &mOptions[RSK_STARTING_EPONAS_SONG], @@ -926,7 +928,7 @@ void Settings::CreateOptions() { &mOptions[RSK_STARTING_SUNS_SONG], &mOptions[RSK_STARTING_SONG_OF_TIME], &mOptions[RSK_STARTING_SONG_OF_STORMS], - }, false, WidgetContainerType::SECTION); + }, WidgetContainerType::SECTION); mOptionGroups[RSG_STARTING_WARP_SONGS_IMGUI] = OptionGroup::SubGroup("Warp Songs", { &mOptions[RSK_STARTING_MINUET_OF_FOREST], &mOptions[RSK_STARTING_BOLERO_OF_FIRE], @@ -934,16 +936,16 @@ void Settings::CreateOptions() { &mOptions[RSK_STARTING_REQUIEM_OF_SPIRIT], &mOptions[RSK_STARTING_NOCTURNE_OF_SHADOW], &mOptions[RSK_STARTING_PRELUDE_OF_LIGHT] - }, false, WidgetContainerType::SECTION); + }, WidgetContainerType::SECTION); mOptionGroups[RSG_STARTING_SONGS_IMGUI] = OptionGroup::SubGroup("Starting Songs", std::initializer_list({ &mOptionGroups[RSG_STARTING_NORMAL_SONGS_IMGUI], &mOptionGroups[RSG_STARTING_WARP_SONGS_IMGUI], - }), false, WidgetContainerType::COLUMN); + }), WidgetContainerType::COLUMN); mOptionGroups[RSG_STARTING_INVENTORY_IMGUI_TABLE] = OptionGroup::SubGroup("Starting Inventory", { &mOptionGroups[RSG_STARTING_EQUIPMENT_IMGUI], &mOptionGroups[RSG_STARTING_ITEMS_IMGUI], &mOptionGroups[RSG_STARTING_SONGS_IMGUI] - }, false, WidgetContainerType::TABLE); + }, WidgetContainerType::TABLE); mOptionGroups[RSG_OPEN] = OptionGroup("Open Settings", { &mOptions[RSK_FOREST], &mOptions[RSK_KAK_GATE], @@ -1089,7 +1091,7 @@ void Settings::CreateOptions() { &mOptions[RSK_STARTING_OCARINA], &mOptions[RSK_STARTING_KOKIRI_SWORD], &mOptions[RSK_STARTING_DEKU_SHIELD] - }, false); + }); mOptionGroups[RSG_STARTING_SONGS] = OptionGroup::SubGroup("Ocarina Songs", { &mOptions[RSK_STARTING_ZELDAS_LULLABY], &mOptions[RSK_STARTING_EPONAS_SONG], @@ -1104,19 +1106,19 @@ void Settings::CreateOptions() { &mOptions[RSK_STARTING_REQUIEM_OF_SPIRIT], &mOptions[RSK_STARTING_NOCTURNE_OF_SHADOW], &mOptions[RSK_STARTING_PRELUDE_OF_LIGHT], - }, false); + }); mOptionGroups[RSG_STARTING_OTHER] = OptionGroup::SubGroup("Other", { &mOptions[RSK_STARTING_STICKS], &mOptions[RSK_STARTING_NUTS], &mOptions[RSK_FULL_WALLETS], &mOptions[RSK_STARTING_SKULLTULA_TOKEN], &mOptions[RSK_STARTING_HEARTS], - }, false); + }); mOptionGroups[RSG_STARTING_INVENTORY] = OptionGroup("Starting Inventory", { &mOptionGroups[RSG_STARTING_ITEMS], &mOptionGroups[RSG_STARTING_SONGS], &mOptionGroups[RSG_STARTING_OTHER], - }, OptionGroupType::DEFAULT, false); + }, OptionGroupType::DEFAULT); mOptionGroups[RSG_TIMESAVERS] = OptionGroup("Timesaver Settings", { &mOptions[RSK_SKIP_CHILD_STEALTH], &mOptions[RSK_SKIP_CHILD_ZELDA], @@ -1168,38 +1170,38 @@ void Settings::CreateOptions() { &mOptions[RSK_ICE_TRAPS] })); // TODO: Progressive Goron Sword, Remove Double Defense - mOptionGroups[RSG_EXCLUDES_KOKIRI_FOREST] = OptionGroup::SubGroup("Kokiri Forest", mExcludeLocationsOptionsAreas[RCAREA_KOKIRI_FOREST], false); - mOptionGroups[RSG_EXCLUDES_LOST_WOODS] = OptionGroup::SubGroup("Lost Woods", mExcludeLocationsOptionsAreas[RCAREA_LOST_WOODS], false); - mOptionGroups[RSG_EXCLUDES_SACRED_FOREST_MEADOW] = OptionGroup::SubGroup("Sacred Forest Meadow", mExcludeLocationsOptionsAreas[RCAREA_SACRED_FOREST_MEADOW], false); - mOptionGroups[RSG_EXCLUDES_DEKU_TREE] = OptionGroup::SubGroup("Deku Tree", mExcludeLocationsOptionsAreas[RCAREA_DEKU_TREE], false); - mOptionGroups[RSG_EXCLUDES_FOREST_TEMPLE] = OptionGroup::SubGroup("Forest Temple", mExcludeLocationsOptionsAreas[RCAREA_FOREST_TEMPLE], false); - mOptionGroups[RSG_EXCLUDES_KAKARIKO_VILLAGE] = OptionGroup::SubGroup("Kakariko Village", mExcludeLocationsOptionsAreas[RCAREA_KAKARIKO_VILLAGE], false); - mOptionGroups[RSG_EXCLUDES_GRAVEYARD] = OptionGroup::SubGroup("Graveyard", mExcludeLocationsOptionsAreas[RCAREA_GRAVEYARD], false); - mOptionGroups[RSG_EXCLUDES_BOTTOM_OF_THE_WELL] = OptionGroup::SubGroup("Bottom of the Well", mExcludeLocationsOptionsAreas[RCAREA_BOTTOM_OF_THE_WELL], false); - mOptionGroups[RSG_EXCLUDES_SHADOW_TEMPLE] = OptionGroup::SubGroup("Shadow Temple", mExcludeLocationsOptionsAreas[RCAREA_SHADOW_TEMPLE], false); - mOptionGroups[RSG_EXCLUDES_DEATH_MOUNTAIN_TRAIL] = OptionGroup::SubGroup("Death Mountain Trail", mExcludeLocationsOptionsAreas[RCAREA_DEATH_MOUNTAIN_TRAIL], false); - mOptionGroups[RSG_EXCLUDES_DEATH_MOUNTAIN_CRATER] = OptionGroup::SubGroup("Death Mountain Crater", mExcludeLocationsOptionsAreas[RCAREA_DEATH_MOUNTAIN_CRATER], false); - mOptionGroups[RSG_EXCLUDES_GORON_CITY] = OptionGroup::SubGroup("Goron City", mExcludeLocationsOptionsAreas[RCAREA_GORON_CITY], false); - mOptionGroups[RSG_EXCLUDES_DODONGOS_CAVERN] = OptionGroup::SubGroup("Dodongo's Cavern", mExcludeLocationsOptionsAreas[RCAREA_DODONGOS_CAVERN], false); - mOptionGroups[RSG_EXCLUDES_FIRE_TEMPLE] = OptionGroup::SubGroup("Fire Temple", mExcludeLocationsOptionsAreas[RCAREA_FIRE_TEMPLE], false); - mOptionGroups[RSG_EXCLUDES_ZORAS_RIVER] = OptionGroup::SubGroup("Zora's River", mExcludeLocationsOptionsAreas[RCAREA_ZORAS_RIVER], false); - mOptionGroups[RSG_EXCLUDES_ZORAS_DOMAIN] = OptionGroup::SubGroup("Zora's Domain", mExcludeLocationsOptionsAreas[RCAREA_ZORAS_DOMAIN], false); - mOptionGroups[RSG_EXCLUDES_ZORAS_FOUNTAIN] = OptionGroup::SubGroup("Zora's Fountain", mExcludeLocationsOptionsAreas[RCAREA_ZORAS_FOUNTAIN], false); - mOptionGroups[RSG_EXCLUDES_JABU_JABU] = OptionGroup::SubGroup("Jabu Jabu's Belly", mExcludeLocationsOptionsAreas[RCAREA_JABU_JABUS_BELLY], false); - mOptionGroups[RSG_EXCLUDES_ICE_CAVERN] = OptionGroup::SubGroup("Ice Cavern", mExcludeLocationsOptionsAreas[RCAREA_ICE_CAVERN], false); - mOptionGroups[RSG_EXCLUDES_HYRULE_FIELD] = OptionGroup::SubGroup("Hyrule Field", mExcludeLocationsOptionsAreas[RCAREA_HYRULE_FIELD], false); - mOptionGroups[RSG_EXCLUDES_LON_LON_RANCH] = OptionGroup::SubGroup("Lon Lon Ranch", mExcludeLocationsOptionsAreas[RCAREA_LON_LON_RANCH], false); - mOptionGroups[RSG_EXCLUDES_LAKE_HYLIA] = OptionGroup::SubGroup("Lake Hylia", mExcludeLocationsOptionsAreas[RCAREA_LAKE_HYLIA], false); - mOptionGroups[RSG_EXCLUDES_WATER_TEMPLE] = OptionGroup::SubGroup("Water Temple", mExcludeLocationsOptionsAreas[RCAREA_WATER_TEMPLE], false); - mOptionGroups[RSG_EXCLUDES_GERUDO_VALLEY] = OptionGroup::SubGroup("Gerudo Valley", mExcludeLocationsOptionsAreas[RCAREA_GERUDO_VALLEY], false); - mOptionGroups[RSG_EXCLUDES_GERUDO_FORTRESS] = OptionGroup::SubGroup("Gerudo Fortress", mExcludeLocationsOptionsAreas[RCAREA_GERUDO_FORTRESS], false); - mOptionGroups[RSG_EXCLUDES_HAUNTED_WASTELAND] = OptionGroup::SubGroup("Haunted Wasteland", mExcludeLocationsOptionsAreas[RCAREA_WASTELAND], false); - mOptionGroups[RSG_EXCLUDES_DESERT_COLOSSUS] = OptionGroup::SubGroup("Desert Colossus", mExcludeLocationsOptionsAreas[RCAREA_DESERT_COLOSSUS], false); - mOptionGroups[RSG_EXCLUDES_GERUDO_TRAINING_GROUNDS] = OptionGroup::SubGroup("Gerudo Training Grounds", mExcludeLocationsOptionsAreas[RCAREA_GERUDO_TRAINING_GROUND], false); - mOptionGroups[RSG_EXCLUDES_SPIRIT_TEMPLE] = OptionGroup::SubGroup("Spirit Temple", mExcludeLocationsOptionsAreas[RCAREA_SPIRIT_TEMPLE], false); - mOptionGroups[RSG_EXCLUDES_HYRULE_CASTLE] = OptionGroup::SubGroup("Hyrule Castle", mExcludeLocationsOptionsAreas[RCAREA_HYRULE_CASTLE], false); - mOptionGroups[RSG_EXCLUDES_MARKET] = OptionGroup::SubGroup("Market", mExcludeLocationsOptionsAreas[RCAREA_MARKET], false); - mOptionGroups[RSG_EXCLUDES_GANONS_CASTLE] = OptionGroup::SubGroup("Ganon's Castle", mExcludeLocationsOptionsAreas[RCAREA_GANONS_CASTLE], false); + mOptionGroups[RSG_EXCLUDES_KOKIRI_FOREST] = OptionGroup::SubGroup("Kokiri Forest", mExcludeLocationsOptionsAreas[RCAREA_KOKIRI_FOREST]); + mOptionGroups[RSG_EXCLUDES_LOST_WOODS] = OptionGroup::SubGroup("Lost Woods", mExcludeLocationsOptionsAreas[RCAREA_LOST_WOODS]); + mOptionGroups[RSG_EXCLUDES_SACRED_FOREST_MEADOW] = OptionGroup::SubGroup("Sacred Forest Meadow", mExcludeLocationsOptionsAreas[RCAREA_SACRED_FOREST_MEADOW]); + mOptionGroups[RSG_EXCLUDES_DEKU_TREE] = OptionGroup::SubGroup("Deku Tree", mExcludeLocationsOptionsAreas[RCAREA_DEKU_TREE]); + mOptionGroups[RSG_EXCLUDES_FOREST_TEMPLE] = OptionGroup::SubGroup("Forest Temple", mExcludeLocationsOptionsAreas[RCAREA_FOREST_TEMPLE]); + mOptionGroups[RSG_EXCLUDES_KAKARIKO_VILLAGE] = OptionGroup::SubGroup("Kakariko Village", mExcludeLocationsOptionsAreas[RCAREA_KAKARIKO_VILLAGE]); + mOptionGroups[RSG_EXCLUDES_GRAVEYARD] = OptionGroup::SubGroup("Graveyard", mExcludeLocationsOptionsAreas[RCAREA_GRAVEYARD]); + mOptionGroups[RSG_EXCLUDES_BOTTOM_OF_THE_WELL] = OptionGroup::SubGroup("Bottom of the Well", mExcludeLocationsOptionsAreas[RCAREA_BOTTOM_OF_THE_WELL]); + mOptionGroups[RSG_EXCLUDES_SHADOW_TEMPLE] = OptionGroup::SubGroup("Shadow Temple", mExcludeLocationsOptionsAreas[RCAREA_SHADOW_TEMPLE]); + mOptionGroups[RSG_EXCLUDES_DEATH_MOUNTAIN_TRAIL] = OptionGroup::SubGroup("Death Mountain Trail", mExcludeLocationsOptionsAreas[RCAREA_DEATH_MOUNTAIN_TRAIL]); + mOptionGroups[RSG_EXCLUDES_DEATH_MOUNTAIN_CRATER] = OptionGroup::SubGroup("Death Mountain Crater", mExcludeLocationsOptionsAreas[RCAREA_DEATH_MOUNTAIN_CRATER]); + mOptionGroups[RSG_EXCLUDES_GORON_CITY] = OptionGroup::SubGroup("Goron City", mExcludeLocationsOptionsAreas[RCAREA_GORON_CITY]); + mOptionGroups[RSG_EXCLUDES_DODONGOS_CAVERN] = OptionGroup::SubGroup("Dodongo's Cavern", mExcludeLocationsOptionsAreas[RCAREA_DODONGOS_CAVERN]); + mOptionGroups[RSG_EXCLUDES_FIRE_TEMPLE] = OptionGroup::SubGroup("Fire Temple", mExcludeLocationsOptionsAreas[RCAREA_FIRE_TEMPLE]); + mOptionGroups[RSG_EXCLUDES_ZORAS_RIVER] = OptionGroup::SubGroup("Zora's River", mExcludeLocationsOptionsAreas[RCAREA_ZORAS_RIVER]); + mOptionGroups[RSG_EXCLUDES_ZORAS_DOMAIN] = OptionGroup::SubGroup("Zora's Domain", mExcludeLocationsOptionsAreas[RCAREA_ZORAS_DOMAIN]); + mOptionGroups[RSG_EXCLUDES_ZORAS_FOUNTAIN] = OptionGroup::SubGroup("Zora's Fountain", mExcludeLocationsOptionsAreas[RCAREA_ZORAS_FOUNTAIN]); + mOptionGroups[RSG_EXCLUDES_JABU_JABU] = OptionGroup::SubGroup("Jabu Jabu's Belly", mExcludeLocationsOptionsAreas[RCAREA_JABU_JABUS_BELLY]); + mOptionGroups[RSG_EXCLUDES_ICE_CAVERN] = OptionGroup::SubGroup("Ice Cavern", mExcludeLocationsOptionsAreas[RCAREA_ICE_CAVERN]); + mOptionGroups[RSG_EXCLUDES_HYRULE_FIELD] = OptionGroup::SubGroup("Hyrule Field", mExcludeLocationsOptionsAreas[RCAREA_HYRULE_FIELD]); + mOptionGroups[RSG_EXCLUDES_LON_LON_RANCH] = OptionGroup::SubGroup("Lon Lon Ranch", mExcludeLocationsOptionsAreas[RCAREA_LON_LON_RANCH]); + mOptionGroups[RSG_EXCLUDES_LAKE_HYLIA] = OptionGroup::SubGroup("Lake Hylia", mExcludeLocationsOptionsAreas[RCAREA_LAKE_HYLIA]); + mOptionGroups[RSG_EXCLUDES_WATER_TEMPLE] = OptionGroup::SubGroup("Water Temple", mExcludeLocationsOptionsAreas[RCAREA_WATER_TEMPLE]); + mOptionGroups[RSG_EXCLUDES_GERUDO_VALLEY] = OptionGroup::SubGroup("Gerudo Valley", mExcludeLocationsOptionsAreas[RCAREA_GERUDO_VALLEY]); + mOptionGroups[RSG_EXCLUDES_GERUDO_FORTRESS] = OptionGroup::SubGroup("Gerudo Fortress", mExcludeLocationsOptionsAreas[RCAREA_GERUDO_FORTRESS]); + mOptionGroups[RSG_EXCLUDES_HAUNTED_WASTELAND] = OptionGroup::SubGroup("Haunted Wasteland", mExcludeLocationsOptionsAreas[RCAREA_WASTELAND]); + mOptionGroups[RSG_EXCLUDES_DESERT_COLOSSUS] = OptionGroup::SubGroup("Desert Colossus", mExcludeLocationsOptionsAreas[RCAREA_DESERT_COLOSSUS]); + mOptionGroups[RSG_EXCLUDES_GERUDO_TRAINING_GROUNDS] = OptionGroup::SubGroup("Gerudo Training Grounds", mExcludeLocationsOptionsAreas[RCAREA_GERUDO_TRAINING_GROUND]); + mOptionGroups[RSG_EXCLUDES_SPIRIT_TEMPLE] = OptionGroup::SubGroup("Spirit Temple", mExcludeLocationsOptionsAreas[RCAREA_SPIRIT_TEMPLE]); + mOptionGroups[RSG_EXCLUDES_HYRULE_CASTLE] = OptionGroup::SubGroup("Hyrule Castle", mExcludeLocationsOptionsAreas[RCAREA_HYRULE_CASTLE]); + mOptionGroups[RSG_EXCLUDES_MARKET] = OptionGroup::SubGroup("Market", mExcludeLocationsOptionsAreas[RCAREA_MARKET]); + mOptionGroups[RSG_EXCLUDES_GANONS_CASTLE] = OptionGroup::SubGroup("Ganon's Castle", mExcludeLocationsOptionsAreas[RCAREA_GANONS_CASTLE]); mOptionGroups[RSG_EXCLUDES] = OptionGroup::SubGroup("Exclude Locations", { &mOptionGroups[RSG_EXCLUDES_KOKIRI_FOREST], &mOptionGroups[RSG_EXCLUDES_LOST_WOODS], @@ -1233,7 +1235,7 @@ void Settings::CreateOptions() { &mOptionGroups[RSG_EXCLUDES_HYRULE_CASTLE], &mOptionGroups[RSG_EXCLUDES_MARKET], &mOptionGroups[RSG_EXCLUDES_GANONS_CASTLE], - }, false); + }); mOptionGroups[RSG_DETAILED_LOGIC] = OptionGroup("Detailed Logic Settings", { &mOptionGroups[RSG_LOGIC], &mOptionGroups[RSG_TRICKS], @@ -1260,210 +1262,14 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_100_GS_REWARD], &mOptions[RSK_GOSSIP_STONE_HINTS], }; +} -//RANDOTODO refactor OptionGroups so we can actually make maintainable enum conversion. - mSpoilerfileSettingNameToEnum = { - { "Logic Options:Logic", RSK_LOGIC_RULES }, - { "Open Settings:Forest", RSK_FOREST }, - { "Open Settings:Kakariko Gate", RSK_KAK_GATE }, - { "Open Settings:Door of Time", RSK_DOOR_OF_TIME }, - { "Open Settings:Zora's Fountain", RSK_ZORAS_FOUNTAIN }, - { "Open Settings:Sleeping Waterfall", RSK_SLEEPING_WATERFALL }, - { "World Settings:Starting Age", RSK_STARTING_AGE }, - { "Open Settings:Gerudo Fortress", RSK_GERUDO_FORTRESS }, - { "Open Settings:Rainbow Bridge", RSK_RAINBOW_BRIDGE }, - { "Open Settings:Stone Count", RSK_RAINBOW_BRIDGE_STONE_COUNT }, - { "Open Settings:Medallion Count", RSK_RAINBOW_BRIDGE_MEDALLION_COUNT }, - { "Open Settings:Reward Count", RSK_RAINBOW_BRIDGE_REWARD_COUNT }, - { "Open Settings:Dungeon Count", RSK_RAINBOW_BRIDGE_DUNGEON_COUNT }, - { "Open Settings:Token Count", RSK_RAINBOW_BRIDGE_TOKEN_COUNT }, - { "Open Settings:Bridge Reward Options", RSK_BRIDGE_OPTIONS }, - { "Open Settings:Ganon's Trials", RSK_GANONS_TRIALS }, - { "Open Settings:Ganon's Trials Count", RSK_TRIAL_COUNT }, - { "Start with Ocarina", RSK_STARTING_OCARINA }, - { "Shuffle Settings:Shuffle Ocarinas", RSK_SHUFFLE_OCARINA }, - { "Shuffle Settings:Shuffle Ocarina Buttons", RSK_SHUFFLE_OCARINA_BUTTONS }, - { "Shuffle Settings:Shuffle Swim", RSK_SHUFFLE_SWIM }, - { "Start with Deku Shield", RSK_STARTING_DEKU_SHIELD }, - { "Start with Kokiri Sword", RSK_STARTING_KOKIRI_SWORD }, - { "Start with Master Sword", RSK_STARTING_MASTER_SWORD }, - { "Start with Zelda's Lullaby", RSK_STARTING_ZELDAS_LULLABY }, - { "Start with Epona's Song", RSK_STARTING_EPONAS_SONG }, - { "Start with Saria's Song", RSK_STARTING_SARIAS_SONG }, - { "Start with Sun's Song", RSK_STARTING_SUNS_SONG }, - { "Start with Song of Time", RSK_STARTING_SONG_OF_TIME }, - { "Start with Song of Storms", RSK_STARTING_SONG_OF_STORMS }, - { "Start with Minuet of Forest", RSK_STARTING_MINUET_OF_FOREST }, - { "Start with Bolero of Fire", RSK_STARTING_BOLERO_OF_FIRE }, - { "Start with Serenade of Water", RSK_STARTING_SERENADE_OF_WATER }, - { "Start with Requiem of Spirit", RSK_STARTING_REQUIEM_OF_SPIRIT }, - { "Start with Nocturne of Shadow", RSK_STARTING_NOCTURNE_OF_SHADOW }, - { "Start with Prelude of Light", RSK_STARTING_PRELUDE_OF_LIGHT }, - { "Shuffle Settings:Shuffle Kokiri Sword", RSK_SHUFFLE_KOKIRI_SWORD }, - { "Shuffle Settings:Shuffle Master Sword", RSK_SHUFFLE_MASTER_SWORD }, - { "Shuffle Settings:Shuffle Child's Wallet", RSK_SHUFFLE_CHILD_WALLET }, - { "Shuffle Settings:Include Tycoon Wallet", RSK_INCLUDE_TYCOON_WALLET }, - { "Shuffle Settings:Shuffle Dungeon Rewards", RSK_SHUFFLE_DUNGEON_REWARDS }, - { "Shuffle Settings:Shuffle Songs", RSK_SHUFFLE_SONGS }, - { "Shuffle Settings:Tokensanity", RSK_SHUFFLE_TOKENS }, - { "Shuffle Settings:Shopsanity", RSK_SHOPSANITY }, - { "Shuffle Settings:Shopsanity Specific Count", RSK_SHOPSANITY_COUNT }, - { "Shuffle Settings:Shopsanity Prices", RSK_SHOPSANITY_PRICES }, - { "Shuffle Settings:Shopsanity Fixed Amount", RSK_SHOPSANITY_PRICES_FIXED_PRICE }, - { "Shuffle Settings:Shopsanity Range 1", RSK_SHOPSANITY_PRICES_RANGE_1 }, - { "Shuffle Settings:Shopsanity Range 2", RSK_SHOPSANITY_PRICES_RANGE_2 }, - { "Shuffle Settings:Shopsanity No Wallet Weight", RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT }, - { "Shuffle Settings:Shopsanity Child Wallet Weight", RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT }, - { "Shuffle Settings:Shopsanity Adult Wallet Weight", RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT }, - { "Shuffle Settings:Shopsanity Giants Wallet Weight", RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT }, - { "Shuffle Settings:Shopsanity Tycoon Wallet Weight", RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT }, - { "Shuffle Settings:Shopsanity Affordable Prices", RSK_SHOPSANITY_PRICES_AFFORDABLE }, - { "Shuffle Settings:Scrub Shuffle", RSK_SHUFFLE_SCRUBS }, - { "Shuffle Settings:Scrubs Prices", RSK_SCRUBS_PRICES }, - { "Shuffle Settings:Scrubs Fixed Amount", RSK_SCRUBS_PRICES_FIXED_PRICE }, - { "Shuffle Settings:Scrubs Range 1", RSK_SCRUBS_PRICES_RANGE_1 }, - { "Shuffle Settings:Scrubs Range 2", RSK_SCRUBS_PRICES_RANGE_2 }, - { "Shuffle Settings:Scrubs No Wallet Weight", RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT }, - { "Shuffle Settings:Scrubs Child Wallet Weight", RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT }, - { "Shuffle Settings:Scrubs Adult Wallet Weight", RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT }, - { "Shuffle Settings:Scrubs Giants Wallet Weight", RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT }, - { "Shuffle Settings:Scrubs Tycoon Wallet Weight", RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT }, - { "Shuffle Settings:Scrubs Affordable Prices", RSK_SCRUBS_PRICES_AFFORDABLE }, - { "Shuffle Settings:Beehive Shuffle", RSK_SHUFFLE_BEEHIVES }, - { "Shuffle Settings:Shuffle Cows", RSK_SHUFFLE_COWS }, - { "Shuffle Settings:Shuffle Weird Egg", RSK_SHUFFLE_WEIRD_EGG }, - { "Shuffle Settings:Shuffle Gerudo Membership Card", RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD }, - { "Shuffle Settings:Shuffle Frog Song Rupees", RSK_SHUFFLE_FROG_SONG_RUPEES }, - { "Item Pool Settings:Item Pool", RSK_ITEM_POOL }, - { "Item Pool Settings:Ice Traps", RSK_ICE_TRAPS }, - { "Miscellaneous Settings:Gossip Stone Hints", RSK_GOSSIP_STONE_HINTS }, - { "Miscellaneous Settings:ToT Altar Hint", RSK_TOT_ALTAR_HINT }, - { "Miscellaneous Settings:Ganondorf Hint", RSK_GANONDORF_HINT }, - { "Miscellaneous Settings:Sheik Light Arrow Hint", RSK_SHEIK_LA_HINT }, - { "Miscellaneous Settings:Dampe's Diary Hint", RSK_DAMPES_DIARY_HINT }, - { "Miscellaneous Settings:Greg the Rupee Hint", RSK_GREG_HINT }, - { "Miscellaneous Settings:Hyrule Loach Hint", RSK_LOACH_HINT }, - { "Miscellaneous Settings:Saria's Hint", RSK_SARIA_HINT }, - { "Miscellaneous Settings:Frog Ocarina Game Hint", RSK_FROGS_HINT }, - { "Miscellaneous Settings:Ocarina of Time Hint", RSK_OOT_HINT }, - { "Miscellaneous Settings:10 GS Hint", RSK_KAK_10_SKULLS_HINT }, - { "Miscellaneous Settings:20 GS Hint", RSK_KAK_20_SKULLS_HINT }, - { "Miscellaneous Settings:30 GS Hint", RSK_KAK_30_SKULLS_HINT }, - { "Miscellaneous Settings:40 GS Hint", RSK_KAK_40_SKULLS_HINT }, - { "Miscellaneous Settings:50 GS Hint", RSK_KAK_50_SKULLS_HINT }, - { "Miscellaneous Settings:100 GS Hint", RSK_KAK_100_SKULLS_HINT }, - { "Miscellaneous Settings:Mask Shop Hint", RSK_MASK_SHOP_HINT }, - { "Miscellaneous Settings:Biggoron's Hint", RSK_BIGGORON_HINT }, - { "Miscellaneous Settings:Big Poes Hint", RSK_BIG_POES_HINT }, - { "Miscellaneous Settings:Chickens Hint", RSK_CHICKENS_HINT }, - { "Miscellaneous Settings:Malon Hint", RSK_MALON_HINT }, - { "Miscellaneous Settings:Horseback Archery Hint", RSK_HBA_HINT }, - { "Miscellaneous Settings:Warp Song Hints", RSK_WARP_SONG_HINTS }, - { "Miscellaneous Settings:Scrub Hint Text", RSK_SCRUB_TEXT_HINT }, - { "Miscellaneous Settings:Merchant Hint Text", RSK_MERCHANT_TEXT_HINT }, - { "Miscellaneous Settings:Fishing Pole Hint", RSK_FISHING_POLE_HINT }, - { "Miscellaneous Settings:Hint Clarity", RSK_HINT_CLARITY }, - { "Miscellaneous Settings:Hint Distribution", RSK_HINT_DISTRIBUTION }, - { "Shuffle Dungeon Items:Maps/Compasses", RSK_SHUFFLE_MAPANDCOMPASS }, - { "Shuffle Dungeon Items:Small Keys", RSK_KEYSANITY }, - { "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 }, - { "Timesaver Settings:Skip Child Stealth", RSK_SKIP_CHILD_STEALTH }, - { "Timesaver Settings:Skip Child Zelda", RSK_SKIP_CHILD_ZELDA }, - { "Start with Sticks", RSK_STARTING_STICKS }, - { "Start with Nuts", RSK_STARTING_NUTS }, - { "Full Wallets", RSK_FULL_WALLETS }, - { "Timesaver Settings:Cuccos to return", RSK_CUCCO_COUNT }, - { "Timesaver Settings:Big Poe Target Count", RSK_BIG_POE_COUNT }, - { "Timesaver Settings:Skip Epona Race", RSK_SKIP_EPONA_RACE }, - { "Timesaver Settings:Complete Mask Quest", RSK_COMPLETE_MASK_QUEST }, - { "Timesaver Settings:Skip Scarecrow's Song", RSK_SKIP_SCARECROWS_SONG }, - { "Timesaver Settings:Enable Glitch-Useful Cutscenes", RSK_ENABLE_GLITCH_CUTSCENES }, - { "Logic Options:Night Skulltula's Expect Sun's Song", RSK_SKULLS_SUNS_SONG }, - { "Shuffle Settings:Shuffle Adult Trade", RSK_SHUFFLE_ADULT_TRADE }, - { "Shuffle Settings:Shuffle Merchants", RSK_SHUFFLE_MERCHANTS }, - { "Shuffle Settings:Merchant Prices", RSK_MERCHANT_PRICES }, - { "Shuffle Settings:Merchant Fixed Amount", RSK_MERCHANT_PRICES_FIXED_PRICE }, - { "Shuffle Settings:Merchant Range 1", RSK_MERCHANT_PRICES_RANGE_1 }, - { "Shuffle Settings:Merchant Range 2", RSK_MERCHANT_PRICES_RANGE_2 }, - { "Shuffle Settings:Merchant No Wallet Weight", RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT }, - { "Shuffle Settings:Merchant Child Wallet Weight", RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT }, - { "Shuffle Settings:Merchant Adult Wallet Weight", RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT }, - { "Shuffle Settings:Merchant Giants Wallet Weight", RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT }, - { "Shuffle Settings:Merchant Tycoon Wallet Weight", RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT }, - { "Shuffle Settings:Merchant Affordable Prices", RSK_MERCHANT_PRICES_AFFORDABLE }, - { "Miscellaneous Settings:Blue Fire Arrows", RSK_BLUE_FIRE_ARROWS }, - { "Miscellaneous Settings:Sunlight Arrows", RSK_SUNLIGHT_ARROWS }, - // TODO: Ammo Drop settings - { "World Settings:Bombchu Drops", RSK_ENABLE_BOMBCHU_DROPS }, - { "World Settings:Bombchus in Logic", RSK_BOMBCHUS_IN_LOGIC }, - { "Shuffle Settings:Link's Pocket", RSK_LINKS_POCKET }, - { "World Settings:MQ Dungeon Setting", RSK_MQ_DUNGEON_RANDOM }, - { "World Settings:MQ Dungeon Count", RSK_MQ_DUNGEON_COUNT }, - { "World Settings:Set Dungeon Quests", RSK_MQ_DUNGEON_SET }, - { "Shuffle Dungeon Quest:Deku Tree", RSK_MQ_DEKU_TREE }, - { "Shuffle Dungeon Quest:Dodongo's Cavern", RSK_MQ_DODONGOS_CAVERN }, - { "Shuffle Dungeon Quest:Jabu-Jabu's Belly", RSK_MQ_JABU_JABU }, - { "Shuffle Dungeon Quest:Forest Temple", RSK_MQ_FOREST_TEMPLE }, - { "Shuffle Dungeon Quest:Fire Temple", RSK_MQ_FIRE_TEMPLE }, - { "Shuffle Dungeon Quest:Water Temple", RSK_MQ_WATER_TEMPLE }, - { "Shuffle Dungeon Quest:Spirit Temple", RSK_MQ_SPIRIT_TEMPLE }, - { "Shuffle Dungeon Quest:Shadow Temple", RSK_MQ_SHADOW_TEMPLE }, - { "Shuffle Dungeon Quest:Bottom of the Well", RSK_MQ_BOTTOM_OF_THE_WELL }, - { "Shuffle Dungeon Quest:Ice Cavern", RSK_MQ_ICE_CAVERN }, - { "Shuffle Dungeon Quest:GTG", RSK_MQ_GTG }, - { "Shuffle Dungeon Quest:Ganon's Castle", RSK_MQ_GANONS_CASTLE }, - { "Shuffle Dungeon Items:Stone Count", RSK_LACS_STONE_COUNT }, - { "Shuffle Dungeon Items:Medallion Count", RSK_LACS_MEDALLION_COUNT }, - { "Shuffle Dungeon Items:Reward Count", RSK_LACS_REWARD_COUNT }, - { "Shuffle Dungeon Items:Dungeon Count", RSK_LACS_DUNGEON_COUNT }, - { "Shuffle Dungeon Items:Token Count", RSK_LACS_TOKEN_COUNT }, - { "Shuffle Dungeon Items:LACS Reward Options", RSK_LACS_OPTIONS }, - { "Shuffle Dungeon Items:Key Rings", RSK_KEYRINGS }, - { "Shuffle Dungeon Items:Keyring Dungeon Count", RSK_KEYRINGS_RANDOM_COUNT }, - { "Shuffle Dungeon Items:Gerudo Fortress Keyring", RSK_KEYRINGS_GERUDO_FORTRESS }, - { "Shuffle Dungeon Items:Forest Temple Keyring", RSK_KEYRINGS_FOREST_TEMPLE }, - { "Shuffle Dungeon Items:Fire Temple Keyring", RSK_KEYRINGS_FIRE_TEMPLE }, - { "Shuffle Dungeon Items:Water Temple Keyring", RSK_KEYRINGS_WATER_TEMPLE }, - { "Shuffle Dungeon Items:Spirit Temple Keyring", RSK_KEYRINGS_SPIRIT_TEMPLE }, - { "Shuffle Dungeon Items:Shadow Temple Keyring", RSK_KEYRINGS_SHADOW_TEMPLE }, - { "Shuffle Dungeon Items:Bottom of the Well Keyring", RSK_KEYRINGS_BOTTOM_OF_THE_WELL }, - { "Shuffle Dungeon Items:GTG Keyring", RSK_KEYRINGS_GTG }, - { "Shuffle Dungeon Items:Ganon's Castle Keyring", RSK_KEYRINGS_GANONS_CASTLE }, - { "World Settings:Shuffle Entrances", RSK_SHUFFLE_ENTRANCES }, - { "World Settings:Dungeon Entrances", RSK_SHUFFLE_DUNGEON_ENTRANCES }, - { "World Settings:Overworld Entrances", RSK_SHUFFLE_OVERWORLD_ENTRANCES }, - { "World Settings:Interior Entrances", RSK_SHUFFLE_INTERIOR_ENTRANCES }, - { "World Settings:Grottos Entrances", RSK_SHUFFLE_GROTTO_ENTRANCES }, - { "World Settings:Owl Drops", RSK_SHUFFLE_OWL_DROPS }, - { "World Settings:Warp Songs", RSK_SHUFFLE_WARP_SONGS }, - { "World Settings:Overworld Spawns", RSK_SHUFFLE_OVERWORLD_SPAWNS }, - { "World Settings:Mixed Entrance Pools", RSK_MIXED_ENTRANCE_POOLS }, - { "World Settings:Mix Dungeons", RSK_MIX_DUNGEON_ENTRANCES }, - { "World Settings:Mix Bosses", RSK_MIX_BOSS_ENTRANCES }, - { "World Settings:Mix Overworld", RSK_MIX_OVERWORLD_ENTRANCES }, - { "World Settings:Mix Interiors", RSK_MIX_INTERIOR_ENTRANCES }, - { "World Settings:Mix Grottos", RSK_MIX_GROTTO_ENTRANCES }, - { "World Settings:Decouple Entrances", RSK_DECOUPLED_ENTRANCES }, - { "Gold Skulltula Tokens", RSK_STARTING_SKULLTULA_TOKEN }, - { "Hearts", RSK_STARTING_HEARTS }, - { "Logic Options:All Locations Reachable", RSK_ALL_LOCATIONS_REACHABLE }, - { "World Settings:Boss Entrances", RSK_SHUFFLE_BOSS_ENTRANCES }, - { "Shuffle Settings:Shuffle 100 GS Reward", RSK_SHUFFLE_100_GS_REWARD }, - { "World Settings:Triforce Hunt", RSK_TRIFORCE_HUNT }, - { "World Settings:Triforce Hunt Total Pieces", RSK_TRIFORCE_HUNT_PIECES_TOTAL }, - { "World Settings:Triforce Hunt Required Pieces", RSK_TRIFORCE_HUNT_PIECES_REQUIRED }, - { "Shuffle Settings:Shuffle Boss Souls", RSK_SHUFFLE_BOSS_SOULS }, - { "Shuffle Settings:Fishsanity", RSK_FISHSANITY }, - { "Shuffle Settings:Pond Fish Count", RSK_FISHSANITY_POND_COUNT }, - { "Shuffle Settings:Split Pond Fish", RSK_FISHSANITY_AGE_SPLIT }, - { "Shuffle Settings:Shuffle Fishing Pole", RSK_SHUFFLE_FISHING_POLE }, - { "Miscellaneous Settings:Infinite Upgrades", RSK_INFINITE_UPGRADES }, - { "Miscellaneous Settings:Skeleton Key", RSK_SKELETON_KEY }, - { "Shuffle Settings:Shuffle Deku Stick Bag", RSK_SHUFFLE_DEKU_STICK_BAG }, - { "Shuffle Settings:Shuffle Deku Nut Bag", RSK_SHUFFLE_DEKU_NUT_BAG }, - }; +std::unordered_map Settings::PopulateOptionNameToEnum(){ + std::unordered_map output = {}; + for (size_t count = 0; count < RSK_MAX; count++) { + output[mOptions[count].GetName()] = static_cast(count); + } + return output; } Option& Settings::GetOption(const RandomizerSettingKey key) { @@ -2601,619 +2407,12 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { nlohmann::json settingsJson = spoilerFileJson["settings"]; for (auto it = settingsJson.begin(); it != settingsJson.end(); ++it) { // todo load into cvars for UI - - if (mSpoilerfileSettingNameToEnum.contains(it.key())) { - std::string numericValueString; - // this is annoying but the same strings are used in different orders - // and i don't want the spoilerfile to just have numbers instead of - // human readable settings values so it'll have to do for now - switch (const RandomizerSettingKey index = mSpoilerfileSettingNameToEnum[it.key()]) { - case RSK_LOGIC_RULES: - if (it.value() == "Glitchless") { - mOptions[index].SetContextIndex(RO_LOGIC_GLITCHLESS); - } else if (it.value() == "No Logic") { - mOptions[index].SetContextIndex(RO_LOGIC_NO_LOGIC); - } else if (it.value() == "Vanilla") { - mOptions[index].SetContextIndex(RO_LOGIC_VANILLA); - } - break; - case RSK_FOREST: - if (it.value() == "Closed") { - mOptions[index].SetContextIndex(RO_FOREST_CLOSED); - } else if (it.value() == "Open") { - mOptions[index].SetContextIndex(RO_FOREST_OPEN); - } else if (it.value() == "Closed Deku") { - mOptions[index].SetContextIndex(RO_FOREST_CLOSED_DEKU); - } - break; - case RSK_KAK_GATE: - if (it.value() == "Closed") { - mOptions[index].SetContextIndex(RO_KAK_GATE_CLOSED); - } else if (it.value() == "Open") { - mOptions[index].SetContextIndex(RO_KAK_GATE_OPEN); - } - break; - case RSK_DOOR_OF_TIME: - if (it.value() == "Open") { - mOptions[index].SetContextIndex(RO_DOOROFTIME_OPEN); - } else if (it.value() == "Song only") { - mOptions[index].SetContextIndex(RO_DOOROFTIME_SONGONLY); - } else if (it.value() == "Closed") { - mOptions[index].SetContextIndex(RO_DOOROFTIME_CLOSED); - } - break; - case RSK_ZORAS_FOUNTAIN: - if (it.value() == "Closed") { - mOptions[index].SetContextIndex(RO_ZF_CLOSED); - } else if (it.value() == "Closed as child") { - mOptions[index].SetContextIndex(RO_ZF_CLOSED_CHILD); - } else if (it.value() == "Open") { - mOptions[index].SetContextIndex(RO_ZF_OPEN); - } - break; - case RSK_SLEEPING_WATERFALL: - if (it.value() == "Closed") { - mOptions[index].SetContextIndex(RO_WATERFALL_CLOSED); - } else if (it.value() == "Open") { - mOptions[index].SetContextIndex(RO_WATERFALL_OPEN); - } - break; - case RSK_STARTING_AGE: - if (it.value() == "Child") { - mOptions[index].SetContextIndex(RO_AGE_CHILD); - } else if (it.value() == "Adult") { - mOptions[index].SetContextIndex(RO_AGE_ADULT); - } - break; - case RSK_GERUDO_FORTRESS: - if (it.value() == "Normal") { - mOptions[index].SetContextIndex(RO_GF_NORMAL); - } else if (it.value() == "Fast") { - mOptions[index].SetContextIndex(RO_GF_FAST); - } else if (it.value() == "Open") { - mOptions[index].SetContextIndex(RO_GF_OPEN); - } - break; - case RSK_RAINBOW_BRIDGE: - if (it.value() == "Vanilla") { - mOptions[index].SetContextIndex(RO_BRIDGE_VANILLA); - } else if (it.value() == "Always open") { - mOptions[index].SetContextIndex(RO_BRIDGE_ALWAYS_OPEN); - } else if (it.value() == "Stones") { - mOptions[index].SetContextIndex(RO_BRIDGE_STONES); - } else if (it.value() == "Medallions") { - mOptions[index].SetContextIndex(RO_BRIDGE_MEDALLIONS); - } else if (it.value() == "Dungeon rewards") { - mOptions[index].SetContextIndex(RO_BRIDGE_DUNGEON_REWARDS); - } else if (it.value() == "Dungeons") { - mOptions[index].SetContextIndex(RO_BRIDGE_DUNGEONS); - } else if (it.value() == "Tokens") { - mOptions[index].SetContextIndex(RO_BRIDGE_TOKENS); - } else if (it.value() == "Greg") { - mOptions[index].SetContextIndex(RO_BRIDGE_GREG); - } - break; - case RSK_BRIDGE_OPTIONS: - if (it.value() == "Standard Rewards") { - mOptions[index].SetContextIndex(RO_BRIDGE_STANDARD_REWARD); - } else if (it.value() == "Greg as Reward") { - mOptions[index].SetContextIndex(RO_BRIDGE_GREG_REWARD); - } else if (it.value() == "Greg as Wildcard") { - mOptions[index].SetContextIndex(RO_BRIDGE_WILDCARD_REWARD); - } - break; - case RSK_LACS_OPTIONS: - if (it.value() == "Standard Reward") { - mOptions[index].SetContextIndex(RO_LACS_STANDARD_REWARD); - } else if (it.value() == "Greg as Reward") { - mOptions[index].SetContextIndex(RO_LACS_GREG_REWARD); - } else if (it.value() == "Greg as Wildcard") { - mOptions[index].SetContextIndex(RO_LACS_WILDCARD_REWARD); - } - break; - case RSK_DAMAGE_MULTIPLIER: - if (it.value() == "x1/2") { - mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_HALF); - } else if (it.value() == "x1") { - mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_DEFAULT); - } else if (it.value() == "x2") { - mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_DOUBLE); - } else if (it.value() == "x4") { - mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_QUADRUPLE); - } else if (it.value() == "x8") { - mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_OCTUPLE); - } else if (it.value() == "x16") { - mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_SEXDECUPLE); - } else if (it.value() == "OHKO") { - mOptions[index].SetContextIndex(RO_DAMAGE_MULTIPLIER_OHKO); - } - break; - case RSK_RAINBOW_BRIDGE_STONE_COUNT: - case RSK_RAINBOW_BRIDGE_MEDALLION_COUNT: - case RSK_RAINBOW_BRIDGE_REWARD_COUNT: - case RSK_RAINBOW_BRIDGE_DUNGEON_COUNT: - case RSK_RAINBOW_BRIDGE_TOKEN_COUNT: - case RSK_TRIAL_COUNT: - case RSK_LACS_STONE_COUNT: - case RSK_LACS_MEDALLION_COUNT: - case RSK_LACS_REWARD_COUNT: - case RSK_LACS_DUNGEON_COUNT: - case RSK_LACS_TOKEN_COUNT: - case RSK_KEYRINGS_RANDOM_COUNT: - case RSK_CUCCO_COUNT: - case RSK_FISHSANITY_POND_COUNT: - case RSK_STARTING_SKULLTULA_TOKEN: - case RSK_SHOPSANITY_COUNT: - numericValueString = it.value(); - mOptions[index].SetContextIndex(std::stoi(numericValueString)); - break; - // Same as the above section, but the indexes are off by one from the text - // (i.e. 10 Big Poes is index 9). - case RSK_BIG_POE_COUNT: - case RSK_TRIFORCE_HUNT_PIECES_TOTAL: - case RSK_TRIFORCE_HUNT_PIECES_REQUIRED: - case RSK_STARTING_HEARTS: - numericValueString = it.value(); - mOptions[index].SetContextIndex(std::stoi(numericValueString) - 1); - break; - case RSK_GANONS_TRIALS: - if (it.value() == "Skip") { - mOptions[index].SetContextIndex(RO_GANONS_TRIALS_SKIP); - } else if (it.value() == "Set Number") { - mOptions[index].SetContextIndex(RO_GANONS_TRIALS_SET_NUMBER); - } else if (it.value() == "Random Number") { - mOptions[index].SetContextIndex(RO_GANONS_TRIALS_RANDOM_NUMBER); - } - case RSK_SHOPSANITY: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_SHOPSANITY_OFF); - } else if (it.value() == "Specific Count") { - mOptions[index].SetContextIndex(RO_SHOPSANITY_SPECIFIC_COUNT); - } else if (it.value() == "Random") { - mOptions[index].SetContextIndex(RO_SHOPSANITY_RANDOM); - } - break; - case RSK_SHOPSANITY_PRICES: - case RSK_SCRUBS_PRICES: - case RSK_MERCHANT_PRICES: - if (it.value() == "Vanilla") { - mOptions[index].SetContextIndex(RO_PRICE_VANILLA); - } else if (it.value() == "Cheap Balanced") { - mOptions[index].SetContextIndex(RO_PRICE_CHEAP_BALANCED); - } else if (it.value() == "Balanced") { - mOptions[index].SetContextIndex(RO_PRICE_BALANCED); - } else if (it.value() == "Fixed") { - mOptions[index].SetContextIndex(RO_PRICE_FIXED); - } else if (it.value() == "Range") { - mOptions[index].SetContextIndex(RO_PRICE_RANGE); - } else if (it.value() == "Set By Wallet") { - mOptions[index].SetContextIndex(RO_PRICE_SET_BY_WALLET); - } - break; - case RSK_SHUFFLE_SCRUBS: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_SCRUBS_OFF); - } else if (it.value() == "Major Items Only") { - mOptions[index].SetContextIndex(RO_SCRUBS_MAJOR_ONLY); - } else if (it.value() == "All") { - mOptions[index].SetContextIndex(RO_SCRUBS_ALL); - } - break; - case RSK_SHUFFLE_FISHING_POLE: - case RSK_FISHSANITY_AGE_SPLIT: - case RSK_FISHING_POLE_HINT: - case RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD: - case RSK_SHUFFLE_BEEHIVES: - case RSK_SHUFFLE_COWS: - case RSK_SHUFFLE_ADULT_TRADE: - case RSK_SHUFFLE_KOKIRI_SWORD: - case RSK_SHUFFLE_WEIRD_EGG: - case RSK_SHUFFLE_FROG_SONG_RUPEES: - case RSK_SHUFFLE_100_GS_REWARD: - case RSK_SHUFFLE_OCARINA: - case RSK_SHUFFLE_OCARINA_BUTTONS: - case RSK_SHUFFLE_SWIM: - case RSK_SHUFFLE_CHILD_WALLET: - case RSK_INCLUDE_TYCOON_WALLET: - case RSK_STARTING_DEKU_SHIELD: - case RSK_STARTING_KOKIRI_SWORD: - case RSK_STARTING_ZELDAS_LULLABY: - case RSK_STARTING_EPONAS_SONG: - case RSK_STARTING_SARIAS_SONG: - case RSK_STARTING_SUNS_SONG: - case RSK_STARTING_SONG_OF_TIME: - case RSK_STARTING_SONG_OF_STORMS: - case RSK_STARTING_MINUET_OF_FOREST: - case RSK_STARTING_BOLERO_OF_FIRE: - case RSK_STARTING_SERENADE_OF_WATER: - case RSK_STARTING_REQUIEM_OF_SPIRIT: - case RSK_STARTING_NOCTURNE_OF_SHADOW: - case RSK_STARTING_PRELUDE_OF_LIGHT: - case RSK_COMPLETE_MASK_QUEST: - case RSK_SKIP_SCARECROWS_SONG: - case RSK_ENABLE_GLITCH_CUTSCENES: - case RSK_SKULLS_SUNS_SONG: - case RSK_BLUE_FIRE_ARROWS: - case RSK_SUNLIGHT_ARROWS: - case RSK_INFINITE_UPGRADES: - case RSK_SKELETON_KEY: - case RSK_BOMBCHUS_IN_LOGIC: - case RSK_TOT_ALTAR_HINT: - case RSK_GANONDORF_HINT: - case RSK_SHEIK_LA_HINT: - case RSK_DAMPES_DIARY_HINT: - case RSK_GREG_HINT: - case RSK_LOACH_HINT: - case RSK_SARIA_HINT: - case RSK_FROGS_HINT: - case RSK_OOT_HINT: - case RSK_KAK_10_SKULLS_HINT: - case RSK_KAK_20_SKULLS_HINT: - case RSK_KAK_30_SKULLS_HINT: - case RSK_KAK_40_SKULLS_HINT: - case RSK_KAK_50_SKULLS_HINT: - case RSK_KAK_100_SKULLS_HINT: - case RSK_MASK_SHOP_HINT: - case RSK_BIGGORON_HINT: - case RSK_BIG_POES_HINT: - case RSK_CHICKENS_HINT: - case RSK_MALON_HINT: - case RSK_HBA_HINT: - case RSK_WARP_SONG_HINTS: - case RSK_SCRUB_TEXT_HINT: - case RSK_MERCHANT_TEXT_HINT: - case RSK_SHUFFLE_ENTRANCES: - case RSK_SHUFFLE_OVERWORLD_ENTRANCES: - case RSK_SHUFFLE_GROTTO_ENTRANCES: - case RSK_SHUFFLE_OWL_DROPS: - case RSK_SHUFFLE_WARP_SONGS: - case RSK_SHUFFLE_OVERWORLD_SPAWNS: - case RSK_MIXED_ENTRANCE_POOLS: - case RSK_MIX_DUNGEON_ENTRANCES: - case RSK_MIX_BOSS_ENTRANCES: - case RSK_MIX_OVERWORLD_ENTRANCES: - case RSK_MIX_INTERIOR_ENTRANCES: - case RSK_MIX_GROTTO_ENTRANCES: - case RSK_DECOUPLED_ENTRANCES: - case RSK_SHOPSANITY_PRICES_AFFORDABLE: - case RSK_SCRUBS_PRICES_AFFORDABLE: - case RSK_MERCHANT_PRICES_AFFORDABLE: - case RSK_ALL_LOCATIONS_REACHABLE: - case RSK_TRIFORCE_HUNT: - case RSK_MQ_DUNGEON_SET: - case RSK_SHUFFLE_DEKU_NUT_BAG: - case RSK_SHUFFLE_DEKU_STICK_BAG: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_GENERIC_OFF); - } else if (it.value() == "On") { - mOptions[index].SetContextIndex(RO_GENERIC_ON); - } - break; - case RSK_KEYRINGS: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_KEYRINGS_OFF); - } else if (it.value() == "Random") { - mOptions[index].SetContextIndex(RO_KEYRINGS_RANDOM); - } else if (it.value() == "Count") { - mOptions[index].SetContextIndex(RO_KEYRINGS_COUNT); - } else if (it.value() == "Selection") { - mOptions[index].SetContextIndex(RO_KEYRINGS_SELECTION); - } - break; - case RSK_KEYRINGS_GERUDO_FORTRESS: - case RSK_KEYRINGS_FOREST_TEMPLE: - case RSK_KEYRINGS_FIRE_TEMPLE: - case RSK_KEYRINGS_WATER_TEMPLE: - case RSK_KEYRINGS_SHADOW_TEMPLE: - case RSK_KEYRINGS_SPIRIT_TEMPLE: - case RSK_KEYRINGS_BOTTOM_OF_THE_WELL: - case RSK_KEYRINGS_GTG: - case RSK_KEYRINGS_GANONS_CASTLE: - if (it.value() == "No") { - mOptions[index].SetContextIndex(RO_KEYRING_FOR_DUNGEON_OFF); - } else if (it.value() == "Random") { - mOptions[index].SetContextIndex(RO_KEYRING_FOR_DUNGEON_RANDOM); - } else if (it.value() == "Yes") { - mOptions[index].SetContextIndex(RO_KEYRING_FOR_DUNGEON_ON); - } - break; - case RSK_SHUFFLE_MERCHANTS: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_SHUFFLE_MERCHANTS_OFF); - } else if (it.value() == "Beans Only") { - mOptions[index].SetContextIndex(RO_SHUFFLE_MERCHANTS_BEANS_ONLY); - } else if (it.value() == "All but Beans") { - mOptions[index].SetContextIndex(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS); - } else if (it.value() == "All") { - mOptions[index].SetContextIndex(RO_SHUFFLE_MERCHANTS_ALL); - } - break; - // Uses Ammo Drops option for now. "Off" not yet implemented - // TODO: Change to Ammo Drops - case RSK_ENABLE_BOMBCHU_DROPS: - if (it.value() == "Yes") { - mOptions[index].SetContextIndex(RO_AMMO_DROPS_ON); - // } else if (it.value() == "On + Bombchu") { - // mOptions[index].SetContextIndex(RO_AMMO_DROPS_ON_PLUS_BOMBCHU); - } else if (it.value() == "No") { - mOptions[index].SetContextIndex(RO_AMMO_DROPS_OFF); - } - break; - case RSK_FISHSANITY: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_FISHSANITY_OFF); - } else if (it.value() == "Shuffle Fishing Pond") { - mOptions[index].SetContextIndex(RO_FISHSANITY_POND); - } else if (it.value() == "Shuffle Overworld Fish") { - mOptions[index].SetContextIndex(RO_FISHSANITY_OVERWORLD); - } else if (it.value() == "Shuffle Both") { - mOptions[index].SetContextIndex(RO_FISHSANITY_BOTH); - } - break; - case RSK_SHUFFLE_BOSS_SOULS: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_BOSS_SOULS_OFF); - } else if (it.value() == "On") { - mOptions[index].SetContextIndex(RO_BOSS_SOULS_ON); - } else if (it.value() == "On + Ganon") { - mOptions[index].SetContextIndex(RO_BOSS_SOULS_ON_PLUS_GANON); - } - case RSK_STARTING_OCARINA: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_STARTING_OCARINA_OFF); - } else if (it.value() == "Fairy Ocarina") { - mOptions[index].SetContextIndex(RO_STARTING_OCARINA_FAIRY); - } - break; - case RSK_ITEM_POOL: - if (it.value() == "Plentiful") { - mOptions[index].SetContextIndex(RO_ITEM_POOL_PLENTIFUL); - } else if (it.value() == "Balanced") { - mOptions[index].SetContextIndex(RO_ITEM_POOL_BALANCED); - } else if (it.value() == "Scarce") { - mOptions[index].SetContextIndex(RO_ITEM_POOL_SCARCE); - } else if (it.value() == "Minimal") { - mOptions[index].SetContextIndex(RO_ITEM_POOL_MINIMAL); - } - break; - case RSK_ICE_TRAPS: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_ICE_TRAPS_OFF); - } else if (it.value() == "Normal") { - mOptions[index].SetContextIndex(RO_ICE_TRAPS_NORMAL); - } else if (it.value() == "Extra") { - mOptions[index].SetContextIndex(RO_ICE_TRAPS_EXTRA); - } else if (it.value() == "Mayhem") { - mOptions[index].SetContextIndex(RO_ICE_TRAPS_MAYHEM); - } else if (it.value() == "Onslaught") { - mOptions[index].SetContextIndex(RO_ICE_TRAPS_ONSLAUGHT); - } - break; - case RSK_GOSSIP_STONE_HINTS: - if (it.value() == "No Hints") { - mOptions[index].SetContextIndex(RO_GOSSIP_STONES_NONE); - } else if (it.value() == "Need Nothing") { - mOptions[index].SetContextIndex(RO_GOSSIP_STONES_NEED_NOTHING); - } else if (it.value() == "Mask of Truth") { - mOptions[index].SetContextIndex(RO_GOSSIP_STONES_NEED_TRUTH); - } else if (it.value() == "Stone of Agony") { - mOptions[index].SetContextIndex(RO_GOSSIP_STONES_NEED_STONE); - } - break; - case RSK_HINT_CLARITY: - if (it.value() == "Obscure") { - mOptions[index].SetContextIndex(RO_HINT_CLARITY_OBSCURE); - } else if (it.value() == "Ambiguous") { - mOptions[index].SetContextIndex(RO_HINT_CLARITY_AMBIGUOUS); - } else if (it.value() == "Clear") { - mOptions[index].SetContextIndex(RO_HINT_CLARITY_CLEAR); - } - break; - case RSK_HINT_DISTRIBUTION: - if (it.value() == "Useless") { - mOptions[index].SetContextIndex(RO_HINT_DIST_USELESS); - } else if (it.value() == "Balanced") { - mOptions[index].SetContextIndex(RO_HINT_DIST_BALANCED); - } else if (it.value() == "Strong") { - mOptions[index].SetContextIndex(RO_HINT_DIST_STRONG); - } else if (it.value() == "Very Strong") { - mOptions[index].SetContextIndex(RO_HINT_DIST_VERY_STRONG); - } - break; - case RSK_GERUDO_KEYS: - if (it.value() == "Vanilla") { - mOptions[index].SetContextIndex(RO_GERUDO_KEYS_VANILLA); - } else if (it.value() == "Any Dungeon") { - mOptions[index].SetContextIndex(RO_GERUDO_KEYS_ANY_DUNGEON); - } else if (it.value() == "Overworld") { - mOptions[index].SetContextIndex(RO_GERUDO_KEYS_OVERWORLD); - } else if (it.value() == "Anywhere") { - mOptions[index].SetContextIndex(RO_GERUDO_KEYS_ANYWHERE); - } - break; - case RSK_KEYSANITY: - case RSK_BOSS_KEYSANITY: - case RSK_SHUFFLE_MAPANDCOMPASS: - if (it.value() == "Start With") { - mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_STARTWITH); - } else if (it.value() == "Vanilla") { - mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_VANILLA); - } else if (it.value() == "Own Dungeon") { - mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON); - } else if (it.value() == "Any Dungeon") { - mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON); - } else if (it.value() == "Overworld") { - mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_OVERWORLD); - } else if (it.value() == "Anywhere") { - mOptions[index].SetContextIndex(RO_DUNGEON_ITEM_LOC_ANYWHERE); - } - break; - case RSK_GANONS_BOSS_KEY: - if (it.value() == "Vanilla") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_VANILLA); - } else if (it.value() == "Own dungeon") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_OWN_DUNGEON); - } else if (it.value() == "Start with") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_STARTWITH); - } else if (it.value() == "Any Dungeon") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_ANY_DUNGEON); - } else if (it.value() == "Overworld") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_OVERWORLD); - } else if (it.value() == "Anywhere") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_ANYWHERE); - } else if (it.value() == "LACS-Vanilla") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_VANILLA); - } else if (it.value() == "LACS-Stones") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_STONES); - } else if (it.value() == "LACS-Medallions") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_MEDALLIONS); - } else if (it.value() == "LACS-Rewards") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_REWARDS); - } else if (it.value() == "LACS-Dungeons") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_DUNGEONS); - } else if (it.value() == "LACS-Tokens") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_LACS_TOKENS); - } else if (it.value() == "100 GS Reward") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_KAK_TOKENS); - } else if (it.value() == "Triforce Hunt") { - mOptions[index].SetContextIndex(RO_GANON_BOSS_KEY_TRIFORCE_HUNT); - } - break; - case RSK_MQ_DUNGEON_RANDOM: - if (it.value() == "None") { - mOptions[index].SetContextIndex(RO_MQ_DUNGEONS_NONE); - } else if (it.value() == "Random Number") { - mOptions[index].SetContextIndex(RO_MQ_DUNGEONS_RANDOM_NUMBER); - } else if (it.value() == "Set Number") { - mOptions[index].SetContextIndex(RO_MQ_DUNGEONS_SET_NUMBER); - } else if (it.value() == "Selection Only") { - mOptions[index].SetContextIndex(RO_MQ_DUNGEONS_SELECTION); - } - break; - case RSK_STARTING_STICKS: - case RSK_STARTING_NUTS: - case RSK_FULL_WALLETS: - if (it.value() == "No") { - mOptions[index].SetContextIndex(RO_GENERIC_NO); - } else if (it.value() == "Yes") { - mOptions[index].SetContextIndex(RO_GENERIC_YES); - } - break; - case RSK_SKIP_CHILD_ZELDA: - case RSK_SKIP_CHILD_STEALTH: - case RSK_SKIP_EPONA_RACE: - if (it.value() == "Don't Skip") { - mOptions[index].SetContextIndex(RO_GENERIC_DONT_SKIP); - } else if (it.value() == "Skip") { - mOptions[index].SetContextIndex(RO_GENERIC_SKIP); - } - break; - case RSK_SHUFFLE_DUNGEON_REWARDS: - if (it.value() == "End of dungeons") { - mOptions[index].SetContextIndex(RO_DUNGEON_REWARDS_END_OF_DUNGEON); - } else if (it.value() == "Any dungeon") { - mOptions[index].SetContextIndex(RO_DUNGEON_REWARDS_ANY_DUNGEON); - } else if (it.value() == "Overworld") { - mOptions[index].SetContextIndex(RO_DUNGEON_REWARDS_OVERWORLD); - } else if (it.value() == "Anywhere") { - mOptions[index].SetContextIndex(RO_DUNGEON_REWARDS_ANYWHERE); - } - break; - case RSK_SHUFFLE_SONGS: - if (it.value() == "Song locations") { - mOptions[index].SetContextIndex(RO_SONG_SHUFFLE_SONG_LOCATIONS); - } else if (it.value() == "Dungeon rewards") { - mOptions[index].SetContextIndex(RO_SONG_SHUFFLE_DUNGEON_REWARDS); - } else if (it.value() == "Anywhere") { - mOptions[index].SetContextIndex(RO_SONG_SHUFFLE_ANYWHERE); - } - break; - case RSK_SHUFFLE_TOKENS: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_TOKENSANITY_OFF); - } else if (it.value() == "Dungeons") { - mOptions[index].SetContextIndex(RO_TOKENSANITY_DUNGEONS); - } else if (it.value() == "Overworld") { - mOptions[index].SetContextIndex(RO_TOKENSANITY_OVERWORLD); - } else if (it.value() == "All Tokens") { - mOptions[index].SetContextIndex(RO_TOKENSANITY_ALL); - } - break; - case RSK_LINKS_POCKET: - if (it.value() == "Dungeon Reward") { - mOptions[index].SetContextIndex(RO_LINKS_POCKET_DUNGEON_REWARD); - } else if (it.value() == "Advancement") { - mOptions[index].SetContextIndex(RO_LINKS_POCKET_ADVANCEMENT); - } else if (it.value() == "Anything") { - mOptions[index].SetContextIndex(RO_LINKS_POCKET_ANYTHING); - } else if (it.value() == "Nothing") { - mOptions[index].SetContextIndex(RO_LINKS_POCKET_NOTHING); - } - break; - case RSK_MQ_DUNGEON_COUNT: - numericValueString = it.value(); - mOptions[index].SetContextIndex(std::stoi(numericValueString)); - break; - case RSK_SHUFFLE_DUNGEON_ENTRANCES: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF); - } else if (it.value() == "On") { - mOptions[index].SetContextIndex(RO_DUNGEON_ENTRANCE_SHUFFLE_ON); - } else if (it.value() == "On + Ganon") { - mOptions[index].SetContextIndex(RO_DUNGEON_ENTRANCE_SHUFFLE_ON_PLUS_GANON); - } - break; - case RSK_SHUFFLE_BOSS_ENTRANCES: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF); - } else if (it.value() == "Age Restricted") { - mOptions[index].SetContextIndex(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_AGE_RESTRICTED); - } else if (it.value() == "Full") { - mOptions[index].SetContextIndex(RO_BOSS_ROOM_ENTRANCE_SHUFFLE_FULL); - } - break; - case RSK_SHUFFLE_INTERIOR_ENTRANCES: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_INTERIOR_ENTRANCE_SHUFFLE_OFF); - } else if (it.value() == "Simple") { - mOptions[index].SetContextIndex(RO_INTERIOR_ENTRANCE_SHUFFLE_SIMPLE); - } else if (it.value() == "All") { - mOptions[index].SetContextIndex(RO_INTERIOR_ENTRANCE_SHUFFLE_ALL); - } - break; - case RSK_SHUFFLE_CHEST_MINIGAME: - if (it.value() == "Off") { - mOptions[index].SetContextIndex(RO_CHEST_GAME_OFF); - } else if (it.value() == "On (Separate)") { - mOptions[index].SetContextIndex(RO_CHEST_GAME_SINGLE_KEYS); - } else if (it.value() == "On (Pack)") { - mOptions[index].SetContextIndex(RO_CHEST_GAME_PACK); - } - break; - case RSK_MQ_DEKU_TREE: - case RSK_MQ_DODONGOS_CAVERN: - case RSK_MQ_JABU_JABU: - case RSK_MQ_FOREST_TEMPLE: - case RSK_MQ_FIRE_TEMPLE: - case RSK_MQ_WATER_TEMPLE: - case RSK_MQ_SPIRIT_TEMPLE: - case RSK_MQ_SHADOW_TEMPLE: - case RSK_MQ_BOTTOM_OF_THE_WELL: - case RSK_MQ_ICE_CAVERN: - case RSK_MQ_GTG: - case RSK_MQ_GANONS_CASTLE: - if (it.value() == "Vanilla") { - mOptions[index].SetContextIndex(RO_MQ_SET_VANILLA); - } else if (it.value() == "Master Quest") { - mOptions[index].SetContextIndex(RO_MQ_SET_MQ); - } else if (it.value() == "Random") { - mOptions[index].SetContextIndex(RO_MQ_SET_RANDOM); - } - break; - default: - SPDLOG_DEBUG("No string to enum conversion for option: %s", it.key()); - break; - } + //RANDOTODO handle numeric value to options conversion better than brute froce + if (StaticData::optionNameToEnum.contains(it.key())) { + auto test = it.key(); + auto test2 = it.value(); + const RandomizerSettingKey index = StaticData::optionNameToEnum[it.key()]; + mOptions[index].SetContextIndexFromText(it.value()); } } diff --git a/soh/soh/Enhancements/randomizer/settings.h b/soh/soh/Enhancements/randomizer/settings.h index 8bb484b16..90613cf14 100644 --- a/soh/soh/Enhancements/randomizer/settings.h +++ b/soh/soh/Enhancements/randomizer/settings.h @@ -25,6 +25,14 @@ class Settings { */ void CreateOptions(); + /** + * @brief Populates the map used to translate strings into RandomiserSettingKeys + * + * @return std::unordered_map + */ + + std::unordered_map PopulateOptionNameToEnum(); + /** * @brief Get a reference to the `Option` corresponding to the provided RandomizerSettingKey. * @@ -192,7 +200,6 @@ class Settings { std::array mOptionGroups = {}; std::array mTrickOptions = {}; std::vector> mExcludeLocationsOptionsAreas = {}; - std::unordered_map mSpoilerfileSettingNameToEnum; RandoOptionStartingAge mResolvedStartingAge = RO_AGE_CHILD; RandoOptionLACSCondition mLACSCondition = RO_LACS_VANILLA; std::string mHash; diff --git a/soh/soh/Enhancements/randomizer/static_data.cpp b/soh/soh/Enhancements/randomizer/static_data.cpp index 15697d9e0..84da0d3c1 100644 --- a/soh/soh/Enhancements/randomizer/static_data.cpp +++ b/soh/soh/Enhancements/randomizer/static_data.cpp @@ -251,7 +251,8 @@ std::unordered_map StaticData::hintNameToEnum = {}; std::unordered_map StaticData::hintTypeNameToEnum = {}; std::unordered_map StaticData::areaNameToEnum = {}; std::unordered_map StaticData::trialNameToEnum = {}; -std::unordered_map StaticData::locationNameToEnum = {}; //is filled in context based on location table, not touching that because of VB +std::unordered_map StaticData::optionNameToEnum = {}; +std::unordered_map StaticData::locationNameToEnum = {}; //is filled in context based on location table std::unordered_map StaticData::stoneParamsToHint{ {0x1, RH_ZF_FAIRY_GOSSIP_STONE}, diff --git a/soh/soh/Enhancements/randomizer/static_data.h b/soh/soh/Enhancements/randomizer/static_data.h index 5ff0f1d26..7aade57de 100644 --- a/soh/soh/Enhancements/randomizer/static_data.h +++ b/soh/soh/Enhancements/randomizer/static_data.h @@ -61,6 +61,7 @@ class StaticData { static std::unordered_map areaNameToEnum; static std::unordered_map trialData; static std::unordered_map trialNameToEnum; + static std::unordered_map optionNameToEnum; static std::unordered_map staticHintInfoMap; static std::unordered_map stoneParamsToHint; static std::unordered_map grottoChestParamsToHint; From 6823b6990b62d421f98aba2dc5ed9b8051b16d9d Mon Sep 17 00:00:00 2001 From: Jordan Longstaff Date: Mon, 9 Dec 2024 21:23:14 -0500 Subject: [PATCH 3/6] Name alpha-distance update function from decomp (#4658) --- soh/include/functions.h | 2 +- soh/src/code/z_actor.c | 16 ++++++++-------- soh/src/overlays/actors/ovl_En_Md/z_en_md.c | 2 +- soh/src/overlays/actors/ovl_En_Sa/z_en_sa.c | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/soh/include/functions.h b/soh/include/functions.h index 97e3be4d9..f6480e499 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -537,7 +537,7 @@ void func_80034BA0(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overr PostLimbDraw postLimbDraw, Actor* actor, s16 alpha); void func_80034CC4(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, s16 alpha); -s16 func_80034DD4(Actor* actor, PlayState* play, s16 arg2, f32 arg3); +s16 Actor_UpdateAlphaByDistance(Actor* actor, PlayState* play, s16 arg2, f32 arg3); void Animation_ChangeByInfo(SkelAnime* skelAnime, AnimationInfo* animationInfo, s32 index); void func_80034F54(PlayState* play, s16* arg1, s16* arg2, s32 arg3); void Actor_Noop(Actor* actor, PlayState* play); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 4cd4d7584..be846b173 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -4547,25 +4547,25 @@ void func_80034CC4(PlayState* play, SkelAnime* skelAnime, OverrideLimbDraw overr CLOSE_DISPS(play->state.gfxCtx); } -s16 func_80034DD4(Actor* actor, PlayState* play, s16 arg2, f32 arg3) { +s16 Actor_UpdateAlphaByDistance(Actor* actor, PlayState* play, s16 alpha, f32 radius) { Player* player = GET_PLAYER(play); - f32 var; + f32 distance; if ((play->csCtx.state != CS_STATE_IDLE) || (gDbgCamEnabled)) { - var = Math_Vec3f_DistXYZ(&actor->world.pos, &play->view.eye) * 0.25f; + distance = Math_Vec3f_DistXYZ(&actor->world.pos, &play->view.eye) * 0.25f; } else { - var = Math_Vec3f_DistXYZ(&actor->world.pos, &player->actor.world.pos); + distance = Math_Vec3f_DistXYZ(&actor->world.pos, &player->actor.world.pos); } - if (arg3 < var) { + if (radius < distance) { actor->flags &= ~ACTOR_FLAG_TARGETABLE; - Math_SmoothStepToS(&arg2, 0, 6, 0x14, 1); + Math_SmoothStepToS(&alpha, 0, 6, 0x14, 1); } else { actor->flags |= ACTOR_FLAG_TARGETABLE; - Math_SmoothStepToS(&arg2, 0xFF, 6, 0x14, 1); + Math_SmoothStepToS(&alpha, 0xFF, 6, 0x14, 1); } - return arg2; + return alpha; } void Animation_ChangeByInfo(SkelAnime* skelAnime, AnimationInfo* animationInfo, s32 index) { diff --git a/soh/src/overlays/actors/ovl_En_Md/z_en_md.c b/soh/src/overlays/actors/ovl_En_Md/z_en_md.c index 7902b1bb8..b808afa4b 100644 --- a/soh/src/overlays/actors/ovl_En_Md/z_en_md.c +++ b/soh/src/overlays/actors/ovl_En_Md/z_en_md.c @@ -629,7 +629,7 @@ void func_80AAB5A4(EnMd* this, PlayState* play) { : 400.0f; } - this->alpha = func_80034DD4(&this->actor, play, this->alpha, temp); + this->alpha = Actor_UpdateAlphaByDistance(&this->actor, play, this->alpha, temp); this->actor.shape.shadowAlpha = this->alpha; } else { this->alpha = 255; diff --git a/soh/src/overlays/actors/ovl_En_Sa/z_en_sa.c b/soh/src/overlays/actors/ovl_En_Sa/z_en_sa.c index ed09470a0..a50872d41 100644 --- a/soh/src/overlays/actors/ovl_En_Sa/z_en_sa.c +++ b/soh/src/overlays/actors/ovl_En_Sa/z_en_sa.c @@ -742,10 +742,10 @@ void EnSa_Update(Actor* thisx, PlayState* play) { if (this->actionFunc != func_80AF68E4) { if (CVarGetInteger(CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), 0) != 0) { - this->alpha = func_80034DD4(&this->actor, play, this->alpha, 32767); + this->alpha = Actor_UpdateAlphaByDistance(&this->actor, play, this->alpha, 32767); } else { - this->alpha = func_80034DD4(&this->actor, play, this->alpha, 400.0f); + this->alpha = Actor_UpdateAlphaByDistance(&this->actor, play, this->alpha, 400.0f); } } else { this->alpha = 255; From 35dcf93c51c6ebc92aaaf711d04a562ba1303361 Mon Sep 17 00:00:00 2001 From: Jordan Longstaff Date: Mon, 9 Dec 2024 21:23:57 -0500 Subject: [PATCH 4/6] Adult Ruto function and property names pulled in from decomp (#4654) * Adult Ruto function and property names pulled in from decomp * Align name changes more with decomp * Nope, missed a couple more --- .../Enhancements/timesaver_hook_handlers.cpp | 4 +- soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c | 762 +++++++++++------- soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.h | 18 +- .../ovl_En_Ru2/z_en_ru2_cutscene_data.c | 2 +- 4 files changed, 461 insertions(+), 325 deletions(-) diff --git a/soh/soh/Enhancements/timesaver_hook_handlers.cpp b/soh/soh/Enhancements/timesaver_hook_handlers.cpp index c78c3f19c..86e8c37e9 100644 --- a/soh/soh/Enhancements/timesaver_hook_handlers.cpp +++ b/soh/soh/Enhancements/timesaver_hook_handlers.cpp @@ -38,7 +38,7 @@ extern int32_t D_8011D3AC; extern void BgSpot03Taki_HandleWaterfallState(BgSpot03Taki* bgSpot03Taki, PlayState* play); extern void BgSpot03Taki_ApplyOpeningAlpha(BgSpot03Taki* bgSpot03Taki, s32 bufferIndex); -extern void func_80AF36EC(EnRu2* enRu2, PlayState* play); +extern void EnRu2_SetEncounterSwitchFlag(EnRu2* enRu2, PlayState* play); } #define RAND_GET_OPTION(option) Rando::Context::GetInstance()->GetOption(option).GetContextOptionIndex() @@ -893,7 +893,7 @@ void TimeSaverOnActorInitHandler(void* actorRef) { if (actor->id == ACTOR_EN_RU2 && gPlayState->sceneNum == SCENE_WATER_TEMPLE) { if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { EnRu2* enRu2 = (EnRu2*)actor; - func_80AF36EC(enRu2, gPlayState); + EnRu2_SetEncounterSwitchFlag(enRu2, gPlayState); Actor_Kill(actor); } } diff --git a/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c b/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c index 162db0512..b4c4d9053 100644 --- a/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c +++ b/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c @@ -18,32 +18,61 @@ void EnRu2_Destroy(Actor* thisx, PlayState* play); void EnRu2_Update(Actor* thisx, PlayState* play); void EnRu2_Draw(Actor* thisx, PlayState* play); -void func_80AF2CB4(EnRu2* this, PlayState* play); -void func_80AF2CD4(EnRu2* this, PlayState* play); -void func_80AF2CF4(EnRu2* this, PlayState* play); -void func_80AF2D2C(EnRu2* this, PlayState* play); -void func_80AF2D6C(EnRu2* this, PlayState* play); -void func_80AF2DAC(EnRu2* this, PlayState* play); -void func_80AF2DEC(EnRu2* this, PlayState* play); -void func_80AF3144(EnRu2* this, PlayState* play); -void func_80AF3174(EnRu2* this, PlayState* play); -void func_80AF31C8(EnRu2* this, PlayState* play); -void func_80AF3604(EnRu2* this, PlayState* play); -void func_80AF3624(EnRu2* this, PlayState* play); -void func_80AF366C(EnRu2* this, PlayState* play); -void func_80AF36AC(EnRu2* this, PlayState* play); -void func_80AF3BC8(EnRu2* this, PlayState* play); -void func_80AF3C04(EnRu2* this, PlayState* play); -void func_80AF3C64(EnRu2* this, PlayState* play); -void func_80AF3CB8(EnRu2* this, PlayState* play); -void func_80AF3D0C(EnRu2* this, PlayState* play); -void func_80AF3D60(EnRu2* this, PlayState* play); +void EnRu2_SetupWaterMedallionCutscene(EnRu2* this, PlayState* play); +void EnRu2_AwaitBlueWarp(EnRu2* this, PlayState* play); +void EnRu2_RiseThroughBlueWarp(EnRu2* this, PlayState* play); +void EnRu2_SageOfWaterDialog(EnRu2* this, PlayState* play); +void EnRu2_RaiseArms(EnRu2* this, PlayState* play); +void EnRu2_AwaitWaterMedallion(EnRu2* this, PlayState* play); +void EnRu2_FinishWaterMedallionCutscene(EnRu2* this, PlayState* play); +void EnRu2_WaterTrialInvisible(EnRu2* this, PlayState* play); +void EnRu2_WaterTrialFade(EnRu2* this, PlayState* play); +void EnRu2_AwaitSpawnLightBall(EnRu2* this, PlayState* play); +void EnRu2_CreditsInvisible(EnRu2* this, PlayState* play); +void EnRu2_CreditsFadeIn(EnRu2* this, PlayState* play); +void EnRu2_CreditsVisible(EnRu2* this, PlayState* play); +void EnRu2_CreditsTurnHeadDownLeft(EnRu2* this, PlayState* play); +void EnRu2_WaterTempleEncounterRangeCheck(EnRu2* this, PlayState* play); +void EnRu2_WaterTempleEncounterUnconditional(EnRu2* this, PlayState* play); +void EnRu2_WaterTempleEncounterBegin(EnRu2* this, PlayState* play); +void EnRu2_WaterTempleEncounterDialog(EnRu2* this, PlayState* play); +void EnRu2_WaterTempleEncounterEnd(EnRu2* this, PlayState* play); +void EnRu2_WaterTempleSwimmingUp(EnRu2* this, PlayState* play); -void func_80AF3F14(EnRu2* this, PlayState* play); -void func_80AF3F20(EnRu2* this, PlayState* play); -void func_80AF321C(EnRu2* this, PlayState* play); +void EnRu2_DrawNothing(EnRu2* this, PlayState* play); +void EnRu2_DrawOpa(EnRu2* this, PlayState* play); +void EnRu2_DrawXlu(EnRu2* this, PlayState* play); -void func_80AF2AB4(EnRu2* this, PlayState* play); +void EnRu2_CheckWaterMedallionCutscene(EnRu2* this, PlayState* play); + +typedef enum { + /* 00 */ ENRU2_SETUP_WATER_MEDALLION_CS, + /* 01 */ ENRU2_AWAIT_BLUE_WARP, + /* 02 */ ENRU2_RISE_THROUGH_BLUE_WARP, + /* 03 */ ENRU2_SAGE_OF_WATER_DIALOG, + /* 04 */ ENRU2_RAISE_ARMS, + /* 05 */ ENRU2_AWAIT_SPAWN_WATER_MEDALLION, + /* 06 */ ENRU2_FINISH_WATER_MEDALLION_CS, + /* 07 */ ENRU2_WATER_TRIAL_INVISIBLE, + /* 08 */ ENRU2_WATER_TRIAL_FADE, + /* 09 */ ENRU2_AWAIT_SPAWN_LIGHT_BALL, + /* 10 */ ENRU2_CREDITS_INVISIBLE, + /* 11 */ ENRU2_CREDITS_FADE_IN, + /* 12 */ ENRU2_CREDITS_VISIBLE, + /* 13 */ ENRU2_CREDITS_TURN_HEAD_DOWN_LEFT, + /* 14 */ ENRU2_WATER_TEMPLE_ENCOUNTER_RANGE_CHECK, + /* 15 */ ENRU2_WATER_TEMPLE_ENCOUNTER_UNCONDITIONAL, // unused + /* 16 */ ENRU2_WATER_TEMPLE_ENCOUNTER_BEGINNING, + /* 17 */ ENRU2_WATER_TEMPLE_ENCOUNTER_DIALOG, + /* 18 */ ENRU2_WATER_TEMPLE_ENCOUNTER_END, + /* 19 */ ENRU2_WATER_TEMPLE_SWIMMING_UP, +} EnRu2Action; + +typedef enum { + /* 00 */ ENRU2_DRAW_NOTHING, + /* 01 */ ENRU2_DRAW_OPA, + /* 02 */ ENRU2_DRAW_XLU, +} EnRu2DrawConfig; static ColliderCylinderInitType1 sCylinderInit = { { @@ -68,15 +97,32 @@ static UNK_TYPE D_80AF4118 = 0; #include "z_en_ru2_cutscene_data.c" EARLY static EnRu2ActionFunc sActionFuncs[] = { - func_80AF2CB4, func_80AF2CD4, func_80AF2CF4, func_80AF2D2C, func_80AF2D6C, func_80AF2DAC, func_80AF2DEC, - func_80AF3144, func_80AF3174, func_80AF31C8, func_80AF3604, func_80AF3624, func_80AF366C, func_80AF36AC, - func_80AF3BC8, func_80AF3C04, func_80AF3C64, func_80AF3CB8, func_80AF3D0C, func_80AF3D60, + EnRu2_SetupWaterMedallionCutscene, + EnRu2_AwaitBlueWarp, + EnRu2_RiseThroughBlueWarp, + EnRu2_SageOfWaterDialog, + EnRu2_RaiseArms, + EnRu2_AwaitWaterMedallion, + EnRu2_FinishWaterMedallionCutscene, + EnRu2_WaterTrialInvisible, + EnRu2_WaterTrialFade, + EnRu2_AwaitSpawnLightBall, + EnRu2_CreditsInvisible, + EnRu2_CreditsFadeIn, + EnRu2_CreditsVisible, + EnRu2_CreditsTurnHeadDownLeft, + EnRu2_WaterTempleEncounterRangeCheck, + EnRu2_WaterTempleEncounterUnconditional, + EnRu2_WaterTempleEncounterBegin, + EnRu2_WaterTempleEncounterDialog, + EnRu2_WaterTempleEncounterEnd, + EnRu2_WaterTempleSwimmingUp, }; static EnRu2DrawFunc sDrawFuncs[] = { - func_80AF3F14, - func_80AF3F20, - func_80AF321C, + EnRu2_DrawNothing, + EnRu2_DrawOpa, + EnRu2_DrawXlu, }; const ActorInit En_Ru2_InitVars = { @@ -92,14 +138,14 @@ const ActorInit En_Ru2_InitVars = { NULL, }; -void func_80AF2550(Actor* thisx, PlayState* play) { +void EnRu2_InitCollider(Actor* thisx, PlayState* play) { EnRu2* this = (EnRu2*)thisx; Collider_InitCylinder(play, &this->collider); Collider_SetCylinderType1(play, &this->collider, &this->actor, &sCylinderInit); } -void func_80AF259C(EnRu2* this, PlayState* play) { +void EnRu2_UpdateCollider(EnRu2* this, PlayState* play) { s32 pad[5]; Collider_UpdateCylinder(&this->actor, &this->collider); @@ -114,40 +160,40 @@ void EnRu2_Destroy(Actor* thisx, PlayState* play) { ResourceMgr_UnregisterSkeleton(&this->skelAnime); } -void func_80AF2608(EnRu2* this) { +void EnRu2_UpdateEyes(EnRu2* this) { s32 pad[3]; - s16* unk_2A6 = &this->unk_2A6; - s16* unk_2A4 = &this->unk_2A4; + s16* blinkTimer = &this->blinkTimer; + s16* eyeIndex = &this->eyeIndex; - if (!DECR(*unk_2A6)) { - *unk_2A6 = Rand_S16Offset(0x3C, 0x3C); + if (!DECR(*blinkTimer)) { + *blinkTimer = Rand_S16Offset(0x3C, 0x3C); } - *unk_2A4 = *unk_2A6; - if (*unk_2A4 >= 3) { - *unk_2A4 = 0; + *eyeIndex = *blinkTimer; + if (*eyeIndex >= 3) { + *eyeIndex = 0; } } -s32 func_80AF2690(EnRu2* this) { - s32 params_shift = this->actor.params >> 8; +s32 EnRu2_GetSwitchFlag(EnRu2* this) { + s32 switchFlag = this->actor.params >> 8; - return params_shift & 0xFF; + return switchFlag & 0xFF; } -s32 func_80AF26A0(EnRu2* this) { +s32 EnRu2_GetType(EnRu2* this) { s16 params = this->actor.params; return params & 0xFF; } void func_80AF26AC(EnRu2* this) { - this->action = 7; - this->drawConfig = 0; + this->action = ENRU2_WATER_TRIAL_INVISIBLE; + this->drawConfig = ENRU2_DRAW_NOTHING; this->alpha = 0; - this->unk_2B8 = 0; + this->isLightBall = false; this->actor.shape.shadowAlpha = 0; - this->unk_2B0 = 0.0f; + this->fadeTimer = 0.0f; } void func_80AF26D0(EnRu2* this, PlayState* play) { @@ -155,6 +201,7 @@ void func_80AF26D0(EnRu2* this, PlayState* play) { if (play->csCtx.state == CS_STATE_IDLE) { if (D_80AF4118 != 0) { + // Seems like this state is never reached if (this->actor.params == 2) { func_80AF26AC(this); } @@ -169,7 +216,7 @@ void func_80AF26D0(EnRu2* this, PlayState* play) { } } -void func_80AF2744(EnRu2* this, PlayState* play) { +void EnRu2_UpdateBgCheckInfo(EnRu2* this, PlayState* play) { Actor_UpdateBgCheckInfo(play, &this->actor, 75.0f, 30.0f, 30.0f, 4); } @@ -177,75 +224,93 @@ s32 EnRu2_UpdateSkelAnime(EnRu2* this) { return SkelAnime_Update(&this->skelAnime); } -CsCmdActorCue* func_80AF27AC(PlayState* play, s32 npcActionIdx) { +CsCmdActorCue* EnRu2_GetCue(PlayState* play, s32 cueChannel) { if (play->csCtx.state != CS_STATE_IDLE) { - return play->csCtx.npcActions[npcActionIdx]; + return play->csCtx.npcActions[cueChannel]; } return NULL; } -s32 func_80AF27D0(EnRu2* this, PlayState* play, u16 arg2, s32 npcActionIdx) { - CsCmdActorCue* csCmdActorAction = func_80AF27AC(play, npcActionIdx); +s32 EnRu2_CheckCueMatchingId(EnRu2* this, PlayState* play, u16 cueId, s32 cueChannel) { + CsCmdActorCue* cue = EnRu2_GetCue(play, cueChannel); - if ((csCmdActorAction != NULL) && (csCmdActorAction->action == arg2)) { + if ((cue != NULL) && (cue->action == cueId)) { return true; } return false; } -s32 func_80AF281C(EnRu2* this, PlayState* play, u16 arg2, s32 npcActionIdx) { - CsCmdActorCue* csCmdNPCAction = func_80AF27AC(play, npcActionIdx); +s32 EnRu2_CheckCueNotMatchingId(EnRu2* this, PlayState* play, u16 cueId, s32 cueChannel) { + CsCmdActorCue* cue = EnRu2_GetCue(play, cueChannel); - if ((csCmdNPCAction != NULL) && (csCmdNPCAction->action != arg2)) { + if ((cue != NULL) && (cue->action != cueId)) { return true; } return false; } -void func_80AF2868(EnRu2* this, PlayState* play, u32 npcActionIdx) { - CsCmdActorCue* csCmdNPCAction = func_80AF27AC(play, npcActionIdx); +/** + * Checks cutscene data and, if applicable, configures Ruto's position accordingly. + */ +void EnRu2_InitPositionFromCue(EnRu2* this, PlayState* play, u32 npcActionIdx) { + CsCmdActorCue* cue = EnRu2_GetCue(play, npcActionIdx); s16 newRotY; Actor* thisx = &this->actor; - if (csCmdNPCAction != NULL) { - thisx->world.pos.x = csCmdNPCAction->startPos.x; - thisx->world.pos.y = csCmdNPCAction->startPos.y; - thisx->world.pos.z = csCmdNPCAction->startPos.z; - newRotY = csCmdNPCAction->rot.y; + if (cue != NULL) { + thisx->world.pos.x = cue->startPos.x; + thisx->world.pos.y = cue->startPos.y; + thisx->world.pos.z = cue->startPos.z; + newRotY = cue->rot.y; thisx->shape.rot.y = newRotY; thisx->world.rot.y = newRotY; } } -void func_80AF28E8(EnRu2* this, AnimationHeader* animation, u8 arg2, f32 transitionRate, s32 arg4) { +/** + * Changes the animation for Ruto's actor. The direction argument decides whether to play the animation + * forwards (if 0) or backwards (otherwise). + */ +void EnRu2_AnimationChange(EnRu2* this, AnimationHeader* animation, u8 mode, f32 transitionRate, s32 direction) { f32 frameCount = Animation_GetLastFrame(animation); f32 playbackSpeed; - f32 unk0; - f32 fc; + f32 startFrame; + f32 endFrame; - if (arg4 == 0) { - unk0 = 0.0f; - fc = frameCount; + if (direction == 0) { + startFrame = 0.0f; + endFrame = frameCount; playbackSpeed = 1.0f; } else { - unk0 = frameCount; - fc = 0.0f; + startFrame = frameCount; + endFrame = 0.0f; playbackSpeed = -1.0f; } - Animation_Change(&this->skelAnime, animation, playbackSpeed, unk0, fc, arg2, transitionRate); + Animation_Change(&this->skelAnime, animation, playbackSpeed, startFrame, endFrame, mode, transitionRate); } -void func_80AF2978(EnRu2* this, PlayState* play) { +/** + * Gradually increases Ruto's model's Y-offset as she rises up through the blue warp in the Chamber of Sages. + */ +void EnRu2_Rise(EnRu2* this, PlayState* play) { this->actor.shape.yOffset += 250.0f / 3.0f; } -void func_80AF2994(EnRu2* this, PlayState* play) { - func_80AF28E8(this, &gAdultRutoIdleAnim, 0, 0.0f, 0); +/** + * Sets up Ruto's actor in the Chamber of Sages. + * Note: All sages actors are present in the Chamber of Sages, regardless of which dungeon was just completed. + * This function runs unconditionally, even if it is not relevant for Ruto. + */ +void EnRu2_InitChamberOfSages(EnRu2* this, PlayState* play) { + EnRu2_AnimationChange(this, &gAdultRutoIdleAnim, 0, 0.0f, 0); this->actor.shape.yOffset = -10000.0f; } -void func_80AF29DC(EnRu2* this, PlayState* play) { +/** + * Spawns the blue warp for Ruto to rise up through in the Chamber of Sages. + */ +void EnRu2_SpawnBlueWarp(EnRu2* this, PlayState* play) { Actor* thisx = &this->actor; f32 posX = thisx->world.pos.x; f32 posY = thisx->world.pos.y; @@ -255,229 +320,265 @@ void func_80AF29DC(EnRu2* this, PlayState* play) { WARP_SAGES); } -void func_80AF2A38(EnRu2* this, PlayState* play) { +/** + * Spawns the Water Medallion. + */ +void EnRu2_SpawnWaterMedallion(EnRu2* this, PlayState* play) { Player* player = GET_PLAYER(play); f32 posX = player->actor.world.pos.x; f32 posY = player->actor.world.pos.y + 50.0f; f32 posZ = player->actor.world.pos.z; Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DEMO_EFFECT, posX, posY, posZ, 0, 0, 0, 10); + // Give the water medallion. This is redundant as it was already given in `EnRu2_CheckWaterMedallionCutscene` if (GameInteractor_Should(VB_GIVE_ITEM_WATER_MEDALLION, true)) { Item_Give(play, ITEM_MEDALLION_WATER); } } -void func_80AF2AB4(EnRu2* this, PlayState* play) { +/** + * Sets up the Water Medallion Cutscene if coming from Water Temple. + * All sage actors are present in the Chamber of Sages regardless of which dungeon was just completed. + * This function will loop endlessly if the current sage cutscene is not for the Water Medallion. + */ +void EnRu2_CheckWaterMedallionCutscene(EnRu2* this, PlayState* play) { s32 pad[2]; Player* player; - s16 temp; + s16 yaw; if ((gSaveContext.chamberCutsceneNum == 2) && (gSaveContext.sceneSetupIndex < 4)) { player = GET_PLAYER(play); - this->action = 1; - play->csCtx.segment = &D_80AF411C; + this->action = ENRU2_AWAIT_BLUE_WARP; + play->csCtx.segment = &gWaterMedallionCs; gSaveContext.cutsceneTrigger = 2; if (GameInteractor_Should(VB_GIVE_ITEM_WATER_MEDALLION, true)) { Item_Give(play, ITEM_MEDALLION_WATER); } - temp = this->actor.world.rot.y + 0x8000; - player->actor.shape.rot.y = temp; - player->actor.world.rot.y = temp; + yaw = this->actor.world.rot.y + 0x8000; + player->actor.shape.rot.y = yaw; + player->actor.world.rot.y = yaw; } } -void func_80AF2B44(EnRu2* this, PlayState* play) { +void EnRu2_CheckIfBlueWarpShouldSpawn(EnRu2* this, PlayState* play) { CutsceneContext* csCtx = &play->csCtx; - CsCmdActorCue* csCmdNPCAction; + CsCmdActorCue* cue; if (csCtx->state != CS_STATE_IDLE) { - csCmdNPCAction = csCtx->npcActions[3]; - if ((csCmdNPCAction != NULL) && (csCmdNPCAction->action == 2)) { - this->action = 2; - this->drawConfig = 1; - func_80AF29DC(this, play); + cue = csCtx->npcActions[3]; + if ((cue != NULL) && (cue->action == 2)) { + this->action = ENRU2_RISE_THROUGH_BLUE_WARP; + this->drawConfig = ENRU2_DRAW_OPA; + EnRu2_SpawnBlueWarp(this, play); } } } -void func_80AF2B94(EnRu2* this) { +/* Halts Ruto's rise up through the blue warp in the Chamber of Sages once finished. */ +void EnRu2_EndRise(EnRu2* this) { if (this->actor.shape.yOffset >= 0.0f) { - this->action = 3; + this->action = ENRU2_SAGE_OF_WATER_DIALOG; this->actor.shape.yOffset = 0.0f; } } -void func_80AF2BC0(EnRu2* this, PlayState* play) { +/** + * Sets up the animation for Ruto to raise her arms to give Link the Water Medallion. + */ +void EnRu2_CheckStartRaisingArms(EnRu2* this, PlayState* play) { AnimationHeader* animation = &gAdultRutoRaisingArmsUpAnim; - CsCmdActorCue* csCmdNPCAction; + CsCmdActorCue* cue; if (play->csCtx.state != CS_STATE_IDLE) { - csCmdNPCAction = play->csCtx.npcActions[3]; - if ((csCmdNPCAction != NULL) && (csCmdNPCAction->action == 3)) { + cue = play->csCtx.npcActions[3]; + if ((cue != NULL) && (cue->action == 3)) { Animation_Change(&this->skelAnime, animation, 1.0f, 0.0f, Animation_GetLastFrame(animation), ANIMMODE_ONCE, 0.0f); - this->action = 4; + this->action = ENRU2_RAISE_ARMS; } } } -void func_80AF2C54(EnRu2* this, s32 arg1) { - if (arg1 != 0) { - this->action = 5; +/** + * At the end of Ruto's arms-raising animation, cues the next action: spawning the + * Water Medallion. + */ +void EnRu2_HoldArmsUp(EnRu2* this, s32 doneRaising) { + if (doneRaising != 0) { + this->action = ENRU2_AWAIT_SPAWN_WATER_MEDALLION; } } -void func_80AF2C68(EnRu2* this, PlayState* play) { - CsCmdActorCue* csCmdNPCAction; +/** + * Checks to see if the Water Medallion should spawn. + */ +void EnRu2_CheckIfWaterMedallionShouldSpawn(EnRu2* this, PlayState* play) { + CsCmdActorCue* cue; if (play->csCtx.state != CS_STATE_IDLE) { - csCmdNPCAction = play->csCtx.npcActions[6]; - if ((csCmdNPCAction != NULL) && (csCmdNPCAction->action == 2)) { - this->action = 6; - func_80AF2A38(this, play); + cue = play->csCtx.npcActions[6]; + if ((cue != NULL) && (cue->action == 2)) { + this->action = ENRU2_FINISH_WATER_MEDALLION_CS; + EnRu2_SpawnWaterMedallion(this, play); } } } -void func_80AF2CB4(EnRu2* this, PlayState* play) { - func_80AF2AB4(this, play); +void EnRu2_SetupWaterMedallionCutscene(EnRu2* this, PlayState* play) { + EnRu2_CheckWaterMedallionCutscene(this, play); } -void func_80AF2CD4(EnRu2* this, PlayState* play) { - func_80AF2B44(this, play); +void EnRu2_AwaitBlueWarp(EnRu2* this, PlayState* play) { + EnRu2_CheckIfBlueWarpShouldSpawn(this, play); } -void func_80AF2CF4(EnRu2* this, PlayState* play) { - func_80AF2978(this, play); +void EnRu2_RiseThroughBlueWarp(EnRu2* this, PlayState* play) { + EnRu2_Rise(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); - func_80AF2B94(this); + EnRu2_UpdateEyes(this); + EnRu2_EndRise(this); } -void func_80AF2D2C(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); +void EnRu2_SageOfWaterDialog(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); - func_80AF2BC0(this, play); + EnRu2_UpdateEyes(this); + EnRu2_CheckStartRaisingArms(this, play); } -void func_80AF2D6C(EnRu2* this, PlayState* play) { - s32 something; +void EnRu2_RaiseArms(EnRu2* this, PlayState* play) { + s32 animDone; - func_80AF2744(this, play); - something = EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); - func_80AF2C54(this, something); + EnRu2_UpdateBgCheckInfo(this, play); + animDone = EnRu2_UpdateSkelAnime(this); + EnRu2_UpdateEyes(this); + EnRu2_HoldArmsUp(this, animDone); } -void func_80AF2DAC(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); +void EnRu2_AwaitWaterMedallion(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); - func_80AF2C68(this, play); + EnRu2_UpdateEyes(this); + EnRu2_CheckIfWaterMedallionShouldSpawn(this, play); } -void func_80AF2DEC(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); +void EnRu2_FinishWaterMedallionCutscene(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); + EnRu2_UpdateEyes(this); } -void func_80AF2E1C(EnRu2* this, PlayState* play) { - func_80AF28E8(this, &gAdultRutoCrossingArmsAnim, 2, 0.0f, 0); - this->action = 7; +/** + * Sets up Ruto in her arms-crossing pose. Used in the Water Trial in Ganon's Castle and in the + * Chamber of Sages during the "Sealing Ganon" cutscene. + */ +void EnRu2_InitWaterTrial(EnRu2* this, PlayState* play) { + EnRu2_AnimationChange(this, &gAdultRutoCrossingArmsAnim, 2, 0.0f, 0); + this->action = ENRU2_WATER_TRIAL_INVISIBLE; this->actor.shape.shadowAlpha = 0; } -void func_80AF2E64() { +void EnRu2_PlayWhiteOutSound() { Sfx_PlaySfxCentered2(NA_SE_SY_WHITE_OUT_T); } -void func_80AF2E84(EnRu2* this, PlayState* play) { +/** + * Spawns the ball of light that replaces Ruto's actor in the Water Trial. + */ +void EnRu2_SpawnLightBall(EnRu2* this, PlayState* play) { Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DEMO_6K, this->actor.world.pos.x, kREG(19) + 24.0f + this->actor.world.pos.y, this->actor.world.pos.z, 0, 0, 0, 8); } -void func_80AF2F04(EnRu2* this, PlayState* play) { - if (func_80AF27D0(this, play, 4, 3)) { - this->action = 8; - this->drawConfig = 2; +/** + * Checks to see if it's time for Ruto to fade in while crossing her arms. + */ +void EnRu2_CheckFadeIn(EnRu2* this, PlayState* play) { + if (EnRu2_CheckCueMatchingId(this, play, 4, 3)) { + this->action = ENRU2_WATER_TRIAL_FADE; + this->drawConfig = ENRU2_DRAW_XLU; this->alpha = 0; this->actor.shape.shadowAlpha = 0; - this->unk_2B0 = 0.0f; - func_80AF2E64(); + this->fadeTimer = 0.0f; + EnRu2_PlayWhiteOutSound(); } } -void func_80AF2F58(EnRu2* this, PlayState* play) { - f32* unk_2B0 = &this->unk_2B0; +/** + * Fades Ruto's actor in or out. Both happen during the Water Trial. + */ +void EnRu2_Fade(EnRu2* this, PlayState* play) { + f32* fadeTimer = &this->fadeTimer; s32 alpha; - if (func_80AF27D0(this, play, 4, 3)) { - *unk_2B0 += 1.0f; - if (*unk_2B0 >= kREG(5) + 10.0f) { - this->action = 9; - this->drawConfig = 1; - *unk_2B0 = kREG(5) + 10.0f; + if (EnRu2_CheckCueMatchingId(this, play, 4, 3)) { + *fadeTimer += 1.0f; + if (*fadeTimer >= kREG(5) + 10.0f) { + this->action = ENRU2_AWAIT_SPAWN_LIGHT_BALL; + this->drawConfig = ENRU2_DRAW_OPA; + *fadeTimer = kREG(5) + 10.0f; this->alpha = 255; this->actor.shape.shadowAlpha = 0xFF; return; } } else { - *unk_2B0 -= 1.0f; - if (*unk_2B0 <= 0.0f) { - this->action = 7; - this->drawConfig = 0; - *unk_2B0 = 0.0f; + *fadeTimer -= 1.0f; + if (*fadeTimer <= 0.0f) { + this->action = ENRU2_WATER_TRIAL_INVISIBLE; + this->drawConfig = ENRU2_DRAW_NOTHING; + *fadeTimer = 0.0f; this->alpha = 0; this->actor.shape.shadowAlpha = 0; return; } } - alpha = (*unk_2B0 / (kREG(5) + 10.0f)) * 255.0f; + alpha = (*fadeTimer / (kREG(5) + 10.0f)) * 255.0f; this->alpha = alpha; this->actor.shape.shadowAlpha = alpha; } -void func_80AF30AC(EnRu2* this, PlayState* play) { - if (func_80AF281C(this, play, 4, 3)) { - this->action = 8; - this->drawConfig = 2; - this->unk_2B0 = kREG(5) + 10.0f; +/** + * Checks to see if it's time for Ruto to fade out while her arms are crossed. + */ +void EnRu2_CheckFadeOut(EnRu2* this, PlayState* play) { + if (EnRu2_CheckCueNotMatchingId(this, play, 4, 3)) { + this->action = ENRU2_WATER_TRIAL_FADE; + this->drawConfig = ENRU2_DRAW_XLU; + this->fadeTimer = kREG(5) + 10.0f; this->alpha = 255; - if (this->unk_2B8 == 0) { - func_80AF2E84(this, play); - this->unk_2B8 = 1; + if (!this->isLightBall) { + EnRu2_SpawnLightBall(this, play); + this->isLightBall = true; } this->actor.shape.shadowAlpha = 0xFF; } } -void func_80AF3144(EnRu2* this, PlayState* play) { - func_80AF2F04(this, play); +void EnRu2_WaterTrialInvisible(EnRu2* this, PlayState* play) { + EnRu2_CheckFadeIn(this, play); func_80AF26D0(this, play); } -void func_80AF3174(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); +void EnRu2_WaterTrialFade(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); - func_80AF2F58(this, play); + EnRu2_UpdateEyes(this); + EnRu2_Fade(this, play); func_80AF26D0(this, play); } -void func_80AF31C8(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); +void EnRu2_AwaitSpawnLightBall(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); - func_80AF30AC(this, play); + EnRu2_UpdateEyes(this); + EnRu2_CheckFadeOut(this, play); func_80AF26D0(this, play); } -void func_80AF321C(EnRu2* this, PlayState* play) { +void EnRu2_DrawXlu(EnRu2* this, PlayState* play) { s32 pad[2]; - s16 temp = this->unk_2A4; - void* tex = sEyeTextures[temp]; + s16 eyeIndex = this->eyeIndex; + void* tex = sEyeTextures[eyeIndex]; SkelAnime* skelAnime = &this->skelAnime; OPEN_DISPS(play->state.gfxCtx); @@ -495,140 +596,164 @@ void func_80AF321C(EnRu2* this, PlayState* play) { CLOSE_DISPS(play->state.gfxCtx); } -void func_80AF3394(EnRu2* this, PlayState* play) { - func_80AF28E8(this, &gAdultRutoIdleHandsOnHipsAnim, 0, 0.0f, 0); - this->action = 10; - this->drawConfig = 0; +/** + * Sets up Ruto's hands-on-hips pose during the credits sequence. + */ +void EnRu2_InitCredits(EnRu2* this, PlayState* play) { + EnRu2_AnimationChange(this, &gAdultRutoIdleHandsOnHipsAnim, 0, 0.0f, 0); + this->action = ENRU2_CREDITS_INVISIBLE; + this->drawConfig = ENRU2_DRAW_NOTHING; this->actor.shape.shadowAlpha = 0; } -void func_80AF33E0(EnRu2* this) { - f32* unk_2B0 = &this->unk_2B0; - f32 temp_f0; - s32 temp_f18; +/** + * Fades in Ruto's actor during the credits sequence. + */ +void EnRu2_FadeInCredits(EnRu2* this) { + f32* fadeTimer = &this->fadeTimer; + f32 fadeDuration; + s32 alpha; - *unk_2B0 += 1.0f; + *fadeTimer += 1.0f; - temp_f0 = kREG(17) + 10.0f; - if (temp_f0 <= *unk_2B0) { + fadeDuration = kREG(17) + 10.0f; + if (fadeDuration <= *fadeTimer) { this->alpha = 255; this->actor.shape.shadowAlpha = 0xFF; } else { - temp_f18 = (*unk_2B0 / temp_f0) * 255.0f; - this->alpha = temp_f18; - this->actor.shape.shadowAlpha = temp_f18; + alpha = (*fadeTimer / fadeDuration) * 255.0f; + this->alpha = alpha; + this->actor.shape.shadowAlpha = alpha; } } -void func_80AF346C(EnRu2* this, PlayState* play) { - func_80AF2868(this, play, 3); - this->action = 11; - this->drawConfig = 2; +void EnRu2_InitCreditsPosition(EnRu2* this, PlayState* play) { + EnRu2_InitPositionFromCue(this, play, 3); + this->action = ENRU2_CREDITS_FADE_IN; + this->drawConfig = ENRU2_DRAW_XLU; } -void func_80AF34A4(EnRu2* this) { - if (this->unk_2B0 >= kREG(17) + 10.0f) { - this->action = 12; - this->drawConfig = 1; +/** + * Checks for the end of Ruto's fade-in during the credits sequence. + */ +void EnRu2_CheckVisibleInCredits(EnRu2* this) { + if (this->fadeTimer >= kREG(17) + 10.0f) { + this->action = ENRU2_CREDITS_VISIBLE; + this->drawConfig = ENRU2_DRAW_OPA; } } -void func_80AF34F0(EnRu2* this) { - func_80AF28E8(this, &gAdultRutoHeadTurnDownLeftAnim, 2, 0.0f, 0); - this->action = 13; +/** + * Starts Ruto's animation to look down towards Nabooru during the credits sequence. + */ +void EnRu2_SetupTurnHeadDownLeftAnimation(EnRu2* this) { + EnRu2_AnimationChange(this, &gAdultRutoHeadTurnDownLeftAnim, 2, 0.0f, 0); + this->action = ENRU2_CREDITS_TURN_HEAD_DOWN_LEFT; } -void func_80AF3530(EnRu2* this, s32 arg1) { - if (arg1 != 0) { - func_80AF28E8(this, &gAdultRutoLookingDownLeftAnim, 0, 0.0f, 0); +/** + * Holds Ruto's pose looking down towards Nabooru during the credits sequence. + */ +void EnRu2_HoldLookingDownLeftPose(EnRu2* this, s32 isDoneTurning) { + if (isDoneTurning != 0) { + EnRu2_AnimationChange(this, &gAdultRutoLookingDownLeftAnim, 0, 0.0f, 0); } } -void func_80AF3564(EnRu2* this, PlayState* play) { - CsCmdActorCue* csCmdNPCAction = func_80AF27AC(play, 3); - s32 action; - s32 unk_2BC; +/** + * Advances Ruto's actions in two different places. + */ +void EnRu2_NextCreditsAction(EnRu2* this, PlayState* play) { + CsCmdActorCue* cue = EnRu2_GetCue(play, 3); + s32 nextCueId; + s32 currentCueId; - if (csCmdNPCAction != NULL) { - action = csCmdNPCAction->action; - unk_2BC = this->unk_2BC; - if (action != unk_2BC) { - switch (action) { + if (cue != NULL) { + nextCueId = cue->action; + currentCueId = this->cueId; + if (nextCueId != currentCueId) { + switch (nextCueId) { case 7: - func_80AF346C(this, play); + EnRu2_InitCreditsPosition(this, play); break; case 8: - func_80AF34F0(this); + EnRu2_SetupTurnHeadDownLeftAnimation(this); break; default: // "There is no such action!" osSyncPrintf("En_Ru2_inEnding_Check_DemoMode:そんな動作は無い!!!!!!!!\n"); break; } - this->unk_2BC = action; + this->cueId = nextCueId; } } } -void func_80AF3604(EnRu2* this, PlayState* play) { - func_80AF3564(this, play); +void EnRu2_CreditsInvisible(EnRu2* this, PlayState* play) { + EnRu2_NextCreditsAction(this, play); } -void func_80AF3624(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); +void EnRu2_CreditsFadeIn(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); - func_80AF33E0(this); - func_80AF34A4(this); + EnRu2_UpdateEyes(this); + EnRu2_FadeInCredits(this); + EnRu2_CheckVisibleInCredits(this); } -void func_80AF366C(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); +void EnRu2_CreditsVisible(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); - func_80AF3564(this, play); + EnRu2_UpdateEyes(this); + EnRu2_NextCreditsAction(this, play); } -void func_80AF36AC(EnRu2* this, PlayState* play) { - s32 something; +void EnRu2_CreditsTurnHeadDownLeft(EnRu2* this, PlayState* play) { + s32 animDone; - func_80AF2744(this, play); - something = EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); - func_80AF3530(this, something); + EnRu2_UpdateBgCheckInfo(this, play); + animDone = EnRu2_UpdateSkelAnime(this); + EnRu2_UpdateEyes(this); + EnRu2_HoldLookingDownLeftPose(this, animDone); } -void func_80AF36EC(EnRu2* this, PlayState* play) { - Flags_SetSwitch(play, func_80AF2690(this)); +void EnRu2_SetEncounterSwitchFlag(EnRu2* this, PlayState* play) { + Flags_SetSwitch(play, EnRu2_GetSwitchFlag(this)); } -s32 func_80AF3718(EnRu2* this, PlayState* play) { - return Flags_GetSwitch(play, func_80AF2690(this)); +s32 EnRu2_GetEncounterSwitchFlag(EnRu2* this, PlayState* play) { + return Flags_GetSwitch(play, EnRu2_GetSwitchFlag(this)); } -void func_80AF3744(EnRu2* this, PlayState* play) { - if (func_80AF3718(this, play)) { +/** + * Initializes Ruto's actor in the Water Temple, or destroys it if the encounter already happened. + */ +void EnRu2_InitWaterTempleEncounter(EnRu2* this, PlayState* play) { + if (EnRu2_GetEncounterSwitchFlag(this, play)) { Actor_Kill(&this->actor); } else { - func_80AF28E8(this, &gAdultRutoIdleAnim, 0, 0.0f, 0); - this->action = 14; - this->drawConfig = 1; + EnRu2_AnimationChange(this, &gAdultRutoIdleAnim, 0, 0.0f, 0); + this->action = ENRU2_WATER_TEMPLE_ENCOUNTER_RANGE_CHECK; + this->drawConfig = ENRU2_DRAW_OPA; } } -void func_80AF37AC(void) { +void EnRu2_PlayFanfare(void) { Audio_PlayFanfare(NA_BGM_APPEAR); } -void func_80AF37CC(EnRu2* this) { +/** + * Accelerates Ruto's actor upwards as she swims. + */ +void EnRu2_SwimUpProgress(EnRu2* this) { f32 funcFloat; - this->unk_2C0++; - funcFloat = Environment_LerpWeightAccelDecel((kREG(2) + 0x96) & 0xFFFF, 0, this->unk_2C0, 8, 0); + this->swimmingUpFrame++; + funcFloat = Environment_LerpWeightAccelDecel((kREG(2) + 0x96) & 0xFFFF, 0, this->swimmingUpFrame, 8, 0); this->actor.world.pos.y = this->actor.home.pos.y + (300.0f * funcFloat); } -s32 func_80AF383C(EnRu2* this, PlayState* play) { +s32 EnRu2_IsPlayerInRangeForEncounter(EnRu2* this, PlayState* play) { Player* player = GET_PLAYER(play); f32 thisPosX = this->actor.world.pos.x; f32 playerPosX = player->actor.world.pos.x; @@ -639,32 +764,42 @@ s32 func_80AF383C(EnRu2* this, PlayState* play) { return 0; } -void func_80AF3878(EnRu2* this, PlayState* play) { - if (func_80AF383C(this, play) && !Play_InCsMode(play)) { - this->action = 16; +/** + * Checks if Link is close enough to Ruto and conditionally triggers the encounter cutscene in the Water Temple. + */ +void EnRu2_CheckRangeToStartEncounter(EnRu2* this, PlayState* play) { + if (EnRu2_IsPlayerInRangeForEncounter(this, play) && !Play_InCsMode(play)) { + this->action = ENRU2_WATER_TEMPLE_ENCOUNTER_BEGINNING; this->subCamId = OnePointCutscene_Init(play, 3130, -99, &this->actor, MAIN_CAM); } } -void func_80AF38D0(EnRu2* this, PlayState* play) { - this->action = 16; +/** + * Triggers the encounter cutscene in the Water Temple, unconditionally. Appears to be unused. + */ +void EnRu2_StartEncounter(EnRu2* this, PlayState* play) { + this->action = ENRU2_WATER_TEMPLE_ENCOUNTER_BEGINNING; this->subCamId = OnePointCutscene_Init(play, 3130, -99, &this->actor, MAIN_CAM); } -void func_80AF390C(EnRu2* this, PlayState* play) { - f32* unk_2C4 = &this->unk_2C4; +/** + * Handles the starting moments of Ruto's encounter with Link at the Water Temple. Responds to a running timer to + * initiate, on cue, both the fanfare and Ruto's dialogue. + */ +void EnRu2_EncounterBeginningHandler(EnRu2* this, PlayState* play) { + f32* encounterTimer = &this->encounterTimer; - *unk_2C4 += 1.0f; - if (*unk_2C4 == kREG(6) + 40.0f) { - func_80AF37AC(); - } else if (*unk_2C4 > kREG(4) + 50.0f) { + *encounterTimer += 1.0f; + if (*encounterTimer == kREG(6) + 40.0f) { + EnRu2_PlayFanfare(); + } else if (*encounterTimer > kREG(4) + 50.0f) { this->actor.textId = 0x403E; Message_StartTextbox(play, this->actor.textId, NULL); - this->action = 17; + this->action = ENRU2_WATER_TEMPLE_ENCOUNTER_DIALOG; } } -void func_80AF39DC(EnRu2* this, PlayState* play) { +void EnRu2_DialogCameraHandler(EnRu2* this, PlayState* play) { s32 pad; MessageContext* msgCtx; s32 pad2; @@ -676,11 +811,11 @@ void func_80AF39DC(EnRu2* this, PlayState* play) { dialogState = Message_GetState(msgCtx); if (dialogState == TEXT_STATE_DONE_FADING) { - if (this->unk_2C3 != TEXT_STATE_DONE_FADING) { + if (this->lastDialogState != TEXT_STATE_DONE_FADING) { // "I'm Komatsu!" (cinema scene dev) osSyncPrintf("おれが小松だ! \n"); - this->unk_2C2++; - if (this->unk_2C2 % 6 == 3) { + this->textboxCount++; + if (this->textboxCount % 6 == 3) { player = GET_PLAYER(play); // "uorya-!" (screeming sound) osSyncPrintf("うおりゃー! \n"); @@ -692,75 +827,76 @@ void func_80AF39DC(EnRu2* this, PlayState* play) { } } - this->unk_2C3 = dialogState; + this->lastDialogState = dialogState; if (Message_GetState(msgCtx) == TEXT_STATE_CLOSING) { - this->action = 18; + this->action = ENRU2_WATER_TEMPLE_ENCOUNTER_END; func_8005B1A4(GET_ACTIVE_CAM(play)); } } -void func_80AF3ADC(EnRu2* this, PlayState* play) { - this->unk_2C4 += 1.0f; - if (this->unk_2C4 > kREG(5) + 100.0f) { - func_80AF28E8(this, &gAdultRutoSwimmingUpAnim, 0, -12.0f, 0); - this->action = 19; - func_80AF36EC(this, play); +void EnRu2_StartSwimmingUp(EnRu2* this, PlayState* play) { + this->encounterTimer += 1.0f; + if (this->encounterTimer > kREG(5) + 100.0f) { + EnRu2_AnimationChange(this, &gAdultRutoSwimmingUpAnim, 0, -12.0f, 0); + this->action = ENRU2_WATER_TEMPLE_SWIMMING_UP; + EnRu2_SetEncounterSwitchFlag(this, play); } } -void func_80AF3B74(EnRu2* this, PlayState* play) { - if (this->unk_2C0 > ((((u16)(kREG(3) + 0x28)) + ((u16)(kREG(2) + 0x96))) & 0xFFFF)) { +void EnRu2_EndSwimmingUp(EnRu2* this, PlayState* play) { + if (this->swimmingUpFrame > ((((u16)(kREG(3) + 0x28)) + ((u16)(kREG(2) + 0x96))) & 0xFFFF)) { Actor_Kill(&this->actor); OnePointCutscene_EndCutscene(play, this->subCamId); } } -void func_80AF3BC8(EnRu2* this, PlayState* play) { - func_80AF3878(this, play); +void EnRu2_WaterTempleEncounterRangeCheck(EnRu2* this, PlayState* play) { + EnRu2_CheckRangeToStartEncounter(this, play); Actor_SetFocus(&this->actor, 50.0f); - func_80AF259C(this, play); + EnRu2_UpdateCollider(this, play); } -void func_80AF3C04(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); - func_80AF259C(this, play); +// This one seems to be unused. +void EnRu2_WaterTempleEncounterUnconditional(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); + EnRu2_UpdateCollider(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); + EnRu2_UpdateEyes(this); Actor_SetFocus(&this->actor, 50.0f); - func_80AF38D0(this, play); + EnRu2_StartEncounter(this, play); } -void func_80AF3C64(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); +void EnRu2_WaterTempleEncounterBegin(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); + EnRu2_UpdateEyes(this); Actor_SetFocus(&this->actor, 50.0f); - func_80AF390C(this, play); + EnRu2_EncounterBeginningHandler(this, play); } -void func_80AF3CB8(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); +void EnRu2_WaterTempleEncounterDialog(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); + EnRu2_UpdateEyes(this); Actor_SetFocus(&this->actor, 50.0f); - func_80AF39DC(this, play); + EnRu2_DialogCameraHandler(this, play); } -void func_80AF3D0C(EnRu2* this, PlayState* play) { - func_80AF2744(this, play); +void EnRu2_WaterTempleEncounterEnd(EnRu2* this, PlayState* play) { + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); + EnRu2_UpdateEyes(this); Actor_SetFocus(&this->actor, 50.0f); - func_80AF3ADC(this, play); + EnRu2_StartSwimmingUp(this, play); } -void func_80AF3D60(EnRu2* this, PlayState* play) { - func_80AF37CC(this); - func_80AF2744(this, play); +void EnRu2_WaterTempleSwimmingUp(EnRu2* this, PlayState* play) { + EnRu2_SwimUpProgress(this); + EnRu2_UpdateBgCheckInfo(this, play); EnRu2_UpdateSkelAnime(this); - func_80AF2608(this); + EnRu2_UpdateEyes(this); Actor_SetFocus(&this->actor, 50.0f); - func_80AF3B74(this, play); + EnRu2_EndSwimmingUp(this, play); } void EnRu2_Update(Actor* thisx, PlayState* play) { @@ -778,36 +914,36 @@ void EnRu2_Init(Actor* thisx, PlayState* play) { EnRu2* this = (EnRu2*)thisx; ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 30.0f); - func_80AF2550(thisx, play); + EnRu2_InitCollider(thisx, play); SkelAnime_InitFlex(play, &this->skelAnime, &gAdultRutoSkel, NULL, this->jointTable, this->morphTable, 23); - switch (func_80AF26A0(this)) { + switch (EnRu2_GetType(this)) { case 2: - func_80AF2E1C(this, play); + EnRu2_InitWaterTrial(this, play); break; case 3: - func_80AF3394(this, play); + EnRu2_InitCredits(this, play); break; case 4: - func_80AF3744(this, play); + EnRu2_InitWaterTempleEncounter(this, play); break; default: - func_80AF2994(this, play); + EnRu2_InitChamberOfSages(this, play); break; } - this->unk_2C2 = 0; - this->unk_2C3 = TEXT_STATE_DONE_FADING; + this->textboxCount = 0; + this->lastDialogState = TEXT_STATE_DONE_FADING; this->subCamId = 0; } -void func_80AF3F14(EnRu2* this, PlayState* play) { +void EnRu2_DrawNothing(EnRu2* this, PlayState* play) { } -void func_80AF3F20(EnRu2* this, PlayState* play) { +void EnRu2_DrawOpa(EnRu2* this, PlayState* play) { s32 pad[2]; - s16 temp = this->unk_2A4; - void* tex = sEyeTextures[temp]; + s16 eyeIndex = this->eyeIndex; + void* tex = sEyeTextures[eyeIndex]; SkelAnime* skelAnime = &this->skelAnime; OPEN_DISPS(play->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.h b/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.h index 5334857fc..4d3da728b 100644 --- a/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.h +++ b/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.h @@ -14,18 +14,18 @@ typedef struct EnRu2 { /* 0x014C */ SkelAnime skelAnime; /* 0x0190 */ Vec3s jointTable[23]; /* 0x021A */ Vec3s morphTable[23]; - /* 0x02A4 */ s16 unk_2A4; - /* 0x02A6 */ s16 unk_2A6; + /* 0x02A4 */ s16 eyeIndex; + /* 0x02A6 */ s16 blinkTimer; /* 0x02A8 */ s32 action; /* 0x02AC */ s32 drawConfig; - /* 0x02B0 */ f32 unk_2B0; + /* 0x02B0 */ f32 fadeTimer; /* 0x02B4 */ u32 alpha; - /* 0x02B8 */ s32 unk_2B8; - /* 0x02BC */ s32 unk_2BC; - /* 0x02C0 */ u16 unk_2C0; - /* 0x02C2 */ u8 unk_2C2; - /* 0x02C3 */ u8 unk_2C3; - /* 0x02C4 */ f32 unk_2C4; + /* 0x02B8 */ s32 isLightBall; + /* 0x02BC */ s32 cueId; + /* 0x02C0 */ u16 swimmingUpFrame; + /* 0x02C2 */ u8 textboxCount; + /* 0x02C3 */ u8 lastDialogState; + /* 0x02C4 */ f32 encounterTimer; /* 0x02C8 */ ColliderCylinder collider; /* 0x02C8 */ s16 subCamId; } EnRu2; // size = 0x0314 diff --git a/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2_cutscene_data.c b/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2_cutscene_data.c index e265d10a9..998ae8b24 100644 --- a/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2_cutscene_data.c +++ b/soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2_cutscene_data.c @@ -2,7 +2,7 @@ #include "z64cutscene_commands.h" // clang-format off -static CutsceneData D_80AF411C[] = { +static CutsceneData gWaterMedallionCs[] = { CS_BEGIN_CUTSCENE(35, 3338), CS_UNK_DATA_LIST(0x00000020, 1), CS_UNK_DATA(0x00010000, 0x0BB80000, 0x00000000, 0x00000000, 0xFFFFFFFC, 0x00000002, 0x00000000, 0xFFFFFFFC, 0x00000002, 0x00000000, 0x00000000, 0x00000000), From f852d70767c68139a85826f34103bedc60b8d124 Mon Sep 17 00:00:00 2001 From: Jordan Longstaff Date: Mon, 9 Dec 2024 21:24:37 -0500 Subject: [PATCH 5/6] Properly replicate NaviTalk kill check (#4647) * Restrict disabled Navi workaround to Dodongo's Cavern * Properly replicate NaviTalk kill check * Move `*should = false` out of condition --- soh/soh/Enhancements/timesaver_hook_handlers.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/soh/soh/Enhancements/timesaver_hook_handlers.cpp b/soh/soh/Enhancements/timesaver_hook_handlers.cpp index 86e8c37e9..74a2f2138 100644 --- a/soh/soh/Enhancements/timesaver_hook_handlers.cpp +++ b/soh/soh/Enhancements/timesaver_hook_handlers.cpp @@ -340,11 +340,14 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li if (ForcedDialogIsDisabled(FORCED_DIALOG_SKIP_NAVI)) { ElfMsg* naviTalk = va_arg(args, ElfMsg*); int32_t paramsHighByte = naviTalk->actor.params >> 8; - if ((paramsHighByte & 0x80) == 0 && (paramsHighByte & 0x3F) != 0x3F) { - Flags_SetSwitch(gPlayState, paramsHighByte & 0x3F); - Actor_Kill(&naviTalk->actor); - *should = false; + if ((paramsHighByte & 0x80) != 0) { + break; } + if ((paramsHighByte & 0x3F) != 0x3F) { + Flags_SetSwitch(gPlayState, paramsHighByte & 0x3F); + } + Actor_Kill(&naviTalk->actor); + *should = false; } break; } From 7d80d1c85d6cec09faa22da3532cd9928496ccdf Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Tue, 10 Dec 2024 02:24:51 +0000 Subject: [PATCH 6/6] Fix boss hints and gift from sages hint. (#4634) --- .../randomizer/3drando/hint_list.cpp | 135 +++++++++--------- .../Enhancements/randomizer/location_list.cpp | 2 +- .../Enhancements/randomizer/randomizerTypes.h | 1 + 3 files changed, 72 insertions(+), 66 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp index e0097a6f6..6c0beacd5 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp @@ -2493,86 +2493,91 @@ void StaticData::HintTable_Init() { /*-------------------------- | BOSS HINT TEXT | ---------------------------*/ - - hintTextTable[RHT_QUEEN_GOHMA] = HintText(CustomMessage("#Queen Gohma# holds", - /*german*/ "#Königin Gohma# hält", - /*french*/ "la #Reine Gohma# possède"), - // /*spanish*/la #Reina Goma# porta +//RANDOTODO check the beginning and end on the french and german translations + hintTextTable[RHT_QUEEN_GOHMA] = HintText(CustomMessage("They say that #Queen Gohma# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß #Königin Gohma# hält #[[1]]# lehre.", + /*french*/ "Selon moi, la #Reine Gohma# possède #[[1]]#.", {QM_RED, QM_GREEN}), + // /*spanish*/la #Reina Goma# porta #[[1]]#. {}, - {CustomMessage("the #Parasitic Armored Arachnid# holds", - /*german*/ "die #gepanzerte parasitäre Spinne# hält", - /*french*/ "le #monstre insectoïde géant# possède")}); - // /*spanish*/el #arácnido parasitario acorazado# porta + {CustomMessage("They say that the #Parasitic Armored Arachnid# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß die #gepanzerte parasitäre Spinne# hält #[[1]]# lehre.", + /*french*/ "Selon moi, le #monstre insectoïde géant# possède #[[1]]#.", {QM_RED, QM_GREEN})}); + // /*spanish*/el #arácnido parasitario acorazado# porta #[[1]]#. - hintTextTable[RHT_KING_DODONGO] = HintText(CustomMessage("#King Dodongo# holds", - /*german*/ "#König Dodongo# hält", - /*french*/ "le #Roi Dodongo# possède"), - // /*spanish*/el #Rey Dodongo# porta + hintTextTable[RHT_KING_DODONGO] = HintText(CustomMessage("They say that #King Dodongo# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß #König Dodongo# hält #[[1]]# lehre.", + /*french*/ "Selon moi, le #Roi Dodongo# possède #[[1]]#.", {QM_RED, QM_GREEN}), + // /*spanish*/el #Rey Dodongo# porta #[[1]]#. {}, - {CustomMessage("the #Infernal Dinosaur# holds", - /*german*/ "der #infernalische Dinosaurier# hält", - /*french*/ "le #dinosaure infernal# possède")}); - // /*spanish*/el #dinosaurio infernal# porta + {CustomMessage("They say that the #Infernal Dinosaur# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß der #infernalische Dinosaurier# hält #[[1]]# lehre.", + /*french*/ "Selon moi, le #dinosaure infernal# possède #[[1]]#.", {QM_RED, QM_GREEN})}); + // /*spanish*/el #dinosaurio infernal# porta #[[1]]#. - hintTextTable[RHT_BARINADE] = HintText(CustomMessage("#Barinade# holds", - /*german*/ "#Barinade# hält", - /*french*/ "#Barinade# possède"), - // /*spanish*/#Barinade# porta + hintTextTable[RHT_BARINADE] = HintText(CustomMessage("They say that #Barinade# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß #Barinade# hält #[[1]]# lehre.", + /*french*/ "Selon moi, #Barinade# possède #[[1]]#.", {QM_RED, QM_GREEN}), + // /*spanish*/#Barinade# porta #[[1]]#. {}, - {CustomMessage("the #Bio-Electric Anemone# holds", - /*german*/ "die #bioelektrische Anemone# hält", - /*french*/ "l'#anémone bioélectrique# possède")}); - // /*spanish*/la #anémona bioeléctrica# porta + {CustomMessage("They say that the #Bio-Electric Anemone# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß die #bioelektrische Anemone# hält #[[1]]# lehre.", + /*french*/ "Selon moi, l'#anémone bioélectrique# possède #[[1]]#.", {QM_RED, QM_GREEN})}); + // /*spanish*/la #anémona bioeléctrica# porta #[[1]]#. - hintTextTable[RHT_PHANTOM_GANON] = HintText(CustomMessage("#Phantom Ganon# holds", - /*german*/ "#Phantom-Ganon# hält", - /*french*/ "#Ganon Spectral# possède"), - // /*spanish*/#Ganon Fantasma# porta + hintTextTable[RHT_PHANTOM_GANON] = HintText(CustomMessage("They say that #Phantom Ganon# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß #Phantom-Ganon# hält #[[1]]# lehre.", + /*french*/ "Selon moi, #Ganon Spectral# possède #[[1]]#.", {QM_RED, QM_GREEN}), + // /*spanish*/#Ganon Fantasma# porta #[[1]]#. {}, - {CustomMessage("the #Evil Spirit from Beyond# holds", - /*german*/ "der #böse Geist aus dem Jenseits# hält", - /*french*/ "l'#esprit maléfique de l'au-delà# possède")}); - // /*spanish*/el #espíritu maligno de ultratumba# porta + {CustomMessage("They say that the #Evil Spirit from Beyond# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß der #böse Geist aus dem Jenseits# hält #[[1]]# lehre.", + /*french*/ "Selon moi, l'#esprit maléfique de l'au-delà# possède #[[1]]#.", {QM_RED, QM_GREEN})}); + // /*spanish*/el #espíritu maligno de ultratumba# porta #[[1]]#. - hintTextTable[RHT_VOLVAGIA] = HintText(CustomMessage("#Volvagia# holds", - /*german*/ "#Volvagia# hält", - /*french*/ "#Volvagia# possède"), - // /*spanish*/#Volvagia# porta + hintTextTable[RHT_VOLVAGIA] = HintText(CustomMessage("They say that #Volvagia# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß #Volvagia# hält #[[1]]# lehre.", + /*french*/ "Selon moi, #Volvagia# possède #[[1]]#.", {QM_RED, QM_GREEN}), + // /*spanish*/#Volvagia# porta #[[1]]#. {}, - {CustomMessage("the #Subterranean Lava Dragon# holds", - /*german*/ "der #subterrane Lavadrache# hält", - /*french*/ "le #dragon des profondeurs# possède")}); - // /*spanish*/el #dragón de lava subterráneo# porta + {CustomMessage("They say that the #Subterranean Lava Dragon# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß der #subterrane Lavadrache# hält #[[1]]# lehre.", + /*french*/ "Selon moi, le #dragon des profondeurs# possède #[[1]]#.", {QM_RED, QM_GREEN})}); + // /*spanish*/el #dragón de lava subterráneo# porta #[[1]]#. - hintTextTable[RHT_MORPHA] = HintText(CustomMessage("#Morpha# holds", - /*german*/ "#Morpha# hält", - /*french*/ "#Morpha# possède"), - // /*spanish*/#Morpha# porta + hintTextTable[RHT_MORPHA] = HintText(CustomMessage("They say that #Morpha# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß #Morpha# hält #[[1]]# lehre.", + /*french*/ "Selon moi, #Morpha# possède #[[1]]#.", {QM_RED, QM_GREEN}), + // /*spanish*/#Morpha# porta #[[1]]#. {}, - {CustomMessage("the #Giant Aquatic Amoeba# holds", - /*german*/ "die #gigantische aquatische Amöbe# hält", - /*french*/ "l'#amibe aquatique géante# possède")}); - // /*spanish*/la #ameba acuática gigante# porta + {CustomMessage("They say that the #Giant Aquatic Amoeba# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß die #gigantische aquatische Amöbe# hält #[[1]]# lehre.", + /*french*/ "Selon moi, l'#amibe aquatique géante# possède #[[1]]#.", {QM_RED, QM_GREEN})}); + // /*spanish*/la #ameba acuática gigante# porta #[[1]]#. - hintTextTable[RHT_BONGO_BONGO] = HintText(CustomMessage("#Bongo Bongo# holds", - /*german*/ "#Bongo Bongo# hält", - /*french*/ "#Bongo Bongo# possède"), - // /*spanish*/#Bongo Bongo# porta + hintTextTable[RHT_BONGO_BONGO] = HintText(CustomMessage("They say that #Bongo Bongo# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß #Bongo Bongo# hält #[[1]]# lehre.", + /*french*/ "Selon moi, #Bongo Bongo# possède #[[1]]#.", {QM_RED, QM_GREEN}), + // /*spanish*/#Bongo Bongo# porta #[[1]]#. {}, - {CustomMessage("the #Phantom Shadow Beast# holds", - /*german*/ "das #Phantomschattenbiest# hält", - /*french*/ "le #monstre de l'ombre# possède")}); - // /*spanish*/la #alimaña oscura espectral# porta + {CustomMessage("They say that the #Phantom Shadow Beast# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß das #Phantomschattenbiest# hält #[[1]]# lehre.", + /*french*/ "Selon moi, le #monstre de l'ombre# possède #[[1]]#.", {QM_RED, QM_GREEN})}); + // /*spanish*/la #alimaña oscura espectral# porta #[[1]]#. - hintTextTable[RHT_TWINROVA] = HintText(CustomMessage("#Twinrova# holds", - /*german*/ "#Twinrova# hält", - /*french*/ "#Twinrova# possède"), - // /*spanish*/#Birova# porta + hintTextTable[RHT_TWINROVA] = HintText(CustomMessage("They say that #Twinrova# holds #[[1]]#.", + /*german*/ "Man erzählt sich, daß #Twinrova# hält #[[1]]# lehre.", + /*french*/ "Selon moi, #Twinrova# possède #[[1]]#.", {QM_RED, QM_GREEN}), + // /*spanish*/#Birova# porta #[[1]]#. {}, - {CustomMessage("the #Sorceress Sisters# hold", - /*german*/ "die #Hexenschwestern# halten", - /*french*/ "#les sorcières jumelles# possède")}); - // /*spanish*/las #hermanas hechiceras# portan + {CustomMessage("They say that the #Sorceress Sisters# hold #[[1]]#.", + /*german*/ "Man erzählt sich, daß die #Hexenschwestern# halten #[[1]]# lehre.", + /*french*/ "Selon moi, #les sorcières jumelles# possède #[[1]]#.", {QM_RED, QM_GREEN})}); + // /*spanish*/las #hermanas hechiceras# portan #[[1]]#. + + hintTextTable[RHT_GIFT_FROM_SAGES] = HintText(CustomMessage("They say that the #Sage of Light# gifts @ #[[1]]#.", {QM_RED, QM_GREEN}), + {}, + {CustomMessage("They say that #a former owl# gifts @ #[[1]]#.", {QM_RED, QM_GREEN})}); + /*-------------------------- | BRIDGE HINT TEXT | ---------------------------*/ diff --git a/soh/soh/Enhancements/randomizer/location_list.cpp b/soh/soh/Enhancements/randomizer/location_list.cpp index cdfd88680..9bf35b1f9 100644 --- a/soh/soh/Enhancements/randomizer/location_list.cpp +++ b/soh/soh/Enhancements/randomizer/location_list.cpp @@ -818,7 +818,7 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_TWINROVA] = Location::Base(RC_TWINROVA, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, ACTOR_DOOR_WARP1, SCENE_SPIRIT_TEMPLE_BOSS, 0x00, "Twinrova", "Twinrova", RHT_TWINROVA, RG_SPIRIT_MEDALLION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DUNGEONS_DONE_SPIRIT_TEMPLE), true); locationTable[RC_BONGO_BONGO] = Location::Base(RC_BONGO_BONGO, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, ACTOR_DOOR_WARP1, SCENE_SHADOW_TEMPLE_BOSS, 0x00, "Bongo Bongo", "Bongo Bongo", RHT_BONGO_BONGO, RG_SHADOW_MEDALLION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DUNGEONS_DONE_SHADOW_TEMPLE), true); locationTable[RC_GANON] = Location::Base(RC_GANON, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, ACTOR_DOOR_WARP1, SCENE_GANON_BOSS, 0x00, "Ganon", "Ganon", RHT_NONE, RG_TRIFORCE); - locationTable[RC_GIFT_FROM_SAGES] = Location::Base(RC_GIFT_FROM_SAGES, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, "Gift from Raoru", "Gift from Raoru", RHT_NONE, RG_LIGHT_MEDALLION, SpoilerCollectionCheck::EventChkInf(0xC9), true); + locationTable[RC_GIFT_FROM_SAGES] = Location::Base(RC_GIFT_FROM_SAGES, RCQUEST_BOTH, RCTYPE_DUNGEON_REWARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, "Gift from Raoru", "Gift from Raoru", RHT_GIFT_FROM_SAGES, RG_LIGHT_MEDALLION, SpoilerCollectionCheck::EventChkInf(0xC9), true); // Heart Containers locationTable[RC_DEKU_TREE_QUEEN_GOHMA_HEART] = Location::Base(RC_DEKU_TREE_QUEEN_GOHMA_HEART, RCQUEST_BOTH, RCTYPE_BOSS_HEART_OR_OTHER_REWARD, ACTOR_ITEM_B_HEART, SCENE_DEKU_TREE_BOSS, 0x00, "Queen Gohma Heart Container", RHT_DEKU_TREE_QUEEN_GOHMA_HEART, RG_HEART_CONTAINER, SpoilerCollectionCheck::Collectable(0x11, 0x1F), true); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index e5b6df090..0c4686f75 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -2661,6 +2661,7 @@ typedef enum { RHT_MORPHA, RHT_BONGO_BONGO, RHT_TWINROVA, + RHT_GIFT_FROM_SAGES, RHT_SONG_FROM_IMPA, RHT_SONG_FROM_MALON, RHT_SONG_FROM_SARIA,