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 // setting, or randomize one dungeon reward to Link's Pocket if that setting is on
static void RandomizeDungeonRewards() { static void RandomizeDungeonRewards() {
auto ctx = Rando::Context::GetInstance(); 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 // End of Dungeons includes Link's Pocket
if (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON) || 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)) { 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) { std::vector<RandomizerGet> rewards = FilterAndEraseFromPool(itemPool, [](const auto i) {
return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD; return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD;
}); });
@@ -978,12 +975,38 @@ static void RandomizeDungeonRewards() {
if (rewards.size() < 9) { if (rewards.size() < 9) {
ctx->PlaceItemInLocation(RC_LINKS_POCKET, RG_GREEN_RUPEE); ctx->PlaceItemInLocation(RC_LINKS_POCKET, RG_GREEN_RUPEE);
} else { } 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); AssumedFill(rewards, rewardLocations);
} }
} else if (ctx->GetOption(RSK_LINKS_POCKET).Is(RO_LINKS_POCKET_DUNGEON_REWARD)) { } 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) { std::vector<RandomizerGet> rewards = FilterFromPool(itemPool, [](const auto i) {
return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD; return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD;
}); });
@@ -992,13 +1015,27 @@ static void RandomizeDungeonRewards() {
ctx->PlaceItemInLocation(RC_LINKS_POCKET, RG_GREEN_RUPEE); ctx->PlaceItemInLocation(RC_LINKS_POCKET, RG_GREEN_RUPEE);
return; 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() - ctx->PlaceItemInLocation(RC_LINKS_POCKET, startingReward);
// baseOffset]; // erase the stone/medallion from the Item Pool
ctx->PlaceItemInLocation(RC_LINKS_POCKET, startingReward); FilterAndEraseFromPool(itemPool, [startingReward](const RandomizerGet i) { return i == 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_ITEM(RO_LINKS_POCKET_NOTHING)
RANDO_ENUM_END(RandoOptionLinksPocket) 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) // Logic (glitchless/no logic)
RANDO_ENUM_BEGIN(RandoOptionLogic) RANDO_ENUM_BEGIN(RandoOptionLogic)
RANDO_ENUM_ITEM(RO_LOGIC_GLITCHLESS) 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_ENABLE_BOMBCHU_DROPS)
RANDO_ENUM_ITEM(RSK_BOMBCHU_BAG) RANDO_ENUM_ITEM(RSK_BOMBCHU_BAG)
RANDO_ENUM_ITEM(RSK_LINKS_POCKET) 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_RANDOM)
RANDO_ENUM_ITEM(RSK_MQ_DUNGEON_COUNT) RANDO_ENUM_ITEM(RSK_MQ_DUNGEON_COUNT)
RANDO_ENUM_ITEM(RSK_MQ_DUNGEON_SET) RANDO_ENUM_ITEM(RSK_MQ_DUNGEON_SET)

View File

@@ -574,11 +574,34 @@ void Settings::CreateOptions() {
RO_DUNGEON_REWARDS_END_OF_DUNGEON) { RO_DUNGEON_REWARDS_END_OF_DUNGEON) {
mOptions[RSK_LINKS_POCKET].Disable( mOptions[RSK_LINKS_POCKET].Disable(
"This option is disabled because \"Dungeon Rewards\" are shuffled to \"End of Dungeons\"."); "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 { } else {
mOptions[RSK_LINKS_POCKET].Enable(); 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_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_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_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, { OPT_CALLBACK(RSK_SHOPSANITY, {
@@ -2547,11 +2570,11 @@ void Settings::CreateOptions() {
&mOptionGroups[RSG_MENU_COLUMN_STATIC_HINTS], &mOptionGroups[RSG_MENU_COLUMN_STATIC_HINTS],
}, },
WidgetContainerType::TABLE); WidgetContainerType::TABLE);
mOptionGroups[RSG_MENU_SECTION_STARTING_EQUIPS] = mOptionGroups[RSG_MENU_SECTION_STARTING_EQUIPS] = OptionGroup::SubGroup(
OptionGroup::SubGroup("Equips", "Equips",
{ &mOptions[RSK_LINKS_POCKET], &mOptions[RSK_STARTING_KOKIRI_SWORD], { &mOptions[RSK_LINKS_POCKET], &mOptions[RSK_LINKS_POCKET_REWARD], &mOptions[RSK_STARTING_KOKIRI_SWORD],
&mOptions[RSK_STARTING_MASTER_SWORD], &mOptions[RSK_STARTING_DEKU_SHIELD] }, &mOptions[RSK_STARTING_MASTER_SWORD], &mOptions[RSK_STARTING_DEKU_SHIELD] },
WidgetContainerType::SECTION); WidgetContainerType::SECTION);
mOptionGroups[RSG_MENU_SECTION_STARTING_ITEMS] = OptionGroup::SubGroup("Items", mOptionGroups[RSG_MENU_SECTION_STARTING_ITEMS] = OptionGroup::SubGroup("Items",
{ {
&mOptions[RSK_STARTING_OCARINA], &mOptions[RSK_STARTING_OCARINA],