mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-06-04 18:28:45 -04:00
add config menu and hook it up into current config system
currently any options that requires additional settings, like "Hyrule Barrier Requirements", wont actually have any additional options yet until i figure out a clean way to handle that
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -175,6 +175,9 @@ struct UserSettings {
|
||||
ConfigVar<bool> speedrunMode;
|
||||
ConfigVar<bool> liveSplitEnabled;
|
||||
ConfigVar<bool> recordingMode;
|
||||
|
||||
// Misc
|
||||
ConfigVar<bool> randomizerEnabled;
|
||||
} game;
|
||||
|
||||
struct {
|
||||
|
||||
@@ -60,10 +60,14 @@ namespace dusk {
|
||||
|
||||
std::list<std::string> 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()) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
|
||||
#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<AchievementsWindow>()); });
|
||||
|
||||
mTabBar->add_tab("Randomizer", [this] { push(std::make_unique<RandomizerWindow>()); });
|
||||
|
||||
mTabBar->add_tab("Reset", [this] {
|
||||
mTabBar->set_active_tab(-1);
|
||||
const auto dismiss = [](Modal& modal) { modal.pop(); };
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
#include "rando_config.hpp"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#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<void(bool)> onChange;
|
||||
std::function<bool()> 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<bool>& var, ConfigBoolProps props) {
|
||||
auto& button = leftPane.add_child<BoolButton>(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>(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<Pane>(content, Pane::Type::Controlled);
|
||||
auto& rightPane = add_child<Pane>(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<Pane>(content, Pane::Type::Controlled);
|
||||
auto& rightPane = add_child<Pane>(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");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "window.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
class RandomizerWindow : public Window {
|
||||
public:
|
||||
RandomizerWindow();
|
||||
|
||||
private:
|
||||
bool m_showRandoGeneration = false;
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user