fix selection only and make MQ dungeon settings set themselves more smartley (#4232)

This commit is contained in:
Pepper0ni 2024-07-17 17:45:29 +01:00 committed by GitHub
parent a5c0cede12
commit 7595a5a65e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 149 additions and 85 deletions

View File

@ -30,6 +30,7 @@ const auto& RandomElement(const Container& container) {
} }
//Shuffle items within a vector or array //Shuffle items within a vector or array
//RANDOTODO There's probably a more efficient way to do what this does.
template <typename T> template <typename T>
void Shuffle(std::vector<T>& vector) { void Shuffle(std::vector<T>& vector) {
for (std::size_t i = 0; i + 1 < vector.size(); i++) for (std::size_t i = 0; i + 1 < vector.size(); i++)

View File

@ -8,10 +8,12 @@ namespace Rando {
DungeonInfo::DungeonInfo(std::string name_, const RandomizerHintTextKey hintKey_, const RandomizerGet map_, DungeonInfo::DungeonInfo(std::string name_, const RandomizerHintTextKey hintKey_, const RandomizerGet map_,
const RandomizerGet compass_, const RandomizerGet smallKey_, const RandomizerGet keyRing_, const RandomizerGet compass_, const RandomizerGet smallKey_, const RandomizerGet keyRing_,
const RandomizerGet bossKey_, RandomizerArea area_, const uint8_t vanillaKeyCount_, const uint8_t mqKeyCount_, const RandomizerGet bossKey_, RandomizerArea area_, const uint8_t vanillaKeyCount_, const uint8_t mqKeyCount_,
const RandomizerSettingKey mqSetting_,
std::vector<RandomizerCheck> vanillaLocations_, std::vector<RandomizerCheck> mqLocations_, std::vector<RandomizerCheck> vanillaLocations_, std::vector<RandomizerCheck> mqLocations_,
std::vector<RandomizerCheck> sharedLocations_, std::vector<RandomizerCheck> bossRoomLocations_) std::vector<RandomizerCheck> sharedLocations_, std::vector<RandomizerCheck> bossRoomLocations_)
: name(std::move(name_)), hintKey(hintKey_), map(map_), compass(compass_), smallKey(smallKey_), keyRing(keyRing_), : name(std::move(name_)), hintKey(hintKey_), map(map_), compass(compass_), smallKey(smallKey_), keyRing(keyRing_),
bossKey(bossKey_), area(area_), vanillaKeyCount(vanillaKeyCount_), mqKeyCount(mqKeyCount_), bossKey(bossKey_), area(area_), vanillaKeyCount(vanillaKeyCount_), mqKeyCount(mqKeyCount_),
mqSetting(mqSetting_),
vanillaLocations(std::move(vanillaLocations_)), mqLocations(std::move(mqLocations_)), vanillaLocations(std::move(vanillaLocations_)), mqLocations(std::move(mqLocations_)),
sharedLocations(std::move(sharedLocations_)), bossRoomLocations(std::move(bossRoomLocations_)) { sharedLocations(std::move(sharedLocations_)), bossRoomLocations(std::move(bossRoomLocations_)) {
} }
@ -83,6 +85,14 @@ RandomizerGet DungeonInfo::GetBossKey() const {
return bossKey; return bossKey;
} }
RandomizerSettingKey DungeonInfo::GetMQSetting() const {
return mqSetting;
}
void DungeonInfo::SetDungeonKnown(bool known) {
isDungeonModeKnown = known;
}
void DungeonInfo::PlaceVanillaMap() const { void DungeonInfo::PlaceVanillaMap() const {
if (map == RG_NONE) { if (map == RG_NONE) {
return; return;
@ -152,7 +162,7 @@ std::vector<RandomizerCheck> DungeonInfo::GetEveryLocation() const {
Dungeons::Dungeons() { Dungeons::Dungeons() {
dungeonList[DEKU_TREE] = dungeonList[DEKU_TREE] =
DungeonInfo("Deku Tree", RHT_DEKU_TREE, RG_DEKU_TREE_MAP, RG_DEKU_TREE_COMPASS, RG_NONE, RG_NONE, RG_NONE, RA_DEKU_TREE, 0, 0, DungeonInfo("Deku Tree", RHT_DEKU_TREE, RG_DEKU_TREE_MAP, RG_DEKU_TREE_COMPASS, RG_NONE, RG_NONE, RG_NONE, RA_DEKU_TREE, 0, 0, RSK_MQ_DEKU_TREE,
{ {
// Vanilla Locations // Vanilla Locations
RC_DEKU_TREE_MAP_CHEST, RC_DEKU_TREE_MAP_CHEST,
@ -188,7 +198,7 @@ Dungeons::Dungeons() {
RC_QUEEN_GOHMA, RC_QUEEN_GOHMA,
}); });
dungeonList[DODONGOS_CAVERN] = DungeonInfo("Dodongo's Cavern", RHT_DODONGOS_CAVERN, RG_DODONGOS_CAVERN_MAP, dungeonList[DODONGOS_CAVERN] = DungeonInfo("Dodongo's Cavern", RHT_DODONGOS_CAVERN, RG_DODONGOS_CAVERN_MAP,
RG_DODONGOS_CAVERN_COMPASS, RG_NONE, RG_NONE, RG_NONE, RA_DODONGOS_CAVERN, 0, 0, RG_DODONGOS_CAVERN_COMPASS, RG_NONE, RG_NONE, RG_NONE, RA_DODONGOS_CAVERN, 0, 0, RSK_MQ_DODONGOS_CAVERN,
{ {
// Vanilla Locations // Vanilla Locations
RC_DODONGOS_CAVERN_MAP_CHEST, RC_DODONGOS_CAVERN_MAP_CHEST,
@ -232,7 +242,7 @@ Dungeons::Dungeons() {
RC_KING_DODONGO, RC_KING_DODONGO,
}); });
dungeonList[JABU_JABUS_BELLY] = DungeonInfo("Jabu Jabu's Belly", RHT_JABU_JABUS_BELLY, RG_JABU_JABUS_BELLY_MAP, dungeonList[JABU_JABUS_BELLY] = DungeonInfo("Jabu Jabu's Belly", RHT_JABU_JABUS_BELLY, RG_JABU_JABUS_BELLY_MAP,
RG_JABU_JABUS_BELLY_COMPASS, RG_NONE, RG_NONE, RG_NONE, RA_JABU_JABUS_BELLY, 0, 0, RG_JABU_JABUS_BELLY_COMPASS, RG_NONE, RG_NONE, RG_NONE, RA_JABU_JABUS_BELLY, 0, 0, RSK_MQ_JABU_JABU,
{ {
// Vanilla Locations // Vanilla Locations
RC_JABU_JABUS_BELLY_MAP_CHEST, RC_JABU_JABUS_BELLY_MAP_CHEST,
@ -271,7 +281,7 @@ Dungeons::Dungeons() {
}); });
dungeonList[FOREST_TEMPLE] = dungeonList[FOREST_TEMPLE] =
DungeonInfo("Forest Temple", RHT_FOREST_TEMPLE, RG_FOREST_TEMPLE_MAP, RG_FOREST_TEMPLE_COMPASS, DungeonInfo("Forest Temple", RHT_FOREST_TEMPLE, RG_FOREST_TEMPLE_MAP, RG_FOREST_TEMPLE_COMPASS,
RG_FOREST_TEMPLE_SMALL_KEY, RG_FOREST_TEMPLE_KEY_RING, RG_FOREST_TEMPLE_BOSS_KEY, RA_FOREST_TEMPLE, 5, 6, RG_FOREST_TEMPLE_SMALL_KEY, RG_FOREST_TEMPLE_KEY_RING, RG_FOREST_TEMPLE_BOSS_KEY, RA_FOREST_TEMPLE, 5, 6, RSK_MQ_FOREST_TEMPLE,
{ {
// Vanilla Locations // Vanilla Locations
RC_FOREST_TEMPLE_FIRST_ROOM_CHEST, RC_FOREST_TEMPLE_FIRST_ROOM_CHEST,
@ -321,7 +331,7 @@ Dungeons::Dungeons() {
}); });
dungeonList[FIRE_TEMPLE] = dungeonList[FIRE_TEMPLE] =
DungeonInfo("Fire Temple", RHT_FIRE_TEMPLE, RG_FIRE_TEMPLE_MAP, RG_FIRE_TEMPLE_COMPASS, DungeonInfo("Fire Temple", RHT_FIRE_TEMPLE, RG_FIRE_TEMPLE_MAP, RG_FIRE_TEMPLE_COMPASS,
RG_FIRE_TEMPLE_SMALL_KEY, RG_FIRE_TEMPLE_KEY_RING, RG_FIRE_TEMPLE_BOSS_KEY, RA_FIRE_TEMPLE, 8, 5, RG_FIRE_TEMPLE_SMALL_KEY, RG_FIRE_TEMPLE_KEY_RING, RG_FIRE_TEMPLE_BOSS_KEY, RA_FIRE_TEMPLE, 8, 5, RSK_MQ_FIRE_TEMPLE,
{ {
// Vanilla Locations // Vanilla Locations
RC_FIRE_TEMPLE_NEAR_BOSS_CHEST, RC_FIRE_TEMPLE_NEAR_BOSS_CHEST,
@ -372,7 +382,7 @@ Dungeons::Dungeons() {
}); });
dungeonList[WATER_TEMPLE] = dungeonList[WATER_TEMPLE] =
DungeonInfo("Water Temple", RHT_WATER_TEMPLE, RG_WATER_TEMPLE_MAP, RG_WATER_TEMPLE_COMPASS, DungeonInfo("Water Temple", RHT_WATER_TEMPLE, RG_WATER_TEMPLE_MAP, RG_WATER_TEMPLE_COMPASS,
RG_WATER_TEMPLE_SMALL_KEY, RG_WATER_TEMPLE_KEY_RING, RG_WATER_TEMPLE_BOSS_KEY, RA_WATER_TEMPLE, 6, 2, RG_WATER_TEMPLE_SMALL_KEY, RG_WATER_TEMPLE_KEY_RING, RG_WATER_TEMPLE_BOSS_KEY, RA_WATER_TEMPLE, 6, 2, RSK_MQ_WATER_TEMPLE,
{ {
// Vanilla Locations // Vanilla Locations
RC_WATER_TEMPLE_MAP_CHEST, RC_WATER_TEMPLE_MAP_CHEST,
@ -413,7 +423,7 @@ Dungeons::Dungeons() {
}); });
dungeonList[SPIRIT_TEMPLE] = dungeonList[SPIRIT_TEMPLE] =
DungeonInfo("Spirit Temple", RHT_SPIRIT_TEMPLE, RG_SPIRIT_TEMPLE_MAP, RG_SPIRIT_TEMPLE_COMPASS, DungeonInfo("Spirit Temple", RHT_SPIRIT_TEMPLE, RG_SPIRIT_TEMPLE_MAP, RG_SPIRIT_TEMPLE_COMPASS,
RG_SPIRIT_TEMPLE_SMALL_KEY, RG_SPIRIT_TEMPLE_KEY_RING, RG_SPIRIT_TEMPLE_BOSS_KEY, RA_SPIRIT_TEMPLE, 5, 7, RG_SPIRIT_TEMPLE_SMALL_KEY, RG_SPIRIT_TEMPLE_KEY_RING, RG_SPIRIT_TEMPLE_BOSS_KEY, RA_SPIRIT_TEMPLE, 5, 7, RSK_MQ_SPIRIT_TEMPLE,
{ {
// Vanilla Locations // Vanilla Locations
RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST,
@ -479,7 +489,7 @@ Dungeons::Dungeons() {
}); });
dungeonList[SHADOW_TEMPLE] = dungeonList[SHADOW_TEMPLE] =
DungeonInfo("Shadow Temple", RHT_SHADOW_TEMPLE, RG_SHADOW_TEMPLE_MAP, RG_SHADOW_TEMPLE_COMPASS, DungeonInfo("Shadow Temple", RHT_SHADOW_TEMPLE, RG_SHADOW_TEMPLE_MAP, RG_SHADOW_TEMPLE_COMPASS,
RG_SHADOW_TEMPLE_SMALL_KEY, RG_SHADOW_TEMPLE_KEY_RING, RG_SHADOW_TEMPLE_BOSS_KEY, RA_SHADOW_TEMPLE, 5, 6, RG_SHADOW_TEMPLE_SMALL_KEY, RG_SHADOW_TEMPLE_KEY_RING, RG_SHADOW_TEMPLE_BOSS_KEY, RA_SHADOW_TEMPLE, 5, 6, RSK_MQ_SHADOW_TEMPLE,
{ {
// Vanilla Locations // Vanilla Locations
RC_SHADOW_TEMPLE_MAP_CHEST, RC_SHADOW_TEMPLE_MAP_CHEST,
@ -541,7 +551,7 @@ Dungeons::Dungeons() {
}); });
dungeonList[BOTTOM_OF_THE_WELL] = DungeonInfo( dungeonList[BOTTOM_OF_THE_WELL] = DungeonInfo(
"Bottom of the Well", RHT_BOTTOM_OF_THE_WELL, RG_BOTTOM_OF_THE_WELL_MAP, RG_BOTTOM_OF_THE_WELL_COMPASS, "Bottom of the Well", RHT_BOTTOM_OF_THE_WELL, RG_BOTTOM_OF_THE_WELL_MAP, RG_BOTTOM_OF_THE_WELL_COMPASS,
RG_BOTTOM_OF_THE_WELL_SMALL_KEY, RG_BOTTOM_OF_THE_WELL_KEY_RING, RG_NONE, RA_BOTTOM_OF_THE_WELL, 3, 2, RG_BOTTOM_OF_THE_WELL_SMALL_KEY, RG_BOTTOM_OF_THE_WELL_KEY_RING, RG_NONE, RA_BOTTOM_OF_THE_WELL, 3, 2, RSK_MQ_BOTTOM_OF_THE_WELL,
{ {
// Vanilla Locations // Vanilla Locations
RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST,
@ -575,7 +585,7 @@ Dungeons::Dungeons() {
}, },
{}, {}); {}, {});
dungeonList[ICE_CAVERN] = DungeonInfo("Ice Cavern", RHT_ICE_CAVERN, RG_ICE_CAVERN_MAP, RG_ICE_CAVERN_COMPASS, dungeonList[ICE_CAVERN] = DungeonInfo("Ice Cavern", RHT_ICE_CAVERN, RG_ICE_CAVERN_MAP, RG_ICE_CAVERN_COMPASS,
RG_NONE, RG_NONE, RG_NONE, RA_ICE_CAVERN, 0, 0, RG_NONE, RG_NONE, RG_NONE, RA_ICE_CAVERN, 0, 0, RSK_MQ_ICE_CAVERN,
{ {
// Vanilla Locations // Vanilla Locations
RC_ICE_CAVERN_MAP_CHEST, RC_ICE_CAVERN_MAP_CHEST,
@ -603,7 +613,7 @@ Dungeons::Dungeons() {
{}); {});
dungeonList[GERUDO_TRAINING_GROUNDS] = dungeonList[GERUDO_TRAINING_GROUNDS] =
DungeonInfo("Gerudo Training Grounds", RHT_GERUDO_TRAINING_GROUND, RG_NONE, RG_NONE, DungeonInfo("Gerudo Training Grounds", RHT_GERUDO_TRAINING_GROUND, RG_NONE, RG_NONE,
RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, RG_GERUDO_TRAINING_GROUNDS_KEY_RING, RG_NONE, RA_GERUDO_TRAINING_GROUND, 9, 3, RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, RG_GERUDO_TRAINING_GROUNDS_KEY_RING, RG_NONE, RA_GERUDO_TRAINING_GROUND, 9, 3, RSK_MQ_GTG,
{ {
// Vanilla Locations // Vanilla Locations
RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST, RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST,
@ -652,7 +662,7 @@ Dungeons::Dungeons() {
{}, {}); {}, {});
dungeonList[GANONS_CASTLE] = dungeonList[GANONS_CASTLE] =
DungeonInfo("Ganon's Castle", RHT_GANONS_CASTLE, RG_NONE, RG_NONE, RG_GANONS_CASTLE_SMALL_KEY, DungeonInfo("Ganon's Castle", RHT_GANONS_CASTLE, RG_NONE, RG_NONE, RG_GANONS_CASTLE_SMALL_KEY,
RG_GANONS_CASTLE_KEY_RING, RG_GANONS_CASTLE_BOSS_KEY, RA_GANONS_CASTLE, 2, 3, RG_GANONS_CASTLE_KEY_RING, RG_GANONS_CASTLE_BOSS_KEY, RA_GANONS_CASTLE, 2, 3, RSK_MQ_GANONS_CASTLE,
{ {
// Vanilla Locations // Vanilla Locations
RC_GANONS_CASTLE_FOREST_TRIAL_CHEST, RC_GANONS_CASTLE_FOREST_TRIAL_CHEST,

View File

@ -12,7 +12,8 @@ class DungeonInfo {
public: public:
DungeonInfo(std::string name_, RandomizerHintTextKey hintKey_, RandomizerGet map_, RandomizerGet compass_, DungeonInfo(std::string name_, RandomizerHintTextKey hintKey_, RandomizerGet map_, RandomizerGet compass_,
RandomizerGet smallKey_, RandomizerGet keyRing_, RandomizerGet bossKey_, RandomizerArea area_, RandomizerGet smallKey_, RandomizerGet keyRing_, RandomizerGet bossKey_, RandomizerArea area_,
uint8_t vanillaKeyCount_, uint8_t mqKeyCount_, std::vector<RandomizerCheck> vanillaLocations_, uint8_t vanillaKeyCount_, uint8_t mqKeyCount_, RandomizerSettingKey mqSetting_,
std::vector<RandomizerCheck> vanillaLocations_,
std::vector<RandomizerCheck> mqLocations_, std::vector<RandomizerCheck> sharedLocations_, std::vector<RandomizerCheck> mqLocations_, std::vector<RandomizerCheck> sharedLocations_,
std::vector<RandomizerCheck> bossRoomLocations_); std::vector<RandomizerCheck> bossRoomLocations_);
DungeonInfo(); DungeonInfo();
@ -34,6 +35,8 @@ class DungeonInfo {
RandomizerGet GetMap() const; RandomizerGet GetMap() const;
RandomizerGet GetCompass() const; RandomizerGet GetCompass() const;
RandomizerGet GetBossKey() const; RandomizerGet GetBossKey() const;
RandomizerSettingKey GetMQSetting() const;
void SetDungeonKnown(bool known);
void PlaceVanillaMap() const; void PlaceVanillaMap() const;
void PlaceVanillaCompass() const; void PlaceVanillaCompass() const;
void PlaceVanillaBossKey() const; void PlaceVanillaBossKey() const;
@ -50,6 +53,8 @@ class DungeonInfo {
RandomizerGet smallKey; RandomizerGet smallKey;
RandomizerGet keyRing; RandomizerGet keyRing;
RandomizerGet bossKey; RandomizerGet bossKey;
RandomizerSettingKey mqSetting;
bool isDungeonModeKnown = true;
uint8_t vanillaKeyCount{}; uint8_t vanillaKeyCount{};
uint8_t mqKeyCount{}; uint8_t mqKeyCount{};
bool masterQuest = false; bool masterQuest = false;

View File

@ -98,7 +98,8 @@ void Settings::CreateOptionDescriptions() {
"\n" "\n"
"Random Number - A Random number and set of dungeons will be their Master Quest varieties.\n" "Random Number - A Random number and set of dungeons will be their Master Quest varieties.\n"
"\n" "\n"
"Selection Only - Specify which dungeons are Vanilla or Master Quest."; "Selection Only - Specify which dungeons are Vanilla, Master Quest or a 50/50 between the two.\n"
"Differs from Random Number in that they are rolled individually, making the exact total a bell curve.";
mOptionDescriptions[RSK_MQ_DUNGEON_SET] = mOptionDescriptions[RSK_MQ_DUNGEON_SET] =
"Choose specific Dungeons to be Master Quest or Vanilla.\n" "Choose specific Dungeons to be Master Quest or Vanilla.\n"
"\n" "\n"

View File

@ -112,12 +112,12 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() {
(location.GetRandomizerCheck() != RC_UNKNOWN_CHECK) && (location.GetRandomizerCheck() != RC_UNKNOWN_CHECK) &&
(!RandomizerCheckObjects::AreaIsDungeon(location.GetArea()) || location.GetQuest() == RCQUEST_BOTH || (!RandomizerCheckObjects::AreaIsDungeon(location.GetArea()) || location.GetQuest() == RCQUEST_BOTH ||
location.GetQuest() == RCQUEST_MQ && location.GetQuest() == RCQUEST_MQ &&
((CVarGetInteger(CVAR_RANDOMIZER_SETTING("MqDungeons"), RO_MQ_DUNGEONS_NONE) == RO_MQ_DUNGEONS_SET_NUMBER && ((CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeons"), RO_MQ_DUNGEONS_NONE) == RO_MQ_DUNGEONS_SET_NUMBER &&
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("MqDungeonCount"), 12) > 0) || // at least one MQ dungeon (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeonCount"), 12) > 0) || // at least one MQ dungeon
CVarGetInteger(CVAR_RANDOMIZER_SETTING("MqDungeons"), RO_MQ_DUNGEONS_NONE) == RO_MQ_DUNGEONS_RANDOM_NUMBER)) || CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeons"), RO_MQ_DUNGEONS_NONE) == RO_MQ_DUNGEONS_RANDOM_NUMBER)) ||
location.GetQuest() == RCQUEST_VANILLA && location.GetQuest() == RCQUEST_VANILLA &&
(CVarGetInteger(CVAR_RANDOMIZER_SETTING("MqDungeons"), RO_MQ_DUNGEONS_NONE) != RO_MQ_DUNGEONS_SET_NUMBER || (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeons"), RO_MQ_DUNGEONS_NONE) != RO_MQ_DUNGEONS_SET_NUMBER ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("MqDungeonCount"), 12) < 12) // at least one vanilla dungeon CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeonCount"), 12) < 12) // at least one vanilla dungeon
) && ) &&
(location.GetRCType() != RCTYPE_SHOP || (location.GetRCType() != RCTYPE_SHOP ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("Shopsanity"), RO_SHOPSANITY_OFF) > RO_SHOPSANITY_ZERO_ITEMS) && CVarGetInteger(CVAR_RANDOMIZER_SETTING("Shopsanity"), RO_SHOPSANITY_OFF) > RO_SHOPSANITY_ZERO_ITEMS) &&

View File

@ -1486,7 +1486,7 @@ void Settings::UpdateOptionProperties() {
} else { } else {
// If any MQ Options are available, show the MQ Dungeon Randomization Combobox // If any MQ Options are available, show the MQ Dungeon Randomization Combobox
mOptions[RSK_MQ_DUNGEON_RANDOM].Unhide(); mOptions[RSK_MQ_DUNGEON_RANDOM].Unhide();
switch(CVarGetInteger(CVAR_RANDOMIZER_SETTING("MqDungeons"), RO_MQ_DUNGEONS_NONE)) { switch(CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeons"), RO_MQ_DUNGEONS_NONE)) {
// If No MQ Dungeons, add a separator after the combobx and hide // If No MQ Dungeons, add a separator after the combobx and hide
// the count slider and the toggle for individual dungeon selections. // the count slider and the toggle for individual dungeon selections.
case RO_MQ_DUNGEONS_NONE: case RO_MQ_DUNGEONS_NONE:
@ -1504,17 +1504,22 @@ void Settings::UpdateOptionProperties() {
// else if random number or selection only, remove the separator and only show // else if random number or selection only, remove the separator and only show
// the individual dungeon selection toggle. // the individual dungeon selection toggle.
case RO_MQ_DUNGEONS_RANDOM_NUMBER: case RO_MQ_DUNGEONS_RANDOM_NUMBER:
case RO_MQ_DUNGEONS_SELECTION:
mOptions[RSK_MQ_DUNGEON_RANDOM].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM); mOptions[RSK_MQ_DUNGEON_RANDOM].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM);
mOptions[RSK_MQ_DUNGEON_COUNT].Hide(); mOptions[RSK_MQ_DUNGEON_COUNT].Hide();
mOptions[RSK_MQ_DUNGEON_SET].Unhide(); mOptions[RSK_MQ_DUNGEON_SET].Unhide();
break; break;
case RO_MQ_DUNGEONS_SELECTION:
mOptions[RSK_MQ_DUNGEON_RANDOM].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM);
mOptions[RSK_MQ_DUNGEON_COUNT].Hide();
mOptions[RSK_MQ_DUNGEON_SET].Hide();
break;
default: default:
break; break;
} }
// Controls whether or not to show the selectors for individual dungeons. // Controls whether or not to show the selectors for individual dungeons.
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MqDungeons"), RO_MQ_DUNGEONS_NONE) != RO_MQ_DUNGEONS_NONE && if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeons"), RO_MQ_DUNGEONS_NONE) != RO_MQ_DUNGEONS_NONE &&
CVarGetInteger(CVAR_RANDOMIZER_SETTING("MqDungeonsSelection"), RO_GENERIC_OFF) == RO_GENERIC_ON) { (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeonsSelection"), RO_GENERIC_OFF) == RO_GENERIC_ON ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeons"), RO_MQ_DUNGEONS_NONE) == RO_MQ_DUNGEONS_SELECTION)) {
// if showing the dungeon selectors, remove the separator after the Set Dungeons checkbox. // if showing the dungeon selectors, remove the separator after the Set Dungeons checkbox.
mOptions[RSK_MQ_DUNGEON_SET].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM); mOptions[RSK_MQ_DUNGEON_SET].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM);
mOptions[RSK_MQ_DEKU_TREE].Unhide(); mOptions[RSK_MQ_DEKU_TREE].Unhide();
@ -1546,12 +1551,7 @@ void Settings::UpdateOptionProperties() {
mOptions[RSK_MQ_GANONS_CASTLE].Hide(); mOptions[RSK_MQ_GANONS_CASTLE].Hide();
} }
} }
// Disable interaction with Set Dungeons checkbox if MQ Dungeon Randomization is set to Selection Only.
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MqDungeons"), RO_MQ_DUNGEONS_NONE) == RO_MQ_DUNGEONS_SELECTION) {
mOptions[RSK_MQ_DUNGEON_SET].Disable("This option is force-enabled because Master Quest Dungeons is set to Selection Only", UIWidgets::CheckboxGraphics::Checkmark);
} else {
mOptions[RSK_MQ_DUNGEON_SET].Enable();
}
// Show mixed entrance pool options if mixed entrance pools are enabled at all. // Show mixed entrance pool options if mixed entrance pools are enabled at all.
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MixedEntrances"), RO_GENERIC_OFF)) { if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MixedEntrances"), RO_GENERIC_OFF)) {
mOptions[RSK_MIXED_ENTRANCE_POOLS].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM); mOptions[RSK_MIXED_ENTRANCE_POOLS].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM);
@ -1871,74 +1871,121 @@ void Settings::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocatio
// RANDOTODO implement chest shuffle with keysanity // RANDOTODO implement chest shuffle with keysanity
// ShuffleChestMinigame.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_CHEST_MINIGAME]); // ShuffleChestMinigame.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_CHEST_MINIGAME]);
mOptions[RSK_SHUFFLE_CHEST_MINIGAME].SetSelectedIndex(RO_CHEST_GAME_OFF); mOptions[RSK_SHUFFLE_CHEST_MINIGAME].SetSelectedIndex(RO_CHEST_GAME_OFF);
//TODO: RandomizeAllSettings(true) when implementing the ability to randomize the options themselves. //TODO: RandomizeAllSettings(true) when implementing the ability to randomize the options themselves.
std::array<DungeonInfo*, 12> dungeons = ctx->GetDungeons()->GetDungeonList(); std::array<DungeonInfo*, 12> dungeons = ctx->GetDungeons()->GetDungeonList();
std::array<bool, 12> dungeonModesKnown{};
const std::vector<Option*> dungeonOptions = { //reset the MQ vars
&mOptions[RSK_MQ_DEKU_TREE], for (auto dungeon: dungeons) {
&mOptions[RSK_MQ_DODONGOS_CAVERN], dungeon->ClearMQ();
&mOptions[RSK_MQ_JABU_JABU], dungeon->SetDungeonKnown(true);
&mOptions[RSK_MQ_FOREST_TEMPLE],
&mOptions[RSK_MQ_FIRE_TEMPLE],
&mOptions[RSK_MQ_WATER_TEMPLE],
&mOptions[RSK_MQ_SPIRIT_TEMPLE],
&mOptions[RSK_MQ_SHADOW_TEMPLE],
&mOptions[RSK_MQ_BOTTOM_OF_THE_WELL],
&mOptions[RSK_MQ_ICE_CAVERN],
&mOptions[RSK_MQ_GTG],
&mOptions[RSK_MQ_GANONS_CASTLE]
};
auto mqSet = mOptions[RSK_MQ_DUNGEON_COUNT].Value<uint8_t>();
if (mOptions[RSK_MQ_DUNGEON_RANDOM].Is(RO_MQ_DUNGEONS_SELECTION)) {
mqSet = 0;
} }
std::vector<uint8_t> randMQOption = {}; //if it's selection mode, process the selection directly
if (mOptions[RSK_MQ_DUNGEON_SET]) { if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value<uint8_t>() == RO_MQ_DUNGEONS_SELECTION){
uint8_t dungeonCount = 0; mOptions[RSK_MQ_DUNGEON_SET].SetSelectedIndex(RO_GENERIC_ON);
for (size_t i = 0; i < dungeons.size(); i++) { //How many dungeons are set to MQ in selection
dungeons[i]->ClearMQ(); uint8_t mqSet = 0;
dungeonModesKnown[i] = true; for (auto dungeon: dungeons) {
switch (dungeonOptions[i]->Value<uint8_t>()) { switch (mOptions[dungeon->GetMQSetting()].Value<uint8_t>()) {
case 1: case RO_MQ_SET_MQ:
dungeons[i]->SetMQ(); dungeon->SetMQ();
dungeonCount++; mqSet += 1;
break; break;
case 2: case RO_MQ_SET_RANDOM:
randMQOption.push_back(i); //50% per dungeon, rolled seperatly so people can either have a linear distribtuion
dungeonModesKnown[i] = false; //or a bell curve for the number of MQ dungeons per seed.
if (Random(0,2)){
dungeon->SetMQ();
mqSet += 1;
}
dungeon->SetDungeonKnown(false);
break; break;
default: default:
break; break;
} }
} }
Shuffle(randMQOption); //override the dungeons set with the ones set by selection, so it's accurate for anything that wants to know MQ dungeon count
if (mOptions[RSK_MQ_DUNGEON_RANDOM].Is(RO_MQ_DUNGEONS_RANDOM_NUMBER)) { mOptions[RSK_MQ_DUNGEON_COUNT].SetSelectedIndex(mqSet);
mqSet = dungeonCount + Random(0, static_cast<int>(randMQOption.size()) + 1); //handling set number and random number together
} } else if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value<uint8_t>() != RO_MQ_DUNGEONS_NONE){
for (uint8_t i = 0; dungeonCount < mqSet; i++) { // so we don't have to call this repeatedly
if (i > randMQOption.size()) { uint8_t mqCount = mOptions[RSK_MQ_DUNGEON_COUNT].Value<uint8_t>();
// This can happen if the amount of MQ Dungeons is specifically //How many dungeons are set to MQ in selection
// set to a higher number than the amount of Dungeons specifically set to MQ or Random, uint8_t mqSet = 0;
// break out of the loop and just have fewer MQ dungeons than the Set Count. //the number of random
uint8_t mqToSet = 0;
//store the dungeons to randomly decide between. we use the id instead of a dungeon object to avoid a lot of casting.
std::vector<uint8_t> randMQOption = {};
//if dungeons have been preset, process them
if (mOptions[RSK_MQ_DUNGEON_SET]){
for (size_t i = 0; i < dungeons.size(); i++) {
switch (mOptions[dungeons[i]->GetMQSetting()].Value<uint8_t>()) {
case RO_MQ_SET_MQ:
dungeons[i]->SetMQ();
mqSet += 1;
break;
case RO_MQ_SET_RANDOM:
randMQOption.push_back(i);
dungeons[i]->SetDungeonKnown(false);
break;
default:
break; break;
} }
}
//otherwise, every dungeon is possible
} else {
//if the count is fixed to 12, we know everything is MQ, so can skip some setps and do not set Known
if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value<uint8_t>() == RO_MQ_DUNGEONS_SET_NUMBER &&
mqCount == 12) {
randMQOption = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
for (auto dungeon: dungeons) {
mOptions[dungeon->GetMQSetting()].SetSelectedIndex(RO_MQ_SET_MQ);
}
//if it's fixed to zero, set it to None instead. the rest is processed after
} else if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value<uint8_t>() == RO_MQ_DUNGEONS_SET_NUMBER &&
mqCount == 0){
mOptions[RSK_MQ_DUNGEON_RANDOM].SetSelectedIndex(RO_MQ_DUNGEONS_NONE);
//otherwise, make everything a possibility and unknown
} else {
for (size_t i = 0; i < dungeons.size(); i++) {
randMQOption.push_back(i);
dungeons[i]->SetDungeonKnown(false);
mOptions[dungeons[i]->GetMQSetting()].SetSelectedIndex(RO_MQ_SET_RANDOM);
}
}
}
//if there's no random options, we can skip this
if (randMQOption.size() > 0){
//Figure out how many dungeons to select, rolling the random number if needed
if (mOptions[RSK_MQ_DUNGEON_RANDOM].Is(RO_MQ_DUNGEONS_RANDOM_NUMBER)){
mqToSet = Random(0, static_cast<int>(randMQOption.size()) + 1);
} else if (mqCount > mqSet) {
mqToSet = std::min(mqCount - mqSet, static_cast<int>(randMQOption.size()));
}
//we only need to shuffle if we're not using them all
if (mqToSet <= static_cast<int8_t>(randMQOption.size()) && mqToSet > 0) {
Shuffle(randMQOption);
}
for (uint8_t i = 0; i < mqToSet; i++){
dungeons[randMQOption[i]]->SetMQ(); dungeons[randMQOption[i]]->SetMQ();
dungeonCount++;
} }
} else { } else {
Shuffle(dungeons); //if there's no random options, check if we can collapse the setting into None or Selection
for (const auto dungeon : dungeons) { if (mqSet == 0){
dungeon->ClearMQ(); mOptions[RSK_MQ_DUNGEON_RANDOM].SetSelectedIndex(RO_MQ_DUNGEONS_NONE);
} else {
mOptions[RSK_MQ_DUNGEON_RANDOM].SetSelectedIndex(RO_MQ_DUNGEONS_SELECTION);
} }
const bool allDungeonModesKnown = mqSet == 0 || mqSet == dungeons.size();
for (bool & i : dungeonModesKnown) {
i = allDungeonModesKnown;
} }
if (mOptions[RSK_MQ_DUNGEON_RANDOM].Is(RO_MQ_DUNGEONS_RANDOM_NUMBER)) { //reset the value set based on what was actually set
mqSet = Random(0, 13); mOptions[RSK_MQ_DUNGEON_COUNT].SetSelectedIndex(mqToSet + mqSet);
} }
for (uint8_t i = 0; i < mqSet; i++) { //Not an if else as other settings can become None in processing
dungeons[i]->SetMQ(); if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value<uint8_t>() == RO_MQ_DUNGEONS_NONE) {
mOptions[RSK_MQ_DUNGEON_SET].SetSelectedIndex(RO_GENERIC_OFF);
mOptions[RSK_MQ_DUNGEON_COUNT].SetSelectedIndex(0);
for (auto dungeon: dungeons) {
mOptions[dungeon->GetMQSetting()].SetSelectedIndex(RO_MQ_SET_VANILLA);
} }
} }