Choose Link's Pocket Dungeon Reward Type (#6213)

This commit is contained in:
A Green Spoon
2026-03-06 07:05:55 +09:00
committed by GitHub
parent 6340ad3d5c
commit 92a1d260da
4 changed files with 95 additions and 27 deletions

View File

@@ -944,24 +944,21 @@ static void AssumedFill(const std::vector<RandomizerGet>& items, const std::vect
// setting, or randomize one dungeon reward to Link's Pocket if that setting is on
static void RandomizeDungeonRewards() {
auto ctx = Rando::Context::GetInstance();
// quest item bit mask of each stone/medallion for the savefile
// static constexpr std::array<uint32_t, 9> bitMaskTable = {
// 0x00040000, //Kokiri Emerald
// 0x00080000, //Goron Ruby
// 0x00100000, //Zora Sapphire
// 0x00000001, //Forest Medallion
// 0x00000002, //Fire Medallion
// 0x00000004, //Water Medallion
// 0x00000008, //Spirit Medallion
// 0x00000010, //Shadow Medallion
// 0x00000020, //Light Medallion
// };
int baseOffset = Rando::StaticData::RetrieveItem(RG_KOKIRI_EMERALD).GetItemID();
// End of Dungeons includes Link's Pocket
if (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON) ||
ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_VANILLA)) {
// get stones and medallions
// make temporary pools of stones and medallions, get rewards
std::vector<RandomizerGet> stones = FilterFromPool(itemPool, [](const auto i) {
return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD &&
Rando::StaticData::RetrieveItem(i).GetRandomizerGet() >= RG_KOKIRI_EMERALD &&
Rando::StaticData::RetrieveItem(i).GetRandomizerGet() <= RG_ZORA_SAPPHIRE;
});
std::vector<RandomizerGet> medallions = FilterFromPool(itemPool, [](const auto i) {
return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD &&
Rando::StaticData::RetrieveItem(i).GetRandomizerGet() >= RG_FOREST_MEDALLION &&
Rando::StaticData::RetrieveItem(i).GetRandomizerGet() <= RG_LIGHT_MEDALLION;
});
std::vector<RandomizerGet> rewards = FilterAndEraseFromPool(itemPool, [](const auto i) {
return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD;
});
@@ -978,12 +975,38 @@ static void RandomizeDungeonRewards() {
if (rewards.size() < 9) {
ctx->PlaceItemInLocation(RC_LINKS_POCKET, RG_GREEN_RUPEE);
} else {
rewardLocations.push_back(RC_LINKS_POCKET);
if (ctx->GetOption(RSK_LINKS_POCKET_REWARD).IsNot(RO_LINKS_POCKET_REWARD)) {
if (ctx->GetOption(RSK_LINKS_POCKET_REWARD).Is(RO_LINKS_POCKET_STONE)) {
// get one stone
RandomizerGet startingStone = RandomElement(stones, true);
// erase from rewards so remaining are placed
erase_if(rewards, [&](RandomizerGet r) { return r == startingStone; });
ctx->PlaceItemInLocation(RC_LINKS_POCKET, startingStone);
} else {
// get one medallion
RandomizerGet startingMedallion = RandomElement(medallions, true);
// erase from rewards so remaining are placed
erase_if(rewards, [&](RandomizerGet r) { return r == startingMedallion; });
ctx->PlaceItemInLocation(RC_LINKS_POCKET, startingMedallion);
}
} else {
rewardLocations.push_back(RC_LINKS_POCKET);
}
}
AssumedFill(rewards, rewardLocations);
}
} else if (ctx->GetOption(RSK_LINKS_POCKET).Is(RO_LINKS_POCKET_DUNGEON_REWARD)) {
// get 1 stone/medallion
// make temporary pools of stones, medallions, and rewards
std::vector<RandomizerGet> stones = FilterFromPool(itemPool, [](const auto i) {
return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD &&
Rando::StaticData::RetrieveItem(i).GetRandomizerGet() >= RG_KOKIRI_EMERALD &&
Rando::StaticData::RetrieveItem(i).GetRandomizerGet() <= RG_ZORA_SAPPHIRE;
});
std::vector<RandomizerGet> medallions = FilterFromPool(itemPool, [](const auto i) {
return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD &&
Rando::StaticData::RetrieveItem(i).GetRandomizerGet() >= RG_FOREST_MEDALLION &&
Rando::StaticData::RetrieveItem(i).GetRandomizerGet() <= RG_LIGHT_MEDALLION;
});
std::vector<RandomizerGet> rewards = FilterFromPool(itemPool, [](const auto i) {
return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD;
});
@@ -992,13 +1015,27 @@ static void RandomizeDungeonRewards() {
ctx->PlaceItemInLocation(RC_LINKS_POCKET, RG_GREEN_RUPEE);
return;
}
RandomizerGet startingReward = RandomElement(rewards, true);
if (ctx->GetOption(RSK_LINKS_POCKET_REWARD).Is(RO_LINKS_POCKET_STONE)) {
// get one stone
RandomizerGet startingStone = RandomElement(stones, true);
ctx->PlaceItemInLocation(RC_LINKS_POCKET, startingStone);
// erase stone from item pool
FilterAndEraseFromPool(itemPool, [startingStone](const RandomizerGet i) { return i == startingStone; });
} else if (ctx->GetOption(RSK_LINKS_POCKET_REWARD).Is(RO_LINKS_POCKET_MEDALLION)) {
// get one medallion
RandomizerGet startingMedallion = RandomElement(medallions, true);
ctx->PlaceItemInLocation(RC_LINKS_POCKET, startingMedallion);
// erase medallion from item pool
FilterAndEraseFromPool(itemPool,
[startingMedallion](const RandomizerGet i) { return i == startingMedallion; });
} else {
// get one reward
RandomizerGet startingReward = RandomElement(rewards, true);
// LinksPocketRewardBitMask = bitMaskTable[Rando::StaticData::RetrieveItem(startingReward).GetItemID() -
// baseOffset];
ctx->PlaceItemInLocation(RC_LINKS_POCKET, startingReward);
// erase the stone/medallion from the Item Pool
FilterAndEraseFromPool(itemPool, [startingReward](const RandomizerGet i) { return i == startingReward; });
ctx->PlaceItemInLocation(RC_LINKS_POCKET, startingReward);
// erase the stone/medallion from the Item Pool
FilterAndEraseFromPool(itemPool, [startingReward](const RandomizerGet i) { return i == startingReward; });
}
}
}

View File

@@ -397,6 +397,13 @@ RANDO_ENUM_ITEM(RO_LINKS_POCKET_ANYTHING)
RANDO_ENUM_ITEM(RO_LINKS_POCKET_NOTHING)
RANDO_ENUM_END(RandoOptionLinksPocket)
// Link's Pocket Dungeon Reward Settings (dungeon reward, stone, medallion)
RANDO_ENUM_BEGIN(RandoOptionLinksPocketReward)
RANDO_ENUM_ITEM(RO_LINKS_POCKET_REWARD)
RANDO_ENUM_ITEM(RO_LINKS_POCKET_STONE)
RANDO_ENUM_ITEM(RO_LINKS_POCKET_MEDALLION)
RANDO_ENUM_END(RandoOptionLinksPocketReward)
// Logic (glitchless/no logic)
RANDO_ENUM_BEGIN(RandoOptionLogic)
RANDO_ENUM_ITEM(RO_LOGIC_GLITCHLESS)

View File

@@ -166,6 +166,7 @@ RANDO_ENUM_ITEM(RSK_SLINGBOW_BREAK_BEEHIVES)
RANDO_ENUM_ITEM(RSK_ENABLE_BOMBCHU_DROPS)
RANDO_ENUM_ITEM(RSK_BOMBCHU_BAG)
RANDO_ENUM_ITEM(RSK_LINKS_POCKET)
RANDO_ENUM_ITEM(RSK_LINKS_POCKET_REWARD)
RANDO_ENUM_ITEM(RSK_MQ_DUNGEON_RANDOM)
RANDO_ENUM_ITEM(RSK_MQ_DUNGEON_COUNT)
RANDO_ENUM_ITEM(RSK_MQ_DUNGEON_SET)

View File

@@ -574,11 +574,34 @@ void Settings::CreateOptions() {
RO_DUNGEON_REWARDS_END_OF_DUNGEON) {
mOptions[RSK_LINKS_POCKET].Disable(
"This option is disabled because \"Dungeon Rewards\" are shuffled to \"End of Dungeons\".");
mOptions[RSK_LINKS_POCKET_REWARD].Enable();
mOptions[RSK_LINKS_POCKET_REWARD].Unhide();
} else if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleDungeonReward"), RO_DUNGEON_REWARDS_END_OF_DUNGEON) ==
RO_DUNGEON_REWARDS_VANILLA) {
mOptions[RSK_LINKS_POCKET_REWARD].Disable("This option is disabled because \"Dungeon Rewards\" are shuffled to \"Vanilla\".");
mOptions[RSK_LINKS_POCKET_REWARD].Hide();
mOptions[RSK_LINKS_POCKET].Enable();
} else {
mOptions[RSK_LINKS_POCKET].Enable();
mOptions[RSK_LINKS_POCKET_REWARD].Enable();
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("LinksPocket"), RO_LINKS_POCKET_DUNGEON_REWARD) == RO_LINKS_POCKET_DUNGEON_REWARD) {
mOptions[RSK_LINKS_POCKET_REWARD].Unhide();
}
}
});
OPT_U8(RSK_LINKS_POCKET, "Link's Pocket", {"Dungeon Reward", "Advancement", "Anything", "Nothing"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LinksPocket"), "", WIDGET_CVAR_COMBOBOX, RO_LINKS_POCKET_DUNGEON_REWARD);
OPT_CALLBACK(RSK_LINKS_POCKET, {
// Only show the dungeon reward type if Link's Pocket is set to Dungeon Reward and Dungeon Rewards are not Vanilla, OR Dungeon Rewards are end of dungeon
if ((CVarGetInteger(CVAR_RANDOMIZER_SETTING("LinksPocket"), RO_LINKS_POCKET_DUNGEON_REWARD) ==
RO_LINKS_POCKET_DUNGEON_REWARD && CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleDungeonReward"), RO_DUNGEON_REWARDS_END_OF_DUNGEON) !=
RO_DUNGEON_REWARDS_VANILLA) || CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleDungeonReward"), RO_DUNGEON_REWARDS_END_OF_DUNGEON) ==
RO_DUNGEON_REWARDS_END_OF_DUNGEON) {
mOptions[RSK_LINKS_POCKET_REWARD].Unhide();
} else {
mOptions[RSK_LINKS_POCKET_REWARD].Hide();
}
});
OPT_U8(RSK_LINKS_POCKET_REWARD, "Link's Pocket Reward Type", {"Dungeon Reward", "Stone", "Medallion"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LinksPocketReward"), "", WIDGET_CVAR_COMBOBOX, RO_LINKS_POCKET_REWARD);
OPT_U8(RSK_SHUFFLE_SONGS, "Shuffle Songs", {"Off", "Song Locations", "Dungeon Rewards", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleSongs"), mOptionDescriptions[RSK_SHUFFLE_SONGS], WIDGET_CVAR_COMBOBOX, RO_SONG_SHUFFLE_SONG_LOCATIONS);
OPT_U8(RSK_SHOPSANITY, "Shop Shuffle", {"Off", "Specific Count", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Shopsanity"), mOptionDescriptions[RSK_SHOPSANITY], WIDGET_CVAR_COMBOBOX, RO_SHOPSANITY_OFF);
OPT_CALLBACK(RSK_SHOPSANITY, {
@@ -2547,11 +2570,11 @@ void Settings::CreateOptions() {
&mOptionGroups[RSG_MENU_COLUMN_STATIC_HINTS],
},
WidgetContainerType::TABLE);
mOptionGroups[RSG_MENU_SECTION_STARTING_EQUIPS] =
OptionGroup::SubGroup("Equips",
{ &mOptions[RSK_LINKS_POCKET], &mOptions[RSK_STARTING_KOKIRI_SWORD],
&mOptions[RSK_STARTING_MASTER_SWORD], &mOptions[RSK_STARTING_DEKU_SHIELD] },
WidgetContainerType::SECTION);
mOptionGroups[RSG_MENU_SECTION_STARTING_EQUIPS] = OptionGroup::SubGroup(
"Equips",
{ &mOptions[RSK_LINKS_POCKET], &mOptions[RSK_LINKS_POCKET_REWARD], &mOptions[RSK_STARTING_KOKIRI_SWORD],
&mOptions[RSK_STARTING_MASTER_SWORD], &mOptions[RSK_STARTING_DEKU_SHIELD] },
WidgetContainerType::SECTION);
mOptionGroups[RSG_MENU_SECTION_STARTING_ITEMS] = OptionGroup::SubGroup("Items",
{
&mOptions[RSK_STARTING_OCARINA],