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
//RANDOTODO There's probably a more efficient way to do what this does.
template <typename T>
void Shuffle(std::vector<T>& vector) {
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_,
const RandomizerGet compass_, const RandomizerGet smallKey_, const RandomizerGet keyRing_,
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> sharedLocations_, std::vector<RandomizerCheck> bossRoomLocations_)
: name(std::move(name_)), hintKey(hintKey_), map(map_), compass(compass_), smallKey(smallKey_), keyRing(keyRing_),
bossKey(bossKey_), area(area_), vanillaKeyCount(vanillaKeyCount_), mqKeyCount(mqKeyCount_),
mqSetting(mqSetting_),
vanillaLocations(std::move(vanillaLocations_)), mqLocations(std::move(mqLocations_)),
sharedLocations(std::move(sharedLocations_)), bossRoomLocations(std::move(bossRoomLocations_)) {
}
@ -83,6 +85,14 @@ RandomizerGet DungeonInfo::GetBossKey() const {
return bossKey;
}
RandomizerSettingKey DungeonInfo::GetMQSetting() const {
return mqSetting;
}
void DungeonInfo::SetDungeonKnown(bool known) {
isDungeonModeKnown = known;
}
void DungeonInfo::PlaceVanillaMap() const {
if (map == RG_NONE) {
return;
@ -152,7 +162,7 @@ std::vector<RandomizerCheck> DungeonInfo::GetEveryLocation() const {
Dungeons::Dungeons() {
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
RC_DEKU_TREE_MAP_CHEST,
@ -188,7 +198,7 @@ Dungeons::Dungeons() {
RC_QUEEN_GOHMA,
});
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
RC_DODONGOS_CAVERN_MAP_CHEST,
@ -232,7 +242,7 @@ Dungeons::Dungeons() {
RC_KING_DODONGO,
});
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
RC_JABU_JABUS_BELLY_MAP_CHEST,
@ -271,7 +281,7 @@ Dungeons::Dungeons() {
});
dungeonList[FOREST_TEMPLE] =
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
RC_FOREST_TEMPLE_FIRST_ROOM_CHEST,
@ -321,7 +331,7 @@ Dungeons::Dungeons() {
});
dungeonList[FIRE_TEMPLE] =
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
RC_FIRE_TEMPLE_NEAR_BOSS_CHEST,
@ -372,7 +382,7 @@ Dungeons::Dungeons() {
});
dungeonList[WATER_TEMPLE] =
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
RC_WATER_TEMPLE_MAP_CHEST,
@ -413,7 +423,7 @@ Dungeons::Dungeons() {
});
dungeonList[SPIRIT_TEMPLE] =
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
RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST,
@ -479,7 +489,7 @@ Dungeons::Dungeons() {
});
dungeonList[SHADOW_TEMPLE] =
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
RC_SHADOW_TEMPLE_MAP_CHEST,
@ -541,7 +551,7 @@ Dungeons::Dungeons() {
});
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,
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
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,
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
RC_ICE_CAVERN_MAP_CHEST,
@ -603,7 +613,7 @@ Dungeons::Dungeons() {
{});
dungeonList[GERUDO_TRAINING_GROUNDS] =
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
RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST,
@ -652,7 +662,7 @@ Dungeons::Dungeons() {
{}, {});
dungeonList[GANONS_CASTLE] =
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
RC_GANONS_CASTLE_FOREST_TRIAL_CHEST,

View File

@ -12,7 +12,8 @@ class DungeonInfo {
public:
DungeonInfo(std::string name_, RandomizerHintTextKey hintKey_, RandomizerGet map_, RandomizerGet compass_,
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> bossRoomLocations_);
DungeonInfo();
@ -34,6 +35,8 @@ class DungeonInfo {
RandomizerGet GetMap() const;
RandomizerGet GetCompass() const;
RandomizerGet GetBossKey() const;
RandomizerSettingKey GetMQSetting() const;
void SetDungeonKnown(bool known);
void PlaceVanillaMap() const;
void PlaceVanillaCompass() const;
void PlaceVanillaBossKey() const;
@ -50,6 +53,8 @@ class DungeonInfo {
RandomizerGet smallKey;
RandomizerGet keyRing;
RandomizerGet bossKey;
RandomizerSettingKey mqSetting;
bool isDungeonModeKnown = true;
uint8_t vanillaKeyCount{};
uint8_t mqKeyCount{};
bool masterQuest = false;

View File

@ -98,7 +98,8 @@ void Settings::CreateOptionDescriptions() {
"\n"
"Random Number - A Random number and set of dungeons will be their Master Quest varieties.\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] =
"Choose specific Dungeons to be Master Quest or Vanilla.\n"
"\n"

View File

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

View File

@ -1486,7 +1486,7 @@ void Settings::UpdateOptionProperties() {
} else {
// If any MQ Options are available, show the MQ Dungeon Randomization Combobox
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
// the count slider and the toggle for individual dungeon selections.
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
// the individual dungeon selection toggle.
case RO_MQ_DUNGEONS_RANDOM_NUMBER:
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].Unhide();
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:
break;
}
// 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 &&
CVarGetInteger(CVAR_RANDOMIZER_SETTING("MqDungeonsSelection"), RO_GENERIC_OFF) == RO_GENERIC_ON) {
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("MQDungeons"), RO_MQ_DUNGEONS_NONE) == RO_MQ_DUNGEONS_SELECTION)) {
// 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_DEKU_TREE].Unhide();
@ -1546,12 +1551,7 @@ void Settings::UpdateOptionProperties() {
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.
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MixedEntrances"), RO_GENERIC_OFF)) {
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
// ShuffleChestMinigame.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_CHEST_MINIGAME]);
mOptions[RSK_SHUFFLE_CHEST_MINIGAME].SetSelectedIndex(RO_CHEST_GAME_OFF);
//TODO: RandomizeAllSettings(true) when implementing the ability to randomize the options themselves.
std::array<DungeonInfo*, 12> dungeons = ctx->GetDungeons()->GetDungeonList();
std::array<bool, 12> dungeonModesKnown{};
const std::vector<Option*> dungeonOptions = {
&mOptions[RSK_MQ_DEKU_TREE],
&mOptions[RSK_MQ_DODONGOS_CAVERN],
&mOptions[RSK_MQ_JABU_JABU],
&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;
//reset the MQ vars
for (auto dungeon: dungeons) {
dungeon->ClearMQ();
dungeon->SetDungeonKnown(true);
}
std::vector<uint8_t> randMQOption = {};
if (mOptions[RSK_MQ_DUNGEON_SET]) {
uint8_t dungeonCount = 0;
for (size_t i = 0; i < dungeons.size(); i++) {
dungeons[i]->ClearMQ();
dungeonModesKnown[i] = true;
switch (dungeonOptions[i]->Value<uint8_t>()) {
case 1:
dungeons[i]->SetMQ();
dungeonCount++;
//if it's selection mode, process the selection directly
if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value<uint8_t>() == RO_MQ_DUNGEONS_SELECTION){
mOptions[RSK_MQ_DUNGEON_SET].SetSelectedIndex(RO_GENERIC_ON);
//How many dungeons are set to MQ in selection
uint8_t mqSet = 0;
for (auto dungeon: dungeons) {
switch (mOptions[dungeon->GetMQSetting()].Value<uint8_t>()) {
case RO_MQ_SET_MQ:
dungeon->SetMQ();
mqSet += 1;
break;
case 2:
randMQOption.push_back(i);
dungeonModesKnown[i] = false;
case RO_MQ_SET_RANDOM:
//50% per dungeon, rolled seperatly so people can either have a linear distribtuion
//or a bell curve for the number of MQ dungeons per seed.
if (Random(0,2)){
dungeon->SetMQ();
mqSet += 1;
}
dungeon->SetDungeonKnown(false);
break;
default:
break;
}
}
Shuffle(randMQOption);
if (mOptions[RSK_MQ_DUNGEON_RANDOM].Is(RO_MQ_DUNGEONS_RANDOM_NUMBER)) {
mqSet = dungeonCount + Random(0, static_cast<int>(randMQOption.size()) + 1);
}
for (uint8_t i = 0; dungeonCount < mqSet; i++) {
if (i > randMQOption.size()) {
// This can happen if the amount of MQ Dungeons is specifically
// set to a higher number than the amount of Dungeons specifically set to MQ or Random,
// break out of the loop and just have fewer MQ dungeons than the Set Count.
break;
//override the dungeons set with the ones set by selection, so it's accurate for anything that wants to know MQ dungeon count
mOptions[RSK_MQ_DUNGEON_COUNT].SetSelectedIndex(mqSet);
//handling set number and random number together
} else if (mOptions[RSK_MQ_DUNGEON_RANDOM].Value<uint8_t>() != RO_MQ_DUNGEONS_NONE){
// so we don't have to call this repeatedly
uint8_t mqCount = mOptions[RSK_MQ_DUNGEON_COUNT].Value<uint8_t>();
//How many dungeons are set to MQ in selection
uint8_t mqSet = 0;
//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;
}
}
//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);
}
}
dungeons[randMQOption[i]]->SetMQ();
dungeonCount++;
}
} else {
Shuffle(dungeons);
for (const auto dungeon : dungeons) {
dungeon->ClearMQ();
//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();
}
} else {
//if there's no random options, check if we can collapse the setting into None or Selection
if (mqSet == 0){
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)) {
mqSet = Random(0, 13);
}
for (uint8_t i = 0; i < mqSet; i++) {
dungeons[i]->SetMQ();
//reset the value set based on what was actually set
mOptions[RSK_MQ_DUNGEON_COUNT].SetSelectedIndex(mqToSet + mqSet);
}
//Not an if else as other settings can become None in processing
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);
}
}