diff --git a/files.cmake b/files.cmake index 1a5779d03a..bb55ad7e0c 100644 --- a/files.cmake +++ b/files.cmake @@ -1508,6 +1508,8 @@ set(DUSK_FILES src/dusk/ui/ui.hpp src/dusk/ui/window.cpp src/dusk/ui/window.hpp + src/dusk/ui/rando_config.cpp + src/dusk/ui/rando_config.hpp src/dusk/achievements.cpp src/dusk/iso_validate.cpp src/dusk/livesplit.cpp diff --git a/include/dusk/settings.h b/include/dusk/settings.h index f74a4bf61f..aa93b53c96 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -175,6 +175,9 @@ struct UserSettings { ConfigVar speedrunMode; ConfigVar liveSplitEnabled; ConfigVar recordingMode; + + // Misc + ConfigVar randomizerEnabled; } game; struct { diff --git a/src/dusk/imgui/ImGuiMenuRandomizer.cpp b/src/dusk/imgui/ImGuiMenuRandomizer.cpp index bb2ff02a59..46e59d029f 100644 --- a/src/dusk/imgui/ImGuiMenuRandomizer.cpp +++ b/src/dusk/imgui/ImGuiMenuRandomizer.cpp @@ -60,10 +60,14 @@ namespace dusk { std::list hashes{}; - for (const auto& entry : std::filesystem::directory_iterator(seedDirectory)) { - if (entry.is_directory()) { - hashes.push_back(entry.path().filename().string()); + if (std::filesystem::exists(seedDirectory)) { + for (const auto& entry : std::filesystem::directory_iterator(seedDirectory)) { + if (entry.is_directory()) { + hashes.push_back(entry.path().filename().string()); + } } + }else { + std::filesystem::create_directories(seedDirectory); } if (hashes.empty()) { diff --git a/src/dusk/randomizer/game/randomizer_context.cpp b/src/dusk/randomizer/game/randomizer_context.cpp index ec9746bd6a..4ba48db783 100644 --- a/src/dusk/randomizer/game/randomizer_context.cpp +++ b/src/dusk/randomizer/game/randomizer_context.cpp @@ -304,6 +304,8 @@ int RandomizerContext::OptionToEnum(const std::string& optionName) { RandomizerState g_randomizerState; +randomizer::Randomizer g_RandomizerGenerator; + int RandomizerState::_create() { mInitialized = true; mEventItemStatus = QUEUE_EMPTY; @@ -1164,12 +1166,8 @@ static void DeleteFailedGenerationFiles(randomizer::Randomizer& rando) { * Generates a seed and writes the necessary seed files to the players seed directory */ void GenerateAndWriteSeed(std::string& generationStatusMsg) { - const auto result = SDL_GetPrefPath(dusk::OrgName, dusk::AppName); - if (!result) { - DuskLog.fatal("Unable to get PrefPath: {}", SDL_GetError()); - } - randomizer::Randomizer r; - r.SetBaseOutputPath(result); + auto& r = g_RandomizerGenerator; + auto generationResult = r.Generate(); if (generationResult.has_value()) { generationStatusMsg = fmt::format("Seed Generation failed. Reason:\n{}", generationResult.value()); @@ -1199,3 +1197,12 @@ void GenerateAndWriteSeed(std::string& generationStatusMsg) { generationStatusMsg = fmt::format("Seed generated! Hash: {}", randoData.mHash); } + +void LoadRandomizerConfig() { + const auto result = SDL_GetPrefPath(dusk::OrgName, dusk::AppName); + if (!result) + DuskLog.fatal("Unable to get PrefPath: {}", SDL_GetError()); + g_RandomizerGenerator.SetBaseOutputPath(result); + + g_RandomizerGenerator.LoadConfig(); +} \ No newline at end of file diff --git a/src/dusk/randomizer/game/randomizer_context.hpp b/src/dusk/randomizer/game/randomizer_context.hpp index b44ef962bd..3c9617cb24 100644 --- a/src/dusk/randomizer/game/randomizer_context.hpp +++ b/src/dusk/randomizer/game/randomizer_context.hpp @@ -12,6 +12,8 @@ #include #include +#include "dusk/randomizer/generator/randomizer.hpp" + /* * Class holding all the information necessary for playing * the current randomizer seed @@ -162,6 +164,8 @@ public: u8 mFlowMessageItemId{0}; }; +extern randomizer::Randomizer g_RandomizerGenerator; + extern RandomizerState g_randomizerState; RandomizerContext& randomizer_GetContext(); @@ -215,4 +219,7 @@ class stage_actor_data_class; u32 getStageObjCRC32(u8* data, size_t size); void GenerateAndWriteSeed(std::string& generationStatusMsg); + +void LoadRandomizerConfig(); + #endif //DUSK_RANDOMIZER_CONTEXT_HPP diff --git a/src/dusk/randomizer/generator/data/settings_list.yaml b/src/dusk/randomizer/generator/data/settings_list.yaml index 19265b7d5c..dad4190507 100644 --- a/src/dusk/randomizer/generator/data/settings_list.yaml +++ b/src/dusk/randomizer/generator/data/settings_list.yaml @@ -34,35 +34,35 @@ Tracker Important: True Default Option: 1 Options: - - 1-3: description + - 1-3: No description available. - Name: Hyrule Barrier Mirror Shards Need In Game: True Tracker Important: True Default Option: 1 Options: - - 1-4: description + - 1-4: No description available. - Name: Hyrule Barrier Dungeons Need In Game: True Tracker Important: True Default Option: 1 Options: - - 1-8: description + - 1-8: No description available. - Name: Hyrule Barrier Poe Souls Need In Game: True Tracker Important: True Default Option: 1 Options: - - 1-60: description + - 1-60: No description available. - Name: Hyrule Barrier Hearts Need In Game: True Tracker Important: True Default Option: 4 Options: - - 4-20: description # Hehe 420 + - 4-20: No description available. # Hehe 420 - Name: Palace of Twilight Requirements Need In Game: True @@ -96,62 +96,62 @@ Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Gifts From NPCs Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Shop Items Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Hidden Skills Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Hidden Rupees Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Freestanding Rupees Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Poe Souls Tracker Important: True Default Option: Vanilla Options: - - Vanilla: description - - Overworld: description - - Dungeon: description - - All: description + - Vanilla: No description available. + - Overworld: No description available. + - Dungeon: No description available. + - All: No description available. - Name: Ilia Memory Quest Tracker Important: True Default Option: Vanilla Options: - - Vanilla: description - - Letter: description - - Invoice: description - - Statue: description - - Charm: description + - Vanilla: No description available. + - Letter: No description available. + - Invoice: No description available. + - Statue: No description available. + - Charm: No description available. - Name: Item Scarcity Default Option: Vanilla @@ -218,47 +218,47 @@ Tracker Important: True Default Option: 1 Options: - - 1-3: description + - 1-3: No description available. - Name: Hyrule Castle Big Key Mirror Shards Need In Game: True Tracker Important: True Default Option: 1 Options: - - 1-4: description + - 1-4: No description available. - Name: Hyrule Castle Big Key Dungeons Need In Game: True Tracker Important: True Default Option: 1 Options: - - 1-8: description + - 1-8: No description available. - Name: Hyrule Castle Big Key Poe Souls Need In Game: True Tracker Important: True Default Option: 1 Options: - - 1-60: description + - 1-60: No description available. - Name: Hyrule Castle Big Key Hearts Need In Game: True Tracker Important: True Default Option: 4 Options: - - 4-20: description # Hehe 420 + - 4-20: No description available. # Hehe 420 - Name: Dungeon Rewards Can Be Anywhere Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: No Small Keys on Bosses Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. # - Name: required_dungeons # Default Option: 2 @@ -283,87 +283,87 @@ Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Faron Twilight Cleared Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Eldin Twilight Cleared Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Lanayru Twilight Cleared Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Skip Midna's Desparate Hour Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Skip Minor Cutscenes Need In Game: True Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Skip Major Cutscenes Need In Game: True Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Unlock Map Regions Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Open Door of Time Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Active Goron Mines Magnets Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Lower Hyrule Castle Chandelier Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Skip Bridge Donation Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. ###################### # Additional Settings# @@ -380,22 +380,22 @@ Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Shops Display The Replaced Item Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Bonks Do Damage Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Trap Item Frequency Default Option: None @@ -409,19 +409,19 @@ - Name: Damage Multiplier Default Option: Vanilla Options: - - Vanilla: description - - Double: description - - Triple: description - - Quadruple: description + - Vanilla: No description available. + - Double: No description available. + - Triple: No description available. + - Quadruple: No description available. - OHKO: Any damage taken will kill link - Name: Starting Time of Day Default Option: Noon Options: - - Morning: description - - Noon: description - - Evening: description - - Night: description + - Morning: No description available. + - Noon: No description available. + - Evening: No description available. + - Night: No description available. ############################# # Dungeon Entrance Settings # @@ -431,55 +431,55 @@ Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Arbiters Does Not Require Bulblin Camp Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Snowpeak Does Not Require Reekfish Scent Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Sacred Grove Does Not Require Skull Kid Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: City Does Not Require Filled Skybook Tracker Important: True Default Option: "Off" Options: - - "Off": description - - "On": description + - "Off": No description available. + - "On": No description available. - Name: Goron Mines Entrance Tracker Important: True Default Option: Closed Options: - - Closed: description - - No Wrestling: description - - Open: description + - Closed: No description available. + - No Wrestling: No description available. + - Open: No description available. - Name: Temple of Time Sword Requirement Need In Game: True Tracker Important: True Default Option: None Options: - - None: description - - Wooden Sword: description - - Ordon Sword: description - - Master Sword: description - - Light Sword: description + - None: No description available. + - Wooden Sword: No description available. + - Ordon Sword: No description available. + - Master Sword: No description available. + - Light Sword: No description available. # - Name: chest_type_matches_contents # Default Option: "Off" diff --git a/src/dusk/randomizer/generator/randomizer.cpp b/src/dusk/randomizer/generator/randomizer.cpp index 7b8f2fa5d4..840b956879 100644 --- a/src/dusk/randomizer/generator/randomizer.cpp +++ b/src/dusk/randomizer/generator/randomizer.cpp @@ -31,11 +31,19 @@ namespace randomizer return std::nullopt; } + void Randomizer::LoadConfig() { + this->_config.LoadFromFile(GetConfigPath(), GetPrefPath()); + } + void Randomizer::GenerateWorlds() { utility::time::ScopedTimer<"Seed generation took ", std::chrono::milliseconds> timer; this->_worlds.clear(); - this->_config.LoadFromFile(this->GetBaseOutputPath() + "settings.yaml", this->GetBaseOutputPath() + "preferences.yaml"); + this->_eventIdCounter = 0; + this->_areaIdCounter = 0; + this->_locAccIdCounter = 0; + this->_playthroughSpheres.clear(); + this->_entranceSpheres.clear(); utility::platform::Log(std::string("Seed: ") + this->_config.GetSeed()); diff --git a/src/dusk/randomizer/generator/randomizer.hpp b/src/dusk/randomizer/generator/randomizer.hpp index b7f7d281e9..5e699d9590 100644 --- a/src/dusk/randomizer/generator/randomizer.hpp +++ b/src/dusk/randomizer/generator/randomizer.hpp @@ -32,6 +32,11 @@ namespace randomizer std::string GetSeedOutputPath(); const std::string& GetBaseOutputPath() const { return this->_baseOutputPath; }; void SetBaseOutputPath(const std::string& path) { this->_baseOutputPath = path + "randomizer/"; }; + + void LoadConfig(); + + std::string GetConfigPath() const { return this->GetBaseOutputPath() + "settings.yaml"; } + std::string GetPrefPath() const { return this->GetBaseOutputPath() + "preferences.yaml"; } private: seedgen::config::Config _config{}; logic::world::WorldPool _worlds{}; diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index f0d10d4226..0ae68f45ba 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -111,7 +111,8 @@ UserSettings g_userSettings = { // Tools .speedrunMode {"game.speedrunMode", false}, .liveSplitEnabled {"game.liveSplitEnabled", false}, - .recordingMode {"game.recordingMode", false} + .recordingMode {"game.recordingMode", false}, + .randomizerEnabled = {"game.randomizerEnabled", false} }, .backend = { @@ -222,6 +223,8 @@ void registerSettings() { Register(g_userSettings.game.debugFlyCamLockEvents); Register(g_userSettings.game.allowBackgroundInput); + Register(g_userSettings.game.randomizerEnabled); + Register(g_userSettings.backend.isoPath); Register(g_userSettings.backend.isoVerification); Register(g_userSettings.backend.graphicsBackend); diff --git a/src/dusk/ui/menu_bar.cpp b/src/dusk/ui/menu_bar.cpp index ea791d745b..c2236fdccf 100644 --- a/src/dusk/ui/menu_bar.cpp +++ b/src/dusk/ui/menu_bar.cpp @@ -21,6 +21,8 @@ #include #include +#include "rando_config.hpp" + namespace dusk::ui { namespace { @@ -58,6 +60,9 @@ MenuBar::MenuBar() : Document(kDocumentSource), mRoot(mDocument->GetElementById( } mTabBar->add_tab("Achievements", [this] { push(std::make_unique()); }); + + mTabBar->add_tab("Randomizer", [this] { push(std::make_unique()); }); + mTabBar->add_tab("Reset", [this] { mTabBar->set_active_tab(-1); const auto dismiss = [](Modal& modal) { modal.pop(); }; diff --git a/src/dusk/ui/rando_config.cpp b/src/dusk/ui/rando_config.cpp new file mode 100644 index 0000000000..7781ba157d --- /dev/null +++ b/src/dusk/ui/rando_config.cpp @@ -0,0 +1,270 @@ +#include "rando_config.hpp" + +#include + +#include "bool_button.hpp" +#include "pane.hpp" +#include "dusk/config.hpp" +#include "dusk/logging.h" + +namespace dusk::ui { + +struct ConfigBoolProps { + Rml::String key; + Rml::String icon; + Rml::String helpText; + std::function onChange; + std::function isDisabled; +}; + +static bool generatingSeed = false; +static std::string generationStatusMsg{}; +static std::mutex generationStatusMsgMutex{}; + +static void StartSeedGeneration() { + if (generatingSeed) { + return; + } + + generatingSeed = true; + std::lock_guard lock(generationStatusMsgMutex); + GenerateAndWriteSeed(generationStatusMsg); + generatingSeed = false; + DuskLog.debug("{}", generationStatusMsg); +} + +// ripped straight from settings window +SelectButton& config_bool_select( + Pane& leftPane, Pane& rightPane, ConfigVar& var, ConfigBoolProps props) { + auto& button = leftPane.add_child(BoolButton::Props{ + .key = std::move(props.key), + .icon = std::move(props.icon), + .getValue = [&var] { return var.getValue(); }, + .setValue = + [&var, callback = std::move(props.onChange)](bool value) { + if (value == var.getValue()) { + return; + } + var.setValue(value); + config::Save(); + if (callback) { + callback(value); + } + }, + .isDisabled = std::move(props.isDisabled), + .isModified = [&var] { return var.getValue() != var.getDefaultValue(); }, + }); + leftPane.register_control( + button, rightPane, [helpText = std::move(props.helpText)](Pane& pane) { + pane.clear(); + pane.add_rml(helpText); + }); + return button; +} + +auto& FindSetting(const std::string& key) { + // TODO: handle multi-world selection + auto& settings = g_RandomizerGenerator.GetConfig().GetSettingsList().front(); + return settings.GetMap().at(key); +} + +auto* FindSettingPtr(const std::string& key) { + // TODO: handle multi-world selection + auto& settings = g_RandomizerGenerator.GetConfig().GetSettingsList().front(); + return &settings.GetMap().at(key); +} + +void SaveConfig() { + g_RandomizerGenerator.GetConfig().WriteSettingsToFile(g_RandomizerGenerator.GetConfigPath()); +} + +void rando_config_group(Pane& leftPane, Pane& rightPane, std::string settingKey) { + auto randoSettings = randomizer::seedgen::settings::GetAllSettingsInfo(); + auto& settingData = randoSettings->at(settingKey); + + if (settingData == nullptr) { + return; + } + auto& curSetting = FindSetting(settingKey); + + leftPane.register_control( + leftPane.add_select_button({ + .key = settingKey, + .getValue = + [settingKey = std::move(settingKey)] { return Rml::String{FindSetting(settingKey).GetCurrentOption()}; }, + }), + rightPane, [&curSetting, settingKey](Pane& pane) { + auto curSelIdx = curSetting.GetCurrentOptionIndex(); + auto settingInfo = curSetting.GetInfo(); + + Rml::Element* text_elem = pane.add_rml(settingInfo->GetDescriptions().at(curSelIdx)); + for (int i = 0; i < settingInfo->GetOptions().size(); ++i) { + pane.add_button( + { + .text = settingInfo->GetOptions()[i], + .isSelected = [settingKey = std::move(settingKey), i] { return FindSetting(settingKey).GetCurrentOptionIndex() == i; }, + }) + .on_pressed([i, text_elem, settingKey = std::move(settingKey)] { + auto& curSetting = FindSetting(settingKey); + auto settingInfo = curSetting.GetInfo(); + + mDoAud_seStartMenu(kSoundItemChange); + curSetting.SetCurrentOption(i); + text_elem->SetInnerRML(settingInfo->GetDescriptions().at(i)); + + SaveConfig(); + }); + } + }); +} + +SelectButton& rando_config_toggle( + Pane& leftPane, Pane& rightPane, std::string settingKey) { + auto& button = leftPane.add_child(BoolButton::Props{ + .key = settingKey, + .getValue = [settingKey] { return FindSetting(settingKey).GetCurrentOptionIndex() != 0; }, + .setValue = + [settingKey](bool value) { + auto& setting = FindSetting(settingKey); + auto idx = setting.GetCurrentOptionIndex(); + if (idx == value) { + return; + } + + setting.SetCurrentOption(value); + + SaveConfig(); + }, + }); + auto& comp = leftPane.register_control( + button, rightPane, [settingKey](Pane& pane) { + pane.clear(); + + auto& setting = FindSetting(settingKey); + auto info = setting.GetInfo(); + + pane.add_rml(info->GetDescriptions()[setting.GetCurrentOptionIndex()]); + }); + + comp.listen(comp.root(), Rml::EventId::Click, [&rightPane, settingKey](Rml::Event&) { + rightPane.clear(); + auto& setting = FindSetting(settingKey); + auto info = setting.GetInfo(); + + rightPane.add_rml(info->GetDescriptions()[setting.GetCurrentOptionIndex()]); + }); + + return button; +} + +RandomizerWindow::RandomizerWindow() { + add_tab("Seed Management", [this](Rml::Element* content) { + auto& leftPane = add_child(content, Pane::Type::Controlled); + auto& rightPane = add_child(content, Pane::Type::Controlled); + + config_bool_select(leftPane, rightPane, getSettings().game.randomizerEnabled, { + .key = "Randomizer Enabled", + .helpText = "Determines if a new Save will load as a regular save or randomized save. (Doesn't do anything currently)" + }); + + leftPane.add_button("Generate Seed").on_pressed([this] { + std::thread randoGenerationThread(StartSeedGeneration); + randoGenerationThread.detach(); + m_showRandoGeneration = true; + }); + }); + + add_tab("Seed Options", [this](Rml::Element* content) { + auto& leftPane = add_child(content, Pane::Type::Controlled); + auto& rightPane = add_child(content, Pane::Type::Uncontrolled); + + leftPane.add_section("Logic Settings"); + + rando_config_group(leftPane, rightPane, "Logic Rules"); + + leftPane.add_section("Access Options"); + + rando_config_group(leftPane, rightPane, "Hyrule Barrier Requirements"); + rando_config_group(leftPane, rightPane, "Palace of Twilight Requirements"); + rando_config_group(leftPane, rightPane, "Faron Woods Logic"); + + leftPane.add_section("World (TODO)"); + + leftPane.add_section("Item Pool"); + + rando_config_toggle(leftPane, rightPane, "Golden Bugs"); + rando_config_toggle(leftPane, rightPane, "Sky Characters"); + rando_config_toggle(leftPane, rightPane, "Gifts From NPCs"); + rando_config_toggle(leftPane, rightPane, "Shop Items"); + rando_config_toggle(leftPane, rightPane, "Hidden Skills"); + rando_config_toggle(leftPane, rightPane, "Hidden Rupees"); + rando_config_toggle(leftPane, rightPane, "Freestanding Rupees"); + + rando_config_group(leftPane, rightPane, "Poe Souls"); + rando_config_group(leftPane, rightPane, "Ilia Memory Quest"); + rando_config_group(leftPane, rightPane, "Item Scarcity"); + + leftPane.add_section("Dungeon Items"); + + rando_config_group(leftPane, rightPane, "Small Keys"); + rando_config_group(leftPane, rightPane, "Big Keys"); + rando_config_group(leftPane, rightPane, "Maps and Compasses"); + rando_config_group(leftPane, rightPane, "Hyrule Castle Big Key Requirements"); + // TODO: figure out a way to add conditional options depending on selection above + + rando_config_toggle(leftPane, rightPane, "Dungeon Rewards Can Be Anywhere"); + rando_config_toggle(leftPane, rightPane, "No Small Keys on Bosses"); + rando_config_toggle(leftPane, rightPane, "Unrequired Dungeons Are Barren"); + + leftPane.add_section("Timesavers"); + + rando_config_toggle(leftPane, rightPane, "Skip Prologue"); + rando_config_toggle(leftPane, rightPane, "Faron Twilight Cleared"); + rando_config_toggle(leftPane, rightPane, "Eldin Twilight Cleared"); + rando_config_toggle(leftPane, rightPane, "Lanayru Twilight Cleared"); + rando_config_toggle(leftPane, rightPane, "Skip Midna's Desparate Hour"); + rando_config_toggle(leftPane, rightPane, "Skip Minor Cutscenes"); + rando_config_toggle(leftPane, rightPane, "Skip Major Cutscenes"); + rando_config_toggle(leftPane, rightPane, "Unlock Map Regions"); + rando_config_toggle(leftPane, rightPane, "Open Door of Time"); + rando_config_toggle(leftPane, rightPane, "Active Goron Mines Magnets"); + rando_config_toggle(leftPane, rightPane, "Lower Hyrule Castle Chandelier"); + rando_config_toggle(leftPane, rightPane, "Skip Bridge Donation"); + + leftPane.add_section("Additional Settings"); + + rando_config_group(leftPane, rightPane, "Starting Form"); + rando_config_toggle(leftPane, rightPane, "Increase Wallet Capacity"); + rando_config_toggle(leftPane, rightPane, "Shops Display The Replaced Item"); + rando_config_toggle(leftPane, rightPane, "Bonks Do Damage"); + rando_config_group(leftPane, rightPane, "Trap Item Frequency"); + rando_config_toggle(leftPane, rightPane, "Starting Time of Day"); + + leftPane.add_section("Dungeon Entrance Settings"); + + rando_config_toggle(leftPane, rightPane, "Lakebed Does Not Require Water Bombs"); + rando_config_toggle(leftPane, rightPane, "Arbiters Does Not Require Bulblin Camp"); + rando_config_toggle(leftPane, rightPane, "Snowpeak Does Not Require Reekfish Scent"); + rando_config_toggle(leftPane, rightPane, "Sacred Grove Does Not Require Skull Kid"); + rando_config_toggle(leftPane, rightPane, "City Does Not Require Filled Skybook"); + rando_config_group(leftPane, rightPane, "Goron Mines Entrance"); + rando_config_group(leftPane, rightPane, "Temple of Time Sword Requirement"); + rando_config_toggle(leftPane, rightPane, "Randomize Starting Spawn"); + rando_config_group(leftPane, rightPane, "Randomize Dungeon Entrances"); + rando_config_toggle(leftPane, rightPane, "Randomize Boss Entrances"); + rando_config_toggle(leftPane, rightPane, "Randomize Grotto Entrances"); + rando_config_toggle(leftPane, rightPane, "Randomize Cave Entrances"); + rando_config_toggle(leftPane, rightPane, "Randomize Interior Entrances"); + rando_config_toggle(leftPane, rightPane, "Randomize Overworld Entrances"); + rando_config_toggle(leftPane, rightPane, "Decouple Double Door Entrances"); + rando_config_toggle(leftPane, rightPane, "Decouple Entrances"); + + leftPane.add_section("Tricks"); + + rando_config_toggle(leftPane, rightPane, "Back Slice as Sword"); + rando_config_toggle(leftPane, rightPane, "Ball and Chain Webs"); + rando_config_toggle(leftPane, rightPane, "Logic Transform Anywhere"); + }); +} + +} \ No newline at end of file diff --git a/src/dusk/ui/rando_config.hpp b/src/dusk/ui/rando_config.hpp new file mode 100644 index 0000000000..b620894922 --- /dev/null +++ b/src/dusk/ui/rando_config.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "window.hpp" + +namespace dusk::ui { + class RandomizerWindow : public Window { + public: + RandomizerWindow(); + + private: + bool m_showRandoGeneration = false; + }; +} diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 3e9002a5a3..e969dad881 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -757,6 +757,9 @@ int game_main(int argc, char* argv[]) { dusk::audio::SetEnableReverb(dusk::getSettings().audio.enableReverb); dusk::audio::EnableHrtf = dusk::getSettings().audio.enableHrtf; + // load rando generator configuration data + LoadRandomizerConfig(); + // Run ImGui UI loop if Aurora couldn't initialize a backend if (auroraInfo.backend == BACKEND_NULL) { launchUILoop();