Rando: Keyring tristate (#3960)

* Initial implementation

* Fix build

* Update UIWidgets.cpp

* Update option.cpp

* Update settings.cpp

* Update settings.cpp

* Apply Pepper0ni's patch

Co-Authored-By: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com>

* Update option_descriptions.cpp

---------

Co-authored-by: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com>
This commit is contained in:
Pepe20129 2024-07-17 05:25:06 +02:00 committed by GitHub
parent 2ff795e227
commit 8eb6304999
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 141 additions and 45 deletions

View File

@ -140,6 +140,9 @@ bool Option::RenderImGui() const {
case WidgetType::Checkbox: case WidgetType::Checkbox:
changed = RenderCheckbox(); changed = RenderCheckbox();
break; break;
case WidgetType::TristateCheckbox:
changed = RenderTristateCheckbox();
break;
case WidgetType::Combobox: case WidgetType::Combobox:
changed = RenderCombobox(); changed = RenderCombobox();
break; break;
@ -209,6 +212,26 @@ bool Option::RenderCheckbox() const {
return changed; return changed;
} }
bool Option::RenderTristateCheckbox() const {
bool changed = false;
if (disabled) {
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
int val = CVarGetInteger(cvarName.c_str(), defaultOption);
if (CustomCheckboxTristate(name.c_str(), &val, disabled, disabledGraphic)) {
CVarSetInteger(cvarName.c_str(), val);
changed = true;
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
if (!description.empty()) {
UIWidgets::InsertHelpHoverText(description.c_str());
}
if (disabled) {
UIWidgets::ReEnableComponent(disabledText.c_str());
}
return changed;
}
bool Option::RenderCombobox() const { bool Option::RenderCombobox() const {
bool changed = false; bool changed = false;
if (disabled) { if (disabled) {

View File

@ -34,6 +34,7 @@ enum class OptionCategory {
*/ */
enum class WidgetType { enum class WidgetType {
Checkbox, /** Default for Bools, not compatible if options.size() > 2. */ Checkbox, /** Default for Bools, not compatible if options.size() > 2. */
TristateCheckbox, /** Compatible with U8s, not compatible if options.size() != 3. */
Combobox, /** Default for U8s, works with U8s and Bools. */ Combobox, /** Default for U8s, works with U8s and Bools. */
Slider, /** Compatible with U8s. If constructed with NumOpts, consider using this. Technically can be used for Bool or non-NumOpts options but it would be a bit weird semantically. */ Slider, /** Compatible with U8s. If constructed with NumOpts, consider using this. Technically can be used for Bool or non-NumOpts options but it would be a bit weird semantically. */
}; };
@ -317,6 +318,7 @@ protected:
private: private:
bool RenderCheckbox() const; bool RenderCheckbox() const;
bool RenderTristateCheckbox() const;
bool RenderCombobox() const; bool RenderCombobox() const;
bool RenderSlider() const; bool RenderSlider() const;
std::variant<bool, uint8_t> var; std::variant<bool, uint8_t> var;

View File

@ -370,7 +370,8 @@ void Settings::CreateOptionDescriptions() {
"\n" "\n"
"Count - A specified amount of randomly selected dungeons will have their keys replaced with keyrings.\n" "Count - A specified amount of randomly selected dungeons will have their keys replaced with keyrings.\n"
"\n" "\n"
"Selection - Hand select which dungeons will have their keys replaced with keyrings.\n" "Selection - Hand select which dungeons will have their keys replaced with keyrings\n"
"(can also be left as random, in which case each one will have a 50% chance of being a keyring).\n"
"\n" "\n"
"Selecting key ring for dungeons will have no effect if Small Keys are set to Start With or Vanilla.\n" "Selecting key ring for dungeons will have no effect if Small Keys are set to Start With or Vanilla.\n"
"\n" "\n"

View File

@ -3876,6 +3876,12 @@ typedef enum {
RO_KEYRINGS_SELECTION, RO_KEYRINGS_SELECTION,
} RandoOptionKeyrings; } RandoOptionKeyrings;
typedef enum {
RO_KEYRING_FOR_DUNGEON_OFF,
RO_KEYRING_FOR_DUNGEON_RANDOM,
RO_KEYRING_FOR_DUNGEON_ON,
} RandoOptionKeyringForDungeon;
//Ganon's Boss Key Settings (vanilla, own dungeon, start with, //Ganon's Boss Key Settings (vanilla, own dungeon, start with,
//overworld, anywhere, 100 GS reward) //overworld, anywhere, 100 GS reward)
typedef enum { typedef enum {

View File

@ -136,15 +136,15 @@ void Settings::CreateOptions() {
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_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_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] = 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_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::Bool("Gerudo Fortress", CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGerudoFortress"), "", IMFLAG_NONE); mOptions[RSK_KEYRINGS_GERUDO_FORTRESS] = Option::U8("Gerudo Fortress Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGerudoFortress"), "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_FOREST_TEMPLE] = Option::Bool("Forest Temple", CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsForestTemple"), "", IMFLAG_NONE); mOptions[RSK_KEYRINGS_FOREST_TEMPLE] = Option::U8("Forest Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsForestTemple"), "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_FIRE_TEMPLE] = Option::Bool("Fire Temple", CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsFireTemple"), "", IMFLAG_NONE); mOptions[RSK_KEYRINGS_FIRE_TEMPLE] = Option::U8("Fire Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsFireTemple"), "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_WATER_TEMPLE] = Option::Bool("Water Temple", CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsWaterTemple"), "", IMFLAG_NONE); mOptions[RSK_KEYRINGS_WATER_TEMPLE] = Option::U8("Water Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsWaterTemple"), "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE] = Option::Bool("Spirit Temple", CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsSpiritTemple"), "", IMFLAG_NONE); mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE] = Option::U8("Spirit Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsSpiritTemple"), "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_SHADOW_TEMPLE] = Option::Bool("Shadow Temple", CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsShadowTemple"), "", IMFLAG_NONE); mOptions[RSK_KEYRINGS_SHADOW_TEMPLE] = Option::U8("Shadow Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsShadowTemple"), "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL] = Option::Bool("Bottom of the Well", CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsBottomOfTheWell"), "", IMFLAG_NONE); mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL] = Option::U8("Bottom of the Well Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsBottomOfTheWell"), "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_GTG] = Option::Bool("Gerudo Training Grounds", CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGTG"), "", IMFLAG_NONE); mOptions[RSK_KEYRINGS_GTG] = Option::U8("Gerudo Training Grounds Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGTG"), "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_GANONS_CASTLE] = Option::Bool("Ganon's Castle", CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGanonsCastle")); mOptions[RSK_KEYRINGS_GANONS_CASTLE] = Option::U8("Ganon's Castle Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGanonsCastle"), "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_SKIP_CHILD_STEALTH] = Option::Bool("Skip Child Stealth", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipChildStealth"), mOptionDescriptions[RSK_SKIP_CHILD_STEALTH], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP); mOptions[RSK_SKIP_CHILD_STEALTH] = Option::Bool("Skip Child Stealth", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipChildStealth"), mOptionDescriptions[RSK_SKIP_CHILD_STEALTH], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP);
mOptions[RSK_SKIP_CHILD_ZELDA] = Option::Bool("Skip Child Zelda", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipChildZelda"), mOptionDescriptions[RSK_SKIP_CHILD_ZELDA], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP); mOptions[RSK_SKIP_CHILD_ZELDA] = Option::Bool("Skip Child Zelda", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipChildZelda"), mOptionDescriptions[RSK_SKIP_CHILD_ZELDA], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP);
mOptions[RSK_SKIP_EPONA_RACE] = Option::Bool("Skip Epona Race", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipEponaRace"), mOptionDescriptions[RSK_SKIP_EPONA_RACE], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP); mOptions[RSK_SKIP_EPONA_RACE] = Option::Bool("Skip Epona Race", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipEponaRace"), mOptionDescriptions[RSK_SKIP_EPONA_RACE], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP);
@ -1145,15 +1145,15 @@ void Settings::CreateOptions() {
{ "Shuffle Dungeon Items:LACS Reward Options", RSK_LACS_OPTIONS }, { "Shuffle Dungeon Items:LACS Reward Options", RSK_LACS_OPTIONS },
{ "Shuffle Dungeon Items:Key Rings", RSK_KEYRINGS }, { "Shuffle Dungeon Items:Key Rings", RSK_KEYRINGS },
{ "Shuffle Dungeon Items:Keyring Dungeon Count", RSK_KEYRINGS_RANDOM_COUNT }, { "Shuffle Dungeon Items:Keyring Dungeon Count", RSK_KEYRINGS_RANDOM_COUNT },
{ "Shuffle Dungeon Items:Gerudo Fortress", RSK_KEYRINGS_GERUDO_FORTRESS }, { "Shuffle Dungeon Items:Gerudo Fortress Keyring", RSK_KEYRINGS_GERUDO_FORTRESS },
{ "Shuffle Dungeon Items:Forest Temple", RSK_KEYRINGS_FOREST_TEMPLE }, { "Shuffle Dungeon Items:Forest Temple Keyring", RSK_KEYRINGS_FOREST_TEMPLE },
{ "Shuffle Dungeon Items:Fire Temple", RSK_KEYRINGS_FIRE_TEMPLE }, { "Shuffle Dungeon Items:Fire Temple Keyring", RSK_KEYRINGS_FIRE_TEMPLE },
{ "Shuffle Dungeon Items:Water Temple", RSK_KEYRINGS_WATER_TEMPLE }, { "Shuffle Dungeon Items:Water Temple Keyring", RSK_KEYRINGS_WATER_TEMPLE },
{ "Shuffle Dungeon Items:Spirit Temple", RSK_KEYRINGS_SPIRIT_TEMPLE }, { "Shuffle Dungeon Items:Spirit Temple Keyring", RSK_KEYRINGS_SPIRIT_TEMPLE },
{ "Shuffle Dungeon Items:Shadow Temple", RSK_KEYRINGS_SHADOW_TEMPLE }, { "Shuffle Dungeon Items:Shadow Temple Keyring", RSK_KEYRINGS_SHADOW_TEMPLE },
{ "Shuffle Dungeon Items:Bottom of the Well", RSK_KEYRINGS_BOTTOM_OF_THE_WELL }, { "Shuffle Dungeon Items:Bottom of the Well Keyring", RSK_KEYRINGS_BOTTOM_OF_THE_WELL },
{ "Shuffle Dungeon Items:GTG", RSK_KEYRINGS_GTG }, { "Shuffle Dungeon Items:GTG Keyring", RSK_KEYRINGS_GTG },
{ "Shuffle Dungeon Items:Ganon's Castle", RSK_KEYRINGS_GANONS_CASTLE }, { "Shuffle Dungeon Items:Ganon's Castle Keyring", RSK_KEYRINGS_GANONS_CASTLE },
{ "World Settings:Starting Age", RSK_STARTING_AGE }, { "World Settings:Starting Age", RSK_STARTING_AGE },
// TODO: Ammo Drop settings // TODO: Ammo Drop settings
{ "World Settings:Bombchu Drops", RSK_ENABLE_BOMBCHU_DROPS }, { "World Settings:Bombchu Drops", RSK_ENABLE_BOMBCHU_DROPS },
@ -1952,39 +1952,44 @@ void Settings::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocatio
if (mOptions[RSK_KEYRINGS]) { if (mOptions[RSK_KEYRINGS]) {
// Random Key Rings // Random Key Rings
auto keyrings = keyRingOptions;
if (mOptions[RSK_GERUDO_FORTRESS].Is(RO_GF_NORMAL) && mOptions[RSK_GERUDO_KEYS].IsNot(RO_GERUDO_KEYS_VANILLA)) {
keyrings.push_back(&mOptions[RSK_KEYRINGS_GERUDO_FORTRESS]);
} else {
mOptions[RSK_KEYRINGS_GERUDO_FORTRESS].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_OFF);
}
if (mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_RANDOM) || mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT)) { if (mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_RANDOM) || mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT)) {
auto keyrings = keyRingOptions;
if (mOptions[RSK_GERUDO_FORTRESS].Is(RO_GF_NORMAL) && mOptions[RSK_GERUDO_KEYS].IsNot(RO_GERUDO_KEYS_VANILLA)) {
keyrings.push_back(&mOptions[RSK_KEYRINGS_GERUDO_FORTRESS]);
}
const uint32_t keyRingCount = mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT) ? mOptions[RSK_KEYRINGS_RANDOM_COUNT].Value<uint8_t>() : Random(0, static_cast<int>(keyrings.size())); const uint32_t keyRingCount = mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT) ? mOptions[RSK_KEYRINGS_RANDOM_COUNT].Value<uint8_t>() : Random(0, static_cast<int>(keyrings.size()));
Shuffle(keyrings); Shuffle(keyrings);
for (size_t i = 0; i < keyRingCount; i++) { for (size_t i = 0; i < keyRingCount; i++) {
keyrings[i]->SetSelectedIndex(RO_GENERIC_ON); keyrings[i]->SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_ON);
}
for (size_t i = keyRingCount; i < keyrings.size(); i++) {
keyrings[i]->SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_OFF);
} }
} }
if (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL]) { if (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(BOTTOM_OF_THE_WELL)->SetKeyRing(); ctx->GetDungeon(BOTTOM_OF_THE_WELL)->SetKeyRing();
} }
if (mOptions[RSK_KEYRINGS_FOREST_TEMPLE]) { if (mOptions[RSK_KEYRINGS_FOREST_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_FOREST_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(FOREST_TEMPLE)->SetKeyRing(); ctx->GetDungeon(FOREST_TEMPLE)->SetKeyRing();
} }
if (mOptions[RSK_KEYRINGS_FIRE_TEMPLE]) { if (mOptions[RSK_KEYRINGS_FIRE_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_FIRE_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(FIRE_TEMPLE)->SetKeyRing(); ctx->GetDungeon(FIRE_TEMPLE)->SetKeyRing();
} }
if (mOptions[RSK_KEYRINGS_WATER_TEMPLE]) { if (mOptions[RSK_KEYRINGS_WATER_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_WATER_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(WATER_TEMPLE)->SetKeyRing(); ctx->GetDungeon(WATER_TEMPLE)->SetKeyRing();
} }
if (mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE]) { if (mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(SPIRIT_TEMPLE)->SetKeyRing(); ctx->GetDungeon(SPIRIT_TEMPLE)->SetKeyRing();
} }
if (mOptions[RSK_KEYRINGS_SHADOW_TEMPLE]) { if (mOptions[RSK_KEYRINGS_SHADOW_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_SHADOW_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(SHADOW_TEMPLE)->SetKeyRing(); ctx->GetDungeon(SHADOW_TEMPLE)->SetKeyRing();
} }
if (mOptions[RSK_KEYRINGS_GTG]) { if (mOptions[RSK_KEYRINGS_GTG].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_GTG].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(GERUDO_TRAINING_GROUNDS)->SetKeyRing(); ctx->GetDungeon(GERUDO_TRAINING_GROUNDS)->SetKeyRing();
} }
if (mOptions[RSK_KEYRINGS_GANONS_CASTLE]) { if (mOptions[RSK_KEYRINGS_GANONS_CASTLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_GANONS_CASTLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(GANONS_CASTLE)->SetKeyRing(); ctx->GetDungeon(GANONS_CASTLE)->SetKeyRing();
} }
} }
@ -2322,15 +2327,6 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) {
case RSK_HBA_HINT: case RSK_HBA_HINT:
case RSK_WARP_SONG_HINTS: case RSK_WARP_SONG_HINTS:
case RSK_SCRUB_TEXT_HINT: case RSK_SCRUB_TEXT_HINT:
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:
case RSK_SHUFFLE_ENTRANCES: case RSK_SHUFFLE_ENTRANCES:
case RSK_SHUFFLE_OVERWORLD_ENTRANCES: case RSK_SHUFFLE_OVERWORLD_ENTRANCES:
case RSK_SHUFFLE_GROTTO_ENTRANCES: case RSK_SHUFFLE_GROTTO_ENTRANCES:
@ -2365,6 +2361,23 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) {
mOptions[index].SetSelectedIndex(RO_KEYRINGS_SELECTION); mOptions[index].SetSelectedIndex(RO_KEYRINGS_SELECTION);
} }
break; 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].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_OFF);
} else if (it.value() == "Random") {
mOptions[index].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_RANDOM);
} else if (it.value() == "Yes") {
mOptions[index].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_ON);
}
break;
case RSK_SHUFFLE_MERCHANTS: case RSK_SHUFFLE_MERCHANTS:
if (it.value() == "Off") { if (it.value() == "Off") {
mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_OFF); mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_OFF);

View File

@ -127,7 +127,7 @@ namespace UIWidgets {
draw_list->PathStroke(col, 0, thickness); draw_list->PathStroke(col, 0, thickness);
} }
bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic) { bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic, bool renderCrossWhenOff) {
ImGuiWindow* window = ImGui::GetCurrentWindow(); ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems) { if (window->SkipItems) {
return false; return false;
@ -168,9 +168,9 @@ namespace UIWidgets {
} else if ((!disabled && *v) || (disabled && disabledGraphic == CheckboxGraphics::Checkmark)) { } else if ((!disabled && *v) || (disabled && disabledGraphic == CheckboxGraphics::Checkmark)) {
const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
ImGui::RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f); ImGui::RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f);
} else if (disabled && disabledGraphic == CheckboxGraphics::Cross) { } else if ((!disabled && !*v && renderCrossWhenOff) || (disabled && disabledGraphic == CheckboxGraphics::Cross)) {
const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
RenderCross(window->DrawList, check_bb.Min + ImVec2(pad, pad), cross_col, square_sz - pad * 2.0f); RenderCross(window->DrawList, check_bb.Min + ImVec2(pad, pad), disabled ? cross_col : check_col, square_sz - pad * 2.0f);
} }
ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
@ -185,6 +185,36 @@ namespace UIWidgets {
return pressed; return pressed;
} }
bool CustomCheckboxTristate(const char* label, int* v, bool disabled, CheckboxGraphics disabledGraphic) {
bool ret;
if (*v == 0) {
bool b = false;
ret = CustomCheckbox(label, &b, disabled, disabledGraphic, true);
if (ret) {
*v = 1;
}
} else if (*v == 1) {
ImGui::PushItemFlag(ImGuiItemFlags_MixedValue, true);
bool b = true;
ret = CustomCheckbox(label, &b, disabled, disabledGraphic, true);
if (ret) {
*v = 2;
}
ImGui::PopItemFlag();
} else if (*v == 2) {
bool b = true;
ret = CustomCheckbox(label, &b, disabled, disabledGraphic, true);
if (ret) {
*v = 0;
}
} else {
SPDLOG_INFO("Invalid CheckBoxTristate value: {}", *v);
*v = 0;
return false;
}
return ret;
}
void ReEnableComponent(const char* disabledTooltipText) { void ReEnableComponent(const char* disabledTooltipText) {
// End of disable region of previous component // End of disable region of previous component
ImGui::PopStyleVar(1); ImGui::PopStyleVar(1);
@ -218,6 +248,25 @@ namespace UIWidgets {
return changed; return changed;
} }
bool EnhancementCheckboxTristate(const char* text, const char* cvarName, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic, bool defaultValue) {
bool changed = false;
if (disabled) {
DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
int val = CVarGetInteger(cvarName, defaultValue);
if (CustomCheckboxTristate(text, &val, disabled, disabledGraphic)) {
CVarSetInteger(cvarName, val);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
changed = true;
}
if (disabled) {
ReEnableComponent(disabledTooltipText);
}
return changed;
}
bool PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic, bool defaultValue) { bool PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic, bool defaultValue) {
ImGui::BeginGroup(); ImGui::BeginGroup();
if (padTop) Spacer(0); if (padTop) Spacer(0);

View File

@ -68,12 +68,14 @@ namespace UIWidgets {
void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalTopPadding = 0.0f, float extraVerticalBottomPadding = 0.0f); void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalTopPadding = 0.0f, float extraVerticalBottomPadding = 0.0f);
void RenderCross(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz); void RenderCross(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz);
bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic); bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic, bool renderCrossWhenOff = false);
bool CustomCheckboxTristate(const char* label, int* v, bool disabled, CheckboxGraphics disabledGraphic);
void ReEnableComponent(const char* disabledTooltipText); void ReEnableComponent(const char* disabledTooltipText);
void DisableComponent(const float alpha); void DisableComponent(const float alpha);
bool EnhancementCheckbox(const char* text, const char* cvarName, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false); bool EnhancementCheckbox(const char* text, const char* cvarName, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false);
bool EnhancementCheckboxTristate(const char* text, const char* cvarName, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false);
bool PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false); bool PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false);
bool EnhancementCombobox(const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled = false, const char* disabledTooltipText = "", uint8_t disabledValue = -1); bool EnhancementCombobox(const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled = false, const char* disabledTooltipText = "", uint8_t disabledValue = -1);