diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp index 1386673d9..c24b83fb6 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp +++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp @@ -355,7 +355,7 @@ static size_t NextLineLength(const std::string* textStr, const size_t lastNewlin } } -void CustomMessage::AutoFormatString(std::string& str) const {// did I do this right? +void CustomMessage::AutoFormatString(std::string& str) const { ReplaceAltarIcons(str); ReplaceColors(str); // insert newlines either manually or when encountering a '&' @@ -363,60 +363,86 @@ void CustomMessage::AutoFormatString(std::string& str) const {// did I do this r const bool hasIcon = str.find('$', 0) != std::string::npos; size_t lineLength = NextLineLength(&str, lastNewline, hasIcon); size_t lineCount = 1; - while (lastNewline + lineLength < str.length()) { + size_t yesNo = str.find("\x1B"s[0], lastNewline); + while (lastNewline + lineLength < str.length() || yesNo != std::string::npos) { const size_t carrot = str.find('^', lastNewline); const size_t ampersand = str.find('&', lastNewline); const size_t lastSpace = str.rfind(' ', lastNewline + lineLength); - if (lineCount < 4){ - // replace '&' first if it's within the newline range - if (ampersand < lastNewline + lineLength) { - lastNewline = ampersand + 1; - // or move the lastNewline cursor to the next line if a '^' is encountered - } else if (carrot < lastNewline + lineLength) { - lastNewline = carrot + 1; - lineCount = 0; - // some lines need to be split but don't have spaces, look for periods instead - } else if (lastSpace == std::string::npos) { - const size_t lastPeriod = str.rfind('.', lastNewline + lineLength); - str.replace(lastPeriod, 1, ".&"); - lastNewline = lastPeriod + 2; - } else { - str.replace(lastSpace, 1, "&"); - lastNewline = lastSpace + 1; - } - lineCount += 1; - } else { - const size_t lastColor = str.rfind("\x05"s, lastNewline + lineLength); - std::string colorText = ""; - //check if we are on a non default colour, as ^ resets it, and readd if needed - if (lastColor != std::string::npos && str[lastColor+1] != 0){ - colorText = "\x05"s + str[lastColor+1]; - } - // replace '&' first if it's within the newline range - if (ampersand < lastNewline + lineLength) { - str.replace(ampersand, 1, "^" + colorText); - lastNewline = ampersand + 1; - // or move the lastNewline cursor to the next line if a '^' is encountered. - } else if (carrot < lastNewline + lineLength) { - lastNewline = carrot + 1; - // some lines need to be split but don't have spaces, look for periods instead - } else if (lastSpace == std::string::npos) { - const size_t lastPeriod = str.rfind('.', lastNewline + lineLength); - str.replace(lastPeriod, 1, ".^" + colorText); - lastNewline = lastPeriod + 2; - } else { - str.replace(lastSpace, 1, "^" + colorText); - lastNewline = lastSpace + 1; - } - lineCount = 1; + size_t waitForInput = str.find(WAIT_FOR_INPUT()[0], lastNewline); + size_t newLine = str.find(NEWLINE()[0], lastNewline); + if (carrot < waitForInput){ + waitForInput = carrot; } - lineLength = NextLineLength(&str, lastNewline, hasIcon); + if (ampersand < newLine){ + newLine = ampersand; + } + if (lineCount != 3 && yesNo < lastNewline + lineLength && yesNo < waitForInput && yesNo < newLine){ + if (lineCount >= 4){ + str.replace(yesNo, 1, "^&&\x1B"); + lineCount = 3; + lastNewline = yesNo + 3; + } else { + while(lineCount < 3){ + str.replace(yesNo, 1, "&\x1B"); + yesNo++; + lineCount++; + } + lastNewline = yesNo; + } + } else { + if (lineCount < 4){ + // replace '&' first if it's within the newline range + if (newLine < lastNewline + lineLength) { + lastNewline = newLine + 1; + // or move the lastNewline cursor to the next line if a '^' is encountered + } else if (waitForInput < lastNewline + lineLength) { + lastNewline = waitForInput + 1; + lineCount = 0; + // some lines need to be split but don't have spaces, look for periods instead + } else if (lastSpace == std::string::npos) { + const size_t lastPeriod = str.rfind('.', lastNewline + lineLength); + str.replace(lastPeriod, 1, ".&"); + lastNewline = lastPeriod + 2; + } else { + str.replace(lastSpace, 1, "&"); + lastNewline = lastSpace + 1; + } + lineCount += 1; + } else { + const size_t lastColor = str.rfind("\x05"s, lastNewline + lineLength); + std::string colorText = ""; + //check if we are on a non default colour, as ^ resets it, and readd if needed + if (lastColor != std::string::npos && str[lastColor+1] != 0){ + colorText = "\x05"s + str[lastColor+1]; + } + // replace '&' first if it's within the newline range + if (ampersand < lastNewline + lineLength) { + str.replace(ampersand, 1, "^" + colorText); + lastNewline = ampersand + 1; + // or move the lastNewline cursor to the next line if a '^' is encountered. + } else if (carrot < lastNewline + lineLength) { + lastNewline = carrot + 1; + // some lines need to be split but don't have spaces, look for periods instead + } else if (lastSpace == std::string::npos) { + const size_t lastPeriod = str.rfind('.', lastNewline + lineLength); + str.replace(lastPeriod, 1, ".^" + colorText); + lastNewline = lastPeriod + 2; + } else { + str.replace(lastSpace, 1, "^" + colorText); + lastNewline = lastSpace + 1; + } + lineCount = 1; + } + lineLength = NextLineLength(&str, lastNewline, hasIcon); + } + yesNo = str.find("\x1B"s[0], lastNewline); } ReplaceSpecialCharacters(str); ReplaceAltarIcons(str); std::replace(str.begin(), str.end(), '&', NEWLINE()[0]); std::replace(str.begin(), str.end(), '^', WAIT_FOR_INPUT()[0]); std::replace(str.begin(), str.end(), '@', PLAYER_NAME()[0]); + std::replace(str.begin(), str.end(), '_', " "[0]); str += MESSAGE_END(); } @@ -572,11 +598,10 @@ bool CustomMessageManager::CreateGetItemMessage(std::string tableID, uint16_t gi } bool CustomMessageManager::CreateMessage(std::string tableID, uint16_t textID, CustomMessage messageEntry) { - messageEntry.Format(); return InsertCustomMessage(tableID, textID, messageEntry); } -CustomMessage CustomMessageManager::RetrieveMessage(std::string tableID, uint16_t textID) { +CustomMessage CustomMessageManager::RetrieveMessage(std::string tableID, uint16_t textID, MessageFormat format) { std::unordered_map::const_iterator foundMessageTable = messageTables.find(tableID); if (foundMessageTable == messageTables.end()) { throw(MessageNotFoundException(tableID, textID)); @@ -587,6 +612,15 @@ CustomMessage CustomMessageManager::RetrieveMessage(std::string tableID, uint16_ throw(MessageNotFoundException(tableID, textID)); } CustomMessage message = foundMessage->second; + + if (format == MF_FORMATTED){ + message.Format(); + } else if (format == MF_AUTO_FORMAT){ + message.AutoFormat(); + } else if (format == MF_CLEAN){ + message.Clean(); + } + return message; } diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.h b/soh/soh/Enhancements/custom-message/CustomMessageManager.h index 2c797e527..31455aa40 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageManager.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.h @@ -242,9 +242,10 @@ class CustomMessageManager { * * @param tableID the ID of the custom message table * @param textID the ID of the message you want to retrieve + * @param format the type of formatting to apply to the retrieved message * @return CustomMessage */ - CustomMessage RetrieveMessage(std::string tableID, uint16_t textID); + CustomMessage RetrieveMessage(std::string tableID, uint16_t textID, MessageFormat format = MF_RAW); /** * @brief Empties out the message table identified by tableID. diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index fa8a4bb8a..4a039987e 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -1,6 +1,10 @@ #pragma once +#include "z64.h" +#include "../include/macros.h" + typedef enum { + TEXT_NONE = 0x000, TEXT_SKULLTULA_PEOPLE_CURSE_BROKEN = 0x0021, TEXT_SKULLTULA_PEOPLE_IM_CURSED = 0x0022, TEXT_SKULLTULA_PEOPLE_WELL_BE_CAREFUL = 0x0023, @@ -182,9 +186,12 @@ typedef enum { TEXT_SCRUB_RANDOM = 0x9000, TEXT_SCRUB_RANDOM_FREE = 0x9001, TEXT_SHOP_ITEM_RANDOM = 0x9100, - TEXT_SHOP_ITEM_RANDOM_CONFIRM = 0x9101, + TEXT_SHOP_ITEM_RANDOM_CONFIRM = 0x9100 + NUM_SHOP_ITEMS, + TEXT_SHOP_ITEM_RANDOM_CONFIRM_END = 0x9100 + (NUM_SHOP_ITEMS * 2) - 1, TEXT_WARP_RANDOM_REPLACED_TEXT = 0x9200, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW = 0x9210, + TEXT_CARPET_SALESMAN_MYSTERIOUS = 0x9211, + TEXT_CARPET_SALESMAN_ARMS_DEALER = 0x9212, } TextIDs; #ifdef __cplusplus diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 46f142054..930515ab6 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -1320,16 +1320,7 @@ void DrawEquipmentTab() { "Giant (500)", }; // only display Tycoon wallet if you're in a save file that would allow it. - if ( - IS_RANDO && - !( - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY) == RO_SHOPSANITY_OFF || - ( - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY) == RO_SHOPSANITY_SPECIFIC_COUNT && - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY_COUNT) == RO_SHOPSANITY_COUNT_ZERO_ITEMS - ) - ) - ) { + if (IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_INCLUDE_TYCOON_WALLET)) { const std::string walletName = "Tycoon (999)"; walletNamesImpl.push_back(walletName); } diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index 1a86987f8..57fc9cf35 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -184,6 +184,8 @@ typedef enum { // Opt: *EnMk // Vanilla condition: Flags_GetItemGetInf(ITEMGETINF_30) VB_OFFER_BLUE_POTION, + VB_GRANNY_SAY_INSUFFICIENT_RUPEES, + VB_GRANNY_TAKE_MONEY, // Vanilla condition: Inventory_HasEmptyBottle() == 0 VB_NEED_BOTTLE_FOR_GRANNYS_ITEM, // Opt: *EnNiwLady @@ -369,9 +371,11 @@ typedef enum { // Opt: *EnGo2 VB_GIVE_ITEM_FROM_GORON, // Opt: *EnJs + VB_CHECK_RANDO_PRICE_OF_CARPET_SALESMAN, VB_GIVE_ITEM_FROM_CARPET_SALESMAN, VB_GIVE_BOMBCHUS_FROM_CARPET_SALESMAN, // Opt: *EnGm + VB_CHECK_RANDO_PRICE_OF_MEDIGORON, VB_GIVE_ITEM_FROM_MEDIGORON, // Opt: *EnMs VB_GIVE_ITEM_FROM_MAGIC_BEAN_SALESMAN, diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 53f41daad..b05af71d5 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -437,10 +437,18 @@ const std::vector randomizerCvars = { CVAR_RANDOMIZER_SETTING("RewardCount"), CVAR_RANDOMIZER_SETTING("ScrubText"), CVAR_RANDOMIZER_SETTING("Shopsanity"), + CVAR_RANDOMIZER_SETTING("ShopsanityCount"), CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), + CVAR_RANDOMIZER_SETTING("ShopsanityFixedPrice"), + CVAR_RANDOMIZER_SETTING("ShopsanityPriceRange1"), + CVAR_RANDOMIZER_SETTING("ShopsanityPriceRange2"), + CVAR_RANDOMIZER_SETTING("ShopsanityNoWalletWeight"), + CVAR_RANDOMIZER_SETTING("ShopsanityChildWalletWeight"), + CVAR_RANDOMIZER_SETTING("ShopsanityAdultWalletWeight"), + CVAR_RANDOMIZER_SETTING("ShopsanityGiantWalletWeight"), + CVAR_RANDOMIZER_SETTING("ShopsanityTycoonWalletWeight"), CVAR_RANDOMIZER_SETTING("ShopsanityPricesAffordable"), CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), - CVAR_RANDOMIZER_SETTING("ShuffleBeans"), CVAR_RANDOMIZER_SETTING("ShuffleBossEntrances"), CVAR_RANDOMIZER_SETTING("ShuffleCows"), CVAR_RANDOMIZER_SETTING("ShuffleDungeonReward"), @@ -464,11 +472,29 @@ const std::vector randomizerCvars = { CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsWaterTemple"), CVAR_RANDOMIZER_SETTING("ShuffleKokiriSword"), CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), + CVAR_RANDOMIZER_SETTING("MerchantFixedPrice"), + CVAR_RANDOMIZER_SETTING("MerchantPriceRange1"), + CVAR_RANDOMIZER_SETTING("MerchantPriceRange2"), + CVAR_RANDOMIZER_SETTING("MerchantNoWalletWeight"), + CVAR_RANDOMIZER_SETTING("MerchantChildWalletWeight"), + CVAR_RANDOMIZER_SETTING("MerchantAdultWalletWeight"), + CVAR_RANDOMIZER_SETTING("MerchantGiantWalletWeight"), + CVAR_RANDOMIZER_SETTING("MerchantTycoonWalletWeight"), + CVAR_RANDOMIZER_SETTING("MerchantPricesAffordable"), CVAR_RANDOMIZER_SETTING("ShuffleOcarinas"), CVAR_RANDOMIZER_SETTING("ShuffleOverworldEntrances"), CVAR_RANDOMIZER_SETTING("ShuffleOverworldSpawns"), CVAR_RANDOMIZER_SETTING("ShuffleOwlDrops"), CVAR_RANDOMIZER_SETTING("ShuffleScrubs"), + CVAR_RANDOMIZER_SETTING("ScrubsFixedPrice"), + CVAR_RANDOMIZER_SETTING("ScrubsPriceRange1"), + CVAR_RANDOMIZER_SETTING("ScrubsPriceRange2"), + CVAR_RANDOMIZER_SETTING("ScrubsNoWalletWeight"), + CVAR_RANDOMIZER_SETTING("ScrubsChildWalletWeight"), + CVAR_RANDOMIZER_SETTING("ScrubsAdultWalletWeight"), + CVAR_RANDOMIZER_SETTING("ScrubstGiantWalletWeight"), + CVAR_RANDOMIZER_SETTING("ScrubsTycoonWalletWeight"), + CVAR_RANDOMIZER_SETTING("ScrubsPricesAffordable"), CVAR_RANDOMIZER_SETTING("ShuffleSongs"), CVAR_RANDOMIZER_SETTING("ShuffleTokens"), CVAR_RANDOMIZER_SETTING("ShuffleWarpSongs"), @@ -955,12 +981,16 @@ const std::vector spockRacePresetEntries = { PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("LacsRewardCount"), 5), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("RainbowBridge"), RO_BRIDGE_GREG), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ScrubText"), 1), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("IncludeTycoonWallet"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("Shopsanity"), RO_SHOPSANITY_RANDOM), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), RO_PRICE_BALANCED), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), RO_GANON_BOSS_KEY_LACS_REWARDS), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleKeyRings"), RO_KEYRINGS_COUNT), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleKokiriSword"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleOcarinas"), 1), - PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleScrubs"), RO_SCRUBS_AFFORDABLE), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleScrubs"), RO_SCRUBS_ALL), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ScrubsPrice"), RO_PRICE_FIXED), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ScrubsFixedPrice"), 10), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipChildStealth"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipChildZelda"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("SkipEponaRace"), 1), @@ -1037,9 +1067,12 @@ const std::vector spockRaceNoLogicPresetEntries = { PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_NO_LOGIC), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("RainbowBridge"), RO_BRIDGE_GREG), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ScrubText"), 1), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("IncludeTycoonWallet"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("Shopsanity"), RO_SHOPSANITY_RANDOM), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), RO_PRICE_BALANCED), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), 0), - PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleBeans"), 1), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), RO_SHUFFLE_MERCHANTS_BEANS_ONLY), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleMerchantPrices"), RO_PRICE_VANILLA), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), RO_GANON_BOSS_KEY_LACS_REWARDS), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleKeyRings"), RO_KEYRINGS_COUNT), @@ -1121,11 +1154,15 @@ const std::vector hellModePresetEntries = { PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("LinksPocket"), RO_LINKS_POCKET_NOTHING), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("MQDungeons"), RO_MQ_DUNGEONS_RANDOM_NUMBER), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("RainbowBridge"), RO_BRIDGE_DUNGEON_REWARDS), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("IncludeTycoonWallet"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("Shopsanity"), RO_SHOPSANITY_SPECIFIC_COUNT), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShopsanityCount"), RO_SHOPSANITY_COUNT_FOUR_ITEMS), - PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), RO_SHOPSANITY_PRICE_TYCOON), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), RO_PRICE_RANGE), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShopsanityPriceRange1"), 0), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShopsanityPriceRange2"), 999), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), 1), - PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleBeans"), 1), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), RO_SHUFFLE_MERCHANTS_BEANS_ONLY), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleMerchantPrices"), RO_PRICE_VANILLA), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleCows"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleDungeonReward"), RO_DUNGEON_REWARDS_ANYWHERE), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleFrogSongRupees"), 1), @@ -1135,7 +1172,8 @@ const std::vector hellModePresetEntries = { PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleKokiriSword"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleMasterSword"), 1), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleOcarinas"), 1), - PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleScrubs"), RO_SCRUBS_RANDOM), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleScrubs"), RO_SCRUBS_ALL), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ScrubsPrice"), RO_PRICE_CHEAP_BALANCED), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleSongs"), RO_SONG_SHUFFLE_ANYWHERE), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleTokens"), RO_TOKENSANITY_ALL), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), 1), @@ -1178,7 +1216,8 @@ const std::vector BenchmarkPresetEntries = { PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleDungeonReward"), RO_DUNGEON_REWARDS_END_OF_DUNGEON), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("LinksPocket"), RO_LINKS_POCKET_DUNGEON_REWARD), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleSongs"), RO_SONG_SHUFFLE_ANYWHERE), - PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("Shopsanity"), RO_SHOPSANITY_COUNT_FOUR_ITEMS), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("Shopsanity"), RO_SHOPSANITY_SPECIFIC_COUNT), + PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShopsanityCount"), RO_SHOPSANITY_COUNT_FOUR_ITEMS), //RANDOTODO add refactored price/scrub/merchant settings PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleTokens"), RO_TOKENSANITY_OFF), PRESET_ENTRY_S32(CVAR_RANDOMIZER_SETTING("ShuffleBeehives"), RO_GENERIC_ON), diff --git a/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp b/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp index c00ec8840..64b75b670 100644 --- a/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp @@ -1,5 +1,5 @@ #include "custom_messages.hpp" -#include "shops.hpp" +#include "../../custom-message/CustomMessageManager.h" #include "z64item.h" #include diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index c15e2e742..4d055f1b1 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -24,6 +24,40 @@ using namespace Rando; static bool placementFailure = false; + +PriceSettingsStruct shopsanityPrices = {RSK_SHOPSANITY_PRICES, + RSK_SHOPSANITY_PRICES_FIXED_PRICE, + RSK_SHOPSANITY_PRICES_RANGE_1, + RSK_SHOPSANITY_PRICES_RANGE_2, + RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT, + RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT, + RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT, + RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT, + RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT, + RSK_SHOPSANITY_PRICES_AFFORDABLE}; + +PriceSettingsStruct scrubPrices = {RSK_SCRUBS_PRICES, + RSK_SCRUBS_PRICES_FIXED_PRICE, + RSK_SCRUBS_PRICES_RANGE_1, + RSK_SCRUBS_PRICES_RANGE_2, + RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT, + RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT, + RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT, + RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT, + RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT, + RSK_SCRUBS_PRICES_AFFORDABLE}; + +PriceSettingsStruct merchantPrices = {RSK_MERCHANT_PRICES, + RSK_MERCHANT_PRICES_FIXED_PRICE, + RSK_MERCHANT_PRICES_RANGE_1, + RSK_MERCHANT_PRICES_RANGE_2, + RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT, + RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT, + RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT, + RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT, + RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT, + RSK_MERCHANT_PRICES_AFFORDABLE}; + static void RemoveStartingItemsFromPool() { for (RandomizerGet startingItem : StartingInventory) { for (size_t i = 0; i < ItemPool.size(); i++) { @@ -1133,7 +1167,6 @@ int Fill() { //Place shop items first, since a buy shield is needed to place a dungeon reward on Gohma due to access StartPerformanceTimer(PT_SHOPSANITY); - NonShopItems.clear(); if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_OFF)) { SPDLOG_INFO("Placing Vanilla Shop Items..."); PlaceVanillaShopItems(); //Place vanilla shop items in vanilla location @@ -1154,17 +1187,10 @@ int Fill() { total_replaced += num_to_replace; for (int j = 0; j < num_to_replace; j++) { int itemindex = indices[j]; - int shopsanityPrice = GetRandomShopPrice(); - NonShopItems[Rando::StaticData::GetShopLocations()[i * LOCATIONS_PER_SHOP + itemindex - 1]].Price = shopsanityPrice; // Set price to be retrieved by the patch and textboxes - ctx->GetItemLocation(Rando::StaticData::GetShopLocations()[i * LOCATIONS_PER_SHOP + itemindex - 1])->SetCustomPrice(shopsanityPrice); - } - for (int j = num_to_replace; j < 8; j++) { - ItemAndPrice init; - init.Name = Text { "No Item", "Sin objeto", "Pas d'objet" }; - init.Price = -1; - init.Repurchaseable = false; - int itemindex = indices[j]; - NonShopItems[Rando::StaticData::GetShopLocations()[i * LOCATIONS_PER_SHOP + itemindex - 1]] = init; // Set price to be retrieved by the patch and textboxes + RandomizerCheck rc = Rando::StaticData::GetShopLocations()[i * LOCATIONS_PER_SHOP + itemindex - 1]; + Rando::ItemLocation* itemLoc = ctx->GetItemLocation(rc); + uint16_t shopsanityPrice = GetRandomPrice(Rando::StaticData::GetLocation(rc), shopsanityPrices); + itemLoc->SetCustomPrice(shopsanityPrice); } } #undef LOCATIONS_PER_SHOP @@ -1183,6 +1209,51 @@ int Fill() { //Place the shop items which will still be at shop locations AssumedFill(shopItems, shopLocations); } + + //Add prices to scrubs + auto scrubLoc = Rando::StaticData::GetScrubLocations(); + if (ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_ALL)) { + for (size_t i = 0; i < scrubLoc.size(); i++) { + ctx->GetItemLocation(scrubLoc[i])->SetCustomPrice( + GetRandomPrice(Rando::StaticData::GetLocation(scrubLoc[i]), scrubPrices) + ); + } + } else { + for (size_t i = 0; i < scrubLoc.size(); i++) { + ctx->GetItemLocation(scrubLoc[i])->SetCustomPrice( + Rando::StaticData::GetLocation(scrubLoc[i])->GetVanillaPrice() + ); + } + } + + //set merchant prices + if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_BEANS_ONLY) || + ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL)){ + ctx->GetItemLocation(RC_ZR_MAGIC_BEAN_SALESMAN)->SetCustomPrice( + GetRandomPrice(Rando::StaticData::GetLocation(RC_ZR_MAGIC_BEAN_SALESMAN), merchantPrices) + ); + } else { + ctx->GetItemLocation(RC_ZR_MAGIC_BEAN_SALESMAN)->SetCustomPrice( + Rando::StaticData::GetLocation(RC_ZR_MAGIC_BEAN_SALESMAN)->GetVanillaPrice() + ); + } + + auto merchantLoc = Rando::StaticData::GetMerchantLocations(); + + if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS) || + ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL)){ + for (size_t i = 0; i < merchantLoc.size(); i++) { + ctx->GetItemLocation(merchantLoc[i])->SetCustomPrice( + GetRandomPrice(Rando::StaticData::GetLocation(merchantLoc[i]), merchantPrices) + ); + } + } else { + for (size_t i = 0; i < merchantLoc.size(); i++) { + ctx->GetItemLocation(merchantLoc[i])->SetCustomPrice( + Rando::StaticData::GetLocation(merchantLoc[i])->GetVanillaPrice() + ); + } + } StopPerformanceTimer(PT_SHOPSANITY); StartPerformanceTimer(PT_OWN_DUNGEON); @@ -1245,28 +1316,6 @@ int Fill() { FastFill(remainingPool, GetAllEmptyLocations(), false); StopPerformanceTimer(PT_REMAINING_ITEMS); - //Add default prices to scrubs - for (RandomizerCheck& randomizerCheck : Rando::StaticData::GetScrubLocations()) { - if (randomizerCheck == RC_LW_DEKU_SCRUB_NEAR_BRIDGE || randomizerCheck == RC_LW_DEKU_SCRUB_GROTTO_FRONT) { - ctx->GetItemLocation(randomizerCheck)->SetCustomPrice(40); - } else if (randomizerCheck == RC_HF_DEKU_SCRUB_GROTTO) { - ctx->GetItemLocation(randomizerCheck)->SetCustomPrice(10); - } else { - auto loc = Rando::StaticData::GetLocation(randomizerCheck); - auto item = Rando::StaticData::RetrieveItem(loc->GetVanillaItem()); - ctx->GetItemLocation(randomizerCheck)->SetCustomPrice(item.GetPrice()); - } - } - - if (ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_AFFORDABLE)) { - for (RandomizerCheck& randomizerCheck : Rando::StaticData::GetScrubLocations()) { - ctx->GetItemLocation(randomizerCheck)->SetCustomPrice(10); - } - } else if (ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_RANDOM)) { - for (RandomizerCheck& randomizerCheck : Rando::StaticData::GetScrubLocations()) { - ctx->GetItemLocation(randomizerCheck)->SetCustomPrice(GetRandomScrubPrice()); - } - } StartPerformanceTimer(PT_PLAYTHROUGH_GENERATION); GeneratePlaythrough(); diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp index 4d32d3c00..db934b846 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp @@ -2769,49 +2769,6 @@ void StaticData::HintTable_Init() { | STATIC LOCATION HINTS | ---------------------------*/ - hintTextTable[RHT_MEDIGORON_HINT] = HintText(CustomMessage("How about buying #[[1]]# for #200 Rupees#?&" + TWO_WAY_CHOICE() + "#Buy&Don't buy#", - /*german*/ "Möchtest Du #[[1]]# für #200 Rubine# kaufen?&" + TWO_WAY_CHOICE() + "#Klar!&Nie im Leben!#", - /*french*/ "Veux-tu acheter #[[1]]# pour #200 rubis#?&" + TWO_WAY_CHOICE() + "#Acheter&Ne pas acheter#", - {QM_GREEN, QM_YELLOW, QM_GREEN})); - /*spanish*/ // ¿Me compras #[[1]]# por #200 rupias#?&" + TWO_WAY_CHOICE() + "#Comprar&No comprar# - - hintTextTable[RHT_CARPET_SALESMAN_DIALOG_FIRST] = HintText(CustomMessage("Welcome!^I am selling stuff, strange and rare, from all over the world to everybody. Today's special is...^", - /*german*/ "Sei gegrüßt!^Ich verkaufe allerlei Kuriositäten. Stets sonderliche und seltene Ware aus " - "aller Welt für jedermann. Das heutige Angebot bleibt...^#", - /*french*/ "Bienvenue!^Je vends des objets rares et merveilleux du monde entier. En spécial aujourd'hui...^")); - /*spanish*/ // ¡Acércate!^Vendo productos extraños y difíciles de encontrar... De todo el mundo a todo el mundo. La oferta de hoy es...^#¡ - - hintTextTable[RHT_CARPET_SALESMAN_DIALOG_MYSTERIOUS] = HintText(CustomMessage("Terrifying! I won't tell you what it is until I see the #money#...^How about #200 Rupees#?&&" + - TWO_WAY_CHOICE() + "#Buy&Don't buy#", - /*german*/ "Furchterregend, oder? Ich erzähle Euch mehr, wenn ich #Geld# sehe...^Wie wär's mit #200 Rubinen#?&&" + - TWO_WAY_CHOICE() + "#Aber sicher!&Ich bin weg!#", - /*french*/ "Un concentré de puissance! Mais montre tes #rubis# avant que je te dise ce que c'est...^Disons #200 " - "rubis#?&&" + TWO_WAY_CHOICE() + "#Acheter&Ne pas acheter#", - {QM_RED, QM_YELLOW, QM_GREEN})); - /*spanish*/ // ¡Terrorífico! No te revelaré su nombre hasta que vea el #dinero#...^#200 rupias#, ¿qué te parece?&&" + - // TWO_WAY_CHOICE() + "#Comprar&No comprar# - - hintTextTable[RHT_CARPET_SALESMAN_DIALOG_HINTED] = HintText(CustomMessage("#[[1]]!# It's real, I promise! A lonely man such as myself wouldn't #lie# to you, hmm?^" - "How about #200 Rupees#?&&" + TWO_WAY_CHOICE() + "#Buy&Don't buy#", - /*german*/ "#[[1]]#! Ich kann versichern, es ist ein aufrichtiges Angebot!^Ein einsamer Mann wie ich würde Dich doch " - "nicht #anlügen#, oder?^Wie wär's mit #200 Rubinen#?&&" + TWO_WAY_CHOICE() + "#Aber sicher!&Ich bin weg!#", - /*french*/ "#[[1]]!# C'est vrai! J'te jure! Un gars comme moi ne te #mentirai# pas tu ne crois pas?^Disons #200 " - "rubis#?&&" + TWO_WAY_CHOICE() + "#Acheter&Ne pas acheter#", - {QM_GREEN, QM_YELLOW, QM_GREEN})); - - hintTextTable[RHT_BEAN_SALESMAN_HINT] = HintText(CustomMessage("I tried to be a #magic bean# salesman, but it turns out my marketing skills weren't worth " - "beans!^Anyway, want to buy #[[1]]# for #60 Rupees#?&" + TWO_WAY_CHOICE() + "#Yes&No#", - /*german*/ "Möchten Sie #[[1]]# für #60 Rubine# kaufen?&" + TWO_WAY_CHOICE() + "#Ja&Nein#", - /*french*/ "J'ai essayé d'être un vendeur de #haricots magiques#, mais j'étais mauvais au niveau du marketing et ça " - "me courait sur le haricot...^Enfin bref, ça te dirait de m'acheter #[[1]]# pour #60 Rubis#?&" + TWO_WAY_CHOICE() + "#Oui&Non#", - {QM_RED, QM_GREEN, QM_YELLOW, QM_GREEN})); - - hintTextTable[RHT_GRANNY_HINT] = HintText(CustomMessage("#[[1]]#! How about #100 Rupees#?&" + TWO_WAY_CHOICE() + "#Buy&Don't buy#", - /*german*/ "#[[1]]#! Sagen wir #100 Rubine#?&" + TWO_WAY_CHOICE() + "#Gerne!&Auf keinen Fall!#", - /*french*/ "#[[1]]#! Que dis-tu de #100 rubis#?&" + TWO_WAY_CHOICE() + "#Acheter&Ne pas acheter#", - {QM_GREEN, QM_YELLOW, QM_GREEN}, {true})); - // /*spanish*/#[[1]]#. Vendo por #100 rupias#.&" + TWO_WAY_CHOICE() + "#Comprar&No comprar# - hintTextTable[RHT_HBA_HINT_SIGN] = HintText(CustomMessage("#Horseback Archery# Range Prizes:&1000: #[[1]]#&1500: #[[2]]#^@'s Record: #" + CustomMessage::POINTS(HS_HORSE_ARCHERY) + "#", {QM_RED, QM_GREEN, QM_GREEN, QM_GREEN}, {}, TEXTBOX_TYPE_WOODEN)); diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp index f9aa2a280..60464746c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp @@ -2127,6 +2127,9 @@ void StaticData::HintTable_Init_Item() { hintTextTable[RHT_MYSTERIOUS_ITEM] = HintText(CustomMessage("mysterious item", /*german*/"mysteriöser Gegenstand", /*french*/"objet mystérieux")); // /*spanish*/algo misterioso + + hintTextTable[RHT_MYSTERIOUS_ITEM_CAPITAL] = HintText(CustomMessage("Mysterious Item", /*german*/"Mysteriöser Gegenstand", /*french*/"Objet Mystérieux")); + // /*spanish*/Algo Misterioso } } diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.cpp b/soh/soh/Enhancements/randomizer/3drando/hints.cpp index 9b4eeedf8..0e32813b0 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hints.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hints.cpp @@ -533,7 +533,7 @@ int32_t getRandomWeight(int32_t totalWeight){ static void DistributeHints(std::vector& selected, size_t stoneCount, std::vector distTable, uint8_t junkWieght, bool addFixed = true){ int32_t totalWeight = junkWieght; //Start with our Junk Weight, the natural chance of a junk hint - for (size_t c=0; c < distTable.size(); c++){ //Gather the wieghts of each distribution and, if it's the first pass, apply fixed hints + for (size_t c=0; c < distTable.size(); c++){ //Gather the weights of each distribution and, if it's the first pass, apply fixed hints totalWeight += distTable[c].weight; //Note that PlaceHints will set weights of distributions to zero if it can't place anything from them if (addFixed){ selected[c] += distTable[c].fixed; diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index a2878f78c..08a9a5179 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -358,7 +358,7 @@ const std::array shopsanityRupees = { RG_HUGE_RUPEE, RG_HUGE_RUPEE, RG_HUGE_RUPEE, - RG_PROGRESSIVE_WALLET, + RG_HUGE_RUPEE, }; const std::array dekuScrubItems = { RG_DEKU_NUTS_5, @@ -471,61 +471,67 @@ void PlaceJunkInExcludedLocation(const RandomizerCheck il) { SPDLOG_ERROR("ERROR: No Junk to Place!!!"); } -static void PlaceVanillaDekuScrubItems() { +static void PlaceVanillaDekuScrubItems(bool junkOneTimeScrubs) { auto ctx = Rando::Context::GetInstance(); + if (junkOneTimeScrubs){ + ctx->PlaceItemInLocation(RC_LW_DEKU_SCRUB_GROTTO_FRONT, RG_BLUE_RUPEE, false, true); + ctx->PlaceItemInLocation(RC_LW_DEKU_SCRUB_NEAR_BRIDGE, RG_BLUE_RUPEE, false, true); + ctx->PlaceItemInLocation(RC_HF_DEKU_SCRUB_GROTTO, RG_BLUE_RUPEE, false, true); + } + ctx->PlaceItemInLocation(RC_ZR_DEKU_SCRUB_GROTTO_REAR, RG_RED_POTION_REFILL, false, true); ctx->PlaceItemInLocation(RC_ZR_DEKU_SCRUB_GROTTO_FRONT, RG_GREEN_POTION_REFILL, false, true); ctx->PlaceItemInLocation(RC_SFM_DEKU_SCRUB_GROTTO_REAR, RG_RED_POTION_REFILL, false, true); ctx->PlaceItemInLocation(RC_SFM_DEKU_SCRUB_GROTTO_FRONT, RG_GREEN_POTION_REFILL, false, true); - ctx->PlaceItemInLocation(RC_LH_DEKU_SCRUB_GROTTO_LEFT, RG_DEKU_NUTS_5, false, true); - ctx->PlaceItemInLocation(RC_LH_DEKU_SCRUB_GROTTO_RIGHT, RG_BOMBS_5, false, true); - ctx->PlaceItemInLocation(RC_LH_DEKU_SCRUB_GROTTO_CENTER, RG_DEKU_SEEDS_30, false, true); + ctx->PlaceItemInLocation(RC_LH_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, false, true); + ctx->PlaceItemInLocation(RC_LH_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, false, true); + ctx->PlaceItemInLocation(RC_LH_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_DEKU_SEEDS_30, false, true); ctx->PlaceItemInLocation(RC_GV_DEKU_SCRUB_GROTTO_REAR, RG_RED_POTION_REFILL, false, true); ctx->PlaceItemInLocation(RC_GV_DEKU_SCRUB_GROTTO_FRONT, RG_GREEN_POTION_REFILL, false, true); - ctx->PlaceItemInLocation(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, RG_DEKU_NUTS_5, false, true); - ctx->PlaceItemInLocation(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, RG_DEKU_STICK_1, false, true); - ctx->PlaceItemInLocation(RC_LW_DEKU_SCRUB_GROTTO_REAR, RG_DEKU_SEEDS_30, false, true); + ctx->PlaceItemInLocation(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, RG_BUY_DEKU_NUTS_5, false, true); + ctx->PlaceItemInLocation(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, RG_BUY_DEKU_STICK_1, false, true); + ctx->PlaceItemInLocation(RC_LW_DEKU_SCRUB_GROTTO_REAR, RG_BUY_DEKU_SEEDS_30, false, true); ctx->PlaceItemInLocation(RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR, RG_RED_POTION_REFILL, false, true); ctx->PlaceItemInLocation(RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, RG_GREEN_POTION_REFILL, false, true); - ctx->PlaceItemInLocation(RC_DMC_DEKU_SCRUB, RG_BOMBS_5, false, true); - ctx->PlaceItemInLocation(RC_DMC_DEKU_SCRUB_GROTTO_LEFT, RG_DEKU_NUTS_5, false, true); - ctx->PlaceItemInLocation(RC_DMC_DEKU_SCRUB_GROTTO_RIGHT, RG_BOMBS_5, false, true); - ctx->PlaceItemInLocation(RC_DMC_DEKU_SCRUB_GROTTO_CENTER, RG_DEKU_SEEDS_30, false, true); - ctx->PlaceItemInLocation(RC_GC_DEKU_SCRUB_GROTTO_LEFT, RG_DEKU_NUTS_5, false, true); - ctx->PlaceItemInLocation(RC_GC_DEKU_SCRUB_GROTTO_RIGHT, RG_BOMBS_5, false, true); - ctx->PlaceItemInLocation(RC_GC_DEKU_SCRUB_GROTTO_CENTER, RG_DEKU_SEEDS_30, false, true); - ctx->PlaceItemInLocation(RC_LLR_DEKU_SCRUB_GROTTO_LEFT, RG_DEKU_NUTS_5, false, true); - ctx->PlaceItemInLocation(RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, RG_BOMBS_5, false, true); - ctx->PlaceItemInLocation(RC_LLR_DEKU_SCRUB_GROTTO_CENTER, RG_DEKU_SEEDS_30, false, true); + ctx->PlaceItemInLocation(RC_DMC_DEKU_SCRUB, RG_BUY_BOMBS_535, false, true); + ctx->PlaceItemInLocation(RC_DMC_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, false, true); + ctx->PlaceItemInLocation(RC_DMC_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, false, true); + ctx->PlaceItemInLocation(RC_DMC_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_DEKU_SEEDS_30, false, true); + ctx->PlaceItemInLocation(RC_GC_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, false, true); + ctx->PlaceItemInLocation(RC_GC_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, false, true); + ctx->PlaceItemInLocation(RC_GC_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_DEKU_SEEDS_30, false, true); + ctx->PlaceItemInLocation(RC_LLR_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, false, true); + ctx->PlaceItemInLocation(RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, false, true); + ctx->PlaceItemInLocation(RC_LLR_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_DEKU_SEEDS_30, false, true); //Dungeon Scrubs if (ctx->GetDungeon(Rando::DEKU_TREE)->IsMQ()) { - ctx->PlaceItemInLocation(RC_DEKU_TREE_MQ_DEKU_SCRUB, RG_DEKU_SHIELD, false, true); + ctx->PlaceItemInLocation(RC_DEKU_TREE_MQ_DEKU_SCRUB, RG_BUY_DEKU_SHIELD, false, true); } if (ctx->GetDungeon(Rando::DODONGOS_CAVERN)->IsMQ()) { - ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, RG_DEKU_STICK_1, false, true); - ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, RG_DEKU_SEEDS_30, false, true); - ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, RG_DEKU_SHIELD, false, true); + ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, RG_BUY_DEKU_STICK_1, false, true); + ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, RG_BUY_DEKU_SEEDS_30, false, true); + ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, RG_BUY_DEKU_SHIELD, false, true); ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, RG_RED_POTION_REFILL, false, true); } else { - ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, RG_DEKU_NUTS_5, false, true); - ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, RG_DEKU_STICK_1, false, true); - ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, RG_DEKU_SEEDS_30, false, true); - ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, RG_DEKU_SHIELD, false, true); + ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, RG_BUY_DEKU_NUTS_5, false, true); + ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, RG_BUY_DEKU_STICK_1, false, true); + ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, RG_BUY_DEKU_SEEDS_30, false, true); + ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, RG_BUY_DEKU_SHIELD, false, true); } if (ctx->GetDungeon(Rando::JABU_JABUS_BELLY)->IsVanilla()) { - ctx->PlaceItemInLocation(RC_JABU_JABUS_BELLY_DEKU_SCRUB, RG_DEKU_NUTS_5, false, true); + ctx->PlaceItemInLocation(RC_JABU_JABUS_BELLY_DEKU_SCRUB, RG_BUY_DEKU_NUTS_5, false, true); } if (ctx->GetDungeon(Rando::GANONS_CASTLE)->IsMQ()) { ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, RG_GREEN_POTION_REFILL, false, true); - ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, RG_BOMBS_5, false, true); - ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, RG_ARROWS_30, false, true); + ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, RG_BUY_BOMBS_535, false, true); + ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, RG_BUY_ARROWS_30, false, true); ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, RG_RED_POTION_REFILL, false, true); - ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, RG_DEKU_NUTS_5, false, true); + ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, RG_BUY_DEKU_NUTS_5, false, true); } else { - ctx->PlaceItemInLocation(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, RG_BOMBS_5, false, true); - ctx->PlaceItemInLocation(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, RG_DEKU_SEEDS_30, false, true); + ctx->PlaceItemInLocation(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, RG_BUY_BOMBS_535, false, true); + ctx->PlaceItemInLocation(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, RG_BUY_DEKU_SEEDS_30, false, true); ctx->PlaceItemInLocation(RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT, RG_RED_POTION_REFILL, false, true); ctx->PlaceItemInLocation(RC_GANONS_CASTLE_DEKU_SCRUB_LEFT, RG_GREEN_POTION_REFILL, false, true); } @@ -653,6 +659,7 @@ static void SetMinimalItemPool() { } void GenerateItemPool() { + //RANDOTODO proper removal of items not in pool or logically relevant instead of dummy checks. auto ctx = Rando::Context::GetInstance(); ItemPool.clear(); PendingJunkPool.clear(); @@ -860,7 +867,8 @@ void GenerateItemPool() { AddItemToMainPool(RG_PROGRESSIVE_WALLET); } - if (ctx->GetOption(RSK_SHUFFLE_MAGIC_BEANS)) { + if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_BEANS_ONLY) || + ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL)) { AddItemToMainPool(RG_MAGIC_BEAN_PACK); if (ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) { AddItemToPool(PendingJunkPool, RG_MAGIC_BEAN_PACK); @@ -870,7 +878,8 @@ void GenerateItemPool() { ctx->PlaceItemInLocation(RC_ZR_MAGIC_BEAN_SALESMAN, RG_MAGIC_BEAN, false, true); } - if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).IsNot(RO_SHUFFLE_MERCHANTS_OFF)) { + if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS) || + ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL)) { if (/*!ProgressiveGoronSword TODO: Implement Progressive Goron Sword*/true) { AddItemToMainPool(RG_GIANTS_KNIFE); } @@ -986,6 +995,10 @@ void GenerateItemPool() { AddItemToMainPool(RG_PROGRESSIVE_WALLET); } + if (ctx->GetOption(RSK_INCLUDE_TYCOON_WALLET)) { + AddItemToMainPool(RG_PROGRESSIVE_WALLET); + } + if (ctx->GetOption(RSK_SHUFFLE_DEKU_STICK_BAG)) { AddItemToMainPool(RG_PROGRESSIVE_STICK_UPGRADE); } @@ -1162,7 +1175,7 @@ void GenerateItemPool() { } //Scrubsanity - if (ctx->GetOption(RSK_SHUFFLE_SCRUBS).IsNot(RO_SCRUBS_OFF)) { + if (ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_ALL)) { //Deku Tree if (ctx->GetDungeon(Rando::DEKU_TREE)->IsMQ()) { AddItemToMainPool(RG_DEKU_SHIELD); @@ -1202,7 +1215,7 @@ void GenerateItemPool() { } } } else { - PlaceVanillaDekuScrubItems(); + PlaceVanillaDekuScrubItems(ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_OFF)); } AddItemsToPool(ItemPool, alwaysItems); @@ -1269,7 +1282,9 @@ void GenerateItemPool() { Rando::StaticData::RetrieveItem(RandomElement(bottles)).GetRandomizerGet()); // Get one random bottle type for ice traps for (uint8_t i = 0; i < bottleCount; i++) { if (i >= rutoBottles) { - if ((i == bottleCount - 1) && ctx->GetOption(RSK_SHUFFLE_MERCHANTS).IsNot(RO_SHUFFLE_MERCHANTS_OFF)) { + if ((i == bottleCount - 1) && + (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_BEANS_ONLY) || + ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL))) { AddItemToMainPool(RG_BOTTLE_WITH_BLUE_POTION); } else { AddRandomBottle(bottles); diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp index ca6f0c066..64c3e9287 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp @@ -46,33 +46,22 @@ bool LocationAccess::ConditionsMet() const { } bool LocationAccess::CanBuy() const { - auto ctx = Rando::Context::GetInstance(); - //Not a shop or scrub location, don't need to check if buyable - if (Rando::StaticData::GetLocation(location)->GetRCType() != RCTYPE_SHOP && Rando::StaticData::GetLocation(location)->GetRCType() != RCTYPE_SCRUB) { - return true; - } + return CanBuyAnother(location); +} - //Check if wallet is large enough to buy item - bool SufficientWallet = true; - if (ctx->GetItemLocation(location)->GetPrice() > 500) { - SufficientWallet = logic->HasItem(RG_TYCOON_WALLET); - } else if (ctx->GetItemLocation(location)->GetPrice() > 200) { - SufficientWallet = logic->HasItem(RG_GIANT_WALLET); - } else if (ctx->GetItemLocation(location)->GetPrice() > 99) { - SufficientWallet = logic->HasItem(RG_ADULT_WALLET); - } else if (ctx->GetItemLocation(location)->GetPrice() > 0) { - SufficientWallet = logic->HasItem(RG_CHILD_WALLET); - } +bool CanBuyAnother(RandomizerCheck rc) { + uint16_t price = ctx->GetItemLocation(rc)->GetPrice(); - bool OtherCondition = true; - RandomizerGet placed = ctx->GetItemLocation(location)->GetPlacedRandomizerGet(); - //Need bottle to buy bottle items, only logically relevant bottle items included here - if (placed == RG_BUY_BLUE_FIRE || placed == RG_BUY_BOTTLE_BUG || placed == RG_BUY_FISH || - placed == RG_BUY_FAIRYS_SPIRIT) { - OtherCondition = logic->HasBottle(); + if (price > 500) { + return logic->HasItem(RG_TYCOON_WALLET); + } else if (price > 200) { + return logic->HasItem(RG_GIANT_WALLET); + } else if (price > 99) { + return logic->HasItem(RG_ADULT_WALLET); + } else if (price > 0) { + return logic->HasItem(RG_CHILD_WALLET); } - - return SufficientWallet && OtherCondition; + return true; } Region::Region() = default; diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.hpp b/soh/soh/Enhancements/randomizer/3drando/location_access.hpp index c4d1e9a74..f394c2de5 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access.hpp @@ -128,6 +128,8 @@ protected: bool CanBuy() const; }; +bool CanBuyAnother(RandomizerCheck rc); + namespace Rando { class Entrance; enum class EntranceType; diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp index edd04bb45..5b50d13b4 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp @@ -97,7 +97,7 @@ void RegionTable_Init_DeathMountain() { LOCATION(RC_GC_ROLLING_GORON_AS_ADULT, logic->StopGCRollingGoronAsAdult), LOCATION(RC_GC_GS_BOULDER_MAZE, logic->IsChild && logic->BlastOrSmash()), LOCATION(RC_GC_GS_CENTER_PLATFORM, logic->IsAdult && logic->CanAttack()), - LOCATION(RC_GC_MEDIGORON, logic->IsAdult && logic->HasItem(RG_ADULT_WALLET) && (logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET))), + LOCATION(RC_GC_MEDIGORON, logic->IsAdult && (logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET))), LOCATION(RC_GC_MAZE_GOSSIP_STONE, logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)), LOCATION(RC_GC_MEDIGORON_GOSSIP_STONE, logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET)), }, { diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp index 7c31cbac3..7d40507a3 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp @@ -142,11 +142,11 @@ void RegionTable_Init_GerudoValley() { //Events EventAccess(&logic->FairyPot, {[]{return true;}}), EventAccess(&logic->NutPot, {[]{return true;}}), - EventAccess(&logic->CarpetMerchant, {[]{return logic->HasItem(RG_ADULT_WALLET) && (logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS));}}), + EventAccess(&logic->CarpetMerchant, {[]{return logic->HasItem(RG_ADULT_WALLET) && CanBuyAnother(RC_WASTELAND_BOMBCHU_SALESMAN) && (logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS));}}), }, { //Locations LOCATION(RC_WASTELAND_CHEST, logic->HasFireSource()), - LOCATION(RC_WASTELAND_BOMBCHU_SALESMAN, logic->CarpetMerchant), + LOCATION(RC_WASTELAND_BOMBCHU_SALESMAN, logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS)), LOCATION(RC_WASTELAND_GS, logic->HookshotOrBoomerang()), }, { //Exits diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp index 4670fafd1..96388d043 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp @@ -170,13 +170,14 @@ void RegionTable_Init_Kakariko() { areaTable[RR_KAK_ODD_POTION_BUILDING] = Region("Kak Granny's Potion Shop", "Kak Granny's Potion Shop", RA_NONE, NO_DAY_NIGHT_CYCLE, {}, + // RANDOTODO blue pot access { LOCATION(RC_KAK_TRADE_ODD_MUSHROOM, logic->IsAdult && logic->CanUse(RG_ODD_MUSHROOM)), - LOCATION(RC_KAK_GRANNYS_SHOP, logic->IsAdult && (logic->CanUse(RG_ODD_MUSHROOM) || logic->TradeQuestStep(RG_ODD_MUSHROOM)) && logic->HasItem(RG_ADULT_WALLET)), + LOCATION(RC_KAK_GRANNYS_SHOP, logic->IsAdult && (logic->CanUse(RG_ODD_MUSHROOM) || logic->TradeQuestStep(RG_ODD_MUSHROOM))), }, { - // Exits - Entrance(RR_KAK_BACKYARD, { [] { return true; } }), + // Exits + Entrance(RR_KAK_BACKYARD, { [] { return true; } }), }); areaTable[RR_KAK_REDEAD_GROTTO] = Region("Kak Redead Grotto", "Kak Redead Grotto", RA_NONE, NO_DAY_NIGHT_CYCLE, {}, { diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp index 7ab399266..0d4f39c5c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp @@ -67,7 +67,6 @@ int Playthrough_Init(uint32_t seed, std::set excludedLocations, } GenerateHash(); - WriteIngameSpoilerLog(); if (true) { //TODO: Handle different types of file output (i.e. Spoiler Log, Plando Template, Patch Files, Race Files, etc.) diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.cpp b/soh/soh/Enhancements/randomizer/3drando/shops.cpp index 001c62ced..f6c73de32 100644 --- a/soh/soh/Enhancements/randomizer/3drando/shops.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/shops.cpp @@ -2,13 +2,36 @@ #include "location_access.hpp" #include "random.hpp" #include "shops.hpp" +#include "../location.h" #include #include #include +#include #include "z64item.h" -std::map NonShopItems = {}; +PriceSettingsStruct::PriceSettingsStruct(RandomizerSettingKey _main, + RandomizerSettingKey _fixedPrice, + RandomizerSettingKey _range1, + RandomizerSettingKey _range2, + RandomizerSettingKey _noWallet, + RandomizerSettingKey _childWallet, + RandomizerSettingKey _adultWallet, + RandomizerSettingKey _giantWallet, + RandomizerSettingKey _tycoonWallet, + RandomizerSettingKey _affordable){ + main = _main; + fixedPrice = _fixedPrice; + range1 = _range1; + range2 = _range2; + noWallet = _noWallet; + childWallet = _childWallet; + adultWallet = _adultWallet; + giantWallet= _giantWallet; + tycoonWallet= _tycoonWallet; + affordable= _affordable; +} + static std::array, 0xF1> trickNameTable; // Table of trick names for ice traps bool initTrickNames = false; //Indicates if trick ice trap names have been initialized yet @@ -131,71 +154,97 @@ int GetPriceFromMax(int max) { return Random(1, max) * 5; // random range of 1 - wallet max / 5, where wallet max is the highest it goes as a multiple of 5 } -// Get random price out of available "affordable prices", or just return 10 if Starter wallet is selected (no need to randomly select -// from a single element) -int GetPriceAffordable() { - auto ctx = Rando::Context::GetInstance(); - if (ctx->GetOption(RSK_SHOPSANITY_PRICES).Is(RO_SHOPSANITY_PRICE_STARTER)) { - return 10; - } - - static const std::vector affordablePrices = { 10, 105, 205, 505 }; - std::vector priceList; - uint8_t maxElements = ctx->GetOption(RSK_SHOPSANITY_PRICES).Value(); - for (int i = 0; i < maxElements; i++) { - priceList.push_back(affordablePrices.at(i)); - } - return RandomElement(priceList); +uint16_t GetPriceFromSettings(Rando::Location *loc, PriceSettingsStruct priceSettings) { + auto ctx = Rando::Context::GetInstance(); + switch (ctx->GetOption(priceSettings.main).Value()){ + case RO_PRICE_VANILLA: + return loc->GetVanillaPrice(); + case RO_PRICE_CHEAP_BALANCED: + return GetCheapBalancedPrice(); + case RO_PRICE_BALANCED:{ + double random = RandomDouble(); //Randomly generated probability value + for (size_t i = 0; i < ShopPriceProbability.size(); i++) { + if (random < ShopPriceProbability[i]) { + //The randomly generated value has surpassed the total probability up to this point, so this is the generated price + return i * 5; //i in range [0, 59], output in range [0, 295] in increments of 5 + } + } + return 150; + } + case RO_PRICE_FIXED: + return (uint16_t)ctx->GetOption(priceSettings.fixedPrice).Value() * 5; + case RO_PRICE_RANGE:{ + uint16_t range1 = (uint16_t)ctx->GetOption(priceSettings.range1).Value() * 5; + uint16_t range2 = (uint16_t)ctx->GetOption(priceSettings.range2).Value() * 5; + return range1 < range2 ? Random(range1, range2+1) : Random(range2, range1+1); + } + case RO_PRICE_SET_BY_WALLET:{ + bool isTycoon = ctx->GetOption(RSK_INCLUDE_TYCOON_WALLET).Value(); + uint16_t noWeight = ctx->GetOption(priceSettings.noWallet).Value(); + uint16_t childWeight = ctx->GetOption(priceSettings.childWallet).Value(); + uint16_t adultWeight = ctx->GetOption(priceSettings.adultWallet).Value(); + uint16_t giantWeight = ctx->GetOption(priceSettings.giantWallet).Value(); + uint16_t tycoonWeight = isTycoon ? ctx->GetOption(priceSettings.tycoonWallet).Value() : 0; + uint16_t totalWeight = noWeight + childWeight + adultWeight + giantWeight + tycoonWeight; + if (totalWeight == 0){ //if no weight, return from sane range + return Random(0, 501); + } + int16_t selected = Random(1, totalWeight + 1); + selected = selected - noWeight; + if (selected <= 0){ + return 0; + } + selected = selected - childWeight; + if (selected <= 0){ + return Random(1, 100); + } + selected = selected - adultWeight; + if (selected <= 0){ + return Random(100, 201); + } + selected = selected - giantWeight; + if (selected <= 0){ + return Random(201, 501); + } + return Random(501, 999); + } + } + SPDLOG_ERROR("GetPriceFromSettings has failed to return a price for location {}, assigning a default value.", loc->GetName()); + assert(false); + return 69; //this should never happen, if it does, EASTER EGG that tells us something is wrong } -int GetRandomShopPrice() { - auto ctx = Rando::Context::GetInstance(); - // If Shopsanity prices aren't Balanced, but Affordable is on, don't GetPriceFromMax - if (ctx->GetOption(RSK_SHOPSANITY_PRICES_AFFORDABLE).Is(true) && ctx->GetOption(RSK_SHOPSANITY_PRICES).IsNot(RO_SHOPSANITY_PRICE_BALANCED)) { - return GetPriceAffordable(); - } - - // max 0 means Balanced is selected, and thus shouldn't trigger GetPriceFromMax - int max = 0; - - // check settings for a wallet tier selection and set max amount as method for setting true randomization - if (ctx->GetOption(RSK_SHOPSANITY_PRICES).Is(RO_SHOPSANITY_PRICE_STARTER)) { - max = 19; // 95/5 - } else if (ctx->GetOption(RSK_SHOPSANITY_PRICES).Is(RO_SHOPSANITY_PRICE_ADULT)) { - max = 40; // 200/5 - } else if (ctx->GetOption(RSK_SHOPSANITY_PRICES).Is(RO_SHOPSANITY_PRICE_GIANT)) { - max = 100; // 500/5 - } else if (ctx->GetOption(RSK_SHOPSANITY_PRICES).Is(RO_SHOPSANITY_PRICE_TYCOON)) { - max = 199; // 995/5 - } - if (max != 0) { - return GetPriceFromMax(max); - } - // Balanced is default, so if all other known cases fail, fall back to Balanced - int price = 150; // JUST in case something fails with the randomization, return sane price for balanced - double random = RandomDouble(); //Randomly generated probability value - for (size_t i = 0; i < ShopPriceProbability.size(); i++) { - //The randomly generated value has surpassed the total probability up to this point, so this is the generated price - if (random < ShopPriceProbability[i]) { - price = i * 5; //i in range [0, 59], output in range [0, 295] in increments of 5 - break; - } - } - return price; +uint16_t GetRandomPrice(Rando::Location *loc, PriceSettingsStruct priceSettings) { + uint16_t initialPrice = GetPriceFromSettings(loc, priceSettings); + auto ctx = Rando::Context::GetInstance(); + if (ctx->GetOption(priceSettings.affordable) && !ctx->GetOption(priceSettings.main).Is(RO_PRICE_FIXED)){ + if (initialPrice > 500) { + return 505; + } else if (initialPrice > 200) { + return 205; + } else if (initialPrice > 99) { + return 100; + } else if (initialPrice > 0) { + return 5; + } + return 0; + } else { + return initialPrice; + } } //Similar to above, beta distribution with alpha = 1, beta = 2, // multiplied by 20 instead of 60 to give values in rage [0, 95] in increments of 5 //Average price ~31 -static constexpr std::array ScrubPriceProbability = { +static constexpr std::array CheapPriceProbability = { 0.097500187, 0.190002748, 0.277509301, 0.360018376, 0.437522571, 0.510021715, 0.577520272, 0.640029304, 0.697527584, 0.750024535, 0.797518749, 0.840011707, 0.877508776, 0.910010904, 0.937504342, 0.960004661, 0.977502132, 0.989998967, 0.997500116, 1.000000000, }; -int16_t GetRandomScrubPrice() { +uint16_t GetCheapBalancedPrice() { double random = RandomDouble(); - for (size_t i = 0; i < ScrubPriceProbability.size(); i++) { - if (random < ScrubPriceProbability[i]) { + for (size_t i = 0; i < CheapPriceProbability.size(); i++) { + if (random < CheapPriceProbability[i]) { return i * 5; // i in range [0, 19], output in range [0, 95] in increments of 5 } } diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.hpp b/soh/soh/Enhancements/randomizer/3drando/shops.hpp index 152e64d0f..b1f09a9a7 100644 --- a/soh/soh/Enhancements/randomizer/3drando/shops.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/shops.hpp @@ -2,18 +2,37 @@ #include "../context.h" #include +#include -struct ItemAndPrice { - Text Name; - int Price; - bool Repurchaseable; +struct PriceSettingsStruct { + RandomizerSettingKey main; + RandomizerSettingKey fixedPrice; + RandomizerSettingKey range1; + RandomizerSettingKey range2; + RandomizerSettingKey noWallet; + RandomizerSettingKey childWallet; + RandomizerSettingKey adultWallet; + RandomizerSettingKey giantWallet; + RandomizerSettingKey tycoonWallet; + RandomizerSettingKey affordable; + + PriceSettingsStruct(RandomizerSettingKey _main, + RandomizerSettingKey _fixedPrice, + RandomizerSettingKey _range1, + RandomizerSettingKey _range2, + RandomizerSettingKey _noWallet, + RandomizerSettingKey _childWallet, + RandomizerSettingKey _adultWallet, + RandomizerSettingKey _giantWallet, + RandomizerSettingKey _tycoonWallet, + RandomizerSettingKey _affordable); }; extern void PlaceVanillaShopItems(); extern std::vector GetMinVanillaShopItems(int total_replaced); -extern int GetRandomShopPrice(); -extern int16_t GetRandomScrubPrice(); +extern uint16_t GetRandomPrice(Rando::Location* loc, PriceSettingsStruct priceSettings); +extern uint16_t GetCheapBalancedPrice(); extern int GetShopsanityReplaceAmount(); extern Text GetIceTrapName(uint8_t id); -extern std::map NonShopItems; + diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 5ec183b50..e89ef248c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -8,7 +8,6 @@ #include "../trial.h" #include "tinyxml2.h" #include "utils.hpp" -#include "shops.hpp" #include "hints.hpp" #include "pool_functions.hpp" #include "soh/Enhancements/randomizer/randomizer_check_objects.h" @@ -46,8 +45,6 @@ namespace { std::string placementtxt; } // namespace -static SpoilerData spoilerData; - void GenerateHash() { auto ctx = Rando::Context::GetInstance(); std::string hash = ctx->GetSettings()->GetHash(); @@ -64,10 +61,6 @@ void GenerateHash() { // spoilerData = { 0 }; } -const SpoilerData& GetSpoilerData() { - return spoilerData; -} - static auto GetGeneralPath() { return "./randomizer/haha.xml"; } @@ -80,195 +73,6 @@ static auto GetPlacementLogPath() { return GetGeneralPath(); } -void WriteIngameSpoilerLog() { - auto ctx = Rando::Context::GetInstance(); - uint16_t spoilerItemIndex = 0; - uint32_t spoilerStringOffset = 0; - uint16_t spoilerSphereItemoffset = 0; - uint16_t spoilerAreaOffset = 0; - // Intentionally junk value so we trigger the 'new area, record some stuff' code - RandomizerCheckArea currentArea = RandomizerCheckArea::RCAREA_INVALID; - bool spoilerOutOfSpace = false; - - // Create map of string data offsets for all _unique_ item locations and names in the playthrough - // Some item names, like gold skulltula tokens, can appear many times in a playthrough - std::unordered_map - itemLocationsMap; // Map of LocationKey to an index into spoiler data item locations - itemLocationsMap.reserve(ctx->allLocations.size()); - std::unordered_map - stringOffsetMap; // Map of strings to their offset into spoiler string data array - stringOffsetMap.reserve(ctx->allLocations.size() * 2); - - // Sort all locations by their area, so the in-game log can show a area of items by simply starting/ending at - // certain indices - std::stable_sort(ctx->allLocations.begin(), ctx->allLocations.end(), [](const RandomizerCheck& a, const RandomizerCheck& b) { - RandomizerCheckArea areaA = Rando::StaticData::GetLocation(a)->GetArea(); - RandomizerCheckArea areaB = Rando::StaticData::GetLocation(b)->GetArea(); - return areaA < areaB; - }); - - for (const RandomizerCheck key : ctx->allLocations) { - auto loc = Rando::StaticData::GetLocation(key); - auto itemLocation = ctx->GetItemLocation(key); - - // Hide excluded locations from ingame tracker - // if (loc->IsExcluded()) { - // continue; - // } - // Beehives - if (!ctx->GetOption(RSK_SHUFFLE_BEEHIVES) && loc->GetRCType() == RCTYPE_BEEHIVE) { - continue; - } - // Cows - else if (!ctx->GetOption(RSK_SHUFFLE_COWS) && loc->GetRCType() == RCTYPE_COW) { - continue; - } - // Merchants - else if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_OFF) && loc->GetRCType() == RCTYPE_MERCHANT) { - continue; - } - // Adult Trade - else if (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && loc->GetRCType() == RCTYPE_ADULT_TRADE) { - continue; - } - // Chest Minigame - else if (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_GENERIC_OFF) && loc->GetRCType() == RCTYPE_CHEST_GAME) { - continue; - } - // Gerudo Fortress - else if ((ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_NORMAL) && - (loc->GetRCType() == RCTYPE_GF_KEY || loc->GetHintKey() == RHT_GF_GERUDO_MEMBERSHIP_CARD)) || - (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FAST) && loc->GetRCType() == RCTYPE_GF_KEY && - loc->GetHintKey() != RHT_GF_NORTH_F1_CARPENTER)) { - continue; - } - - // Copy at most 51 chars from the name and location name to avoid issues with names that don't fit on screen - const char* nameFormatStr = "%.51s"; - - auto locName = loc->GetName(); - if (stringOffsetMap.find(locName) == stringOffsetMap.end()) { - if (spoilerStringOffset + locName.size() + 1 >= SPOILER_STRING_DATA_SIZE) { - spoilerOutOfSpace = true; - break; - } else { - stringOffsetMap[locName] = spoilerStringOffset; - spoilerStringOffset += - sprintf(&spoilerData.StringData[spoilerStringOffset], nameFormatStr, locName.c_str()) + 1; - } - } - // PURPLE TODO: LOCALIZATION - auto locItem = itemLocation->GetPlacedItemName().GetEnglish(); - if (itemLocation->GetPlacedRandomizerGet() == RG_ICE_TRAP && loc->GetRCType() == RCTYPE_SHOP) { - locItem = NonShopItems[key].Name.GetEnglish(); - } - if (stringOffsetMap.find(locItem) == stringOffsetMap.end()) { - if (spoilerStringOffset + locItem.size() + 1 >= SPOILER_STRING_DATA_SIZE) { - spoilerOutOfSpace = true; - break; - } else { - stringOffsetMap[locItem] = spoilerStringOffset; - spoilerStringOffset += - sprintf(&spoilerData.StringData[spoilerStringOffset], nameFormatStr, locItem.c_str()) + 1; - } - } - - spoilerData.ItemLocations[spoilerItemIndex].LocationStrOffset = stringOffsetMap[locName]; - spoilerData.ItemLocations[spoilerItemIndex].ItemStrOffset = stringOffsetMap[locItem]; - spoilerData.ItemLocations[spoilerItemIndex].LocationStr = locName; - spoilerData.ItemLocations[spoilerItemIndex].ItemStr = locItem; - spoilerData.ItemLocations[spoilerItemIndex].CollectionCheckType = loc->GetCollectionCheck().type; - spoilerData.ItemLocations[spoilerItemIndex].LocationScene = loc->GetCollectionCheck().scene; - spoilerData.ItemLocations[spoilerItemIndex].LocationFlag = loc->GetCollectionCheck().flag; - - // Collect Type and Reveal Type - if (key == RC_GANON) { - spoilerData.ItemLocations[spoilerItemIndex].CollectType = COLLECTTYPE_NEVER; - spoilerData.ItemLocations[spoilerItemIndex].RevealType = REVEALTYPE_ALWAYS; - } - // Shops - else if (loc->IsShop()) { - if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_OFF)) { - spoilerData.ItemLocations[spoilerItemIndex].RevealType = REVEALTYPE_ALWAYS; - } else { - spoilerData.ItemLocations[spoilerItemIndex].RevealType = REVEALTYPE_SCENE; - } - if (itemLocation->GetPlacedItem().GetItemType() == ITEMTYPE_REFILL || - itemLocation->GetPlacedItem().GetItemType() == ITEMTYPE_SHOP || - itemLocation->GetPlacedItem().GetHintKey() == RHT_PROGRESSIVE_BOMBCHUS) { - spoilerData.ItemLocations[spoilerItemIndex].CollectType = COLLECTTYPE_REPEATABLE; - } - } - // Gold Skulltulas - else if (loc->GetRCType() == RCTYPE_SKULL_TOKEN && - ((ctx->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_OFF)) || - (ctx->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_DUNGEONS) && !loc->IsDungeon()) || - (ctx->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_OVERWORLD) && loc->IsDungeon()))) { - spoilerData.ItemLocations[spoilerItemIndex].RevealType = REVEALTYPE_ALWAYS; - } - // Deku Scrubs - else if ( - loc->GetRCType() == RCTYPE_SCRUB && - // these 3 scrubs are always randomized - !( - loc->GetRandomizerCheck() == RC_LW_DEKU_SCRUB_NEAR_BRIDGE || - loc->GetRandomizerCheck() == RC_LW_DEKU_SCRUB_GROTTO_FRONT || - loc->GetRandomizerCheck() == RC_HF_DEKU_SCRUB_GROTTO - ) && - ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_OFF) - ) { - spoilerData.ItemLocations[spoilerItemIndex].CollectType = COLLECTTYPE_REPEATABLE; - spoilerData.ItemLocations[spoilerItemIndex].RevealType = REVEALTYPE_ALWAYS; - } - - RandomizerCheckArea checkArea = loc->GetArea(); - spoilerData.ItemLocations[spoilerItemIndex].Area = checkArea; - - // Area setup - if (checkArea != currentArea) { - currentArea = checkArea; - spoilerData.AreaOffsets[currentArea] = spoilerAreaOffset; - } - ++spoilerData.AreaItemCounts[currentArea]; - ++spoilerAreaOffset; - - itemLocationsMap[key] = spoilerItemIndex++; - } - spoilerData.ItemLocationsCount = spoilerItemIndex; - - if (/*Settings::IngameSpoilers TODO: Remove: don't think we have any need for this*/ false) { - bool playthroughItemNotFound = false; - // Write playthrough data to in-game spoiler log - if (!spoilerOutOfSpace) { - for (uint32_t i = 0; i < ctx->playthroughLocations.size(); i++) { - if (i >= SPOILER_SPHERES_MAX) { - spoilerOutOfSpace = true; - break; - } - spoilerData.Spheres[i].ItemLocationsOffset = spoilerSphereItemoffset; - for (uint32_t loc = 0; loc < ctx->playthroughLocations[i].size(); ++loc) { - if (spoilerSphereItemoffset >= SPOILER_ITEMS_MAX) { - spoilerOutOfSpace = true; - break; - } - - const auto foundItemLoc = itemLocationsMap.find(ctx->playthroughLocations[i][loc]); - if (foundItemLoc != itemLocationsMap.end()) { - spoilerData.SphereItemLocations[spoilerSphereItemoffset++] = foundItemLoc->second; - } else { - playthroughItemNotFound = true; - } - ++spoilerData.Spheres[i].ItemCount; - } - ++spoilerData.SphereCount; - } - } - if (spoilerOutOfSpace || playthroughItemNotFound) { - SPDLOG_ERROR("In-game spoiler log is out of space, playthrough data will not be written"); - } - } -} - // Writes the location to the specified node. static void WriteLocation( std::string sphere, const RandomizerCheck locationKey, const bool withPadding = false) { @@ -683,6 +487,7 @@ void PlacementLog_Clear() { placementtxt = ""; } +// RANDOTODO: Do we even use this? bool PlacementLog_Write() { auto placementLog = tinyxml2::XMLDocument(false); placementLog.InsertEndChild(placementLog.NewDeclaration()); @@ -692,7 +497,6 @@ bool PlacementLog_Write() { // rootNode->SetAttribute("version", Settings::version.c_str()); // rootNode->SetAttribute("seed", Settings::seed); - // TODO: Do we even use this? // WriteSettings(placementLog, true); // Include hidden settings. // WriteExcludedLocations(placementLog); diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.hpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.hpp index bf2fd9f60..25b64418e 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.hpp @@ -8,7 +8,7 @@ using RandomizerHash = std::array; - +// RANDOTODO this is primarily used by the check tracker now, and should probably be moved typedef enum { SPOILER_CHK_NONE, SPOILER_CHK_CHEST, @@ -21,55 +21,6 @@ typedef enum { SPOILER_CHK_RANDOMIZER_INF, } SpoilerCollectionCheckType; -typedef enum { - COLLECTTYPE_NORMAL, - COLLECTTYPE_REPEATABLE, - COLLECTTYPE_NEVER, -} SpoilerItemCollectType; - -typedef enum { - REVEALTYPE_NORMAL, - REVEALTYPE_SCENE, - REVEALTYPE_ALWAYS, -} SpoilerItemRevealType; - -#define SPOILER_SPHERES_MAX 50 -#define SPOILER_ITEMS_MAX RC_MAX -#define SPOILER_STRING_DATA_SIZE 16384 - -typedef struct { - std::string LocationStr; - std::string ItemStr; - uint16_t LocationStrOffset; - uint16_t ItemStrOffset; - SpoilerCollectionCheckType CollectionCheckType; - uint8_t LocationScene; - uint8_t LocationFlag; - RandomizerCheckArea Area; - SpoilerItemCollectType CollectType; - SpoilerItemRevealType RevealType; -} SpoilerItemLocation; - -typedef struct { - uint8_t ItemCount; - uint16_t ItemLocationsOffset; -} SpoilerSphere; - -typedef struct { - uint8_t SphereCount; - uint16_t ItemLocationsCount; - SpoilerSphere Spheres[SPOILER_SPHERES_MAX]; - SpoilerItemLocation ItemLocations[SPOILER_ITEMS_MAX]; - uint16_t SphereItemLocations[SPOILER_ITEMS_MAX]; - char StringData[SPOILER_STRING_DATA_SIZE]; - uint16_t AreaItemCounts[RCAREA_INVALID]; - uint16_t AreaOffsets[RCAREA_INVALID]; -} SpoilerData; - void GenerateHash(); -const RandomizerHash& GetRandomizerHash(); -void WriteIngameSpoilerLog(); - -const char* SpoilerLog_Write(); -const SpoilerData& GetSpoilerData(); \ No newline at end of file +const char* SpoilerLog_Write(); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/context.cpp b/soh/soh/Enhancements/randomizer/context.cpp index 29e576580..44a27f116 100644 --- a/soh/soh/Enhancements/randomizer/context.cpp +++ b/soh/soh/Enhancements/randomizer/context.cpp @@ -104,15 +104,6 @@ void Context::PlaceItemInLocation(const RandomizerCheck locKey, const Randomizer // TODO? Show Progress - // If we're placing a non-shop item in a shop location, we want to record it for custom messages - if (StaticData::RetrieveItem(item).GetItemType() != ITEMTYPE_SHOP && - StaticData::GetLocation(locKey)->GetRCType() == RCTYPE_SHOP) { - NonShopItems[locKey].Name = StaticData::RetrieveItem(item).GetName(); - NonShopItems[locKey].Repurchaseable = - StaticData::RetrieveItem(item).GetItemType() == ITEMTYPE_REFILL || - StaticData::RetrieveItem(item).GetHintKey() == RHT_PROGRESSIVE_BOMBCHUS; - } - loc->SetPlacedItem(item); if (setHidden) { loc->SetHidden(true); @@ -213,9 +204,6 @@ void Context::CreateItemOverrides() { iceTrapModels[locKey] = val.LooksLike(); val.SetTrickName(GetIceTrapName(val.LooksLike())); // If this is ice trap is in a shop, change the name based on what the model will look like - if (loc->GetRCType() == RCTYPE_SHOP) { - NonShopItems[locKey].Name = val.GetTrickName(); - } overrides[locKey] = val; } SPDLOG_DEBUG(loc->GetName()); diff --git a/soh/soh/Enhancements/randomizer/hint.cpp b/soh/soh/Enhancements/randomizer/hint.cpp index 7d62d29c7..4ff6ba2aa 100644 --- a/soh/soh/Enhancements/randomizer/hint.cpp +++ b/soh/soh/Enhancements/randomizer/hint.cpp @@ -192,12 +192,11 @@ void Hint::NamesChosen(){ hintTextsChosen = namesTemp; } - if (hintType == HINT_TYPE_ITEM || hintType == HINT_TYPE_ITEM_AREA || hintType == HINT_TYPE_MERCHANT){ - bool mysterious = hintType == HINT_TYPE_MERCHANT && ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ON_NO_HINT); + if (hintType == HINT_TYPE_ITEM || hintType == HINT_TYPE_ITEM_AREA){ for(uint8_t c = 0; c < locations.size(); c++){ namesTemp = {}; saveNames = false; - uint8_t selection = GetRandomHintTextEntry(GetItemHintText(c, mysterious)); + uint8_t selection = GetRandomHintTextEntry(GetItemHintText(c)); if (selection > 0){ saveNames = true; } @@ -332,13 +331,6 @@ const CustomMessage Hint::GetHintMessage(MessageFormat format, uint8_t id) const toInsert.push_back(GetItemName(b)); } break;} - case HINT_TYPE_MERCHANT:{ - //if we write items, but need to adjust for merchants - bool mysterious = hintType == HINT_TYPE_MERCHANT && ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ON_NO_HINT); - for(uint8_t b = 0; b < locations.size(); b++){ - toInsert.push_back(GetItemName(b, mysterious)); - } - break;} case HINT_TYPE_TRIAL:{ //If we write trials for(uint8_t b = 0; b < trials.size(); b++){ @@ -507,7 +499,7 @@ void Hint::logHint(oJson& jsonData){ staticHint = false; } if (enabled && - (!(staticHint && (hintType == HINT_TYPE_ITEM || hintType == HINT_TYPE_MERCHANT) && ctx->GetOption(RSK_HINT_CLARITY).Is(RO_HINT_CLARITY_CLEAR)))){ + (!(staticHint && (hintType == HINT_TYPE_ITEM) && ctx->GetOption(RSK_HINT_CLARITY).Is(RO_HINT_CLARITY_CLEAR)))){ //skip if not enabled or if a static hint with no possible variance jsonData[logMap][Rando::StaticData::hintNames[ownKey].GetForCurrentLanguage(MF_CLEAN)] = toJSON(); } diff --git a/soh/soh/Enhancements/randomizer/hint.h b/soh/soh/Enhancements/randomizer/hint.h index dc626ebf9..03e1af850 100644 --- a/soh/soh/Enhancements/randomizer/hint.h +++ b/soh/soh/Enhancements/randomizer/hint.h @@ -38,7 +38,7 @@ class Hint { const HintText GetHintText(uint8_t id = 0) const; oJson toJSON(); void logHint(oJson& jsonData); - const HintText GetItemHintText(uint8_t slot, bool mysterious) const; + const HintText GetItemHintText(uint8_t slot, bool mysterious = false) const; const HintText GetAreaHintText(uint8_t slot) const; const CustomMessage GetItemName(uint8_t slot, bool mysterious = false) const; const CustomMessage GetAreaName(uint8_t slot) const; diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index af56293cb..c71f1965c 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -36,6 +36,9 @@ extern "C" { #include "src/overlays/actors/ovl_Obj_Comb/z_obj_comb.h" #include "src/overlays/actors/ovl_En_Bom_Bowl_Pit/z_en_bom_bowl_pit.h" #include "src/overlays/actors/ovl_En_Ge1/z_en_ge1.h" +#include "src/overlays/actors/ovl_En_Ds/z_en_ds.h" +#include "src/overlays/actors/ovl_En_Gm/z_en_gm.h" +#include "src/overlays/actors/ovl_En_Js/z_en_js.h" #include "src/overlays/actors/ovl_En_Door/z_en_door.h" #include "src/overlays/actors/ovl_Door_Shutter/z_door_shutter.h" #include "src/overlays/actors/ovl_Door_Gerudo/z_door_gerudo.h" @@ -512,7 +515,8 @@ void EnCow_MoveForRandomizer(EnCow* enCow, PlayState* play) { } u8 EnDs_RandoCanGetGrannyItem() { - return RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF && + return (RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS || + RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL) && !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP) && // Traded odd mushroom when adult trade is on ((RAND_GET_OPTION(RSK_SHUFFLE_ADULT_TRADE) && Flags_GetItemGetInf(ITEMGETINF_30)) || @@ -521,6 +525,20 @@ u8 EnDs_RandoCanGetGrannyItem() { INV_CONTENT(ITEM_CLAIM_CHECK) == ITEM_CLAIM_CHECK)); } +u8 EnJs_RandoCanGetCarpetMerchantItem() { + return (RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL || + RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS) && + // If the rando check has already been awarded, use vanilla behavior. + !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN); +} + +u8 EnGm_RandoCanGetMedigoronItem() { + return (RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL || + RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS) && + // If the rando check has already been awarded, use vanilla behavior. + !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_MEDIGORON); +} + RandomizerCheck EnFr_RandomizerCheckFromSongIndex(u16 songIndex) { switch (songIndex) { case FROG_ZL: @@ -574,6 +592,8 @@ void RandomizerSetChestGameRandomizerInf(RandomizerCheck rc) { case RC_MARKET_TREASURE_CHEST_GAME_KEY_5: Flags_SetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_5); break; + default: + break; } } @@ -681,8 +701,9 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void break; } case VB_BE_ELIGIBLE_FOR_MAGIC_BEANS_PURCHASE: { - if (RAND_GET_OPTION(RSK_SHUFFLE_MAGIC_BEANS)) { - *should = gSaveContext.rupees >= 60; + if (RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_BEANS_ONLY || + RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL) { + *should = gSaveContext.rupees >= OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_ZR_MAGIC_BEAN_SALESMAN)->GetPrice(); } break; } @@ -852,8 +873,11 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void if (!EnDs_RandoCanGetGrannyItem()) { break; } + EnDs* granny = static_cast(optionalArg); // Only setting the inf if we've actually gotten the rando item and not the vanilla blue potion Flags_SetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP); + granny->actor.parent = NULL; + granny->actionFunc = EnDs_Talk; *should = false; break; } @@ -878,23 +902,47 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void *should = false; break; } + case VB_CHECK_RANDO_PRICE_OF_CARPET_SALESMAN: { + if (EnJs_RandoCanGetCarpetMerchantItem()){ + *should = gSaveContext.rupees < OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_WASTELAND_BOMBCHU_SALESMAN)->GetPrice(); + } + break; + } case VB_GIVE_ITEM_FROM_CARPET_SALESMAN: { - *should = RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_OFF || - // If the rando check has already been awarded, use vanilla behavior. - Flags_GetRandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN); + EnJs* enJs = static_cast(optionalArg); + if (EnJs_RandoCanGetCarpetMerchantItem()){ + Rupees_ChangeBy(OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_WASTELAND_BOMBCHU_SALESMAN)->GetPrice() * -1); + enJs->actor.parent = NULL; + enJs->actor.textId = TEXT_CARPET_SALESMAN_ARMS_DEALER; + enJs->actionFunc = (EnJsActionFunc)func_80A890C0; + enJs->actor.flags |= ACTOR_FLAG_WILL_TALK; + Flags_SetRandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN); + *should = true; + } break; } case VB_GIVE_BOMBCHUS_FROM_CARPET_SALESMAN: { *should = RAND_GET_OPTION(RSK_BOMBCHUS_IN_LOGIC) == false || INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU; break; } + case VB_CHECK_RANDO_PRICE_OF_MEDIGORON: { + if (EnGm_RandoCanGetMedigoronItem()){ + *should = gSaveContext.rupees < OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_GC_MEDIGORON)->GetPrice(); + } + break; + } + case VB_GIVE_ITEM_FROM_MEDIGORON: { // fallthrough case VB_BE_ELIGIBLE_FOR_GIANTS_KNIFE_PURCHASE: - if (RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF && - !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_MEDIGORON)) { + if (EnGm_RandoCanGetMedigoronItem()) { if (id == VB_GIVE_ITEM_FROM_MEDIGORON) { + EnGm* enGm = static_cast(optionalArg); Flags_SetInfTable(INFTABLE_B1); + Flags_SetRandomizerInf(RAND_INF_MERCHANTS_MEDIGORON); + enGm->actor.parent = NULL; + enGm->actionFunc = (EnGmActionFunc)func_80A3DC44; + Rupees_ChangeBy(OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_GC_MEDIGORON)->GetPrice() * -1); *should = false; } else { // Resets "Talked to Medigoron" flag in infTable to restore initial conversation state @@ -906,8 +954,9 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void } case VB_GIVE_ITEM_FROM_MAGIC_BEAN_SALESMAN: { EnMs* enMs = static_cast(optionalArg); - if (RAND_GET_OPTION(RSK_SHUFFLE_MAGIC_BEANS)) { - Rupees_ChangeBy(-60); + if (RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_BEANS_ONLY || + RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL) { + Rupees_ChangeBy(OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_ZR_MAGIC_BEAN_SALESMAN)->GetPrice() * -1); BEANS_BOUGHT = 10; // Only set inf for buying rando check Flags_SetRandomizerInf(RAND_INF_MERCHANTS_MAGIC_BEAN_SALESMAN); @@ -944,9 +993,13 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void break; } case VB_TRADE_ODD_MUSHROOM: { + EnDs* granny = static_cast(optionalArg); Randomizer_ConsumeAdultTradeItem(gPlayState, ITEM_ODD_MUSHROOM); // Trigger the reward now Flags_SetItemGetInf(ITEMGETINF_30); + granny->actor.textId = 0x504F; + granny->actionFunc = (EnDsActionFunc)EnDs_TalkAfterGiveOddPotion; + granny->actor.flags &= ~ACTOR_FLAG_PLAYER_TALKED_TO; *should = false; break; } @@ -1045,6 +1098,19 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void *should |= RAND_GET_OPTION(RSK_SHUFFLE_ADULT_TRADE) == RO_GENERIC_OFF; break; } + case VB_GRANNY_SAY_INSUFFICIENT_RUPEES: { + if (EnDs_RandoCanGetGrannyItem()){ + *should = gSaveContext.rupees < OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_KAK_GRANNYS_SHOP)->GetPrice(); + } + break; + } + case VB_GRANNY_TAKE_MONEY: { + if (EnDs_RandoCanGetGrannyItem()){ + *should = false; + Rupees_ChangeBy(OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_KAK_GRANNYS_SHOP)->GetPrice() * -1); + } + break; + } case VB_NEED_BOTTLE_FOR_GRANNYS_ITEM: { // Allow buying the rando item regardless of having a bottle *should &= !EnDs_RandoCanGetGrannyItem(); @@ -1333,6 +1399,8 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void case VB_GIVE_ITEM_SHADOW_MEDALLION: *should = false; break; + default: + break; } } diff --git a/soh/soh/Enhancements/randomizer/item.cpp b/soh/soh/Enhancements/randomizer/item.cpp index 2d3f48451..5f94ad6e4 100644 --- a/soh/soh/Enhancements/randomizer/item.cpp +++ b/soh/soh/Enhancements/randomizer/item.cpp @@ -84,14 +84,8 @@ std::shared_ptr Item::GetGIEntry() const { // NOLINT(*-no-recursio std::shared_ptr ctx = Rando::Context::GetInstance(); auto logic = ctx->GetLogic(); RandomizerGet actual = RG_NONE; - const bool tycoonWallet = !( - ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_OFF) || - ( - ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_SPECIFIC_COUNT) && - ctx->GetOption(RSK_SHOPSANITY_COUNT).Is(RO_SHOPSANITY_COUNT_ZERO_ITEMS) - ) - ); - const u8 infiniteUpgrades = ctx->GetOption(RSK_INFINITE_UPGRADES).Value(); + const bool tycoonWallet = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_INCLUDE_TYCOON_WALLET); + const u8 infiniteUpgrades = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_INFINITE_UPGRADES); switch (randomizerGet) { case RG_PROGRESSIVE_STICK_UPGRADE: switch (logic->CurrentUpgrade(UPG_STICKS)) { @@ -287,8 +281,11 @@ std::shared_ptr Item::GetGIEntry() const { // NOLINT(*-no-recursio actual = RG_GIANT_WALLET; break; case 2: - actual = tycoonWallet ? RG_TYCOON_WALLET : RG_GIANT_WALLET; - break; + if(tycoonWallet){ + actual = RG_TYCOON_WALLET; + break; + } + //fallthrough case 3: case 4: if (infiniteUpgrades != RO_INF_UPGRADES_OFF) { diff --git a/soh/soh/Enhancements/randomizer/item_location.cpp b/soh/soh/Enhancements/randomizer/item_location.cpp index 0cce409fc..e5c9ce6cc 100644 --- a/soh/soh/Enhancements/randomizer/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/item_location.cpp @@ -77,6 +77,7 @@ void ItemLocation::ApplyPlacedItemEffect() const { } uint16_t ItemLocation::GetPrice() const { + //RANDOTODO if we ever change price of shop items, this needs replacing with proper price assignment in Fill if (StaticData::RetrieveItem(placedItem).GetItemType() == ITEMTYPE_SHOP) { return StaticData::RetrieveItem(placedItem).GetPrice(); } diff --git a/soh/soh/Enhancements/randomizer/location.cpp b/soh/soh/Enhancements/randomizer/location.cpp index 135fddeea..d7f0a6444 100644 --- a/soh/soh/Enhancements/randomizer/location.cpp +++ b/soh/soh/Enhancements/randomizer/location.cpp @@ -82,6 +82,10 @@ RandomizerGet Rando::Location::GetVanillaItem() const { return vanillaItem; } +int16_t Rando::Location::GetVanillaPrice() const { + return vanillaPrice; +} + RandomizerCheckArea GetAreaFromScene(uint8_t scene) { switch (scene) { case SCENE_LINKS_HOUSE: @@ -243,29 +247,30 @@ RandomizerCheckArea GetAreaFromScene(uint8_t scene) { } } + Rando::Location Rando::Location::Base(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, ActorID actorId_, SceneID scene_, int32_t actorParams_, std::string&& shortName_, std::string&& spoilerName_, const RandomizerHintTextKey hintKey, const RandomizerGet vanillaItem, - SpoilerCollectionCheck collectionCheck, bool isVanillaCompletion_) { + SpoilerCollectionCheck collectionCheck, bool isVanillaCompletion_, uint16_t vanillaPrice_) { return { rc, quest_, checkType_, GetAreaFromScene(scene_), actorId_, scene_, actorParams_, std::move(shortName_), std::move(spoilerName_), hintKey, vanillaItem, - isVanillaCompletion_, collectionCheck }; + isVanillaCompletion_, collectionCheck, vanillaPrice_ }; } Rando::Location Rando::Location::Base(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, RandomizerCheckArea area_, ActorID actorId_, SceneID scene_, int32_t actorParams_, std::string&& shortName_, std::string&& spoilerName_, const RandomizerHintTextKey hintKey, const RandomizerGet vanillaItem, - SpoilerCollectionCheck collectionCheck, bool isVanillaCompletion_) { - return { rc, quest_, checkType_, area_, actorId_, scene_, actorParams_, std::move(shortName_), std::move(spoilerName_), hintKey, vanillaItem, isVanillaCompletion_, collectionCheck }; + SpoilerCollectionCheck collectionCheck, bool isVanillaCompletion_, uint16_t vanillaPrice_) { + return { rc, quest_, checkType_, area_, actorId_, scene_, actorParams_, std::move(shortName_), std::move(spoilerName_), hintKey, vanillaItem, isVanillaCompletion_, collectionCheck, vanillaPrice_ }; } Rando::Location Rando::Location::Base(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, ActorID actorId_, SceneID scene_, int32_t actorParams_, std::string&& shortName_, const RandomizerHintTextKey hintKey, const RandomizerGet vanillaItem, SpoilerCollectionCheck collectionCheck, - bool isVanillaCompletion_) { - return { rc, quest_, checkType_, GetAreaFromScene(scene_), actorId_, scene_, actorParams_, std::move(shortName_), hintKey, vanillaItem, isVanillaCompletion_, collectionCheck }; + bool isVanillaCompletion_, uint16_t vanillaPrice_) { + return { rc, quest_, checkType_, GetAreaFromScene(scene_), actorId_, scene_, actorParams_, std::move(shortName_), hintKey, vanillaItem, isVanillaCompletion_, collectionCheck , vanillaPrice_ }; } Rando::Location Rando::Location::Base(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, RandomizerCheckArea area_, ActorID actorId_, SceneID scene_, int32_t actorParams_, std::string&& shortName_, const RandomizerHintTextKey hintKey, const RandomizerGet vanillaItem, - SpoilerCollectionCheck collectionCheck, bool isVanillaCompletion_) { - return { rc, quest_, checkType_, area_, actorId_, scene_, actorParams_, std::move(shortName_), hintKey, vanillaItem, isVanillaCompletion_, collectionCheck }; + SpoilerCollectionCheck collectionCheck, bool isVanillaCompletion_, uint16_t vanillaPrice_) { + return { rc, quest_, checkType_, area_, actorId_, scene_, actorParams_, std::move(shortName_), hintKey, vanillaItem, isVanillaCompletion_, collectionCheck, vanillaPrice_ }; } Rando::Location Rando::Location::Chest(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, ActorID actorId_, SceneID scene_, int32_t actorParams_, diff --git a/soh/soh/Enhancements/randomizer/location.h b/soh/soh/Enhancements/randomizer/location.h index 09a015a1e..c5ab902e4 100644 --- a/soh/soh/Enhancements/randomizer/location.h +++ b/soh/soh/Enhancements/randomizer/location.h @@ -53,18 +53,20 @@ class Location { Location(const RandomizerCheck rc_, const RandomizerCheckQuest quest_, const RandomizerCheckType checkType_, const RandomizerCheckArea area_, const ActorID actorId_, const SceneID scene_, const int32_t actorParams_, std::string shortName_, std::string spoilerName_, const RandomizerHintTextKey hintKey_, - const RandomizerGet vanillaItem_, const bool isVanillaCompletion_ = false, const SpoilerCollectionCheck collectionCheck_ = SpoilerCollectionCheck()) + const RandomizerGet vanillaItem_, const bool isVanillaCompletion_ = false, const SpoilerCollectionCheck collectionCheck_ = SpoilerCollectionCheck(), + const int vanillaPrice_ = 0) : rc(rc_), quest(quest_), checkType(checkType_), area(area_), actorId(actorId_), scene(scene_), actorParams(actorParams_), shortName(std::move(shortName_)), spoilerName(std::move(spoilerName_)), hintKey(hintKey_), vanillaItem(vanillaItem_), - isVanillaCompletion(isVanillaCompletion_), collectionCheck(collectionCheck_) {} + isVanillaCompletion(isVanillaCompletion_), collectionCheck(collectionCheck_), vanillaPrice(vanillaPrice_) {} Location(const RandomizerCheck rc_, const RandomizerCheckQuest quest_, const RandomizerCheckType checkType_, const RandomizerCheckArea area_, const ActorID actorId_, const SceneID scene_, const int32_t actorParams_, std::string shortName_, const RandomizerHintTextKey hintKey_, const RandomizerGet vanillaItem_, - const bool isVanillaCompletion_ = false, const SpoilerCollectionCheck collectionCheck_ = SpoilerCollectionCheck()) + const bool isVanillaCompletion_ = false, const SpoilerCollectionCheck collectionCheck_ = SpoilerCollectionCheck(), + const int vanillaPrice_ = 0) : rc(rc_), quest(quest_), checkType(checkType_), area(area_), actorId(actorId_), scene(scene_), actorParams(actorParams_), shortName(shortName_), spoilerName(SpoilerNameFromShortName(shortName_, area_)), hintKey(hintKey_), vanillaItem(vanillaItem_), isVanillaCompletion(isVanillaCompletion_), - collectionCheck(collectionCheck_) {} + collectionCheck(collectionCheck_), vanillaPrice(vanillaPrice_) {} static std::string SpoilerNameFromShortName(std::string shortName, RandomizerCheckArea area) { if (area < 0 || area >= RCAREA_INVALID) { @@ -92,22 +94,23 @@ class Location { uint32_t Getuint32_t() const; const HintText& GetHint() const; RandomizerGet GetVanillaItem() const; + int16_t GetVanillaPrice() const; static Location Base(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, ActorID actorId_, SceneID scene_, int32_t actorParams_, std::string&& shortName_, std::string&& spoilerName_, RandomizerHintTextKey hintKey, RandomizerGet vanillaItem, - SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), bool isVanillaCompletion_ = false); + SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), bool isVanillaCompletion_ = false, uint16_t vanillaPrice_ = 0); static Location Base(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, ActorID actorId_, SceneID scene_, int32_t actorParams_, std::string&& shortName_, RandomizerHintTextKey hintKey, RandomizerGet vanillaItem, SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), - bool isVanillaCompletion_ = false); + bool isVanillaCompletion_ = false, uint16_t vanillaPrice_ = 0); static Location Base(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, RandomizerCheckArea area_, ActorID actorId_, SceneID scene_, int32_t actorParams_, std::string&& shortName_, std::string&& spoilerName_, RandomizerHintTextKey hintKey, RandomizerGet vanillaItem, - SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), bool isVanillaCompletion_ = false); + SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), bool isVanillaCompletion_ = false, uint16_t vanillaPrice_ = 0); static Location Base(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, RandomizerCheckArea area_, ActorID actorId_, SceneID scene_, int32_t actorParams_, std::string&& shortName_, RandomizerHintTextKey hintKey, RandomizerGet vanillaItem, - SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), bool isVanillaCompletion_ = false); + SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), bool isVanillaCompletion_ = false, uint16_t vanillaPrice_ = 0); static Location Chest(RandomizerCheck rc, RandomizerCheckQuest quest_, RandomizerCheckType checkType_, RandomizerCheckArea area_, ActorID actorId_, SceneID scene_, int32_t actorParams_, uint8_t flag_, std::string&& shortName_, RandomizerHintTextKey hintKey, RandomizerGet vanillaItem, bool isVanillaCompletion_ = false); @@ -192,6 +195,7 @@ class Location { RandomizerGet vanillaItem; bool isVanillaCompletion; SpoilerCollectionCheck collectionCheck; + int16_t vanillaPrice; bool isHintable = false; }; } // namespace Rando \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_list.cpp b/soh/soh/Enhancements/randomizer/location_list.cpp index 29ef5ae65..f85b32aff 100644 --- a/soh/soh/Enhancements/randomizer/location_list.cpp +++ b/soh/soh/Enhancements/randomizer/location_list.cpp @@ -55,6 +55,16 @@ std::vector Rando::StaticData::GetScrubLocations() { return scrubLocations; } +std::vector Rando::StaticData::GetMerchantLocations() { + std::vector scrubLocations = {}; + for (Location& location : locationTable) { + if (location.GetRCType() == RCTYPE_MERCHANT && location.GetRandomizerCheck() != RC_UNKNOWN_CHECK) { + scrubLocations.push_back(location.GetRandomizerCheck()); + } + } + return scrubLocations; +} + std::vector Rando::StaticData::GetAdultTradeLocations() { std::vector tradeLocations = {}; for (Location& location : locationTable) { @@ -138,24 +148,24 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_LW_TRADE_ODD_POTION] = Location::Base(RC_LW_TRADE_ODD_POTION, RCQUEST_BOTH, RCTYPE_ADULT_TRADE, ACTOR_ID_MAX, SCENE_LOST_WOODS, 0x00, "Trade Odd Potion", RHT_LW_TRADE_COJIRO, RG_POACHERS_SAW, SpoilerCollectionCheck::ItemGetInf(49), true); locationTable[RC_LW_OCARINA_MEMORY_GAME] = Location::Base(RC_LW_OCARINA_MEMORY_GAME, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_LOST_WOODS, 0x00, "Ocarina Memory Game", RHT_LW_OCARINA_MEMORY_GAME, RG_PIECE_OF_HEART, SpoilerCollectionCheck::ItemGetInf(23), true); locationTable[RC_LW_TARGET_IN_WOODS] = Location::Base(RC_LW_TARGET_IN_WOODS, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_LOST_WOODS, 0x00, "Target in Woods", RHT_LW_TARGET_IN_WOODS, RG_PROGRESSIVE_SLINGSHOT, SpoilerCollectionCheck::ItemGetInf(29), true); - locationTable[RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT] = Location::Base(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, RCQUEST_BOTH, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x00, "Deku Scrub Near Deku Theater Right", RHT_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT)); - locationTable[RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT] = Location::Base(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x01, "Deku Scrub Near Deku Theater Left", RHT_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, RG_BUY_DEKU_STICK_1, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT)); - locationTable[RC_LW_DEKU_SCRUB_NEAR_BRIDGE] = Location::Base(RC_LW_DEKU_SCRUB_NEAR_BRIDGE, RCQUEST_BOTH, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x09, "Deku Scrub Near Bridge", RHT_LW_DEKU_SCRUB_NEAR_BRIDGE, RG_PROGRESSIVE_STICK_UPGRADE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_BRIDGE), true); - locationTable[RC_LW_DEKU_SCRUB_GROTTO_REAR] = Location::Base(RC_LW_DEKU_SCRUB_GROTTO_REAR, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03, 0xF5), "Deku Scrub Grotto Rear", RHT_LW_DEKU_SCRUB_GROTTO_REAR, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_REAR)); - locationTable[RC_LW_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_LW_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x0A, 0xF5), "Deku Scrub Grotto Front", RHT_LW_DEKU_SCRUB_GROTTO_FRONT, RG_PROGRESSIVE_NUT_UPGRADE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_FRONT)); + locationTable[RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT] = Location::Base(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, RCQUEST_BOTH, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x00, "Deku Scrub Near Deku Theater Right", RHT_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT), false, 20); + locationTable[RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT] = Location::Base(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x01, "Deku Scrub Near Deku Theater Left", RHT_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, RG_BUY_DEKU_STICK_1, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT), false, 15); + locationTable[RC_LW_DEKU_SCRUB_NEAR_BRIDGE] = Location::Base(RC_LW_DEKU_SCRUB_NEAR_BRIDGE, RCQUEST_BOTH, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_LOST_WOODS, 0x09, "Deku Scrub Near Bridge", RHT_LW_DEKU_SCRUB_NEAR_BRIDGE, RG_PROGRESSIVE_STICK_UPGRADE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_BRIDGE), true, 40); + locationTable[RC_LW_DEKU_SCRUB_GROTTO_REAR] = Location::Base(RC_LW_DEKU_SCRUB_GROTTO_REAR, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03, 0xF5), "Deku Scrub Grotto Rear", RHT_LW_DEKU_SCRUB_GROTTO_REAR, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_REAR), false, 40); + locationTable[RC_LW_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_LW_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LOST_WOODS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x0A, 0xF5), "Deku Scrub Grotto Front", RHT_LW_DEKU_SCRUB_GROTTO_FRONT, RG_PROGRESSIVE_NUT_UPGRADE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_FRONT), false, 40); locationTable[RC_DEKU_THEATER_SKULL_MASK] = Location::Base(RC_DEKU_THEATER_SKULL_MASK, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_LOST_WOODS, ACTOR_ID_MAX, SCENE_GROTTOS, 0x00, "Deku Theater Skull Mask", RHT_DEKU_THEATER_SKULL_MASK, RG_PROGRESSIVE_STICK_UPGRADE, SpoilerCollectionCheck::ItemGetInf(ITEMGETINF_OBTAINED_STICK_UPGRADE_FROM_STAGE), true); locationTable[RC_DEKU_THEATER_MASK_OF_TRUTH] = Location::Base(RC_DEKU_THEATER_MASK_OF_TRUTH, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_LOST_WOODS, ACTOR_ID_MAX, SCENE_GROTTOS, 0x00, "Deku Theater Mask of Truth", RHT_DEKU_THEATER_MASK_OF_TRUTH, RG_PROGRESSIVE_NUT_UPGRADE, SpoilerCollectionCheck::ItemGetInf(ITEMGETINF_OBTAINED_NUT_UPGRADE_FROM_STAGE), true); // Sacred Forest Meadow locationTable[RC_SFM_WOLFOS_GROTTO_CHEST] = Location::Chest(RC_SFM_WOLFOS_GROTTO_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_SACRED_FOREST_MEADOW, ACTOR_EN_BOX, SCENE_GROTTOS, 31409, 0x11, "Wolfos Grotto Chest", RHT_SFM_WOLFOS_GROTTO_CHEST, RG_PURPLE_RUPEE); - locationTable[RC_SFM_DEKU_SCRUB_GROTTO_REAR] = Location::Base(RC_SFM_DEKU_SCRUB_GROTTO_REAR, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_SACRED_FOREST_MEADOW, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x07, 0xEE), "Deku Scrub Grotto Rear", RHT_SFM_DEKU_SCRUB_GROTTO_REAR, RG_BUY_RED_POTION_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_REAR)); - locationTable[RC_SFM_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_SFM_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_SACRED_FOREST_MEADOW, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x08, 0xEE), "Deku Scrub Grotto Front", RHT_SFM_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_FRONT)); + locationTable[RC_SFM_DEKU_SCRUB_GROTTO_REAR] = Location::Base(RC_SFM_DEKU_SCRUB_GROTTO_REAR, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_SACRED_FOREST_MEADOW, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x07, 0xEE), "Deku Scrub Grotto Rear", RHT_SFM_DEKU_SCRUB_GROTTO_REAR, RG_BUY_RED_POTION_40, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_REAR), false, 40); + locationTable[RC_SFM_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_SFM_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_SACRED_FOREST_MEADOW, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x08, 0xEE), "Deku Scrub Grotto Front", RHT_SFM_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_FRONT), false, 40); // Hyrule Field locationTable[RC_HF_SOUTHEAST_GROTTO_CHEST] = Location::Chest(RC_HF_SOUTHEAST_GROTTO_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_HYRULE_FIELD, ACTOR_EN_BOX, SCENE_GROTTOS, 22978, 0x02, "Southeast Grotto Chest", RHT_HF_SOUTHEAST_GROTTO_CHEST, RG_RED_RUPEE); locationTable[RC_HF_OPEN_GROTTO_CHEST] = Location::Chest(RC_HF_OPEN_GROTTO_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_HYRULE_FIELD, ACTOR_EN_BOX, SCENE_GROTTOS, 22947, 0x03, "Open Grotto Chest", RHT_HF_OPEN_GROTTO_CHEST, RG_BLUE_RUPEE); locationTable[RC_HF_NEAR_MARKET_GROTTO_CHEST] = Location::Chest(RC_HF_NEAR_MARKET_GROTTO_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_HYRULE_FIELD, ACTOR_EN_BOX, SCENE_GROTTOS, 22944, 0x00, "Near Market Grotto Chest", RHT_HF_NEAR_MARKET_GROTTO_CHEST, RG_BLUE_RUPEE); locationTable[RC_HF_OCARINA_OF_TIME_ITEM] = Location::Base(RC_HF_OCARINA_OF_TIME_ITEM, RCQUEST_BOTH, RCTYPE_OCARINA, ACTOR_ID_MAX, SCENE_HYRULE_FIELD, 0x00, "Ocarina of Time Item", RHT_HF_OCARINA_OF_TIME_ITEM, RG_PROGRESSIVE_OCARINA, SpoilerCollectionCheck::EventChkInf(0x43)); locationTable[RC_HF_TEKTITE_GROTTO_FREESTANDING_POH] = Location::Collectable(RC_HF_TEKTITE_GROTTO_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_HYRULE_FIELD, ACTOR_EN_ITEM00, SCENE_GROTTOS, 262, 0x01, "Tektite Grotto Freestanding PoH", RHT_HF_TEKTITE_GROTTO_FREESTANDING_POH, RG_PIECE_OF_HEART, true); - locationTable[RC_HF_DEKU_SCRUB_GROTTO] = Location::Base(RC_HF_DEKU_SCRUB_GROTTO, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_HYRULE_FIELD, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x02, 0xE6), "Deku Scrub Grotto", RHT_HF_DEKU_SCRUB_GROTTO, RG_PIECE_OF_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO), true); + locationTable[RC_HF_DEKU_SCRUB_GROTTO] = Location::Base(RC_HF_DEKU_SCRUB_GROTTO, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_HYRULE_FIELD, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x02, 0xE6), "Deku Scrub Grotto", RHT_HF_DEKU_SCRUB_GROTTO, RG_PIECE_OF_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO), true, 10); // Lake Hylia locationTable[RC_LH_CHILD_FISHING] = Location::Base(RC_LH_CHILD_FISHING, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_FISHING_POND, 0x00, "Child Fishing", RHT_LH_CHILD_FISHING, RG_PIECE_OF_HEART, SpoilerCollectionCheck::RandomizerInf(RAND_INF_CHILD_FISHING), true); locationTable[RC_LH_ADULT_FISHING] = Location::Base(RC_LH_ADULT_FISHING, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_FISHING_POND, 0x00, "Adult Fishing", RHT_LH_ADULT_FISHING, RG_PROGRESSIVE_SCALE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_ADULT_FISHING), true); @@ -165,16 +175,16 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_LH_UNDERWATER_ITEM] = Location::Base(RC_LH_UNDERWATER_ITEM, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_LAKE_HYLIA, 0x00, "Underwater Item", RHT_LH_UNDERWATER_ITEM, RG_RUTOS_LETTER, SpoilerCollectionCheck::EventChkInf(0x31), true); locationTable[RC_LH_SUN] = Location::Base(RC_LH_SUN, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_LAKE_HYLIA, 0x00, "Sun", RHT_LH_SUN, RG_FIRE_ARROWS, SpoilerCollectionCheck::Chest(0x57, 0x1F), true); locationTable[RC_LH_FREESTANDING_POH] = Location::Collectable(RC_LH_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_LAKE_HYLIA, 7686, 0x1E, "Freestanding PoH", RHT_LH_FREESTANDING_POH, RG_PIECE_OF_HEART, true); - locationTable[RC_LH_DEKU_SCRUB_GROTTO_LEFT] = Location::Base(RC_LH_DEKU_SCRUB_GROTTO_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LAKE_HYLIA, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x00, 0xEF), "Deku Scrub Grotto Left", RHT_LH_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_LEFT)); - locationTable[RC_LH_DEKU_SCRUB_GROTTO_RIGHT] = Location::Base(RC_LH_DEKU_SCRUB_GROTTO_RIGHT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LAKE_HYLIA, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x05, 0xEF), "Deku Scrub Grotto Right", RHT_LH_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_RIGHT)); - locationTable[RC_LH_DEKU_SCRUB_GROTTO_CENTER] = Location::Base(RC_LH_DEKU_SCRUB_GROTTO_CENTER, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LAKE_HYLIA, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03, 0xEF), "Deku Scrub Grotto Center", RHT_LH_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_CENTER)); + locationTable[RC_LH_DEKU_SCRUB_GROTTO_LEFT] = Location::Base(RC_LH_DEKU_SCRUB_GROTTO_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LAKE_HYLIA, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x00, 0xEF), "Deku Scrub Grotto Left", RHT_LH_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_LEFT), false, 20); + locationTable[RC_LH_DEKU_SCRUB_GROTTO_RIGHT] = Location::Base(RC_LH_DEKU_SCRUB_GROTTO_RIGHT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LAKE_HYLIA, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x05, 0xEF), "Deku Scrub Grotto Right", RHT_LH_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_RIGHT), false, 40); + locationTable[RC_LH_DEKU_SCRUB_GROTTO_CENTER] = Location::Base(RC_LH_DEKU_SCRUB_GROTTO_CENTER, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LAKE_HYLIA, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03, 0xEF), "Deku Scrub Grotto Center", RHT_LH_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_CENTER), false, 40); // Gerudo Valley locationTable[RC_GV_CHEST] = Location::Chest(RC_GV_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_GERUDO_VALLEY, 23200, 0x00, "Chest", RHT_GV_CHEST, RG_PURPLE_RUPEE); locationTable[RC_GV_TRADE_SAW] = Location::Base(RC_GV_TRADE_SAW, RCQUEST_BOTH, RCTYPE_ADULT_TRADE, ACTOR_ID_MAX, SCENE_GERUDO_VALLEY, 0x00, "Trade Saw", RHT_GV_TRADE_SAW, RG_BROKEN_SWORD, SpoilerCollectionCheck::RandomizerInf(RAND_INF_ADULT_TRADES_GV_TRADE_SAW), true); locationTable[RC_GV_WATERFALL_FREESTANDING_POH] = Location::Collectable(RC_GV_WATERFALL_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_GERUDO_VALLEY, 262, 0x01, "Waterfall Freestanding PoH", RHT_GV_WATERFALL_FREESTANDING_POH, RG_PIECE_OF_HEART, true); locationTable[RC_GV_CRATE_FREESTANDING_POH] = Location::Collectable(RC_GV_CRATE_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_GERUDO_VALLEY, 518, 0x02, "Crate Freestanding PoH", RHT_GV_CRATE_FREESTANDING_POH, RG_PIECE_OF_HEART, true); - locationTable[RC_GV_DEKU_SCRUB_GROTTO_REAR] = Location::Base(RC_GV_DEKU_SCRUB_GROTTO_REAR, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GERUDO_VALLEY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x07, 0xF0), "Deku Scrub Grotto Rear", RHT_GV_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_REAR)); - locationTable[RC_GV_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_GV_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GERUDO_VALLEY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x08, 0xF0), "Deku Scrub Grotto Front", RHT_GV_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_FRONT)); + locationTable[RC_GV_DEKU_SCRUB_GROTTO_REAR] = Location::Base(RC_GV_DEKU_SCRUB_GROTTO_REAR, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GERUDO_VALLEY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x07, 0xF0), "Deku Scrub Grotto Rear", RHT_GV_DEKU_SCRUB_GROTTO_REAR, RG_BUY_RED_POTION_40, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_REAR), false, 40); + locationTable[RC_GV_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_GV_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GERUDO_VALLEY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x08, 0xF0), "Deku Scrub Grotto Front", RHT_GV_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_FRONT), false, 40); // Gerudo Fortress locationTable[RC_GF_CHEST] = Location::Chest(RC_GF_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_GERUDOS_FORTRESS, 1984, 0x00, "Chest", RHT_GF_CHEST, RG_PIECE_OF_HEART, true); locationTable[RC_GF_HBA_1000_POINTS] = Location::Base(RC_GF_HBA_1000_POINTS, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_GERUDOS_FORTRESS, 0x00, "GF HBA 1000 Points", RHT_GF_HBA_1000_POINTS, RG_PIECE_OF_HEART, SpoilerCollectionCheck::InfTable(INFTABLE_190), true); @@ -190,8 +200,8 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_WASTELAND_BOMBCHU_SALESMAN] = Location::Base(RC_WASTELAND_BOMBCHU_SALESMAN, RCQUEST_BOTH, RCTYPE_MERCHANT, RCAREA_WASTELAND, ACTOR_ID_MAX, SCENE_HAUNTED_WASTELAND, 0x00, "Carpet Salesman", RHT_WASTELAND_BOMBCHU_SALESMAN, RG_BUY_BOMBCHUS_10, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN)); // Desert Colossus locationTable[RC_COLOSSUS_FREESTANDING_POH] = Location::Collectable(RC_COLOSSUS_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_DESERT_COLOSSUS, 3334, 0x0D, "Freestanding PoH", RHT_COLOSSUS_FREESTANDING_POH, RG_PIECE_OF_HEART, true); - locationTable[RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR] = Location::Base(RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_DESERT_COLOSSUS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x07, 0xFD), "Deku Scrub Grotto Rear", RHT_COLOSSUS_DEKU_SCRUB_GROTTO_REAR, RG_BUY_RED_POTION_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_REAR)); - locationTable[RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_DESERT_COLOSSUS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x08, 0xFD), "Deku Scrub Grotto Front", RHT_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT)); + locationTable[RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR] = Location::Base(RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_DESERT_COLOSSUS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x07, 0xFD), "Deku Scrub Grotto Rear", RHT_COLOSSUS_DEKU_SCRUB_GROTTO_REAR, RG_BUY_RED_POTION_40, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_REAR), false, 40); + locationTable[RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_DESERT_COLOSSUS, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x08, 0xFD), "Deku Scrub Grotto Front", RHT_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT), false, 40); // Market locationTable[RC_MARKET_TREASURE_CHEST_GAME_REWARD] = Location::Chest(RC_MARKET_TREASURE_CHEST_GAME_REWARD, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_TREASURE_BOX_SHOP, 0x00, "Treasure Chest Game Reward", RHT_MARKET_TREASURE_CHEST_GAME_REWARD, RG_TREASURE_GAME_HEART, SpoilerCollectionCheck::ItemGetInf(27), true); locationTable[RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE] = Location::Base(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_BOMBCHU_BOWLING_ALLEY, 0x00, "Bombchu Bowling First Prize", RHT_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, RG_PROGRESSIVE_BOMB_BAG, SpoilerCollectionCheck::ItemGetInf(17), true); @@ -224,7 +234,7 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_KAK_MAN_ON_ROOF] = Location::Base(RC_KAK_MAN_ON_ROOF, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_KAKARIKO_VILLAGE, 0x00, "Man on Roof", RHT_KAK_MAN_ON_ROOF, RG_PIECE_OF_HEART, SpoilerCollectionCheck::ItemGetInf(21), true); locationTable[RC_KAK_SHOOTING_GALLERY_REWARD] = Location::Base(RC_KAK_SHOOTING_GALLERY_REWARD, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_KAKARIKO_VILLAGE, ACTOR_ID_MAX, SCENE_SHOOTING_GALLERY, 0x00, "Shooting Gallery Reward", RHT_KAK_SHOOTING_GALLERY_REWARD, RG_PROGRESSIVE_BOW, SpoilerCollectionCheck::ItemGetInf(ITEMGETINF_0E), true); locationTable[RC_KAK_TRADE_ODD_MUSHROOM] = Location::Base(RC_KAK_TRADE_ODD_MUSHROOM, RCQUEST_BOTH, RCTYPE_ADULT_TRADE, ACTOR_ID_MAX, SCENE_POTION_SHOP_GRANNY, 0x00, "Trade Odd Mushroom", RHT_KAK_TRADE_ODD_MUSHROOM, RG_ODD_POTION, SpoilerCollectionCheck::ItemGetInf(48), true); - locationTable[RC_KAK_GRANNYS_SHOP] = Location::Base(RC_KAK_GRANNYS_SHOP, RCQUEST_BOTH, RCTYPE_MERCHANT, ACTOR_ID_MAX, SCENE_POTION_SHOP_GRANNY, 0x00, "Granny's Shop", RHT_KAK_GRANNYS_SHOP, RG_BUY_BLUE_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP), true); + locationTable[RC_KAK_GRANNYS_SHOP] = Location::Base(RC_KAK_GRANNYS_SHOP, RCQUEST_BOTH, RCTYPE_MERCHANT, ACTOR_ID_MAX, SCENE_POTION_SHOP_GRANNY, 0x00, "Granny's Shop", RHT_KAK_GRANNYS_SHOP, RG_BUY_BLUE_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP), true, 100); locationTable[RC_KAK_ANJU_AS_ADULT] = Location::Base(RC_KAK_ANJU_AS_ADULT, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_KAKARIKO_VILLAGE, 0x00, "Anju as Adult", RHT_KAK_ANJU_AS_ADULT, RG_CLAIM_CHECK, SpoilerCollectionCheck::ItemGetInf(44), true); locationTable[RC_KAK_ANJU_AS_CHILD] = Location::Base(RC_KAK_ANJU_AS_CHILD, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_KAKARIKO_VILLAGE, 0x00, "Anju as Child", RHT_KAK_ANJU_AS_CHILD, RG_EMPTY_BOTTLE, SpoilerCollectionCheck::ItemGetInf(12), true); locationTable[RC_KAK_TRADE_POCKET_CUCCO] = Location::Base(RC_KAK_TRADE_POCKET_CUCCO, RCQUEST_BOTH, RCTYPE_ADULT_TRADE, ACTOR_ID_MAX, SCENE_KAKARIKO_VILLAGE, 0x00, "Trade Pocket Cucco", RHT_KAK_TRADE_POCKET_CUCCO, RG_COJIRO, SpoilerCollectionCheck::ItemGetInf(46), true); @@ -253,21 +263,21 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_GC_ROLLING_GORON_AS_ADULT] = Location::Base(RC_GC_ROLLING_GORON_AS_ADULT, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_GORON_CITY, 0x00, "Rolling Goron as Adult", RHT_GC_ROLLING_GORON_AS_ADULT, RG_GORON_TUNIC, SpoilerCollectionCheck::InfTable(INFTABLE_GORON_CITY_DOORS_UNLOCKED), true); locationTable[RC_GC_DARUNIAS_JOY] = Location::Base(RC_GC_DARUNIAS_JOY, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_GORON_CITY, 0x00, "Darunias Joy", RHT_GC_DARUNIAS_JOY, RG_PROGRESSIVE_STRENGTH, SpoilerCollectionCheck::RandomizerInf(RAND_INF_DARUNIAS_JOY), true); locationTable[RC_GC_POT_FREESTANDING_POH] = Location::Collectable(RC_GC_POT_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_GORON_CITY, 7942, 0x1F, "Pot Freestanding PoH", RHT_GC_POT_FREESTANDING_POH, RG_PIECE_OF_HEART, true); - locationTable[RC_GC_DEKU_SCRUB_GROTTO_LEFT] = Location::Base(RC_GC_DEKU_SCRUB_GROTTO_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GORON_CITY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x00, 0xFB), "Deku Scrub Grotto Left", RHT_GC_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_LEFT)); - locationTable[RC_GC_DEKU_SCRUB_GROTTO_RIGHT] = Location::Base(RC_GC_DEKU_SCRUB_GROTTO_RIGHT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GORON_CITY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x05, 0xFB), "Deku Scrub Grotto Right", RHT_GC_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_RIGHT)); - locationTable[RC_GC_DEKU_SCRUB_GROTTO_CENTER] = Location::Base(RC_GC_DEKU_SCRUB_GROTTO_CENTER, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GORON_CITY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03, 0xFB), "Deku Scrub Grotto Center", RHT_GC_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_ARROWS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_CENTER)); - locationTable[RC_GC_MEDIGORON] = Location::Base(RC_GC_MEDIGORON, RCQUEST_BOTH, RCTYPE_MERCHANT, ACTOR_ID_MAX, SCENE_GORON_CITY, 0x00, "Medigoron", RHT_GC_MEDIGORON, RG_GIANTS_KNIFE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MERCHANTS_MEDIGORON)); + locationTable[RC_GC_DEKU_SCRUB_GROTTO_LEFT] = Location::Base(RC_GC_DEKU_SCRUB_GROTTO_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GORON_CITY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x00, 0xFB), "Deku Scrub Grotto Left", RHT_GC_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_LEFT), false, 20); + locationTable[RC_GC_DEKU_SCRUB_GROTTO_RIGHT] = Location::Base(RC_GC_DEKU_SCRUB_GROTTO_RIGHT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GORON_CITY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x05, 0xFB), "Deku Scrub Grotto Right", RHT_GC_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_RIGHT), false, 40); + locationTable[RC_GC_DEKU_SCRUB_GROTTO_CENTER] = Location::Base(RC_GC_DEKU_SCRUB_GROTTO_CENTER, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_GORON_CITY, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03, 0xFB), "Deku Scrub Grotto Center", RHT_GC_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_ARROWS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_CENTER), false, 70); + locationTable[RC_GC_MEDIGORON] = Location::Base(RC_GC_MEDIGORON, RCQUEST_BOTH, RCTYPE_MERCHANT, ACTOR_ID_MAX, SCENE_GORON_CITY, 0x00, "Medigoron", RHT_GC_MEDIGORON, RG_GIANTS_KNIFE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MERCHANTS_MEDIGORON), false, 200); // Death Mountain Crater locationTable[RC_DMC_UPPER_GROTTO_CHEST] = Location::Chest(RC_DMC_UPPER_GROTTO_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_DEATH_MOUNTAIN_CRATER, ACTOR_EN_BOX, SCENE_GROTTOS, 23802, 0x1A, "Upper Grotto Chest", RHT_DMC_UPPER_GROTTO_CHEST, RG_BOMBS_20); locationTable[RC_DMC_WALL_FREESTANDING_POH] = Location::Collectable(RC_DMC_WALL_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_DEATH_MOUNTAIN_CRATER, 518, 0x02, "Wall Freestanding PoH", RHT_DMC_WALL_FREESTANDING_POH, RG_PIECE_OF_HEART, true); locationTable[RC_DMC_VOLCANO_FREESTANDING_POH] = Location::Collectable(RC_DMC_VOLCANO_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_DEATH_MOUNTAIN_CRATER, 2054, 0x08, "Volcano Freestanding PoH", RHT_DMC_WALL_FREESTANDING_POH, RG_PIECE_OF_HEART, true); - locationTable[RC_DMC_DEKU_SCRUB] = Location::Base(RC_DMC_DEKU_SCRUB, RCQUEST_BOTH, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DEATH_MOUNTAIN_CRATER, 0x05, "Deku Scrub", RHT_DMC_DEKU_SCRUB, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB)); - locationTable[RC_DMC_DEKU_SCRUB_GROTTO_LEFT] = Location::Base(RC_DMC_DEKU_SCRUB_GROTTO_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_DEATH_MOUNTAIN_CRATER, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x00, 0xF9), "Deku Scrub Grotto Left", RHT_DMC_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_LEFT)); - locationTable[RC_DMC_DEKU_SCRUB_GROTTO_RIGHT] = Location::Base(RC_DMC_DEKU_SCRUB_GROTTO_RIGHT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_DEATH_MOUNTAIN_CRATER, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x05, 0xF9), "Deku Scrub Grotto Right", RHT_DMC_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_RIGHT)); - locationTable[RC_DMC_DEKU_SCRUB_GROTTO_CENTER] = Location::Base(RC_DMC_DEKU_SCRUB_GROTTO_CENTER, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_DEATH_MOUNTAIN_CRATER, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03, 0xF9), "Deku Scrub Grotto Center", RHT_DMC_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_ARROWS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_CENTER)); + locationTable[RC_DMC_DEKU_SCRUB] = Location::Base(RC_DMC_DEKU_SCRUB, RCQUEST_BOTH, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DEATH_MOUNTAIN_CRATER, 0x05, "Deku Scrub", RHT_DMC_DEKU_SCRUB, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB), false, 40); + locationTable[RC_DMC_DEKU_SCRUB_GROTTO_LEFT] = Location::Base(RC_DMC_DEKU_SCRUB_GROTTO_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_DEATH_MOUNTAIN_CRATER, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x00, 0xF9), "Deku Scrub Grotto Left", RHT_DMC_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_LEFT), false, 20); + locationTable[RC_DMC_DEKU_SCRUB_GROTTO_RIGHT] = Location::Base(RC_DMC_DEKU_SCRUB_GROTTO_RIGHT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_DEATH_MOUNTAIN_CRATER, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x05, 0xF9), "Deku Scrub Grotto Right", RHT_DMC_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_RIGHT), false, 40); + locationTable[RC_DMC_DEKU_SCRUB_GROTTO_CENTER] = Location::Base(RC_DMC_DEKU_SCRUB_GROTTO_CENTER, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_DEATH_MOUNTAIN_CRATER, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03, 0xF9), "Deku Scrub Grotto Center", RHT_DMC_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_ARROWS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_CENTER), false, 70); // Zoras River - locationTable[RC_ZR_OPEN_GROTTO_CHEST] = Location::Chest(RC_ZR_OPEN_GROTTO_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_ZORAS_RIVER, ACTOR_EN_BOX, SCENE_GROTTOS, 22985, 0x09, "Open Grotto Chest", RHT_ZR_OPEN_GROTTO_CHEST, RG_RED_RUPEE); - locationTable[RC_ZR_MAGIC_BEAN_SALESMAN] = Location::Base(RC_ZR_MAGIC_BEAN_SALESMAN, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_ZORAS_RIVER, 0x00, "Magic Bean Salesman", RHT_ZR_MAGIC_BEAN_SALESMAN, RG_MAGIC_BEAN, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MERCHANTS_MAGIC_BEAN_SALESMAN), true); + locationTable[RC_ZR_OPEN_GROTTO_CHEST] = Location::Chest(RC_ZR_OPEN_GROTTO_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_ZORAS_RIVER, ACTOR_EN_BOX, SCENE_GROTTOS, 22985, 0x09, "Open Grotto Chest", RHT_ZR_OPEN_GROTTO_CHEST, RG_RED_RUPEE); + locationTable[RC_ZR_MAGIC_BEAN_SALESMAN] = Location::Base(RC_ZR_MAGIC_BEAN_SALESMAN, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_ZORAS_RIVER, 0x00, "Magic Bean Salesman", RHT_ZR_MAGIC_BEAN_SALESMAN, RG_MAGIC_BEAN, SpoilerCollectionCheck::RandomizerInf(RAND_INF_MERCHANTS_MAGIC_BEAN_SALESMAN), true, 60); locationTable[RC_ZR_FROGS_ZELDAS_LULLABY] = Location::Base(RC_ZR_FROGS_ZELDAS_LULLABY, RCQUEST_BOTH, RCTYPE_FROG_SONG, ACTOR_EN_FR, SCENE_ZORAS_RIVER, 0x00, "Frogs Zelda's Lullaby", RHT_ZR_FROGS_ZELDAS_LULLABY, RG_PURPLE_RUPEE, SpoilerCollectionCheck::EventChkInf(0xD1)); locationTable[RC_ZR_FROGS_EPONAS_SONG] = Location::Base(RC_ZR_FROGS_EPONAS_SONG, RCQUEST_BOTH, RCTYPE_FROG_SONG, ACTOR_EN_FR, SCENE_ZORAS_RIVER, 0x00, "Frogs Epona's Song", RHT_ZR_FROGS_EPONAS_SONG, RG_PURPLE_RUPEE, SpoilerCollectionCheck::EventChkInf(0xD2)); locationTable[RC_ZR_FROGS_SARIAS_SONG] = Location::Base(RC_ZR_FROGS_SARIAS_SONG, RCQUEST_BOTH, RCTYPE_FROG_SONG, ACTOR_EN_FR, SCENE_ZORAS_RIVER, 0x00, "Frogs Saria's Song", RHT_ZR_FROGS_SARIAS_SONG, RG_PURPLE_RUPEE, SpoilerCollectionCheck::EventChkInf(0xD4)); @@ -277,8 +287,8 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_ZR_FROGS_OCARINA_GAME] = Location::Base(RC_ZR_FROGS_OCARINA_GAME, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_FR, SCENE_ZORAS_RIVER, 0x00, "Frogs Ocarina Game", RHT_ZR_FROGS_OCARINA_GAME, RG_PIECE_OF_HEART, SpoilerCollectionCheck::EventChkInf(0xD0), true); locationTable[RC_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH] = Location::Collectable(RC_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_ZORAS_RIVER, 1030, 0x04, "Near Open Grotto Freestanding PoH", RHT_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, RG_PIECE_OF_HEART, true); locationTable[RC_ZR_NEAR_DOMAIN_FREESTANDING_POH] = Location::Collectable(RC_ZR_NEAR_DOMAIN_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_ZORAS_RIVER, 2822, 0x0B, "Near Domain Freestanding PoH", RHT_ZR_NEAR_DOMAIN_FREESTANDING_POH, RG_PIECE_OF_HEART, true); - locationTable[RC_ZR_DEKU_SCRUB_GROTTO_REAR] = Location::Base(RC_ZR_DEKU_SCRUB_GROTTO_REAR, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_ZORAS_RIVER, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x07, 0xEB), "Deku Scrub Grotto Rear", RHT_ZR_DEKU_SCRUB_GROTTO_REAR, RG_BUY_RED_POTION_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_REAR)); - locationTable[RC_ZR_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_ZR_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_ZORAS_RIVER, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x08, 0xEB), "Deku Scrub Grotto Front", RHT_ZR_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_FRONT)); + locationTable[RC_ZR_DEKU_SCRUB_GROTTO_REAR] = Location::Base(RC_ZR_DEKU_SCRUB_GROTTO_REAR, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_ZORAS_RIVER, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x07, 0xEB), "Deku Scrub Grotto Rear", RHT_ZR_DEKU_SCRUB_GROTTO_REAR, RG_BUY_RED_POTION_40, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_REAR), false, 40); + locationTable[RC_ZR_DEKU_SCRUB_GROTTO_FRONT] = Location::Base(RC_ZR_DEKU_SCRUB_GROTTO_FRONT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_ZORAS_RIVER, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x08, 0xEB), "Deku Scrub Grotto Front", RHT_ZR_DEKU_SCRUB_GROTTO_FRONT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_FRONT), false, 40); // Zoras Domain locationTable[RC_ZD_CHEST] = Location::Chest(RC_ZD_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_ZORAS_DOMAIN, -18496, 0x00, "Chest", RHT_ZD_CHEST, RG_PIECE_OF_HEART, true); locationTable[RC_ZD_DIVING_MINIGAME] = Location::Base(RC_ZD_DIVING_MINIGAME, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_ZORAS_DOMAIN, 0x00, "Diving Minigame", RHT_ZD_DIVING_MINIGAME, RG_PROGRESSIVE_SCALE, SpoilerCollectionCheck::EventChkInf(0x38), true); @@ -290,9 +300,9 @@ void Rando::StaticData::InitLocationTable() { // // Lon Lon Ranch locationTable[RC_LLR_TALONS_CHICKENS] = Location::Base(RC_LLR_TALONS_CHICKENS, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_ID_MAX, SCENE_LON_LON_BUILDINGS, 0x00, "Talons Chickens", RHT_LLR_TALONS_CHICKENS, RG_BOTTLE_WITH_MILK, SpoilerCollectionCheck::ItemGetInf(2), true); locationTable[RC_LLR_FREESTANDING_POH] = Location::Collectable(RC_LLR_FREESTANDING_POH, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_ITEM00, SCENE_LON_LON_BUILDINGS, 262, 0x01, "Freestanding PoH", RHT_LLR_FREESTANDING_POH, RG_PIECE_OF_HEART, true); - locationTable[RC_LLR_DEKU_SCRUB_GROTTO_LEFT] = Location::Base(RC_LLR_DEKU_SCRUB_GROTTO_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LON_LON_RANCH, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x00, 0xFC), "Deku Scrub Grotto Left", RHT_LLR_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_LEFT)); - locationTable[RC_LLR_DEKU_SCRUB_GROTTO_RIGHT] = Location::Base(RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LON_LON_RANCH, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x05, 0xFC), "Deku Scrub Grotto Right", RHT_LLR_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_RIGHT)); - locationTable[RC_LLR_DEKU_SCRUB_GROTTO_CENTER] = Location::Base(RC_LLR_DEKU_SCRUB_GROTTO_CENTER, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LON_LON_RANCH, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03, 0xFC), "Deku Scrub Grotto Center", RHT_LLR_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_CENTER)); + locationTable[RC_LLR_DEKU_SCRUB_GROTTO_LEFT] = Location::Base(RC_LLR_DEKU_SCRUB_GROTTO_LEFT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LON_LON_RANCH, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x00, 0xFC), "Deku Scrub Grotto Left", RHT_LLR_DEKU_SCRUB_GROTTO_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_LEFT), false, 20); + locationTable[RC_LLR_DEKU_SCRUB_GROTTO_RIGHT] = Location::Base(RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LON_LON_RANCH, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x05, 0xFC), "Deku Scrub Grotto Right", RHT_LLR_DEKU_SCRUB_GROTTO_RIGHT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_RIGHT), false, 40); + locationTable[RC_LLR_DEKU_SCRUB_GROTTO_CENTER] = Location::Base(RC_LLR_DEKU_SCRUB_GROTTO_CENTER, RCQUEST_BOTH, RCTYPE_SCRUB, RCAREA_LON_LON_RANCH, ACTOR_EN_DNS, SCENE_GROTTOS, TWO_ACTOR_PARAMS(0x03, 0xFC), "Deku Scrub Grotto Center", RHT_LLR_DEKU_SCRUB_GROTTO_CENTER, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_CENTER), false, 40); // Dungeons // Deku Tree Vanilla @@ -310,7 +320,7 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_DEKU_TREE_MQ_BASEMENT_CHEST] = Location::Chest(RC_DEKU_TREE_MQ_BASEMENT_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DEKU_TREE, -31452, 0x04, "MQ Basement Chest", RHT_DEKU_TREE_MQ_BASEMENT_CHEST, RG_DEKU_SHIELD); locationTable[RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST] = Location::Chest(RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DEKU_TREE, 22789, 0x05, "MQ Before Spinning Log Chest", RHT_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, RG_RECOVERY_HEART); locationTable[RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST] = Location::Chest(RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DEKU_TREE, 23200, 0x00, "MQ After Spinning Log Chest", RHT_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, RG_PURPLE_RUPEE); - locationTable[RC_DEKU_TREE_MQ_DEKU_SCRUB] = Location::Base(RC_DEKU_TREE_MQ_DEKU_SCRUB, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DEKU_TREE, 0x04, "MQ Deku Scrub", RHT_DEKU_TREE_MQ_DEKU_SCRUB, RG_BUY_DEKU_SHIELD, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DEKU_TREE_MQ_DEKU_SCRUB)); + locationTable[RC_DEKU_TREE_MQ_DEKU_SCRUB] = Location::Base(RC_DEKU_TREE_MQ_DEKU_SCRUB, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DEKU_TREE, 0x04, "MQ Deku Scrub", RHT_DEKU_TREE_MQ_DEKU_SCRUB, RG_BUY_DEKU_SHIELD, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DEKU_TREE_MQ_DEKU_SCRUB), false, 50); // Dodongo's Cavern Shared locationTable[RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST] = Location::Chest(RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST, RCQUEST_BOTH, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DODONGOS_CAVERN_BOSS, 20512, 0x00, "Boss Room Chest", RHT_DODONGOS_CAVERN_BOSS_ROOM_CHEST, RG_BOMBS_5); @@ -320,10 +330,10 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST] = Location::Chest(RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, RCQUEST_VANILLA, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DODONGOS_CAVERN, 22982, 0x06, "Bomb Flower Platform Chest", RHT_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, RG_RED_RUPEE); locationTable[RC_DODONGOS_CAVERN_BOMB_BAG_CHEST] = Location::Chest(RC_DODONGOS_CAVERN_BOMB_BAG_CHEST, RCQUEST_VANILLA, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DODONGOS_CAVERN, 1604, 0x04, "Bomb Bag Chest", RHT_DODONGOS_CAVERN_BOMB_BAG_CHEST, RG_PROGRESSIVE_BOMB_BAG, true); locationTable[RC_DODONGOS_CAVERN_END_OF_BRIDGE_CHEST] = Location::Chest(RC_DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, RCQUEST_VANILLA, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DODONGOS_CAVERN, 21802, 0x0A, "End Of Bridge Chest", RHT_DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, RG_DEKU_SHIELD); - locationTable[RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT] = Location::Base(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x00, "Deku Scrub Near Bomb Bag Left", RHT_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT)); - locationTable[RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS] = Location::Base(RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x01, "Deku Scrub Side Room Near Dodongos", RHT_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, RG_BUY_DEKU_STICK_1, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS)); - locationTable[RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT] = Location::Base(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x03, "Deku Scrub Near Bomb Bag Right", RHT_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT)); - locationTable[RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY] = Location::Base(RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x04, "Deku Scrub Lobby", RHT_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, RG_BUY_DEKU_SHIELD, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY)); + locationTable[RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT] = Location::Base(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x00, "Deku Scrub Near Bomb Bag Left", RHT_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT), false, 20); + locationTable[RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS] = Location::Base(RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x01, "Deku Scrub Side Room Near Dodongos", RHT_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, RG_BUY_DEKU_STICK_1, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS), false, 15); + locationTable[RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT] = Location::Base(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x03, "Deku Scrub Near Bomb Bag Right", RHT_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT), false, 40); + locationTable[RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY] = Location::Base(RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x04, "Deku Scrub Lobby", RHT_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, RG_BUY_DEKU_SHIELD, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY), false, 50); // Dodongo's Cavern MQ locationTable[RC_DODONGOS_CAVERN_MQ_MAP_CHEST] = Location::Chest(RC_DODONGOS_CAVERN_MQ_MAP_CHEST, RCQUEST_MQ, RCTYPE_MAP, ACTOR_EN_BOX, SCENE_DODONGOS_CAVERN, 2080, 0x00, "MQ Map Chest", RHT_DODONGOS_CAVERN_MQ_MAP_CHEST, RG_DODONGOS_CAVERN_MAP, true); locationTable[RC_DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST] = Location::Chest(RC_DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DODONGOS_CAVERN, 1604, 0x04, "MQ Bomb Bag Chest", RHT_DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, RG_PROGRESSIVE_BOMB_BAG, true); @@ -331,16 +341,16 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST] = Location::Chest(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DODONGOS_CAVERN, 29986, 0x02, "MQ Larvae Room Chest", RHT_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, RG_DEKU_SHIELD); locationTable[RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST] = Location::Chest(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DODONGOS_CAVERN, 22947, 0x03, "MQ Torch Puzzle Room Chest", RHT_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, RG_BLUE_RUPEE); locationTable[RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST] = Location::Chest(RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_DODONGOS_CAVERN, 21825, 0x01, "MQ Under Grave Chest", RHT_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, RG_HYLIAN_SHIELD); - locationTable[RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR] = Location::Base(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x01, "MQ Deku Scrub Lobby Rear", RHT_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, RG_BUY_DEKU_STICK_1, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR)); - locationTable[RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT] = Location::Base(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x03, "MQ Deku Scrub Lobby Front", RHT_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT)); - locationTable[RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE] = Location::Base(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x04, "MQ Deku Scrub Staircase", RHT_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, RG_BUY_DEKU_SHIELD, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE)); - locationTable[RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS] = Location::Base(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x07, "MQ Deku Scrub Side Room Near Lower Lizalfos", RHT_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, RG_BUY_RED_POTION_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS)); + locationTable[RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR] = Location::Base(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x01, "MQ Deku Scrub Lobby Rear", RHT_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, RG_BUY_DEKU_STICK_1, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR), false, 15); + locationTable[RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT] = Location::Base(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x03, "MQ Deku Scrub Lobby Front", RHT_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT), false, 40); + locationTable[RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE] = Location::Base(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x04, "MQ Deku Scrub Staircase", RHT_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, RG_BUY_DEKU_SHIELD, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE), false, 50); + locationTable[RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS] = Location::Base(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_DODONGOS_CAVERN, 0x07, "MQ Deku Scrub Side Room Near Lower Lizalfos", RHT_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, RG_BUY_RED_POTION_40, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS), false, 40); // Jabu-Jabu's Belly Vanilla locationTable[RC_JABU_JABUS_BELLY_MAP_CHEST] = Location::Chest(RC_JABU_JABUS_BELLY_MAP_CHEST, RCQUEST_VANILLA, RCTYPE_MAP, ACTOR_EN_BOX, SCENE_JABU_JABU, 6178, 0x02, "Map Chest", RHT_JABU_JABUS_BELLY_MAP_CHEST, RG_JABU_JABUS_BELLY_MAP, true); locationTable[RC_JABU_JABUS_BELLY_COMPASS_CHEST] = Location::Chest(RC_JABU_JABUS_BELLY_COMPASS_CHEST, RCQUEST_VANILLA, RCTYPE_COMPASS, ACTOR_EN_BOX, SCENE_JABU_JABU, -18428, 0x04, "Compass Chest", RHT_JABU_JABUS_BELLY_COMPASS_CHEST, RG_JABU_JABUS_BELLY_COMPASS, true); locationTable[RC_JABU_JABUS_BELLY_BOOMERANG_CHEST] = Location::Chest(RC_JABU_JABUS_BELLY_BOOMERANG_CHEST, RCQUEST_VANILLA, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_JABU_JABU, 4289, 0x01, "Boomerang Chest", RHT_JABU_JABUS_BELLY_BOOMERANG_CHEST, RG_BOOMERANG, true); - locationTable[RC_JABU_JABUS_BELLY_DEKU_SCRUB] = Location::Base(RC_JABU_JABUS_BELLY_DEKU_SCRUB, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_JABU_JABU, 0x00, "Deku Scrub", RHT_JABU_JABUS_BELLY_DEKU_SCRUB, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_JABU_JABUS_BELLY_DEKU_SCRUB)); + locationTable[RC_JABU_JABUS_BELLY_DEKU_SCRUB] = Location::Base(RC_JABU_JABUS_BELLY_DEKU_SCRUB, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_JABU_JABU, 0x00, "Deku Scrub", RHT_JABU_JABUS_BELLY_DEKU_SCRUB, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_JABU_JABUS_BELLY_DEKU_SCRUB), false, 20); // Jabu-Jabu's Belly MQ locationTable[RC_JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST] = Location::Chest(RC_JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_JABU_JABU, -32699, 0x05, "MQ First Room Side Chest", RHT_JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, RG_DEKU_NUTS_5); locationTable[RC_JABU_JABUS_BELLY_MQ_MAP_CHEST] = Location::Chest(RC_JABU_JABUS_BELLY_MQ_MAP_CHEST, RCQUEST_MQ, RCTYPE_MAP, ACTOR_EN_BOX, SCENE_JABU_JABU, -18397, 0x03, "MQ Map Chest", RHT_JABU_JABUS_BELLY_MQ_MAP_CHEST, RG_JABU_JABUS_BELLY_MAP, true); @@ -606,10 +616,10 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST] = Location::Chest(RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, RCQUEST_VANILLA, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_INSIDE_GANONS_CASTLE, 24463, 0x0F, "Light Trial Third Right Chest", RHT_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, RG_ICE_TRAP); locationTable[RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST] = Location::Chest(RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, RCQUEST_VANILLA, RCTYPE_SMALL_KEY, ACTOR_EN_BOX, SCENE_INSIDE_GANONS_CASTLE, 30800, 0x10, "Light Trial Invisible Enemies Chest", RHT_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, RG_GANONS_CASTLE_SMALL_KEY, true); locationTable[RC_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST] = Location::Chest(RC_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, RCQUEST_VANILLA, RCTYPE_SMALL_KEY, ACTOR_EN_BOX, SCENE_INSIDE_GANONS_CASTLE, -30639, 0x11, "Light Trial Lullaby Chest", RHT_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, RG_GANONS_CASTLE_SMALL_KEY, true); - locationTable[RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT] = Location::Base(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x05, "Deku Scrub Center-Left", RHT_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT)); - locationTable[RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT] = Location::Base(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x03, "Deku Scrub Center-Right", RHT_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, RG_BUY_ARROWS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT)); - locationTable[RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT] = Location::Base(RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x07, "Deku Scrub Right", RHT_GANONS_CASTLE_DEKU_SCRUB_RIGHT, RG_BUY_RED_POTION_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_RIGHT)); - locationTable[RC_GANONS_CASTLE_DEKU_SCRUB_LEFT] = Location::Base(RC_GANONS_CASTLE_DEKU_SCRUB_LEFT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x08, "Deku Scrub Left", RHT_GANONS_CASTLE_DEKU_SCRUB_LEFT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_LEFT)); + locationTable[RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT] = Location::Base(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x05, "Deku Scrub Center-Left", RHT_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT), false, 40); + locationTable[RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT] = Location::Base(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x03, "Deku Scrub Center-Right", RHT_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, RG_BUY_ARROWS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT), false, 70); + locationTable[RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT] = Location::Base(RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x07, "Deku Scrub Right", RHT_GANONS_CASTLE_DEKU_SCRUB_RIGHT, RG_BUY_RED_POTION_40, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_RIGHT), false, 20); + locationTable[RC_GANONS_CASTLE_DEKU_SCRUB_LEFT] = Location::Base(RC_GANONS_CASTLE_DEKU_SCRUB_LEFT, RCQUEST_VANILLA, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x08, "Deku Scrub Left", RHT_GANONS_CASTLE_DEKU_SCRUB_LEFT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_LEFT), false, 40); // Ganon's Castle MQ locationTable[RC_GANONS_CASTLE_MQ_WATER_TRIAL_CHEST] = Location::Chest(RC_GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_INSIDE_GANONS_CASTLE, 22977, 0x01, "MQ Water Trial Chest", RHT_GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, RG_RED_RUPEE); locationTable[RC_GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST] = Location::Chest(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_INSIDE_GANONS_CASTLE, -30398, 0x02, "MQ Forest Trial Eye Switch Chest", RHT_GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, RG_ARROWS_10); @@ -624,11 +634,11 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST] = Location::Chest(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_INSIDE_GANONS_CASTLE, 20586, 0x0A, "MQ Spirit Trial First Chest", RHT_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, RG_BOMBCHU_10); locationTable[RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST] = Location::Chest(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, RCQUEST_MQ, RCTYPE_STANDARD, ACTOR_EN_BOX, SCENE_INSIDE_GANONS_CASTLE, 26964, 0x14, "MQ Spirit Trial Invisible Chest", RHT_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, RG_ARROWS_10); locationTable[RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY] = Location::Collectable(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, RCQUEST_MQ, RCTYPE_SMALL_KEY, ACTOR_EN_ITEM00, SCENE_INSIDE_GANONS_CASTLE, 273, 0x01, "MQ Forest Trial Freestanding Key", RHT_GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, RG_GANONS_CASTLE_SMALL_KEY, true); - locationTable[RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT] = Location::Base(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x00, "MQ Deku Scrub Right", RHT_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT)); - locationTable[RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT] = Location::Base(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x05, "MQ Deku Scrub Center-Left", RHT_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT)); - locationTable[RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER] = Location::Base(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x03, "MQ Deku Scrub Center", RHT_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, RG_BUY_ARROWS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER)); - locationTable[RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT] = Location::Base(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x07, "MQ Deku Scrub Center-Right", RHT_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, RG_BUY_RED_POTION_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT)); - locationTable[RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT] = Location::Base(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x08, "MQ Deku Scrub Left", RHT_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT)); + locationTable[RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT] = Location::Base(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x00, "MQ Deku Scrub Right", RHT_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT), false, 20); + locationTable[RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT] = Location::Base(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x05, "MQ Deku Scrub Center-Left", RHT_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, RG_BUY_BOMBS_535, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT), false, 40); + locationTable[RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER] = Location::Base(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x03, "MQ Deku Scrub Center", RHT_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, RG_BUY_ARROWS_30, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER), false, 70); + locationTable[RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT] = Location::Base(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x07, "MQ Deku Scrub Center-Right", RHT_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, RG_BUY_RED_POTION_40, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT), false, 40); + locationTable[RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT] = Location::Base(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, RCQUEST_MQ, RCTYPE_SCRUB, ACTOR_EN_DNS, SCENE_INSIDE_GANONS_CASTLE, 0x08, "MQ Deku Scrub Left", RHT_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, RG_BUY_GREEN_POTION, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT), false, 40); // Gold Skulltula Tokens @@ -901,78 +911,78 @@ void Rando::StaticData::InitLocationTable() { // 7 5 1 3 -------------------------------*/ // Kokiri Forest - locationTable[RC_KF_SHOP_ITEM_1] = Location::Base(RC_KF_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x00, "Shop Item 1", RHT_KF_SHOP_ITEM_1, RG_BUY_DEKU_SHIELD); - locationTable[RC_KF_SHOP_ITEM_2] = Location::Base(RC_KF_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x01, "Shop Item 2", RHT_KF_SHOP_ITEM_2, RG_BUY_DEKU_NUTS_5); - locationTable[RC_KF_SHOP_ITEM_3] = Location::Base(RC_KF_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x02, "Shop Item 3", RHT_KF_SHOP_ITEM_3, RG_BUY_DEKU_NUTS_10); - locationTable[RC_KF_SHOP_ITEM_4] = Location::Base(RC_KF_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x03, "Shop Item 4", RHT_KF_SHOP_ITEM_4, RG_BUY_DEKU_STICK_1); - locationTable[RC_KF_SHOP_ITEM_5] = Location::Base(RC_KF_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x04, "Shop Item 5", RHT_KF_SHOP_ITEM_5, RG_BUY_DEKU_SEEDS_30); - locationTable[RC_KF_SHOP_ITEM_6] = Location::Base(RC_KF_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x05, "Shop Item 6", RHT_KF_SHOP_ITEM_6, RG_BUY_ARROWS_10); - locationTable[RC_KF_SHOP_ITEM_7] = Location::Base(RC_KF_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x06, "Shop Item 7", RHT_KF_SHOP_ITEM_7, RG_BUY_ARROWS_30); - locationTable[RC_KF_SHOP_ITEM_8] = Location::Base(RC_KF_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x07, "Shop Item 8", RHT_KF_SHOP_ITEM_8, RG_BUY_HEART); + locationTable[RC_KF_SHOP_ITEM_1] = Location::Base(RC_KF_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x00, "Shop Item 1", RHT_KF_SHOP_ITEM_1, RG_BUY_DEKU_SHIELD, SpoilerCollectionCheck(), false, 40); + locationTable[RC_KF_SHOP_ITEM_2] = Location::Base(RC_KF_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x01, "Shop Item 2", RHT_KF_SHOP_ITEM_2, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck(), false, 15); + locationTable[RC_KF_SHOP_ITEM_3] = Location::Base(RC_KF_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x02, "Shop Item 3", RHT_KF_SHOP_ITEM_3, RG_BUY_DEKU_NUTS_10, SpoilerCollectionCheck(), false, 30); + locationTable[RC_KF_SHOP_ITEM_4] = Location::Base(RC_KF_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x03, "Shop Item 4", RHT_KF_SHOP_ITEM_4, RG_BUY_DEKU_STICK_1, SpoilerCollectionCheck(), false, 10); + locationTable[RC_KF_SHOP_ITEM_5] = Location::Base(RC_KF_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x04, "Shop Item 5", RHT_KF_SHOP_ITEM_5, RG_BUY_DEKU_SEEDS_30, SpoilerCollectionCheck(), false, 30); + locationTable[RC_KF_SHOP_ITEM_6] = Location::Base(RC_KF_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x05, "Shop Item 6", RHT_KF_SHOP_ITEM_6, RG_BUY_ARROWS_10, SpoilerCollectionCheck(), false, 20); + locationTable[RC_KF_SHOP_ITEM_7] = Location::Base(RC_KF_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x06, "Shop Item 7", RHT_KF_SHOP_ITEM_7, RG_BUY_ARROWS_30, SpoilerCollectionCheck(), false, 60); + locationTable[RC_KF_SHOP_ITEM_8] = Location::Base(RC_KF_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_KOKIRI_SHOP, 0x07, "Shop Item 8", RHT_KF_SHOP_ITEM_8, RG_BUY_HEART, SpoilerCollectionCheck(), false, 10); // Kakariko Village - locationTable[RC_KAK_POTION_SHOP_ITEM_1] = Location::Base(RC_KAK_POTION_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x00, "Potion Shop Item 1", RHT_KAK_POTION_SHOP_ITEM_1, RG_BUY_GREEN_POTION); - locationTable[RC_KAK_POTION_SHOP_ITEM_2] = Location::Base(RC_KAK_POTION_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x01, "Potion Shop Item 2", RHT_KAK_POTION_SHOP_ITEM_2, RG_BUY_BLUE_FIRE); - locationTable[RC_KAK_POTION_SHOP_ITEM_3] = Location::Base(RC_KAK_POTION_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x02, "Potion Shop Item 3", RHT_KAK_POTION_SHOP_ITEM_3, RG_BUY_RED_POTION_30); - locationTable[RC_KAK_POTION_SHOP_ITEM_4] = Location::Base(RC_KAK_POTION_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x03, "Potion Shop Item 4", RHT_KAK_POTION_SHOP_ITEM_4, RG_BUY_FAIRYS_SPIRIT); - locationTable[RC_KAK_POTION_SHOP_ITEM_5] = Location::Base(RC_KAK_POTION_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x04, "Potion Shop Item 5", RHT_KAK_POTION_SHOP_ITEM_5, RG_BUY_DEKU_NUTS_5); - locationTable[RC_KAK_POTION_SHOP_ITEM_6] = Location::Base(RC_KAK_POTION_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x05, "Potion Shop Item 6", RHT_KAK_POTION_SHOP_ITEM_6, RG_BUY_BOTTLE_BUG); - locationTable[RC_KAK_POTION_SHOP_ITEM_7] = Location::Base(RC_KAK_POTION_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x06, "Potion Shop Item 7", RHT_KAK_POTION_SHOP_ITEM_7, RG_BUY_POE); - locationTable[RC_KAK_POTION_SHOP_ITEM_8] = Location::Base(RC_KAK_POTION_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x07, "Potion Shop Item 8", RHT_KAK_POTION_SHOP_ITEM_8, RG_BUY_FISH); - locationTable[RC_KAK_BAZAAR_ITEM_1] = Location::Base(RC_KAK_BAZAAR_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x00, "Bazaar Item 1", RHT_KAK_BAZAAR_ITEM_1, RG_BUY_HYLIAN_SHIELD); - locationTable[RC_KAK_BAZAAR_ITEM_2] = Location::Base(RC_KAK_BAZAAR_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x01, "Bazaar Item 2", RHT_KAK_BAZAAR_ITEM_2, RG_BUY_BOMBS_535); - locationTable[RC_KAK_BAZAAR_ITEM_3] = Location::Base(RC_KAK_BAZAAR_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x02, "Bazaar Item 3", RHT_KAK_BAZAAR_ITEM_3, RG_BUY_DEKU_NUTS_5); - locationTable[RC_KAK_BAZAAR_ITEM_4] = Location::Base(RC_KAK_BAZAAR_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x03, "Bazaar Item 4", RHT_KAK_BAZAAR_ITEM_4, RG_BUY_HEART); - locationTable[RC_KAK_BAZAAR_ITEM_5] = Location::Base(RC_KAK_BAZAAR_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x04, "Bazaar Item 5", RHT_KAK_BAZAAR_ITEM_5, RG_BUY_ARROWS_10); - locationTable[RC_KAK_BAZAAR_ITEM_6] = Location::Base(RC_KAK_BAZAAR_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x05, "Bazaar Item 6", RHT_KAK_BAZAAR_ITEM_6, RG_BUY_ARROWS_50); - locationTable[RC_KAK_BAZAAR_ITEM_7] = Location::Base(RC_KAK_BAZAAR_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x06, "Bazaar Item 7", RHT_KAK_BAZAAR_ITEM_7, RG_BUY_DEKU_STICK_1); - locationTable[RC_KAK_BAZAAR_ITEM_8] = Location::Base(RC_KAK_BAZAAR_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x07, "Bazaar Item 8", RHT_KAK_BAZAAR_ITEM_8, RG_BUY_ARROWS_30); + locationTable[RC_KAK_POTION_SHOP_ITEM_1] = Location::Base(RC_KAK_POTION_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x00, "Potion Shop Item 1", RHT_KAK_POTION_SHOP_ITEM_1, RG_BUY_GREEN_POTION, SpoilerCollectionCheck(), false, 30); + locationTable[RC_KAK_POTION_SHOP_ITEM_2] = Location::Base(RC_KAK_POTION_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x01, "Potion Shop Item 2", RHT_KAK_POTION_SHOP_ITEM_2, RG_BUY_BLUE_FIRE, SpoilerCollectionCheck(), false, 300); + locationTable[RC_KAK_POTION_SHOP_ITEM_3] = Location::Base(RC_KAK_POTION_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x02, "Potion Shop Item 3", RHT_KAK_POTION_SHOP_ITEM_3, RG_BUY_RED_POTION_30, SpoilerCollectionCheck(), false, 30); + locationTable[RC_KAK_POTION_SHOP_ITEM_4] = Location::Base(RC_KAK_POTION_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x03, "Potion Shop Item 4", RHT_KAK_POTION_SHOP_ITEM_4, RG_BUY_FAIRYS_SPIRIT, SpoilerCollectionCheck(), false, 50); + locationTable[RC_KAK_POTION_SHOP_ITEM_5] = Location::Base(RC_KAK_POTION_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x04, "Potion Shop Item 5", RHT_KAK_POTION_SHOP_ITEM_5, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck(), false, 15); + locationTable[RC_KAK_POTION_SHOP_ITEM_6] = Location::Base(RC_KAK_POTION_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x05, "Potion Shop Item 6", RHT_KAK_POTION_SHOP_ITEM_6, RG_BUY_BOTTLE_BUG, SpoilerCollectionCheck(), false, 50); + locationTable[RC_KAK_POTION_SHOP_ITEM_7] = Location::Base(RC_KAK_POTION_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x06, "Potion Shop Item 7", RHT_KAK_POTION_SHOP_ITEM_7, RG_BUY_POE, SpoilerCollectionCheck(), false, 30); + locationTable[RC_KAK_POTION_SHOP_ITEM_8] = Location::Base(RC_KAK_POTION_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_KAKARIKO, 0x07, "Potion Shop Item 8", RHT_KAK_POTION_SHOP_ITEM_8, RG_BUY_FISH, SpoilerCollectionCheck(), false, 200); + locationTable[RC_KAK_BAZAAR_ITEM_1] = Location::Base(RC_KAK_BAZAAR_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x00, "Bazaar Item 1", RHT_KAK_BAZAAR_ITEM_1, RG_BUY_HYLIAN_SHIELD, SpoilerCollectionCheck(), false, 80); + locationTable[RC_KAK_BAZAAR_ITEM_2] = Location::Base(RC_KAK_BAZAAR_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x01, "Bazaar Item 2", RHT_KAK_BAZAAR_ITEM_2, RG_BUY_BOMBS_535, SpoilerCollectionCheck(), false, 35); + locationTable[RC_KAK_BAZAAR_ITEM_3] = Location::Base(RC_KAK_BAZAAR_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x02, "Bazaar Item 3", RHT_KAK_BAZAAR_ITEM_3, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck(), false, 10); + locationTable[RC_KAK_BAZAAR_ITEM_4] = Location::Base(RC_KAK_BAZAAR_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x03, "Bazaar Item 4", RHT_KAK_BAZAAR_ITEM_4, RG_BUY_HEART, SpoilerCollectionCheck(), false, 20); + locationTable[RC_KAK_BAZAAR_ITEM_5] = Location::Base(RC_KAK_BAZAAR_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x04, "Bazaar Item 5", RHT_KAK_BAZAAR_ITEM_5, RG_BUY_ARROWS_10, SpoilerCollectionCheck(), false, 20); + locationTable[RC_KAK_BAZAAR_ITEM_6] = Location::Base(RC_KAK_BAZAAR_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x05, "Bazaar Item 6", RHT_KAK_BAZAAR_ITEM_6, RG_BUY_ARROWS_50, SpoilerCollectionCheck(), false, 90); + locationTable[RC_KAK_BAZAAR_ITEM_7] = Location::Base(RC_KAK_BAZAAR_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x06, "Bazaar Item 7", RHT_KAK_BAZAAR_ITEM_7, RG_BUY_DEKU_STICK_1, SpoilerCollectionCheck(), false, 10); + locationTable[RC_KAK_BAZAAR_ITEM_8] = Location::Base(RC_KAK_BAZAAR_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_TEST01, 0x07, "Bazaar Item 8", RHT_KAK_BAZAAR_ITEM_8, RG_BUY_ARROWS_30, SpoilerCollectionCheck(), false, 60); // Market - locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_1] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x00, "Bombchu Shop Item 1", RHT_MARKET_BOMBCHU_SHOP_ITEM_1, RG_BUY_BOMBCHUS_10); - locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_2] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x01, "Bombchu Shop Item 2", RHT_MARKET_BOMBCHU_SHOP_ITEM_2, RG_BUY_BOMBCHUS_10); - locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_3] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x02, "Bombchu Shop Item 3", RHT_MARKET_BOMBCHU_SHOP_ITEM_3, RG_BUY_BOMBCHUS_10); - locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_4] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x03, "Bombchu Shop Item 4", RHT_MARKET_BOMBCHU_SHOP_ITEM_4, RG_BUY_BOMBCHUS_10); - locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_5] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x04, "Bombchu Shop Item 5", RHT_MARKET_BOMBCHU_SHOP_ITEM_5, RG_BUY_BOMBCHUS_20); - locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_6] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x05, "Bombchu Shop Item 6", RHT_MARKET_BOMBCHU_SHOP_ITEM_6, RG_BUY_BOMBCHUS_20); - locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_7] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x06, "Bombchu Shop Item 7", RHT_MARKET_BOMBCHU_SHOP_ITEM_7, RG_BUY_BOMBCHUS_20); - locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_8] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x07, "Bombchu Shop Item 8", RHT_MARKET_BOMBCHU_SHOP_ITEM_8, RG_BUY_BOMBCHUS_20); - locationTable[RC_MARKET_POTION_SHOP_ITEM_1] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x00, "Potion Shop Item 1", RHT_MARKET_POTION_SHOP_ITEM_1, RG_BUY_GREEN_POTION); - locationTable[RC_MARKET_POTION_SHOP_ITEM_2] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x01, "Potion Shop Item 2", RHT_MARKET_POTION_SHOP_ITEM_2, RG_BUY_BLUE_FIRE); - locationTable[RC_MARKET_POTION_SHOP_ITEM_3] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x02, "Potion Shop Item 3", RHT_MARKET_POTION_SHOP_ITEM_3, RG_BUY_RED_POTION_30); - locationTable[RC_MARKET_POTION_SHOP_ITEM_4] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x03, "Potion Shop Item 4", RHT_MARKET_POTION_SHOP_ITEM_4, RG_BUY_FAIRYS_SPIRIT); - locationTable[RC_MARKET_POTION_SHOP_ITEM_5] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x04, "Potion Shop Item 5", RHT_MARKET_POTION_SHOP_ITEM_5, RG_BUY_DEKU_NUTS_5); - locationTable[RC_MARKET_POTION_SHOP_ITEM_6] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x05, "Potion Shop Item 6", RHT_MARKET_POTION_SHOP_ITEM_6, RG_BUY_BOTTLE_BUG); - locationTable[RC_MARKET_POTION_SHOP_ITEM_7] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x06, "Potion Shop Item 7", RHT_MARKET_POTION_SHOP_ITEM_7, RG_BUY_POE); - locationTable[RC_MARKET_POTION_SHOP_ITEM_8] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x07, "Potion Shop Item 8", RHT_MARKET_POTION_SHOP_ITEM_8, RG_BUY_FISH); - locationTable[RC_MARKET_BAZAAR_ITEM_1] = Location::Base(RC_MARKET_BAZAAR_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x00, "Bazaar Item 1", RHT_MARKET_BAZAAR_ITEM_1, RG_BUY_HYLIAN_SHIELD); - locationTable[RC_MARKET_BAZAAR_ITEM_2] = Location::Base(RC_MARKET_BAZAAR_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x01, "Bazaar Item 2", RHT_MARKET_BAZAAR_ITEM_2, RG_BUY_BOMBS_535); - locationTable[RC_MARKET_BAZAAR_ITEM_3] = Location::Base(RC_MARKET_BAZAAR_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x02, "Bazaar Item 3", RHT_MARKET_BAZAAR_ITEM_3, RG_BUY_DEKU_NUTS_5); - locationTable[RC_MARKET_BAZAAR_ITEM_4] = Location::Base(RC_MARKET_BAZAAR_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x03, "Bazaar Item 4", RHT_MARKET_BAZAAR_ITEM_4, RG_BUY_HEART); - locationTable[RC_MARKET_BAZAAR_ITEM_5] = Location::Base(RC_MARKET_BAZAAR_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x04, "Bazaar Item 5", RHT_MARKET_BAZAAR_ITEM_5, RG_BUY_ARROWS_10); - locationTable[RC_MARKET_BAZAAR_ITEM_6] = Location::Base(RC_MARKET_BAZAAR_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x05, "Bazaar Item 6", RHT_MARKET_BAZAAR_ITEM_6, RG_BUY_ARROWS_50); - locationTable[RC_MARKET_BAZAAR_ITEM_7] = Location::Base(RC_MARKET_BAZAAR_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x06, "Bazaar Item 7", RHT_MARKET_BAZAAR_ITEM_7, RG_BUY_DEKU_STICK_1); - locationTable[RC_MARKET_BAZAAR_ITEM_8] = Location::Base(RC_MARKET_BAZAAR_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x07, "Bazaar Item 8", RHT_MARKET_BAZAAR_ITEM_8, RG_BUY_ARROWS_30); + locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_1] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x00, "Bombchu Shop Item 1", RHT_MARKET_BOMBCHU_SHOP_ITEM_1, RG_BUY_BOMBCHUS_10, SpoilerCollectionCheck(), false, 99); + locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_2] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x01, "Bombchu Shop Item 2", RHT_MARKET_BOMBCHU_SHOP_ITEM_2, RG_BUY_BOMBCHUS_10, SpoilerCollectionCheck(), false, 99); + locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_3] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x02, "Bombchu Shop Item 3", RHT_MARKET_BOMBCHU_SHOP_ITEM_3, RG_BUY_BOMBCHUS_10, SpoilerCollectionCheck(), false, 99); + locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_4] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x03, "Bombchu Shop Item 4", RHT_MARKET_BOMBCHU_SHOP_ITEM_4, RG_BUY_BOMBCHUS_10, SpoilerCollectionCheck(), false, 99); + locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_5] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x04, "Bombchu Shop Item 5", RHT_MARKET_BOMBCHU_SHOP_ITEM_5, RG_BUY_BOMBCHUS_20, SpoilerCollectionCheck(), false, 180); + locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_6] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x05, "Bombchu Shop Item 6", RHT_MARKET_BOMBCHU_SHOP_ITEM_6, RG_BUY_BOMBCHUS_20, SpoilerCollectionCheck(), false, 180); + locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_7] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x06, "Bombchu Shop Item 7", RHT_MARKET_BOMBCHU_SHOP_ITEM_7, RG_BUY_BOMBCHUS_20, SpoilerCollectionCheck(), false, 180); + locationTable[RC_MARKET_BOMBCHU_SHOP_ITEM_8] = Location::Base(RC_MARKET_BOMBCHU_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_BOMBCHU_SHOP, 0x07, "Bombchu Shop Item 8", RHT_MARKET_BOMBCHU_SHOP_ITEM_8, RG_BUY_BOMBCHUS_20, SpoilerCollectionCheck(), false, 180); + locationTable[RC_MARKET_POTION_SHOP_ITEM_1] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x00, "Potion Shop Item 1", RHT_MARKET_POTION_SHOP_ITEM_1, RG_BUY_GREEN_POTION, SpoilerCollectionCheck(), false, 30); + locationTable[RC_MARKET_POTION_SHOP_ITEM_2] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x01, "Potion Shop Item 2", RHT_MARKET_POTION_SHOP_ITEM_2, RG_BUY_BLUE_FIRE, SpoilerCollectionCheck(), false, 300); + locationTable[RC_MARKET_POTION_SHOP_ITEM_3] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x02, "Potion Shop Item 3", RHT_MARKET_POTION_SHOP_ITEM_3, RG_BUY_RED_POTION_30, SpoilerCollectionCheck(), false, 30); + locationTable[RC_MARKET_POTION_SHOP_ITEM_4] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x03, "Potion Shop Item 4", RHT_MARKET_POTION_SHOP_ITEM_4, RG_BUY_FAIRYS_SPIRIT, SpoilerCollectionCheck(), false, 50); + locationTable[RC_MARKET_POTION_SHOP_ITEM_5] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x04, "Potion Shop Item 5", RHT_MARKET_POTION_SHOP_ITEM_5, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck(), false, 15); + locationTable[RC_MARKET_POTION_SHOP_ITEM_6] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x05, "Potion Shop Item 6", RHT_MARKET_POTION_SHOP_ITEM_6, RG_BUY_BOTTLE_BUG, SpoilerCollectionCheck(), false, 50); + locationTable[RC_MARKET_POTION_SHOP_ITEM_7] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x06, "Potion Shop Item 7", RHT_MARKET_POTION_SHOP_ITEM_7, RG_BUY_POE, SpoilerCollectionCheck(), false, 30); + locationTable[RC_MARKET_POTION_SHOP_ITEM_8] = Location::Base(RC_MARKET_POTION_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_POTION_SHOP_MARKET, 0x07, "Potion Shop Item 8", RHT_MARKET_POTION_SHOP_ITEM_8, RG_BUY_FISH, SpoilerCollectionCheck(), false, 200); + locationTable[RC_MARKET_BAZAAR_ITEM_1] = Location::Base(RC_MARKET_BAZAAR_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x00, "Bazaar Item 1", RHT_MARKET_BAZAAR_ITEM_1, RG_BUY_HYLIAN_SHIELD, SpoilerCollectionCheck(), false, 80); + locationTable[RC_MARKET_BAZAAR_ITEM_2] = Location::Base(RC_MARKET_BAZAAR_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x01, "Bazaar Item 2", RHT_MARKET_BAZAAR_ITEM_2, RG_BUY_BOMBS_535, SpoilerCollectionCheck(), false, 35); + locationTable[RC_MARKET_BAZAAR_ITEM_3] = Location::Base(RC_MARKET_BAZAAR_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x02, "Bazaar Item 3", RHT_MARKET_BAZAAR_ITEM_3, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck(), false, 15); + locationTable[RC_MARKET_BAZAAR_ITEM_4] = Location::Base(RC_MARKET_BAZAAR_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x03, "Bazaar Item 4", RHT_MARKET_BAZAAR_ITEM_4, RG_BUY_HEART, SpoilerCollectionCheck(), false, 10); + locationTable[RC_MARKET_BAZAAR_ITEM_5] = Location::Base(RC_MARKET_BAZAAR_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x04, "Bazaar Item 5", RHT_MARKET_BAZAAR_ITEM_5, RG_BUY_ARROWS_10, SpoilerCollectionCheck(), false, 20); + locationTable[RC_MARKET_BAZAAR_ITEM_6] = Location::Base(RC_MARKET_BAZAAR_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x05, "Bazaar Item 6", RHT_MARKET_BAZAAR_ITEM_6, RG_BUY_ARROWS_50, SpoilerCollectionCheck(), false, 90); + locationTable[RC_MARKET_BAZAAR_ITEM_7] = Location::Base(RC_MARKET_BAZAAR_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x06, "Bazaar Item 7", RHT_MARKET_BAZAAR_ITEM_7, RG_BUY_DEKU_STICK_1, SpoilerCollectionCheck(), false, 10); + locationTable[RC_MARKET_BAZAAR_ITEM_8] = Location::Base(RC_MARKET_BAZAAR_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, RCAREA_MARKET, ACTOR_EN_GIRLA, SCENE_BAZAAR, 0x07, "Bazaar Item 8", RHT_MARKET_BAZAAR_ITEM_8, RG_BUY_ARROWS_30, SpoilerCollectionCheck(), false, 60); // Zora's Domain - locationTable[RC_ZD_SHOP_ITEM_1] = Location::Base(RC_ZD_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x00, "Shop Item 1", RHT_ZD_SHOP_ITEM_1, RG_BUY_ZORA_TUNIC); - locationTable[RC_ZD_SHOP_ITEM_2] = Location::Base(RC_ZD_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x01, "Shop Item 2", RHT_ZD_SHOP_ITEM_2, RG_BUY_ARROWS_10); - locationTable[RC_ZD_SHOP_ITEM_3] = Location::Base(RC_ZD_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x02, "Shop Item 3", RHT_ZD_SHOP_ITEM_3, RG_BUY_HEART); - locationTable[RC_ZD_SHOP_ITEM_4] = Location::Base(RC_ZD_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x03, "Shop Item 4", RHT_ZD_SHOP_ITEM_4, RG_BUY_ARROWS_30); - locationTable[RC_ZD_SHOP_ITEM_5] = Location::Base(RC_ZD_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x04, "Shop Item 5", RHT_ZD_SHOP_ITEM_5, RG_BUY_DEKU_NUTS_5); - locationTable[RC_ZD_SHOP_ITEM_6] = Location::Base(RC_ZD_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x05, "Shop Item 6", RHT_ZD_SHOP_ITEM_6, RG_BUY_ARROWS_50); - locationTable[RC_ZD_SHOP_ITEM_7] = Location::Base(RC_ZD_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x06, "Shop Item 7", RHT_ZD_SHOP_ITEM_7, RG_BUY_FISH); - locationTable[RC_ZD_SHOP_ITEM_8] = Location::Base(RC_ZD_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x07, "Shop Item 8", RHT_ZD_SHOP_ITEM_8, RG_BUY_RED_POTION_50); + locationTable[RC_ZD_SHOP_ITEM_1] = Location::Base(RC_ZD_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x00, "Shop Item 1", RHT_ZD_SHOP_ITEM_1, RG_BUY_ZORA_TUNIC, SpoilerCollectionCheck(), false, 200); + locationTable[RC_ZD_SHOP_ITEM_2] = Location::Base(RC_ZD_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x01, "Shop Item 2", RHT_ZD_SHOP_ITEM_2, RG_BUY_ARROWS_10, SpoilerCollectionCheck(), false, 20); + locationTable[RC_ZD_SHOP_ITEM_3] = Location::Base(RC_ZD_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x02, "Shop Item 3", RHT_ZD_SHOP_ITEM_3, RG_BUY_HEART, SpoilerCollectionCheck(), false, 10); + locationTable[RC_ZD_SHOP_ITEM_4] = Location::Base(RC_ZD_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x03, "Shop Item 4", RHT_ZD_SHOP_ITEM_4, RG_BUY_ARROWS_30, SpoilerCollectionCheck(), false, 60); + locationTable[RC_ZD_SHOP_ITEM_5] = Location::Base(RC_ZD_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x04, "Shop Item 5", RHT_ZD_SHOP_ITEM_5, RG_BUY_DEKU_NUTS_5, SpoilerCollectionCheck(), false, 15); + locationTable[RC_ZD_SHOP_ITEM_6] = Location::Base(RC_ZD_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x05, "Shop Item 6", RHT_ZD_SHOP_ITEM_6, RG_BUY_ARROWS_50, SpoilerCollectionCheck(), false, 90); + locationTable[RC_ZD_SHOP_ITEM_7] = Location::Base(RC_ZD_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x06, "Shop Item 7", RHT_ZD_SHOP_ITEM_7, RG_BUY_FISH, SpoilerCollectionCheck(), false, 200); + locationTable[RC_ZD_SHOP_ITEM_8] = Location::Base(RC_ZD_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_ZORA_SHOP, 0x07, "Shop Item 8", RHT_ZD_SHOP_ITEM_8, RG_BUY_RED_POTION_50, SpoilerCollectionCheck(), false, 50); // Goron City - locationTable[RC_GC_SHOP_ITEM_1] = Location::Base(RC_GC_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x00, "Shop Item 1", RHT_GC_SHOP_ITEM_1, RG_BUY_BOMBS_525); - locationTable[RC_GC_SHOP_ITEM_2] = Location::Base(RC_GC_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x01, "Shop Item 2", RHT_GC_SHOP_ITEM_2, RG_BUY_BOMBS_10); - locationTable[RC_GC_SHOP_ITEM_3] = Location::Base(RC_GC_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x02, "Shop Item 3", RHT_GC_SHOP_ITEM_3, RG_BUY_BOMBS_20); - locationTable[RC_GC_SHOP_ITEM_4] = Location::Base(RC_GC_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x03, "Shop Item 4", RHT_GC_SHOP_ITEM_4, RG_BUY_BOMBS_30); - locationTable[RC_GC_SHOP_ITEM_5] = Location::Base(RC_GC_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x04, "Shop Item 5", RHT_GC_SHOP_ITEM_5, RG_BUY_GORON_TUNIC); - locationTable[RC_GC_SHOP_ITEM_6] = Location::Base(RC_GC_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x05, "Shop Item 6", RHT_GC_SHOP_ITEM_6, RG_BUY_HEART); - locationTable[RC_GC_SHOP_ITEM_7] = Location::Base(RC_GC_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x06, "Shop Item 7", RHT_GC_SHOP_ITEM_7, RG_BUY_RED_POTION_40); - locationTable[RC_GC_SHOP_ITEM_8] = Location::Base(RC_GC_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x07, "Shop Item 8", RHT_GC_SHOP_ITEM_8, RG_BUY_HEART); + locationTable[RC_GC_SHOP_ITEM_1] = Location::Base(RC_GC_SHOP_ITEM_1, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x00, "Shop Item 1", RHT_GC_SHOP_ITEM_1, RG_BUY_BOMBS_525, SpoilerCollectionCheck(), false, 25); + locationTable[RC_GC_SHOP_ITEM_2] = Location::Base(RC_GC_SHOP_ITEM_2, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x01, "Shop Item 2", RHT_GC_SHOP_ITEM_2, RG_BUY_BOMBS_10, SpoilerCollectionCheck(), false, 50); + locationTable[RC_GC_SHOP_ITEM_3] = Location::Base(RC_GC_SHOP_ITEM_3, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x02, "Shop Item 3", RHT_GC_SHOP_ITEM_3, RG_BUY_BOMBS_20, SpoilerCollectionCheck(), false, 80); + locationTable[RC_GC_SHOP_ITEM_4] = Location::Base(RC_GC_SHOP_ITEM_4, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x03, "Shop Item 4", RHT_GC_SHOP_ITEM_4, RG_BUY_BOMBS_30, SpoilerCollectionCheck(), false, 120); + locationTable[RC_GC_SHOP_ITEM_5] = Location::Base(RC_GC_SHOP_ITEM_5, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x04, "Shop Item 5", RHT_GC_SHOP_ITEM_5, RG_BUY_GORON_TUNIC, SpoilerCollectionCheck(), false, 200); + locationTable[RC_GC_SHOP_ITEM_6] = Location::Base(RC_GC_SHOP_ITEM_6, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x05, "Shop Item 6", RHT_GC_SHOP_ITEM_6, RG_BUY_HEART, SpoilerCollectionCheck(), false, 10); + locationTable[RC_GC_SHOP_ITEM_7] = Location::Base(RC_GC_SHOP_ITEM_7, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x06, "Shop Item 7", RHT_GC_SHOP_ITEM_7, RG_BUY_RED_POTION_40, SpoilerCollectionCheck(), false, 40); + locationTable[RC_GC_SHOP_ITEM_8] = Location::Base(RC_GC_SHOP_ITEM_8, RCQUEST_BOTH, RCTYPE_SHOP, ACTOR_EN_GIRLA, SCENE_GORON_SHOP, 0x07, "Shop Item 8", RHT_GC_SHOP_ITEM_8, RG_BUY_HEART, SpoilerCollectionCheck(), false, 10); /* +--------------+ | FISHSANITY | @@ -1084,7 +1094,7 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_TOT_SHEIK_HINT] = Location::OtherHint(RC_TOT_SHEIK_HINT, RCQUEST_BOTH, ACTOR_EN_XC, SCENE_TEMPLE_OF_TIME, "Ocarina of Time Hint"); locationTable[RC_MASK_SHOP_HINT] = Location::OtherHint(RC_MASK_SHOP_HINT, RCQUEST_BOTH, ACTOR_ID_MAX, SCENE_HAPPY_MASK_SHOP, "Mask Shop Hint"); - locationTable[RC_TRIFORCE_COMPLETED] = Location::Base(RC_TRIFORCE_COMPLETED, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, "Completed Triforce", "Completed Triforce", RHT_NONE, RG_NONE); + locationTable[RC_TRIFORCE_COMPLETED] = Location::Base(RC_TRIFORCE_COMPLETED, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_MARKET, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, "Completed Triforce", "Completed Triforce", RHT_NONE, RG_NONE); // clang-format on // Init locationNameToEnum diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index 547d675df..7de98b3d0 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -218,6 +218,8 @@ void Settings::CreateOptionDescriptions() { "Enabling this shuffles the Child's Wallet into the item pool.\n" "\n" "You will not be able to carry any rupees until you find a wallet."; + mOptionDescriptions[RSK_INCLUDE_TYCOON_WALLET] = + "Enabling this adds an extra Progressive Wallet to the pool and adds a new 999 capacity tier after Giant's Wallet.\n"; mOptionDescriptions[RSK_SHUFFLE_OCARINA] = "Enabling this shuffles the Fairy Ocarina and the Ocarina of Time into the item pool.\n" "\n" @@ -277,12 +279,31 @@ void Settings::CreateOptionDescriptions() { "8 Items - All shops will contain 8 non-vanilla shop items.\n" */; mOptionDescriptions[RSK_SHOPSANITY_PRICES] = - "Balanced - The default randomization. Shop prices for shopsanity items will range between 0 to 300 rupees, " - "with a bias towards values slightly below the middle of the range, in multiples of 5.\n " - "\n" - "X Wallet - Randomized between 5 and the wallet's max size, in multiples of 5"; + "Vanilla - The same price as the item it replaced\n" + "Cheap Balanced - Prices will range between 0 to 95 rupees, favoring lower numbers\n" + "Balanced - Prices will range between 0 to 300 rupees, favoring lower numbers\n" + "Fixed - A fixed number\n" + "Range - A random point between specific ranges\n" + "Set By Wallet - Set weights that decide the choice of each wallet, and get a random price in that range if that wallet is chosen"; + mOptionDescriptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE] = + "The price for Shopsanity checks."; + mOptionDescriptions[RSK_SHOPSANITY_PRICES_RANGE_1] = + "The first part of the inclusive range of prices to allow for Shopsanity checks."; + mOptionDescriptions[RSK_SHOPSANITY_PRICES_RANGE_2] = + "The second part of the inclusive range of prices to allow for Shopsanity checks."; + mOptionDescriptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT] = + "The chance for Shopsanity checks to be free."; + mOptionDescriptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT] = + "The chance for Shopsanity checks to be purchasable with Child's Wallet (1-99)."; + mOptionDescriptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT] = + "The chance for Shopsanity checks to be purchasable with Adult's Wallet (100-200)."; + mOptionDescriptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT] = + "The chance for Shopsanity checks to be purchasable with Giant's Wallet (201-500)."; + mOptionDescriptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT] = + "The chance for Shopsanity checks to be purchasable with Tycoon Wallet. (500+)"; mOptionDescriptions[RSK_SHOPSANITY_PRICES_AFFORDABLE] = - "Affordable prices per tier: starter = 10, adult = 105, giant = 205, tycoon = 505\n\n" + "After choosing a price, set it to the affordable amount based on the wallet required.\n\n" + "Affordable prices per tier: starter = 1, adult = 100, giant = 201, tycoon = 501\n\n" "Use this to enable wallet tier locking, but make shop items not as expensive as they could be."; mOptionDescriptions[RSK_FISHSANITY] = "Off - Fish will not be shuffled. No changes will be made to fishing behavior.\n\n" "Shuffle only Hyrule Loach - Allows you to earn an item by catching the hyrule loach at the fishing pond and giving it to the owner.\n\n" @@ -297,32 +318,84 @@ void Settings::CreateOptionDescriptions() { "If disabled, then the child pond will be shuffled and shared between both ages.\n\n" "Note that, as child, there is a second loach available in the pond!"; mOptionDescriptions[RSK_SHUFFLE_SCRUBS] = - "Off - Scrubs will not be shuffled. The 3 Scrubs that give one-time items in the vanilla game " - "(PoH, Deku Nut capacity, and Deku Stick capacity) will have random items.\n" + "Off - Scrubs will not be shuffled. The 3 Scrubs that give one-time items in the " + "vanilla game (PoH, Deku Nut capacity, and Deku Stick capacity) will not spawn." "\n" - "Affordable - Scrubs will be shuffled and their item will cost 10 rupees.\n" + "One-Time Only - Only the 3 Scrubs that give one-time items in the " + "vanilla game are shuffled.\n" "\n" - "Expensive - Scrubs will be shuffled and their item will cost the vanilla price.\n" - "\n" - "Random - Scrubs will be shuffled and their item will cost will be between 0-95 rupees.\n"; + "All - All Scrubs are shuffled."; + mOptionDescriptions[RSK_SCRUBS_PRICES] = + "Vanilla - The same price as the item it replaced\n" + "Cheap Balanced - Prices will range between 0 to 95 rupees, favoring lower numbers\n" + "Balanced - Prices will range between 0 to 300 rupees, favoring lower numbers\n" + "Fixed - A fixed number\n" + "Range - A random point between specific ranges\n" + "Set By Wallet - Set weights that decide the choice of each wallet, and get a random price in that range if that wallet is chosen"; + mOptionDescriptions[RSK_SCRUBS_PRICES_FIXED_PRICE] = + "The price for Scrub checks."; + mOptionDescriptions[RSK_SCRUBS_PRICES_RANGE_1] = + "The first part of the inclusive range of prices to allow for Scrub checks."; + mOptionDescriptions[RSK_SCRUBS_PRICES_RANGE_2] = + "The second part of the inclusive range of prices to allow for Scrub checks."; + mOptionDescriptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT] = + "The chance for Scrub checks to be free."; + mOptionDescriptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT] = + "The chance for Scrub checks to be purchasable with Child's Wallet (1-99)."; + mOptionDescriptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT] = + "The chance for Scrub checks to be purchasable with Adult's Wallet (100-200)."; + mOptionDescriptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT] = + "The chance for Scrub checks to be purchasable with Giant's Wallet (201-500)."; + mOptionDescriptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT] = + "The chance for Scrub checks to be purchasable with Tycoon Wallet. (500+)"; + mOptionDescriptions[RSK_SCRUBS_PRICES_AFFORDABLE] = + "After choosing a price, set it to the affordable amount based on the wallet required.\n\n" + "Affordable prices per tier: starter = 1, adult = 100, giant = 201, tycoon = 501\n\n" + "Use this to enable wallet tier locking, but make scrub items not as expensive as they could be."; mOptionDescriptions[RSK_SHUFFLE_BEEHIVES] = "Beehives give a randomized item from the pool when broken."; mOptionDescriptions[RSK_SHUFFLE_COWS] = "Cows give a randomized item from the pool upon performing Epona's Song in front of them."; - mOptionDescriptions[RSK_SHUFFLE_MAGIC_BEANS] = - "Enabling this adds a pack of 10 beans to the item pool and changes the Magic Bean " - "Salesman to sell a random item at a price of 60 rupees."; mOptionDescriptions[RSK_SHUFFLE_MERCHANTS] = - "Enabling this changes Medigoron, Granny and the Carpet Salesman to sell a random item " - "once at a high price (100 for Granny, 200 for the others).\n" + "This setting governs if the Bean Salesman, Medigoron, Granny and the Carpet Salesman " + "sell a random item.\n" + "Beans Only - Only the Bean Salesman will have a check, and a pack of Magic Beans will be added " + " to the item pool." + "All But Beans - Medigoron, Granny and the Carpet Salesman will have checks, " "A Giant's Knife and a pack of Bombchus will be added to the item pool, and " "one of the bottles will contain a Blue Potion.\n\n" - "On (no hints) - Salesmen will be included but won't tell you what you'll get.\n" - "On (with hints) - Salesmen will be included and you'll know what you're buying.\n" + "All - Apply both effects.\n" "\n" "Granny's item will only be offered after you have traded in the Odd Mushroom when Shuffle Adult Trade is on. " "Otherwise when off, you will need to have found the Claim Check to buy her item (simulating the trade quest " "is complete)."; + mOptionDescriptions[RSK_MERCHANT_PRICES] = + "Vanilla - The same price as the Check in vanilla, 60 for the Bean Salesman\n" + "Cheap Balanced - Prices will range between 0 to 95 rupees, favoring lower numbers\n" + "Balanced - Prices will range between 0 to 300 rupees, favoring lower numbers\n" + "Fixed - A fixed number\n" + "Range - A random point between specific ranges\n" + "Set By Wallet - Set weights that decide the choice of each wallet, and get a random price in that range if that wallet is chosen"; + mOptionDescriptions[RSK_MERCHANT_PRICES_FIXED_PRICE] = + "The price for Merchant checks."; + mOptionDescriptions[RSK_MERCHANT_PRICES_RANGE_1] = + "The first part of the inclusive range of prices to allow for Merchant checks."; + mOptionDescriptions[RSK_MERCHANT_PRICES_RANGE_2] = + "The second part of the inclusive range of prices to allow for Merchant checks."; + mOptionDescriptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT] = + "The chance for Merchant checks to be free."; + mOptionDescriptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT] = + "The chance for Merchant checks to be purchasable with Child's Wallet (1-99)."; + mOptionDescriptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT] = + "The chance for Merchant checks to be purchasable with Adult's Wallet (100-200)."; + mOptionDescriptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT] = + "The chance for Merchant checks to be purchasable with Giant's Wallet (201-500)."; + mOptionDescriptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT] = + "The chance for Merchant checks to be purchasable with Tycoon Wallet. (500+)"; + mOptionDescriptions[RSK_MERCHANT_PRICES_AFFORDABLE] = + "After choosing a price, set it to the affordable amount based on the wallet required.\n\n" + "Affordable prices per tier: starter = 1, adult = 100, giant = 201, tycoon = 501\n\n" + "Use this to enable wallet tier locking, but make merchant items not as expensive as they could be."; mOptionDescriptions[RSK_SHUFFLE_FROG_SONG_RUPEES] = "Shuffles 5 Purple Rupees into to the item pool, and allows\n" "you to earn items by playing songs at the Frog Choir.\n" "\n" @@ -546,9 +619,9 @@ void Settings::CreateOptionDescriptions() { mOptionDescriptions[RSK_CHICKENS_HINT] = "Talking to Anju as a child will tell you the item she will give you for delivering her Cuccos to the pen"; mOptionDescriptions[RSK_MALON_HINT] = "Talking to Malon as adult will tell you the item on \"Link's cow\", the cow you win from beating her time on the Lon Lon Obsticle Course."; mOptionDescriptions[RSK_HBA_HINT] = "Talking to the Horseback Archery gerudo in Gerudo Fortress, or the nearby sign, will tell you what you win for scoring 1000 and 1500 points on Horseback Archery."; - mOptionDescriptions[RSK_WARP_SONG_HINTS] = "Standing near the pedestal for the frogs in Zora's River will tell you " - "the reward for the frogs' ocarina game."; //RANDOTODO fix this, I can't find the original right now because github search sucks + mOptionDescriptions[RSK_WARP_SONG_HINTS] = "Playing a warp song will tell you where it leads. (If warp song destinations are vanilla, this is always enabled.)"; mOptionDescriptions[RSK_SCRUB_TEXT_HINT] = "Business scrubs will reveal the identity of what they're selling."; + mOptionDescriptions[RSK_MERCHANT_TEXT_HINT] = "Merchants will reveal the identity of what they're selling (Shops are not affected by this setting)."; mOptionDescriptions[RSK_KAK_10_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 10 tokens will tell you the reward"; mOptionDescriptions[RSK_KAK_20_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 20 tokens will tell you the reward"; mOptionDescriptions[RSK_KAK_30_SKULLS_HINT] = "Talking to the Cursed Resident in the Skultulla House who is saved after 30 tokens will tell you the reward"; diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 45c794244..6aeb3dd84 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -242,9 +242,10 @@ void Randomizer::LoadHintMessages() { // Bow Shooting Gallery reminder CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW, - CustomMessage("Come back when you have your own&bow and you'll get a %rdifferent prize%w!", - "Komm wieder sobald Du Deinen eigenen&Bogen hast, um einen %rspeziellen Preis%w zu&erhalten!", - "J'aurai %rune autre récompense%w pour toi&lorsque tu auras ton propre arc.")); + CustomMessage("Come back when you have your own bow and you'll get a #different prize#!", + "Komm wieder sobald Du Deinen eigenen Bogen hast, um einen #speziellen Preis# zu erhalten!", + "J'aurai #une autre récompense# pour toi lorsque tu auras ton propre arc.", + {QM_RED})); // Warp Song Mysterious text CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_WARP_MINUET_OF_FOREST, @@ -259,9 +260,9 @@ void Randomizer::LoadHintMessages() { "Wasserstand Kontrollsystem&Finger weg!", "Système de contrôle du niveau&d'eau.&Ne pas toucher!")); CustomMessageManager::Instance->CreateMessage(Randomizer::hintMessageTableID, TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI, - CustomMessage("%cThis switch is rustier than you think.^%cSomething must be wrong with the&pipe system in the %bWater Temple%c.", - "%cDieser Schalter scheint rostiger zu&sein als er aussieht.^%cEtwas muss mit dem Leitungssystem&im %bWassertempel%c nicht stimmen.", - "%cCet interrupteur est très rouillé.^%cIl doit y avoir un problème avec&la tuyauterie du %bTemple de l'Eau%c.")); + CustomMessage("%cThis switch is rustier than you think.^%cSomething must be wrong with the pipe system in the %bWater Temple%c.", + "%cDieser Schalter scheint rostiger zu sein als er aussieht.^%cEtwas muss mit dem Leitungssystem im %bWassertempel%c nicht stimmen.", + "%cCet interrupteur est très rouillé.^%cIl doit y avoir un problème avec la tuyauterie du %bTemple de l'Eau%c.")); } // Reference soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.h @@ -304,38 +305,101 @@ void Randomizer::LoadMerchantMessages() { // Prices have a chance of being 0, and the "sell" message below doesn't really make sense for a free item, so adding a "free" variation here CustomMessageManager::Instance->CreateMessage(Randomizer::merchantMessageTableID, TEXT_SCRUB_RANDOM_FREE, - CustomMessage("\x12\x38\x82" "All right! You win! In return for&sparing me, I will give you a&%g[[item]]%w!&Please, take it!\x07\x10\xA3", - "\x12\x38\x82" "In Ordnung! Du gewinnst! Im Austausch&dafür, dass Du mich verschont hast,&werde ich Dir einen &%g[[item]]%w geben!\x07\x10\xA3", - "\x12\x38\x82" "J'me rends! Laisse-moi partir et en&échange, je te donne un &%g[[item]]%w! Vas-y prends le!\x07\x10\xA3")); + CustomMessage("\x12\x38\x82" "All right! You win! In return for sparing me, I will give you a #[[1]]#!&Please, take it!\x07\x10\xA3", + "\x12\x38\x82" "In Ordnung! Du gewinnst! Im Austausch dafür, dass Du mich verschont hast, werde ich Dir einen #[[1]]# geben!\x07\x10\xA3", + "\x12\x38\x82" "J'me rends! Laisse-moi partir et en échange, je te donne un #[[1]]#! Vas-y prends le!\x07\x10\xA3", + {QM_GREEN})); CustomMessageManager::Instance->CreateMessage(Randomizer::merchantMessageTableID, TEXT_SCRUB_RANDOM, - CustomMessage("\x12\x38\x82" "All right! You win! In return for&sparing me, I will sell you a&%g[[item]]%w!&%r[[price]] Rupees%w it is!\x07\x10\xA3", - "\x12\x38\x82" "Ich gebe auf! Ich verkaufe Dir einen&%g[[item]]%w&für %r[[price]] Rubine%w!\x07\x10\xA3", - "\x12\x38\x82" "J'abandonne! Tu veux bien m'acheter&un %g[[item]]%w?&Ça fera %r[[price]] Rubis%w!\x07\x10\xA3")); + CustomMessage("\x12\x38\x82" "All right! You win! In return for sparing me, I will sell you a #[[1]]#! #[[2]] Rupees# it is!\x07\x10\xA3", + "\x12\x38\x82" "Ich gebe auf! Ich verkaufe Dir einen #[[1]]# für #[[2]] Rubine#!\x07\x10\xA3", + "\x12\x38\x82" "J'abandonne! Tu veux bien m'acheter un #[[1]]#? Ça fera #[[2]] Rubis#!\x07\x10\xA3", + {QM_GREEN, QM_YELLOW})); //Carpet Salesman CustomMessageManager::Instance->CreateMessage( - Randomizer::merchantMessageTableID, TEXT_CARPET_SALESMAN_2, - CustomMessage("Finally! Now I can go back to being &an %rarms dealer%w!", - /*german*/"Endlich! Schon bald kann ich wieder &%rKrabbelminen-Händler%w sein!", - /*french*/ "Squalala! Je vais enfin pouvoir &%rprendre des vacances%w!")); + Randomizer::merchantMessageTableID, TEXT_CARPET_SALESMAN_ARMS_DEALER, + CustomMessage("Finally! Now I can go back to being an #arms dealer#!", + /*german*/"Endlich! Schon bald kann ich wieder #Krabbelminen-Händler# sein!", + /*french*/"Squalala! Je vais enfin pouvoir #prendre des vacances#!", + {QM_RED})); // Each shop item has two messages, one for when the cursor is over it, and one for when you select it and are // prompted buy/don't buy CustomMessageManager::Instance->CreateMessage( Randomizer::merchantMessageTableID, TEXT_SHOP_ITEM_RANDOM, - CustomMessage("\x08%r[[item]] [[price]] Rupees&%wSpecial deal! ONE LEFT!&Get it while it lasts!\x0A\x02", - "\x08%r[[item]] [[price]] Rubine&%wSonderangebot! NUR NOCH EINES VERFÜGBAR!&Beeilen Sie sich!\x0A\x02", - "\x08%r[[item]] [[price]] Rubis&%wOffre spéciale! DERNIER EN STOCK!&Faites vite!\x0A\x02")); + CustomMessage("\x08#[[1]]# #[[2]]_Rupees#&Special deal! #ONE LEFT#!&Get it while it lasts!\x0A\x02", + "\x08#[[1]]# #[[2]]_Rubine#&Sonderangebot! #NUR NOCH EINES VERFÜGBAR#!&Beeilen Sie sich!\x0A\x02", + "\x08#[[1]]# #[[2]]_Rubis#&Offre spéciale! #DERNIER EN STOCK#!&Faites vite!\x0A\x02", + {QM_GREEN, QM_YELLOW, QM_RED})); + CustomMessageManager::Instance->CreateMessage( Randomizer::merchantMessageTableID, TEXT_SHOP_ITEM_RANDOM_CONFIRM, - CustomMessage("\x08[[item]] [[price]] Rupees\x09&&\x1B%gBuy&Don't buy%w\x09\x02", - "\x08[[item]] [[price]] Rubine\x09&&\x1B%gKaufen&Nicht kaufen%w\x09\x02", - "\x08[[item]] [[price]] Rubis\x09&&\x1B%gAcheter&Ne pas acheter%w\x09\x02")); + CustomMessage("\x08#[[1]]# #[[2]]_Rupees#\x09\x1B#Buy&Don't buy#\x09\x02", + "\x08#[[1]]# #[[2]]_Rubine#\x09\x1B#Kaufen&Nicht kaufen#\x09\x02", + "\x08#[[1]]# #[[2]]_Rubis#\x09\x1B#Acheter&Ne pas acheter#\x09\x02", + {QM_GREEN, QM_YELLOW, QM_GREEN})); + + CustomMessageManager::Instance->CreateMessage( + Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN_BUY_FOR_10, + CustomMessage("I tried to be a #magic bean# salesman, but it turns out my marketing skills weren't worth " + "beans!^Anyway, want to buy #[[1]]# for #[[2]] Rupees#?\x1B#Yes&No#", + /*german*/ "Möchten Sie #[[1]]# für #[[2]] Rubine# kaufen?\x1B#Ja&Nein#", + /*french*/ "J'ai essayé d'être un vendeur de #haricots magiques#, mais j'étais mauvais au niveau du marketing et ça " + "me courait sur le haricot...^Enfin bref, ça te dirait de m'acheter #[[1]]# pour #[[2]] Rubis#?\x1B#Oui&Non#", + {QM_RED, QM_GREEN, QM_YELLOW, QM_GREEN})); + CustomMessageManager::Instance->CreateMessage( Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN_BUY_FOR_100, - CustomMessage("I never thought I'd say this, but I'm &selling the last %rMagic Bean%w. %r99%w Rupees...\x1B&%gYes&No%w", - "Ich hätte nie gedacht, daß ich das&sage, aber ich verkaufe die letzte^%rWundererbse%w für %r99%w Rubine.&\x1B&%gJa&Nein%w", - "Je te vends mon dernier %rHaricot&magique%w pour %r99 Rubis%w.\x1B&%gAcheter&Ne pas acheter%w")); + CustomMessage("I never thought I'd say this, but I'm selling the last #Magic Bean#. #99 Rupees#...\x1B#Yes&No#", + "Ich hätte nie gedacht, daß ich das sage, aber ich verkaufe die letzte^#Wundererbse# für #99 Rubine#.\x1B&#Ja&Nein#", + "Je te vends mon dernier #Haricot&magique# pour #99 Rubis#.\x1B&#AcheterNe pas acheter#", + {QM_RED, QM_YELLOW, QM_GREEN})); + + CustomMessageManager::Instance->CreateMessage( + Randomizer::merchantMessageTableID, TEXT_MEDIGORON, + CustomMessage("How about buying #[[1]]# for #[[2]] Rupees#?\x1B#Buy&Don't buy#", + /*german*/ "Möchtest Du #[[1]]# für #[[2]] Rubine# kaufen?\x1B#Klar!&Nie im Leben!#", + /*french*/ "Veux-tu acheter #[[1]]# pour #[[2]] rubis#?\x1B#Acheter&Ne pas acheter#", + {QM_GREEN, QM_YELLOW, QM_GREEN})); + /*spanish*/ // ¿Me compras #[[1]]# por #[[2]] rupias#?\x1B#Comprar&No comprar# + + CustomMessage firstCarpet = CustomMessage("Welcome!^I am selling stuff, strange and rare, from all over the world to everybody. Today's special is...^", + /*german*/ "Sei gegrüßt!^Ich verkaufe allerlei Kuriositäten. Stets sonderliche und seltene Ware aus " + "aller Welt für jedermann. Das heutige Angebot bleibt...^", + /*french*/ "Bienvenue!^Je vends des objets rares et merveilleux du monde entier. En spécial aujourd'hui...^"); + /*spanish*/ // ¡Acércate!^Vendo productos extraños y difíciles de encontrar... De todo el mundo a todo el mundo. La oferta de hoy es...^#¡ + + CustomMessageManager::Instance->CreateMessage( + Randomizer::merchantMessageTableID, TEXT_CARPET_SALESMAN_MYSTERIOUS, + firstCarpet + + CustomMessage("Terrifying! I won't tell you what it is until I see the #money#...^How about #[[2]] Rupees#?&&" + "\x1B#Buy&Don't buy#", + /*german*/ "Furchterregend, oder? Ich erzähle Euch mehr, wenn ich #Geld# sehe...^Wie wär's mit #[[2]] Rubinen#?&&" + "\x1B#Aber sicher!&Ich bin weg!#", + /*french*/ "Un concentré de puissance! Mais montre tes #rubis# avant que je te dise ce que c'est...^Disons #[[2]] " + "rubis#?&&\x1B#Acheter&Ne pas acheter#", + {QM_RED, QM_YELLOW, QM_GREEN})); + /*spanish*/ // ¡Terrorífico! No te revelaré su nombre hasta que vea el #dinero#...^#[[2]] rupias#, ¿qué te parece?&&" + // "\x1B#Comprar&No comprar# + + CustomMessageManager::Instance->CreateMessage( + Randomizer::merchantMessageTableID, TEXT_CARPET_SALESMAN_1, + firstCarpet + + CustomMessage("#[[1]]!# It's real, I promise! A lonely man such as myself wouldn't #lie# to you, hmm?^" + "How about #[[2]] Rupees#?\x1B#Buy&Don't buy#", + /*german*/ "#[[1]]#! Ich kann versichern, es ist ein aufrichtiges Angebot!^Ein einsamer Mann wie ich würde Dich doch " + "nicht #anlügen#, oder?^Wie wär's mit #[[2]] Rubinen#?\x1B#Aber sicher!&Ich bin weg!#", + /*french*/ "#[[1]]!# C'est vrai! J'te jure! Un gars comme moi ne te #mentirai# pas tu ne crois pas?^Disons #[[2]] " + "rubis#?\x1B#Acheter&Ne pas acheter#", + {QM_GREEN, QM_RED, QM_YELLOW})); + + CustomMessageManager::Instance->CreateMessage( + Randomizer::merchantMessageTableID, TEXT_GRANNYS_SHOP, + CustomMessage("#[[1]]#! How about #[[2]] Rupees#?\x1B#Buy&Don't buy#", + /*german*/ "#[[1]]#! Sagen wir #[[2]] Rubine#?\x1B#Gerne!&Auf keinen Fall!#", + /*french*/ "#[[1]]#! Que dis-tu de #[[2]] rubis#?\x1B#Acheter&Ne pas acheter#", + {QM_GREEN, QM_YELLOW, QM_GREEN}, {true})); + // /*spanish*/#[[1]]#. Vendo por #[[2]] rupias#.&\x1B#Comprar&No comprar# } std::map trialFlagToTrialKey = { @@ -364,16 +428,9 @@ ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerCheck(Randomizer ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGet randoGet) { - // Shopsanity with at least one item shuffled allows for a third wallet upgrade. // This is needed since Plentiful item pool also adds a third progressive wallet - // but we should *not* get Tycoon's Wallet in that mode. - bool tycoonWallet = !( - GetRandoSettingValue(RSK_SHOPSANITY) == RO_SHOPSANITY_OFF || - ( - GetRandoSettingValue(RSK_SHOPSANITY) == RO_SHOPSANITY_SPECIFIC_COUNT && - GetRandoSettingValue(RSK_SHOPSANITY_COUNT) == RO_SHOPSANITY_COUNT_ZERO_ITEMS - ) - ); + // but we should not get Tycoon's Wallet from it if it is off. + bool tycoonWallet = GetRandoSettingValue(RSK_INCLUDE_TYCOON_WALLET); // Same thing with the infinite upgrades, if we're not shuffling them // and we're using the Plentiful item pool, we should prevent the infinite @@ -2006,23 +2063,15 @@ CustomMessage Randomizer::GetFishingPondOwnerMessage(u16 originalTextId) { return messageEntry; } -CustomMessage Randomizer::GetMerchantMessage(RandomizerInf randomizerInf, u16 textId, bool mysterious) { - auto ctx = Rando::Context::GetInstance(); //RANDOTODO If scrubs are allowed to have ambiguous hints, they need to be RandomiserHint objects for logging - CustomMessage messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, textId); - RandomizerCheck rc = GetCheckFromRandomizerInf(randomizerInf); +CustomMessage Randomizer::GetMerchantMessage(RandomizerCheck rc, TextIDs textId, TextIDs freeTextId, bool mysterious) { + auto ctx = Rando::Context::GetInstance(); + CustomMessage messageEntry; RandomizerGet shopItemGet = ctx->GetItemLocation(rc)->GetPlacedRandomizerGet(); CustomMessage shopItemName; + u16 shopItemPrice = ctx->GetItemLocation(rc)->GetPrice(); + if (mysterious || CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0)) { - if (randomizerInf >= RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1 && randomizerInf <= RAND_INF_SHOP_ITEMS_MARKET_BOMBCHU_SHOP_ITEM_8) { - shopItemName = { - "Mysterious Item", - "Mysteriöser Gegenstand", - "Objet Mystérieux" - }; - } else { - shopItemName = Rando::StaticData::hintTextTable[RHT_MYSTERIOUS_ITEM].GetHintMessage(); - } - // TODO: This should eventually be replaced with a full fledged trick model & trick name system + shopItemName = Rando::StaticData::hintTextTable[RHT_MYSTERIOUS_ITEM_CAPITAL].GetHintMessage(); } else if (shopItemGet == RG_ICE_TRAP) { shopItemGet = ctx->overrides[rc].LooksLike(); shopItemName = CustomMessage(ctx->overrides[rc].GetTrickName()); @@ -2030,14 +2079,15 @@ CustomMessage Randomizer::GetMerchantMessage(RandomizerInf randomizerInf, u16 te auto shopItem = Rando::StaticData::RetrieveItem(shopItemGet); shopItemName = {shopItem.GetName()}; } - u16 shopItemPrice = ctx->GetItemLocation(rc)->GetPrice(); - - if (textId == TEXT_SCRUB_RANDOM && shopItemPrice == 0) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, TEXT_SCRUB_RANDOM_FREE); + + if (freeTextId != TEXT_NONE && shopItemPrice == 0) { + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, freeTextId, MF_RAW); + } else { + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, textId, MF_RAW); } - messageEntry.Replace("[[item]]", shopItemName); - messageEntry.Replace("[[price]]", std::to_string(shopItemPrice)); + messageEntry.InsertNames({shopItemName, {std::to_string(shopItemPrice)}}); + messageEntry.AutoFormat(); return messageEntry; } @@ -2199,6 +2249,7 @@ CustomMessage Randomizer::GetTriforcePieceMessage() { messageEntry.Replace("[[current]]", std::to_string(current)); messageEntry.Replace("[[remaining]]", std::to_string(remaining)); messageEntry.Replace("[[required]]", std::to_string(required)); + messageEntry.Format(); return messageEntry; } @@ -2213,11 +2264,6 @@ void CreateNaviRandoMessages() { "%cManchmal kannst Du den %rStahlhammer&%cstatt Bomben verwenden!", "%cParfois, tu peux utiliser la %rMasse&des Titans %cau lieu de tes bombes!" }, - { "%cThere are three %gbusiness scrubs %cin &Hyrule who sell %wmysterious items%c. Do&you know where they are?", - "%cEs gibt drei %gDeku-Händler %cin Hyrule&die mysteriöse Gegenstände&verkaufen. Weißt Du wo sie sind?", - "%cIl y a trois %gPestes Marchandes%c en&Hyrule qui vendent des %wobjets&mystérieux%c. Tu sais où elles " - "sont?" }, - { "%cStuck on this seed? You could &throw in the towel and check the&%wspoiler log%c...", "%cHängst Du bei diesem Seed fest?&Du könntest die Flinte ins Korn&werfen und ins %wSpoiler Log %cschauen...", "%cSi tu es coincé sur cette seed,&tu peux toujours jeter l'éponge&et regader le %wSpoiler log%c..." }, @@ -2566,7 +2612,15 @@ CustomMessage Randomizer::GetIceTrapMessage() { return msg; } -static int goronIDs[9] = { 0x3052, 0x3069, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F, 0x3070 }; +static int goronIDs[9] = { TEXT_FIRE_TEMPLE_GORON_OWE_YOU_BIG_TIME, + TEXT_FIRE_TEMPLE_GORON_FALLING_DOORS_SECRET, + TEXT_FIRE_TEMPLE_GORON_FIRE_SECRET, + TEXT_FIRE_TEMPLE_GORON_FLAME_DANCER_SECRET, + TEXT_FIRE_TEMPLE_GORON_SWITCH_SECRET, + TEXT_FIRE_TEMPLE_GORON_OCARINA_SECRET, + TEXT_FIRE_TEMPLE_GORON_PILLAR_SECRET, + TEXT_FIRE_TEMPLE_GORON_HIDDEN_DOOR_SECRET, + TEXT_FIRE_TEMPLE_GORON_SOUNDS_DIFFERENT_SECRET}; void CreateFireTempleGoronMessages() { CustomMessage FireTempleGoronMessages[NUM_GORON_MESSAGES] = { @@ -2654,6 +2708,7 @@ CustomMessage Randomizer::GetGoronMessage(u16 index) { CustomMessage messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, goronIDs[index]); messageEntry.Replace("[[days]]", std::to_string(gSaveContext.totalDays)); messageEntry.Replace("[[a_btn]]", std::to_string(gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_A])); + messageEntry.Format(); return messageEntry; } diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 14f28311c..4a84d6302 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -19,7 +19,7 @@ #define MAX_SEED_STRING_SIZE 1024 #define NUM_TRIFORCE_PIECE_MESSAGES 6 -#define NUM_NAVI_MESSAGES 19 +#define NUM_NAVI_MESSAGES 18 #define NUM_GORON_MESSAGES 9 class Randomizer { @@ -59,7 +59,7 @@ class Randomizer { ItemObtainability GetItemObtainabilityFromRandomizerGet(RandomizerGet randomizerCheck); CustomMessage GetSheikMessage(s16 scene, u16 originalTextId); CustomMessage GetFishingPondOwnerMessage(u16 originalTextId); - CustomMessage GetMerchantMessage(RandomizerInf randomizerInf, u16 textId, bool mysterious = false); + CustomMessage GetMerchantMessage(RandomizerCheck rc, TextIDs textId, TextIDs freeTextId = TEXT_NONE, bool mysterious = false); RandomizerCheck GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams); CustomMessage GetGoronMessage(u16 index); CustomMessage GetMapGetItemMessageWithHint(GetItemEntry itemEntry); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 7d5a36daa..e657b8ed5 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -34,7 +34,6 @@ typedef enum { HINT_TYPE_TRIAL, HINT_TYPE_ENTRANCE, HINT_TYPE_ITEM_AREA, - HINT_TYPE_MERCHANT, HINT_TYPE_ALTAR_CHILD, HINT_TYPE_ALTAR_ADULT, HINT_TYPE_WOTH, // Way of the Hero @@ -2248,10 +2247,6 @@ typedef enum { RH_REQUIEM_WARP_LOC, RH_NOCTURNE_WARP_LOC, RH_PRELUDE_WARP_LOC, - RH_MEDIGORON, - RH_CARPET_SALESMAN, - RH_BEAN_SALESMAN, - RH_GRANNY, RH_HBA_HINT, RH_MALON_HINT, RH_CHICKENS_HINT, @@ -3429,6 +3424,7 @@ typedef enum { RHT_EPONA, RHT_HINT_MYSTERIOUS, RHT_MYSTERIOUS_ITEM, + RHT_MYSTERIOUS_ITEM_CAPITAL, // Entrances RHT_DESERT_COLOSSUS_TO_COLOSSUS_GROTTO, RHT_GV_GROTTO_LEDGE_TO_GV_OCTOROK_GROTTO, @@ -3617,12 +3613,8 @@ typedef enum { // Static Entrance Hints RHT_WARP_SONG, // Static Location Hints - RHT_MEDIGORON_HINT, RHT_CARPET_SALESMAN_DIALOG_FIRST, RHT_CARPET_SALESMAN_DIALOG_MYSTERIOUS, - RHT_CARPET_SALESMAN_DIALOG_HINTED, - RHT_BEAN_SALESMAN_HINT, - RHT_GRANNY_HINT, RHT_HBA_HINT_SIGN, RHT_HBA_HINT_NOT_ON_HORSE, RHT_HBA_HINT_INITIAL, @@ -3778,14 +3770,33 @@ typedef enum { RSK_SHUFFLE_KOKIRI_SWORD, RSK_SHUFFLE_MASTER_SWORD, RSK_SHUFFLE_CHILD_WALLET, + RSK_INCLUDE_TYCOON_WALLET, RSK_SHUFFLE_DUNGEON_REWARDS, RSK_SHUFFLE_SONGS, RSK_SHUFFLE_TOKENS, RSK_SHOPSANITY, RSK_SHOPSANITY_COUNT, RSK_SHOPSANITY_PRICES, + RSK_SHOPSANITY_PRICES_FIXED_PRICE, + RSK_SHOPSANITY_PRICES_RANGE_1, + RSK_SHOPSANITY_PRICES_RANGE_2, + RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT, + RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT, + RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT, + RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT, + RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT, RSK_SHOPSANITY_PRICES_AFFORDABLE, RSK_SHUFFLE_SCRUBS, + RSK_SCRUBS_PRICES, + RSK_SCRUBS_PRICES_FIXED_PRICE, + RSK_SCRUBS_PRICES_RANGE_1, + RSK_SCRUBS_PRICES_RANGE_2, + RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT, + RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT, + RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT, + RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT, + RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT, + RSK_SCRUBS_PRICES_AFFORDABLE, RSK_SHUFFLE_BEEHIVES, RSK_SHUFFLE_COWS, RSK_SHUFFLE_WEIRD_EGG, @@ -3817,6 +3828,7 @@ typedef enum { RSK_HBA_HINT, RSK_WARP_SONG_HINTS, RSK_SCRUB_TEXT_HINT, + RSK_MERCHANT_TEXT_HINT, RSK_FISHING_POLE_HINT, RSK_HINT_CLARITY, RSK_HINT_DISTRIBUTION, @@ -3838,8 +3850,17 @@ typedef enum { RSK_ENABLE_GLITCH_CUTSCENES, RSK_SKULLS_SUNS_SONG, RSK_SHUFFLE_ADULT_TRADE, - RSK_SHUFFLE_MAGIC_BEANS, RSK_SHUFFLE_MERCHANTS, + RSK_MERCHANT_PRICES, + RSK_MERCHANT_PRICES_FIXED_PRICE, + RSK_MERCHANT_PRICES_RANGE_1, + RSK_MERCHANT_PRICES_RANGE_2, + RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT, + RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT, + RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT, + RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT, + RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT, + RSK_MERCHANT_PRICES_AFFORDABLE, RSK_BLUE_FIRE_ARROWS, RSK_SUNLIGHT_ARROWS, RSK_ENABLE_BOMBCHU_DROPS, @@ -4014,19 +4035,19 @@ typedef enum { //Shopsanity price ranges typedef enum { - RO_SHOPSANITY_PRICE_BALANCED, //Balanced random from 0-300 - RO_SHOPSANITY_PRICE_STARTER, //Wallets are random within their range, in increments of 5 rupees - RO_SHOPSANITY_PRICE_ADULT, - RO_SHOPSANITY_PRICE_GIANT, - RO_SHOPSANITY_PRICE_TYCOON, -} RandoOptionShopsanityPrices; + RO_PRICE_VANILLA, + RO_PRICE_CHEAP_BALANCED, //Balanced random from 0-95, favoring lower numbers + RO_PRICE_BALANCED, //Random from 0-300, favoring lower numbers + RO_PRICE_FIXED, + RO_PRICE_RANGE, + RO_PRICE_SET_BY_WALLET, +} RandoOptionPrices; //Scrubsanity settings (off, affordable, expensive, random) typedef enum { RO_SCRUBS_OFF, - RO_SCRUBS_AFFORDABLE, - RO_SCRUBS_EXPENSIVE, - RO_SCRUBS_RANDOM, + RO_SCRUBS_MAJOR_ONLY, + RO_SCRUBS_ALL, } RandoOptionScrubsanity; //Ammo drop settings (on, "on+bombchu", off) @@ -4161,11 +4182,12 @@ typedef enum { RO_SONG_SHUFFLE_ANYWHERE, } RandoOptionSongShuffle; -//Shuffle Merchants Settings (Off, On no hint, on with wint) +//Shuffle Merchants Settings (Off, Beans Only, All but Beans, All) typedef enum { RO_SHUFFLE_MERCHANTS_OFF, - RO_SHUFFLE_MERCHANTS_ON_NO_HINT, - RO_SHUFFLE_MERCHANTS_ON_HINT, + RO_SHUFFLE_MERCHANTS_BEANS_ONLY, + RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS, + RO_SHUFFLE_MERCHANTS_ALL } RandoOptionShuffleMerchants; //Starting Ocarina Settings (off, fairy) diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp index 45bb928ac..4e50edddd 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp @@ -172,7 +172,7 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() { (location.GetRandomizerCheck() != RC_LH_HYRULE_LOACH || CVarGetInteger(CVAR_RANDOMIZER_SETTING("Fishsanity"), RO_GENERIC_NO) == RO_FISHSANITY_HYRULE_LOACH) && (location.GetRandomizerCheck() != RC_ZR_MAGIC_BEAN_SALESMAN || - CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleBeans"), RO_GENERIC_NO)) && + CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), RO_SHUFFLE_MERCHANTS_OFF) % 2) && (location.GetRandomizerCheck() != RC_HC_MALON_EGG || CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), RO_GENERIC_NO)) && (location.GetRCType() != RCTYPE_FROG_SONG || diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index 469a16f76..645ef85f7 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -1108,13 +1108,15 @@ void LoadSettings() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY) != RO_SHOPSANITY_OFF : false; showBeans = IS_RANDO ? - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MAGIC_BEANS) == RO_GENERIC_YES + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_BEANS_ONLY || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL : true; showScrubs = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) != RO_SCRUBS_OFF : false; showMerchants = IS_RANDO ? - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL : true; showBeehives = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BEEHIVES) == RO_GENERIC_YES diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index 2b67e105d..e07503b20 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -390,13 +390,7 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) { case ITEM_WALLET_ADULT: case ITEM_WALLET_GIANT: result.currentCapacity = IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_WALLET) ? 0 : CUR_CAPACITY(UPG_WALLET); - result.maxCapacity = !IS_RANDO || ( - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY) == RO_SHOPSANITY_OFF || - ( - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY) == RO_SHOPSANITY_SPECIFIC_COUNT && - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY_COUNT) == RO_SHOPSANITY_COUNT_ZERO_ITEMS - ) - ) ? 500 : 999; + result.maxCapacity = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_INCLUDE_TYCOON_WALLET) ? 999 : 500; result.currentAmmo = gSaveContext.rupees; break; case ITEM_BOMBCHU: diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index bab0b4e41..15424960d 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -339,6 +339,13 @@ extern "C" void Randomizer_InitSaveFile() { gSaveContext.adultTradeItems = 0; } + // remove One Time scrubs with scrubsanity off + if (Randomizer_GetSettingValue(RSK_SHUFFLE_SCRUBS) == RO_SCRUBS_OFF) { + Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_BRIDGE); + Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_FRONT); + Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO); + } + int startingAge = OTRGlobals::Instance->gRandoContext->GetSettings()->ResolvedStartingAge(); switch (startingAge) { case RO_AGE_ADULT: // Adult diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index b43d75301..d6738f45a 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -36,6 +36,69 @@ std::vector MultiVecOpts(const std::vector return options; } +void Settings::HandleShopsanityPriceUI(){ + bool isTycoon = CVarGetInteger(CVAR_RANDOMIZER_SETTING("IncludeTycoonWallet"), RO_GENERIC_OFF); + mOptions[RSK_SHOPSANITY].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM); + mOptions[RSK_SHOPSANITY_PRICES].Unhide(); + switch (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), RO_PRICE_VANILLA)){ + case RO_PRICE_FIXED: + mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE].Unhide(); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_1].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_2].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + if (isTycoon ? mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE].GetOptionCount() == 501 : mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE].GetOptionCount() == 1000) { + mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE].ChangeOptions(isTycoon ? NumOpts(0, 999) : NumOpts(0, 500)); + } + mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE].Hide(); + break; + case RO_PRICE_RANGE: + mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_1].Unhide(); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_2].Unhide(); + mOptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + if (isTycoon ? mOptions[RSK_SHOPSANITY_PRICES_RANGE_1].GetOptionCount() == 101 : mOptions[RSK_SHOPSANITY_PRICES_RANGE_1].GetOptionCount() == 200) { + mOptions[RSK_SHOPSANITY_PRICES_RANGE_1].ChangeOptions(isTycoon ? NumOpts(0, 995, 5) : NumOpts(0, 500, 5)); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_2].ChangeOptions(isTycoon ? NumOpts(0, 995, 5) : NumOpts(0, 500, 5)); + } + mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE].Unhide(); + break; + case RO_PRICE_SET_BY_WALLET: + mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_1].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_2].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT].Unhide(); + mOptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT].Unhide(); + mOptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT].Unhide(); + mOptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT].Unhide(); + if (isTycoon){ + mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT].Unhide(); + } else { + mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + } + mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE].Unhide(); + break; + default: + mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_1].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_2].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE].Unhide(); + break; + } +} + Settings::Settings() : mExcludeLocationsOptionsAreas(RCAREA_INVALID) { } @@ -99,23 +162,51 @@ void Settings::CreateOptions() { mOptions[RSK_SHUFFLE_SONGS] = Option::U8("Shuffle Songs", {"Song Locations", "Dungeon Rewards", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleSongs"), mOptionDescriptions[RSK_SHUFFLE_SONGS], WidgetType::Combobox, RO_SONG_SHUFFLE_SONG_LOCATIONS); mOptions[RSK_SHOPSANITY] = Option::U8("Shopsanity", {"Off", "Specific Count", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Shopsanity"), mOptionDescriptions[RSK_SHOPSANITY], WidgetType::Combobox, RO_SHOPSANITY_OFF); mOptions[RSK_SHOPSANITY_COUNT] = Option::U8("Shopsanity Item Count", {NumOpts(0, 7/*8*/)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityCount"), mOptionDescriptions[RSK_SHOPSANITY_COUNT], WidgetType::Slider, 0, false, IMFLAG_NONE); - mOptions[RSK_SHOPSANITY_PRICES] = Option::U8("Shopsanity Prices", {"Balanced", "Starting Wallet", "Adult Wallet", "Giant's Wallet", "Tycoon's Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), mOptionDescriptions[RSK_SHOPSANITY_PRICES], WidgetType::Combobox, RO_SHOPSANITY_PRICE_BALANCED, false, IMFLAG_NONE); - mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE] = Option::Bool("Affordable Prices", CVAR_RANDOMIZER_SETTING("ShopsanityPricesAffordable"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_AFFORDABLE]); + mOptions[RSK_SHOPSANITY_PRICES] = Option::U8("Shopsanity Prices", {"Vanilla", "Cheap Balanced", "Balanced", "Fixed", "Range", "Set By Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), mOptionDescriptions[RSK_SHOPSANITY_PRICES], WidgetType::Combobox, RO_PRICE_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE] = Option::U8("Fixed Price", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityFixedPrice"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE], WidgetType::Slider, 10, true); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_1] = Option::U8("Lower Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPriceRange1"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_RANGE_1], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_2] = Option::U8("Upper Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPriceRange2"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_RANGE_2], WidgetType::Slider, 100, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT] = Option::U8("No Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityNoWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT] = Option::U8("Child Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityChildWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT] = Option::U8("Adult Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityAdultWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT] = Option::U8("Giant Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityGiantWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT] = Option::U8("Tycoon Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityTycoonWalletWeight"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE] = Option::Bool("Shops Affordable Prices", CVAR_RANDOMIZER_SETTING("ShopsanityPricesAffordable"), mOptionDescriptions[RSK_SHOPSANITY_PRICES_AFFORDABLE]); mOptions[RSK_SHUFFLE_TOKENS] = Option::U8("Tokensanity", {"Off", "Dungeons", "Overworld", "All Tokens"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleTokens"), mOptionDescriptions[RSK_SHUFFLE_TOKENS], WidgetType::Combobox, RO_TOKENSANITY_OFF); - mOptions[RSK_SHUFFLE_SCRUBS] = Option::U8("Scrub Shuffle", {"Off", "Affordable", "Expensive", "Random Prices"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleScrubs"), mOptionDescriptions[RSK_SHUFFLE_SCRUBS], WidgetType::Combobox, RO_SCRUBS_OFF); + mOptions[RSK_SHUFFLE_SCRUBS] = Option::U8("Scrub Shuffle", {"Off", "One-Time Only", "All"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleScrubs"), mOptionDescriptions[RSK_SHUFFLE_SCRUBS], WidgetType::Combobox, RO_SCRUBS_OFF); + mOptions[RSK_SCRUBS_PRICES] = Option::U8("Scrub Prices", {"Vanilla", "Cheap Balanced", "Balanced", "Fixed", "Range", "Set By Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsPrices"), mOptionDescriptions[RSK_SCRUBS_PRICES], WidgetType::Combobox, RO_PRICE_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE] = Option::U8("Fixed Price", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsFixedPrice"), mOptionDescriptions[RSK_SCRUBS_PRICES_FIXED_PRICE], WidgetType::Slider, 10, true); + mOptions[RSK_SCRUBS_PRICES_RANGE_1] = Option::U8("Lower Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsPriceRange1"), mOptionDescriptions[RSK_SCRUBS_PRICES_RANGE_1], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_RANGE_2] = Option::U8("Upper Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsPriceRange2"), mOptionDescriptions[RSK_SCRUBS_PRICES_RANGE_2], WidgetType::Slider, 100, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT] = Option::U8("No Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsNoWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT] = Option::U8("Child Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsChildWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT] = Option::U8("Adult Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsAdultWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT] = Option::U8("Giant Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsGiantWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT] = Option::U8("Tycoon Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ScrubsTycoonWalletWeight"), mOptionDescriptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_SCRUBS_PRICES_AFFORDABLE] = Option::Bool("Scrubs Affordable Prices", CVAR_RANDOMIZER_SETTING("ScrubsPricesAffordable"), mOptionDescriptions[RSK_SCRUBS_PRICES_AFFORDABLE]); mOptions[RSK_SHUFFLE_BEEHIVES] = Option::Bool("Shuffle Beehives", CVAR_RANDOMIZER_SETTING("ShuffleBeehives"), mOptionDescriptions[RSK_SHUFFLE_BEEHIVES]); mOptions[RSK_SHUFFLE_COWS] = Option::Bool("Shuffle Cows", CVAR_RANDOMIZER_SETTING("ShuffleCows"), mOptionDescriptions[RSK_SHUFFLE_COWS]); mOptions[RSK_SHUFFLE_KOKIRI_SWORD] = Option::Bool("Shuffle Kokiri Sword", CVAR_RANDOMIZER_SETTING("ShuffleKokiriSword"), mOptionDescriptions[RSK_SHUFFLE_KOKIRI_SWORD]); mOptions[RSK_SHUFFLE_MASTER_SWORD] = Option::Bool("Shuffle Master Sword", CVAR_RANDOMIZER_SETTING("ShuffleMasterSword"), mOptionDescriptions[RSK_SHUFFLE_MASTER_SWORD]); - mOptions[RSK_SHUFFLE_CHILD_WALLET] = Option::Bool("Shuffle Child's Wallet", CVAR_RANDOMIZER_SETTING("ShuffleChildWallet"), mOptionDescriptions[RSK_SHUFFLE_CHILD_WALLET]); + mOptions[RSK_SHUFFLE_CHILD_WALLET] = Option::Bool("Shuffle Child's Wallet", CVAR_RANDOMIZER_SETTING("ShuffleChildWallet"), mOptionDescriptions[RSK_SHUFFLE_CHILD_WALLET], IMFLAG_NONE); + mOptions[RSK_INCLUDE_TYCOON_WALLET] = Option::Bool("Include Tycoon Wallet", CVAR_RANDOMIZER_SETTING("IncludeTycoonWallet"), mOptionDescriptions[RSK_INCLUDE_TYCOON_WALLET]); mOptions[RSK_SHUFFLE_OCARINA] = Option::Bool("Shuffle Ocarinas", CVAR_RANDOMIZER_SETTING("ShuffleOcarinas"), mOptionDescriptions[RSK_SHUFFLE_OCARINA]); mOptions[RSK_SHUFFLE_OCARINA_BUTTONS] = Option::Bool("Shuffle Ocarina Buttons", CVAR_RANDOMIZER_SETTING("ShuffleOcarinaButtons"), mOptionDescriptions[RSK_SHUFFLE_OCARINA_BUTTONS]); mOptions[RSK_SHUFFLE_SWIM] = Option::Bool("Shuffle Swim", CVAR_RANDOMIZER_SETTING("ShuffleSwim"), mOptionDescriptions[RSK_SHUFFLE_SWIM]); mOptions[RSK_SHUFFLE_WEIRD_EGG] = Option::Bool("Shuffle Weird Egg", CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG]); mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD] = Option::Bool("Shuffle Gerudo Membership Card", CVAR_RANDOMIZER_SETTING("ShuffleGerudoToken"), mOptionDescriptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD]); mOptions[RSK_SHUFFLE_FISHING_POLE] = Option::Bool("Shuffle Fishing Pole", CVAR_RANDOMIZER_SETTING("ShuffleFishingPole"), mOptionDescriptions[RSK_SHUFFLE_FISHING_POLE]); - mOptions[RSK_SHUFFLE_MAGIC_BEANS] = Option::Bool("Shuffle Magic Beans", CVAR_RANDOMIZER_SETTING("ShuffleBeans"), mOptionDescriptions[RSK_SHUFFLE_MAGIC_BEANS]); - mOptions[RSK_SHUFFLE_MERCHANTS] = Option::U8("Shuffle Merchants", {"Off", "On (No Hints)", "On (With Hints)"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), mOptionDescriptions[RSK_SHUFFLE_MERCHANTS], WidgetType::Combobox, RO_SHUFFLE_MERCHANTS_OFF); + mOptions[RSK_SHUFFLE_MERCHANTS] = Option::U8("Shuffle Merchants", {"Off", "Bean Merchant Only", "All But Beans", "All"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), mOptionDescriptions[RSK_SHUFFLE_MERCHANTS], WidgetType::Combobox, RO_SHUFFLE_MERCHANTS_OFF, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES] = Option::U8("Merchant Prices", {"Vanilla", "Cheap Balanced", "Balanced", "Fixed", "Range", "Set By Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantPrices"), mOptionDescriptions[RSK_MERCHANT_PRICES], WidgetType::Combobox, RO_PRICE_VANILLA, false, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE] = Option::U8("Fixed Price", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantFixedPrice"), mOptionDescriptions[RSK_MERCHANT_PRICES_FIXED_PRICE], WidgetType::Slider, 10, true); + mOptions[RSK_MERCHANT_PRICES_RANGE_1] = Option::U8("Lower Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantPriceRange1"), mOptionDescriptions[RSK_MERCHANT_PRICES_RANGE_1], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_RANGE_2] = Option::U8("Upper Bound", {NumOpts(0, 995, 5)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantPriceRange2"), mOptionDescriptions[RSK_MERCHANT_PRICES_RANGE_2], WidgetType::Slider, 100, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT] = Option::U8("No Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantNoWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT] = Option::U8("Child Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantChildWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT] = Option::U8("Adult Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantAdultWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT] = Option::U8("Giant Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantGiantWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT] = Option::U8("Tycoon Wallet Weight", {NumOpts(0, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MerchantTycoonWalletWeight"), mOptionDescriptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT], WidgetType::Slider, 10, true, IMFLAG_NONE); + mOptions[RSK_MERCHANT_PRICES_AFFORDABLE] = Option::Bool("Merchant Affordable Prices", CVAR_RANDOMIZER_SETTING("MerchantPricesAffordable"), mOptionDescriptions[RSK_MERCHANT_PRICES_AFFORDABLE]); mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES] = Option::Bool("Shuffle Frog Song Rupees", CVAR_RANDOMIZER_SETTING("ShuffleFrogSongRupees"), mOptionDescriptions[RSK_SHUFFLE_FROG_SONG_RUPEES]); mOptions[RSK_SHUFFLE_ADULT_TRADE] = Option::Bool("Shuffle Adult Trade", CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), mOptionDescriptions[RSK_SHUFFLE_ADULT_TRADE]); mOptions[RSK_SHUFFLE_CHEST_MINIGAME] = Option::U8("Shuffle Chest Minigame", {"Off", "On (Separate)", "On (Pack)"}); @@ -176,6 +267,7 @@ void Settings::CreateOptions() { mOptions[RSK_HBA_HINT] = Option::Bool("Horseback Archery Hint", CVAR_RANDOMIZER_SETTING("HBAHint"), mOptionDescriptions[RSK_HBA_HINT], IMFLAG_NONE); mOptions[RSK_WARP_SONG_HINTS] = Option::Bool("Warp Song Hints", CVAR_RANDOMIZER_SETTING("WarpSongText"), mOptionDescriptions[RSK_WARP_SONG_HINTS], IMFLAG_NONE, WidgetType::Checkbox, RO_GENERIC_ON); mOptions[RSK_SCRUB_TEXT_HINT] = Option::Bool("Scrub Hint Text", CVAR_RANDOMIZER_SETTING("ScrubText"), mOptionDescriptions[RSK_SCRUB_TEXT_HINT], IMFLAG_NONE); + mOptions[RSK_MERCHANT_TEXT_HINT] = Option::Bool("Merchant Hint Text", CVAR_RANDOMIZER_SETTING("MerchantText"), mOptionDescriptions[RSK_MERCHANT_TEXT_HINT], IMFLAG_NONE); mOptions[RSK_KAK_10_SKULLS_HINT] = Option::Bool("10 GS Hint", CVAR_RANDOMIZER_SETTING("10GSHint"), mOptionDescriptions[RSK_KAK_10_SKULLS_HINT], IMFLAG_NONE); mOptions[RSK_KAK_20_SKULLS_HINT] = Option::Bool("20 GS Hint", CVAR_RANDOMIZER_SETTING("20GSHint"), mOptionDescriptions[RSK_KAK_20_SKULLS_HINT], IMFLAG_NONE); mOptions[RSK_KAK_30_SKULLS_HINT] = Option::Bool("30 GS Hint", CVAR_RANDOMIZER_SETTING("30GSHint"), mOptionDescriptions[RSK_KAK_30_SKULLS_HINT], IMFLAG_NONE); @@ -662,6 +754,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_KOKIRI_SWORD], &mOptions[RSK_SHUFFLE_MASTER_SWORD], &mOptions[RSK_SHUFFLE_CHILD_WALLET], + &mOptions[RSK_INCLUDE_TYCOON_WALLET], &mOptions[RSK_SHUFFLE_OCARINA], &mOptions[RSK_SHUFFLE_OCARINA_BUTTONS], &mOptions[RSK_SHUFFLE_SWIM], @@ -675,15 +768,42 @@ void Settings::CreateOptions() { &mOptions[RSK_SHOPSANITY], &mOptions[RSK_SHOPSANITY_COUNT], &mOptions[RSK_SHOPSANITY_PRICES], + &mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE], + &mOptions[RSK_SHOPSANITY_PRICES_RANGE_1], + &mOptions[RSK_SHOPSANITY_PRICES_RANGE_2], + &mOptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT], + &mOptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT], + &mOptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT], + &mOptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT], + &mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT], &mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE], &mOptions[RSK_FISHSANITY], &mOptions[RSK_FISHSANITY_POND_COUNT], &mOptions[RSK_FISHSANITY_AGE_SPLIT], &mOptions[RSK_SHUFFLE_SCRUBS], + &mOptions[RSK_SCRUBS_PRICES], + &mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE], + &mOptions[RSK_SCRUBS_PRICES_RANGE_1], + &mOptions[RSK_SCRUBS_PRICES_RANGE_2], + &mOptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT], + &mOptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT], + &mOptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT], + &mOptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT], + &mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT], + &mOptions[RSK_SCRUBS_PRICES_AFFORDABLE], &mOptions[RSK_SHUFFLE_BEEHIVES], &mOptions[RSK_SHUFFLE_COWS], - &mOptions[RSK_SHUFFLE_MAGIC_BEANS], &mOptions[RSK_SHUFFLE_MERCHANTS], + &mOptions[RSK_MERCHANT_PRICES], + &mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE], + &mOptions[RSK_MERCHANT_PRICES_RANGE_1], + &mOptions[RSK_MERCHANT_PRICES_RANGE_2], + &mOptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT], + &mOptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT], + &mOptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT], + &mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT], + &mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT], + &mOptions[RSK_MERCHANT_PRICES_AFFORDABLE], &mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES], &mOptions[RSK_SHUFFLE_ADULT_TRADE], &mOptions[RSK_SHUFFLE_100_GS_REWARD], @@ -753,6 +873,7 @@ void Settings::CreateOptions() { &mOptions[RSK_FISHING_POLE_HINT], &mOptions[RSK_WARP_SONG_HINTS], &mOptions[RSK_SCRUB_TEXT_HINT], + &mOptions[RSK_MERCHANT_TEXT_HINT], &mOptions[RSK_KAK_10_SKULLS_HINT], &mOptions[RSK_KAK_20_SKULLS_HINT], &mOptions[RSK_KAK_30_SKULLS_HINT], @@ -880,6 +1001,14 @@ void Settings::CreateOptions() { &mOptions[RSK_SHOPSANITY], &mOptions[RSK_SHOPSANITY_COUNT], &mOptions[RSK_SHOPSANITY_PRICES], + &mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE], + &mOptions[RSK_SHOPSANITY_PRICES_RANGE_1], + &mOptions[RSK_SHOPSANITY_PRICES_RANGE_2], + &mOptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT], + &mOptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT], + &mOptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT], + &mOptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT], + &mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT], &mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE], &mOptions[RSK_FISHSANITY], &mOptions[RSK_FISHSANITY_POND_COUNT], @@ -887,6 +1016,16 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_FISHING_POLE], &mOptions[RSK_SHUFFLE_TOKENS], &mOptions[RSK_SHUFFLE_SCRUBS], + &mOptions[RSK_SCRUBS_PRICES], + &mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE], + &mOptions[RSK_SCRUBS_PRICES_RANGE_1], + &mOptions[RSK_SCRUBS_PRICES_RANGE_2], + &mOptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT], + &mOptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT], + &mOptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT], + &mOptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT], + &mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT], + &mOptions[RSK_SCRUBS_PRICES_AFFORDABLE], &mOptions[RSK_SHUFFLE_BEEHIVES], &mOptions[RSK_SHUFFLE_COWS], &mOptions[RSK_SHUFFLE_KOKIRI_SWORD], @@ -895,8 +1034,17 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_SWIM], &mOptions[RSK_SHUFFLE_WEIRD_EGG], &mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD], - &mOptions[RSK_SHUFFLE_MAGIC_BEANS], &mOptions[RSK_SHUFFLE_MERCHANTS], + &mOptions[RSK_MERCHANT_PRICES], + &mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE], + &mOptions[RSK_MERCHANT_PRICES_RANGE_1], + &mOptions[RSK_MERCHANT_PRICES_RANGE_2], + &mOptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT], + &mOptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT], + &mOptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT], + &mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT], + &mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT], + &mOptions[RSK_MERCHANT_PRICES_AFFORDABLE], &mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES], &mOptions[RSK_SHUFFLE_ADULT_TRADE], &mOptions[RSK_SHUFFLE_CHEST_MINIGAME], @@ -997,6 +1145,7 @@ void Settings::CreateOptions() { &mOptions[RSK_KAK_100_SKULLS_HINT], &mOptions[RSK_MASK_SHOP_HINT], &mOptions[RSK_SCRUB_TEXT_HINT], + &mOptions[RSK_MERCHANT_TEXT_HINT], &mOptions[RSK_FISHING_POLE_HINT], // TODO: Compasses show Reward/WOTH, Maps show Dungeon Mode, Starting Time &mOptions[RSK_DAMAGE_MULTIPLIER], @@ -1082,7 +1231,7 @@ void Settings::CreateOptions() { &mOptionGroups[RSG_EXCLUDES] }); - VanillaLogicDefaults = { + VanillaLogicDefaults = {//RANDOTODO check what this does &mOptions[RSK_LINKS_POCKET], &mOptions[RSK_SHUFFLE_DUNGEON_REWARDS], &mOptions[RSK_SHUFFLE_SONGS], @@ -1096,7 +1245,6 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_SCRUBS], &mOptions[RSK_SHUFFLE_BEEHIVES], &mOptions[RSK_SHUFFLE_COWS], - &mOptions[RSK_SHUFFLE_MAGIC_BEANS], &mOptions[RSK_SHUFFLE_MERCHANTS], &mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES], &mOptions[RSK_SHUFFLE_ADULT_TRADE], @@ -1131,12 +1279,30 @@ void Settings::CreateOptions() { { "Shuffle Settings:Shopsanity", RSK_SHOPSANITY }, { "Shuffle Settings:Shopsanity Specific Count", RSK_SHOPSANITY_COUNT }, { "Shuffle Settings:Shopsanity Prices", RSK_SHOPSANITY_PRICES }, - { "Shuffle Settings:Affordable Prices", RSK_SHOPSANITY_PRICES_AFFORDABLE }, + { "Shuffle Settings:Shopsanity Fixed Amount", RSK_SHOPSANITY_PRICES_FIXED_PRICE }, + { "Shuffle Settings:Shopsanity Range 1", RSK_SHOPSANITY_PRICES_RANGE_1 }, + { "Shuffle Settings:Shopsanity Range 2", RSK_SHOPSANITY_PRICES_RANGE_2 }, + { "Shuffle Settings:Shopsanity No Wallet Weight", RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT }, + { "Shuffle Settings:Shopsanity Child Wallet Weight", RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT }, + { "Shuffle Settings:Shopsanity Adult Wallet Weight", RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT }, + { "Shuffle Settings:Shopsanity Giants Wallet Weight", RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT }, + { "Shuffle Settings:Shopsanity Tycoon Wallet Weight", RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT }, + { "Shuffle Settings:Shopsanity Affordable Prices", RSK_SHOPSANITY_PRICES_AFFORDABLE }, { "Shuffle Settings:Fishsanity", RSK_FISHSANITY }, { "Shuffle Settings:Pond Fish Count", RSK_FISHSANITY_POND_COUNT }, { "Shuffle Settings:Split Pond Fish", RSK_FISHSANITY_AGE_SPLIT }, { "Shuffle Settings:Shuffle Fishing Pole", RSK_SHUFFLE_FISHING_POLE }, { "Shuffle Settings:Scrub Shuffle", RSK_SHUFFLE_SCRUBS }, + { "Shuffle Settings:Scrubs Prices", RSK_SCRUBS_PRICES }, + { "Shuffle Settings:Scrubs Fixed Amount", RSK_SCRUBS_PRICES_FIXED_PRICE }, + { "Shuffle Settings:Scrubs Range 1", RSK_SCRUBS_PRICES_RANGE_1 }, + { "Shuffle Settings:Scrubs Range 2", RSK_SCRUBS_PRICES_RANGE_2 }, + { "Shuffle Settings:Scrubs No Wallet Weight", RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT }, + { "Shuffle Settings:Scrubs Child Wallet Weight", RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT }, + { "Shuffle Settings:Scrubs Adult Wallet Weight", RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT }, + { "Shuffle Settings:Scrubs Giants Wallet Weight", RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT }, + { "Shuffle Settings:Scrubs Tycoon Wallet Weight", RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT }, + { "Shuffle Settings:Scrubs Affordable Prices", RSK_SCRUBS_PRICES_AFFORDABLE }, { "Shuffle Settings:Beehive Shuffle", RSK_SHUFFLE_BEEHIVES }, { "Shuffle Settings:Shuffle Cows", RSK_SHUFFLE_COWS }, { "Shuffle Settings:Tokensanity", RSK_SHUFFLE_TOKENS }, @@ -1144,13 +1310,23 @@ void Settings::CreateOptions() { { "Shuffle Settings:Shuffle Ocarina Buttons", RSK_SHUFFLE_OCARINA_BUTTONS }, { "Shuffle Settings:Shuffle Swim", RSK_SHUFFLE_SWIM }, { "Shuffle Settings:Shuffle Adult Trade", RSK_SHUFFLE_ADULT_TRADE }, - { "Shuffle Settings:Shuffle Magic Beans", RSK_SHUFFLE_MAGIC_BEANS }, { "Shuffle Settings:Shuffle Kokiri Sword", RSK_SHUFFLE_KOKIRI_SWORD }, { "Shuffle Settings:Shuffle Master Sword", RSK_SHUFFLE_MASTER_SWORD }, { "Shuffle Settings:Shuffle Child's Wallet", RSK_SHUFFLE_CHILD_WALLET }, + { "Shuffle Settings:Include Tycoon Wallet", RSK_INCLUDE_TYCOON_WALLET }, { "Shuffle Settings:Shuffle Weird Egg", RSK_SHUFFLE_WEIRD_EGG }, { "Shuffle Settings:Shuffle Frog Song Rupees", RSK_SHUFFLE_FROG_SONG_RUPEES }, { "Shuffle Settings:Shuffle Merchants", RSK_SHUFFLE_MERCHANTS }, + { "Shuffle Settings:Merchant Prices", RSK_MERCHANT_PRICES }, + { "Shuffle Settings:Merchant Fixed Amount", RSK_MERCHANT_PRICES_FIXED_PRICE }, + { "Shuffle Settings:Merchant Range 1", RSK_MERCHANT_PRICES_RANGE_1 }, + { "Shuffle Settings:Merchant Range 2", RSK_MERCHANT_PRICES_RANGE_2 }, + { "Shuffle Settings:Merchant No Wallet Weight", RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT }, + { "Shuffle Settings:Merchant Child Wallet Weight", RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT }, + { "Shuffle Settings:Merchant Adult Wallet Weight", RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT }, + { "Shuffle Settings:Merchant Giants Wallet Weight", RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT }, + { "Shuffle Settings:Merchant Tycoon Wallet Weight", RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT }, + { "Shuffle Settings:Merchant Affordable Prices", RSK_MERCHANT_PRICES_AFFORDABLE }, { "Shuffle Settings:Shuffle 100 GS Reward", RSK_SHUFFLE_100_GS_REWARD }, { "Shuffle Settings:Shuffle Boss Souls", RSK_SHUFFLE_BOSS_SOULS }, { "Shuffle Settings:Shuffle Deku Stick Bag", RSK_SHUFFLE_DEKU_STICK_BAG }, @@ -1237,6 +1413,7 @@ void Settings::CreateOptions() { { "Miscellaneous Settings:Big Poes Hint", RSK_BIG_POES_HINT }, { "Miscellaneous Settings:Warp Song Hints", RSK_WARP_SONG_HINTS }, { "Miscellaneous Settings:Scrub Hint Text", RSK_SCRUB_TEXT_HINT }, + { "Miscellaneous Settings:Merchant Hint Text", RSK_MERCHANT_TEXT_HINT }, { "Miscellaneous Settings:Fishing Pole Hint", RSK_FISHING_POLE_HINT }, { "Miscellaneous Settings:Hint Distribution", RSK_HINT_DISTRIBUTION }, { "Miscellaneous Settings:Blue Fire Arrows", RSK_BLUE_FIRE_ARROWS }, @@ -1607,25 +1784,183 @@ void Settings::UpdateOptionProperties() { } else { mOptions[RSK_SHUFFLE_WEIRD_EGG].Enable(); } + bool isTycoon = CVarGetInteger(CVAR_RANDOMIZER_SETTING("IncludeTycoonWallet"), RO_GENERIC_OFF); // Hide shopsanity prices if shopsanity is off or zero switch (CVarGetInteger(CVAR_RANDOMIZER_SETTING("Shopsanity"), RO_SHOPSANITY_OFF)) { case RO_SHOPSANITY_OFF: mOptions[RSK_SHOPSANITY].AddFlag(IMFLAG_SEPARATOR_BOTTOM); mOptions[RSK_SHOPSANITY_COUNT].Hide(); + mOptions[RSK_SHOPSANITY_COUNT].Hide(); mOptions[RSK_SHOPSANITY_PRICES].Hide(); mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_1].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_RANGE_2].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SHOPSANITY_PRICES_TYCOON_WALLET_WEIGHT].Hide(); break; case RO_SHOPSANITY_SPECIFIC_COUNT: - mOptions[RSK_SHOPSANITY].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM); mOptions[RSK_SHOPSANITY_COUNT].Unhide(); - mOptions[RSK_SHOPSANITY_PRICES].Unhide(); - mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE].Unhide(); + HandleShopsanityPriceUI(); + break; + case RO_SHOPSANITY_RANDOM: + mOptions[RSK_SHOPSANITY_COUNT].Hide(); + HandleShopsanityPriceUI(); + break; + } + switch (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleScrubs"), RO_SCRUBS_OFF)) { + case RO_SCRUBS_OFF: + mOptions[RSK_SHUFFLE_SCRUBS].AddFlag(IMFLAG_SEPARATOR_BOTTOM); + mOptions[RSK_SCRUBS_PRICES].Hide(); + mOptions[RSK_SCRUBS_PRICES_AFFORDABLE].Hide(); + mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_SCRUBS_PRICES_RANGE_1].Hide(); + mOptions[RSK_SCRUBS_PRICES_RANGE_2].Hide(); + mOptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT].Hide(); break; default: - mOptions[RSK_SHOPSANITY].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM); - mOptions[RSK_SHOPSANITY_COUNT].Hide(); - mOptions[RSK_SHOPSANITY_PRICES].Unhide(); - mOptions[RSK_SHOPSANITY_PRICES_AFFORDABLE].Unhide(); + mOptions[RSK_SHUFFLE_SCRUBS].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM); + mOptions[RSK_SCRUBS_PRICES].Unhide(); + switch (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ScrubsPrices"), RO_PRICE_VANILLA)){ + case RO_PRICE_FIXED: + mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE].Unhide(); + mOptions[RSK_SCRUBS_PRICES_RANGE_1].Hide(); + mOptions[RSK_SCRUBS_PRICES_RANGE_2].Hide(); + mOptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + if (isTycoon ? mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE].GetOptionCount() == 501 : mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE].GetOptionCount() == 1000) { + mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE].ChangeOptions(isTycoon ? NumOpts(0, 999) : NumOpts(0, 500)); + } + mOptions[RSK_SCRUBS_PRICES_AFFORDABLE].Hide(); + break; + case RO_PRICE_RANGE: + mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_SCRUBS_PRICES_RANGE_1].Unhide(); + mOptions[RSK_SCRUBS_PRICES_RANGE_2].Unhide(); + mOptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + if (isTycoon ? mOptions[RSK_SCRUBS_PRICES_RANGE_1].GetOptionCount() == 101 : mOptions[RSK_SCRUBS_PRICES_RANGE_1].GetOptionCount() == 200) { + mOptions[RSK_SCRUBS_PRICES_RANGE_1].ChangeOptions(isTycoon ? NumOpts(0, 995, 5) : NumOpts(0, 500, 5)); + mOptions[RSK_SCRUBS_PRICES_RANGE_2].ChangeOptions(isTycoon ? NumOpts(0, 995, 5) : NumOpts(0, 500, 5)); + } + mOptions[RSK_SCRUBS_PRICES_AFFORDABLE].Unhide(); + break; + case RO_PRICE_SET_BY_WALLET: + mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_SCRUBS_PRICES_RANGE_1].Hide(); + mOptions[RSK_SCRUBS_PRICES_RANGE_2].Hide(); + mOptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT].Unhide(); + mOptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT].Unhide(); + mOptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT].Unhide(); + mOptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT].Unhide(); + if (isTycoon){ + mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT].Unhide(); + } else { + mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + } + mOptions[RSK_SCRUBS_PRICES_AFFORDABLE].Unhide(); + break; + default: + mOptions[RSK_SCRUBS_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_SCRUBS_PRICES_RANGE_1].Hide(); + mOptions[RSK_SCRUBS_PRICES_RANGE_2].Hide(); + mOptions[RSK_SCRUBS_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + mOptions[RSK_SCRUBS_PRICES_AFFORDABLE].Unhide(); + break; + } + break; + } + switch (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleMerchants"), RO_SHUFFLE_MERCHANTS_OFF)) { + case RO_SHUFFLE_MERCHANTS_OFF: + mOptions[RSK_SHUFFLE_MERCHANTS].AddFlag(IMFLAG_SEPARATOR_BOTTOM); + mOptions[RSK_MERCHANT_PRICES].Hide(); + mOptions[RSK_MERCHANT_PRICES_AFFORDABLE].Hide(); + mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_MERCHANT_PRICES_RANGE_1].Hide(); + mOptions[RSK_MERCHANT_PRICES_RANGE_2].Hide(); + mOptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + break; + default: + mOptions[RSK_SHUFFLE_MERCHANTS].RemoveFlag(IMFLAG_SEPARATOR_BOTTOM); + mOptions[RSK_MERCHANT_PRICES].Unhide(); + switch (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MerchantPrices"), RO_PRICE_VANILLA)){ + case RO_PRICE_FIXED: + mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE].Unhide(); + mOptions[RSK_MERCHANT_PRICES_RANGE_1].Hide(); + mOptions[RSK_MERCHANT_PRICES_RANGE_2].Hide(); + mOptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + if (isTycoon ? mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE].GetOptionCount() == 501 : mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE].GetOptionCount() == 1000) { + mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE].ChangeOptions(isTycoon ? NumOpts(0, 999) : NumOpts(0, 500)); + } + mOptions[RSK_MERCHANT_PRICES_AFFORDABLE].Hide(); + break; + case RO_PRICE_RANGE: + mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_MERCHANT_PRICES_RANGE_1].Unhide(); + mOptions[RSK_MERCHANT_PRICES_RANGE_2].Unhide(); + mOptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + if (isTycoon ? mOptions[RSK_MERCHANT_PRICES_RANGE_1].GetOptionCount() == 101 : mOptions[RSK_MERCHANT_PRICES_RANGE_1].GetOptionCount() == 200) { + mOptions[RSK_MERCHANT_PRICES_RANGE_1].ChangeOptions(isTycoon ? NumOpts(0, 995, 5) : NumOpts(0, 500, 5)); + mOptions[RSK_MERCHANT_PRICES_RANGE_2].ChangeOptions(isTycoon ? NumOpts(0, 995, 5) : NumOpts(0, 500, 5)); + } + mOptions[RSK_MERCHANT_PRICES_AFFORDABLE].Unhide(); + break; + case RO_PRICE_SET_BY_WALLET: + mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_MERCHANT_PRICES_RANGE_1].Hide(); + mOptions[RSK_MERCHANT_PRICES_RANGE_2].Hide(); + mOptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT].Unhide(); + mOptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT].Unhide(); + mOptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT].Unhide(); + mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT].Unhide(); + if (isTycoon){ + mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT].Unhide(); + } else { + mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + } + mOptions[RSK_MERCHANT_PRICES_AFFORDABLE].Unhide(); + break; + default: + mOptions[RSK_MERCHANT_PRICES_FIXED_PRICE].Hide(); + mOptions[RSK_MERCHANT_PRICES_RANGE_1].Hide(); + mOptions[RSK_MERCHANT_PRICES_RANGE_2].Hide(); + mOptions[RSK_MERCHANT_PRICES_NO_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_CHILD_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_ADULT_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_GIANT_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_TYCOON_WALLET_WEIGHT].Hide(); + mOptions[RSK_MERCHANT_PRICES_AFFORDABLE].Unhide(); + break; + } break; } // Hide fishing pond settings if we aren't shuffling the fishing pond @@ -2347,27 +2682,29 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { } break; case RSK_SHOPSANITY_PRICES: - if (it.value() == "Random") { - mOptions[index].SetSelectedIndex(RO_SHOPSANITY_PRICE_BALANCED); - } else if (it.value() == "Starter Wallet") { - mOptions[index].SetSelectedIndex(RO_SHOPSANITY_PRICE_STARTER); - } else if (it.value() == "Adult's Wallet") { - mOptions[index].SetSelectedIndex(RO_SHOPSANITY_PRICE_ADULT); - } else if (it.value() == "Giant's Wallet") { - mOptions[index].SetSelectedIndex(RO_SHOPSANITY_PRICE_GIANT); - } else if (it.value() == "Tycoon's Wallet") { - mOptions[index].SetSelectedIndex(RO_SHOPSANITY_PRICE_TYCOON); + case RSK_SCRUBS_PRICES: + case RSK_MERCHANT_PRICES: + if (it.value() == "Vanilla") { + mOptions[index].SetSelectedIndex(RO_PRICE_VANILLA); + } else if (it.value() == "Cheap Balanced") { + mOptions[index].SetSelectedIndex(RO_PRICE_CHEAP_BALANCED); + } else if (it.value() == "Balanced") { + mOptions[index].SetSelectedIndex(RO_PRICE_BALANCED); + } else if (it.value() == "Fixed") { + mOptions[index].SetSelectedIndex(RO_PRICE_FIXED); + } else if (it.value() == "Range") { + mOptions[index].SetSelectedIndex(RO_PRICE_RANGE); + } else if (it.value() == "Set By Wallet") { + mOptions[index].SetSelectedIndex(RO_PRICE_SET_BY_WALLET); } break; case RSK_SHUFFLE_SCRUBS: if (it.value() == "Off") { mOptions[index].SetSelectedIndex(RO_SCRUBS_OFF); - } else if (it.value() == "Affordable") { - mOptions[index].SetSelectedIndex(RO_SCRUBS_AFFORDABLE); - } else if (it.value() == "Expensive") { - mOptions[index].SetSelectedIndex(RO_SCRUBS_EXPENSIVE); - } else if (it.value() == "Random Prices") { - mOptions[index].SetSelectedIndex(RO_SCRUBS_RANDOM); + } else if (it.value() == "Major Items Only") { + mOptions[index].SetSelectedIndex(RO_SCRUBS_MAJOR_ONLY); + } else if (it.value() == "All") { + mOptions[index].SetSelectedIndex(RO_SCRUBS_ALL); } break; case RSK_SHUFFLE_FISHING_POLE: @@ -2377,7 +2714,6 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_SHUFFLE_BEEHIVES: case RSK_SHUFFLE_COWS: case RSK_SHUFFLE_ADULT_TRADE: - case RSK_SHUFFLE_MAGIC_BEANS: case RSK_SHUFFLE_KOKIRI_SWORD: case RSK_SHUFFLE_WEIRD_EGG: case RSK_SHUFFLE_FROG_SONG_RUPEES: @@ -2386,6 +2722,7 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_SHUFFLE_OCARINA_BUTTONS: case RSK_SHUFFLE_SWIM: case RSK_SHUFFLE_CHILD_WALLET: + case RSK_INCLUDE_TYCOON_WALLET: case RSK_STARTING_DEKU_SHIELD: case RSK_STARTING_KOKIRI_SWORD: case RSK_STARTING_ZELDAS_LULLABY: @@ -2432,6 +2769,7 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_HBA_HINT: case RSK_WARP_SONG_HINTS: case RSK_SCRUB_TEXT_HINT: + case RSK_MERCHANT_TEXT_HINT: case RSK_SHUFFLE_ENTRANCES: case RSK_SHUFFLE_OVERWORLD_ENTRANCES: case RSK_SHUFFLE_GROTTO_ENTRANCES: @@ -2446,6 +2784,8 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_MIX_GROTTO_ENTRANCES: case RSK_DECOUPLED_ENTRANCES: case RSK_SHOPSANITY_PRICES_AFFORDABLE: + case RSK_SCRUBS_PRICES_AFFORDABLE: + case RSK_MERCHANT_PRICES_AFFORDABLE: case RSK_ALL_LOCATIONS_REACHABLE: case RSK_TRIFORCE_HUNT: case RSK_MQ_DUNGEON_SET: @@ -2486,10 +2826,12 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_SHUFFLE_MERCHANTS: if (it.value() == "Off") { mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_OFF); - } else if (it.value() == "On (No Hints)") { - mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_ON_NO_HINT); - } else if (it.value() == "On (With Hints)") { - mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_ON_HINT); + } else if (it.value() == "Beans Only") { + mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_BEANS_ONLY); + } else if (it.value() == "All but Beans") { + mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS); + } else if (it.value() == "All") { + mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_ALL); } break; // Uses Ammo Drops option for now. "Off" not yet implemented diff --git a/soh/soh/Enhancements/randomizer/settings.h b/soh/soh/Enhancements/randomizer/settings.h index 07041c411..197d074bd 100644 --- a/soh/soh/Enhancements/randomizer/settings.h +++ b/soh/soh/Enhancements/randomizer/settings.h @@ -14,6 +14,11 @@ class Settings { public: Settings(); + /** + * @brief Hides or Unhides the price UI of Shopsanity based on settings. + */ + void HandleShopsanityPriceUI(); + /** * @brief Creates the `Option` and `OptionGroup` objects. This happens after construction because certain * other events in the codebase need to happen before all of the `Option`s can be created. diff --git a/soh/soh/Enhancements/randomizer/static_data.cpp b/soh/soh/Enhancements/randomizer/static_data.cpp index af8ee692d..773d9f209 100644 --- a/soh/soh/Enhancements/randomizer/static_data.cpp +++ b/soh/soh/Enhancements/randomizer/static_data.cpp @@ -11,7 +11,6 @@ std::unordered_map StaticData::hintTypeNames = { {HINT_TYPE_TRIAL, CustomMessage("Trial")}, {HINT_TYPE_ENTRANCE, CustomMessage("Entrance")}, {HINT_TYPE_ITEM_AREA, CustomMessage("Item Area")}, - {HINT_TYPE_MERCHANT, CustomMessage("Merchant")}, {HINT_TYPE_ALTAR_CHILD, CustomMessage("Child Altar")}, {HINT_TYPE_ALTAR_ADULT, CustomMessage("Adult Altar")}, {HINT_TYPE_WOTH, CustomMessage("Way of the Hero")}, @@ -79,10 +78,6 @@ std::unordered_map StaticData::hintNames = { {RH_REQUIEM_WARP_LOC, CustomMessage("Requiem of Spirit Destination")}, {RH_NOCTURNE_WARP_LOC, CustomMessage("Nocturne of Shadow Destination")}, {RH_PRELUDE_WARP_LOC, CustomMessage("Prelude of Light Destination")}, - {RH_MEDIGORON, CustomMessage("Medigoron Hint")}, - {RH_CARPET_SALESMAN, CustomMessage("Carpet Salseman Hint")}, - {RH_BEAN_SALESMAN, CustomMessage("Bean Salseman Hint")}, - {RH_GRANNY, CustomMessage("Granny Hint")}, {RH_HBA_HINT, CustomMessage("Horseback Archery Hint")}, {RH_MALON_HINT, CustomMessage("Malon Hint")}, {RH_CHICKENS_HINT, CustomMessage("Anju's Child Chickens Hint")}, @@ -194,18 +189,14 @@ std::unordered_map StaticData::trialData = { std::unordered_map StaticData::staticHintInfoMap = { // RH_GANONDORF_HINT is special cased due to being different based on master sword shuffle // Altar hints are special cased due to special hint marking rules - // warp song hints are special cased due to entrances not being done properly yet - // Ganondorf Joke is special Cased as the text is random + // warp song hints are special cased due to entrences not being done properly yet + // Ganondorf Joke is special cased as the text is random {RH_SHEIK_HINT, StaticHintInfo(HINT_TYPE_AREA, {RHT_SHEIK_HINT_LA_ONLY}, RSK_SHEIK_LA_HINT, true, {}, {RG_LIGHT_ARROWS}, {RC_SHEIK_HINT_GC, RC_SHEIK_HINT_MQ_GC}, true)}, {RH_DAMPES_DIARY, StaticHintInfo(HINT_TYPE_AREA, {RHT_DAMPE_DIARY}, RSK_DAMPES_DIARY_HINT, true, {}, {RG_PROGRESSIVE_HOOKSHOT}, {RC_DAMPE_HINT})}, {RH_GREG_RUPEE, StaticHintInfo(HINT_TYPE_AREA, {RHT_GREG_HINT}, RSK_GREG_HINT, true, {}, {RG_GREG_RUPEE}, {RC_GREG_HINT})}, {RH_SARIA_HINT, StaticHintInfo(HINT_TYPE_AREA, {RHT_SARIA_TALK_HINT, RHT_SARIA_SONG_HINT}, RSK_SARIA_HINT, true, {}, {RG_PROGRESSIVE_MAGIC_METER}, {RC_SARIA_SONG_HINT, RC_SONG_FROM_SARIA}, true)}, {RH_LOACH_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_LOACH_HINT}, RSK_LOACH_HINT, true, {RC_LH_HYRULE_LOACH})}, {RH_FISHING_POLE, StaticHintInfo(HINT_TYPE_AREA, {RHT_FISHING_POLE_HINT}, RSK_FISHING_POLE_HINT, true, {}, {RG_FISHING_POLE}, {RC_FISHING_POLE_HINT}, true)}, - {RH_MEDIGORON, StaticHintInfo(HINT_TYPE_MERCHANT, {RHT_MEDIGORON_HINT}, RSK_SHUFFLE_MERCHANTS, (uint8_t)RO_SHUFFLE_MERCHANTS_ON_HINT, {RC_GC_MEDIGORON})}, - {RH_GRANNY, StaticHintInfo(HINT_TYPE_MERCHANT, {RHT_GRANNY_HINT}, RSK_SHUFFLE_MERCHANTS, (uint8_t)RO_SHUFFLE_MERCHANTS_ON_HINT, {RC_KAK_GRANNYS_SHOP})}, - {RH_CARPET_SALESMAN, StaticHintInfo(HINT_TYPE_MERCHANT, {RHT_CARPET_SALESMAN_DIALOG_HINTED}, RSK_SHUFFLE_MERCHANTS, (uint8_t)RO_SHUFFLE_MERCHANTS_ON_HINT, {RC_WASTELAND_BOMBCHU_SALESMAN})}, - {RH_BEAN_SALESMAN, StaticHintInfo(HINT_TYPE_MERCHANT, {RHT_BEAN_SALESMAN_HINT}, RSK_SHUFFLE_MAGIC_BEANS, true, {RC_ZR_MAGIC_BEAN_SALESMAN})}, {RH_HBA_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_HBA_HINT_SIGN, RHT_HBA_HINT_NOT_ON_HORSE, RHT_HBA_HINT_INITIAL, RHT_HBA_HINT_HAVE_1000}, RSK_HBA_HINT, true, {RC_GF_HBA_1000_POINTS, RC_GF_HBA_1500_POINTS})}, {RH_MALON_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_MALON_HINT_TURNING_EVIL, RHT_MALON_HINT_HOW_IS_EPONA, RHT_MALON_HINT_OBSTICLE_COURSE, RHT_MALON_HINT_INGO_TEMPTED}, RSK_MALON_HINT, true, {RC_KF_LINKS_HOUSE_COW})}, {RH_BIG_POES_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_BIG_POES_HINT}, RSK_BIG_POES_HINT, true, {RC_MARKET_10_BIG_POES})}, diff --git a/soh/soh/Enhancements/randomizer/static_data.h b/soh/soh/Enhancements/randomizer/static_data.h index 8232f93b5..78ec5e118 100644 --- a/soh/soh/Enhancements/randomizer/static_data.h +++ b/soh/soh/Enhancements/randomizer/static_data.h @@ -40,6 +40,7 @@ class StaticData { static std::vector dungeonRewardLocations; static std::vector GetShopLocations(); static std::vector GetScrubLocations(); + static std::vector GetMerchantLocations(); static std::vector GetAdultTradeLocations(); static std::vector GetGossipStoneLocations(); static std::vector GetStaticHintLocations(); diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index f99152f16..32b035f82 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2516,6 +2516,8 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { s16 actorParams = 0; if (IS_RANDO) { auto ctx = Rando::Context::GetInstance(); + bool nonBeanMerchants = ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS) || + ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL); Player* player = GET_PLAYER(play); if (textId == TEXT_RANDOMIZER_CUSTOM_ITEM) { if (player->getItemEntry.getItemId == RG_ICE_TRAP) { @@ -2602,21 +2604,20 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { } } else if (textId == TEXT_SHEIK_NEED_HOOK || textId == TEXT_SHEIK_HAVE_HOOK) { messageEntry = OTRGlobals::Instance->gRandomizer->GetSheikMessage(gPlayState->sceneNum, textId); - // textId: TEXT_SCRUB_RANDOM + (randomizerInf - RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT) - } else if (textId == TEXT_SCRUB_RANDOM) { - EnDns* enDns = (EnDns*)GET_PLAYER(play)->targetActor; - messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(enDns->sohScrubIdentity.randomizerInf, TEXT_SCRUB_RANDOM, Randomizer_GetSettingValue(RSK_SCRUB_TEXT_HINT) == RO_GENERIC_OFF); // Shop items each have two message entries, second one offset by NUM_SHOP_ITEMS // textId: TEXT_SHOP_ITEM_RANDOM + (randomizerInf - RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1) // textId: TEXT_SHOP_ITEM_RANDOM + ((randomizerInf - RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1) + NUM_SHOP_ITEMS) - } else if (textId >= TEXT_SHOP_ITEM_RANDOM && textId <= TEXT_SHOP_ITEM_RANDOM + (NUM_SHOP_ITEMS * 2)) { - if (textId < TEXT_SHOP_ITEM_RANDOM + NUM_SHOP_ITEMS) { - RandomizerInf randoInf = (RandomizerInf)((textId - TEXT_SHOP_ITEM_RANDOM) + RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1); - messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(randoInf, TEXT_SHOP_ITEM_RANDOM); - } else { - RandomizerInf randoInf = (RandomizerInf)((textId - (TEXT_SHOP_ITEM_RANDOM + NUM_SHOP_ITEMS)) + RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1); - messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(randoInf, TEXT_SHOP_ITEM_RANDOM_CONFIRM); - } + } else if (textId >= TEXT_SHOP_ITEM_RANDOM && textId < TEXT_SHOP_ITEM_RANDOM_CONFIRM) { + RandomizerCheck rc = OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf((RandomizerInf)((textId - TEXT_SHOP_ITEM_RANDOM) + RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1)); + messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(rc, TEXT_SHOP_ITEM_RANDOM); + } else if (textId >= TEXT_SHOP_ITEM_RANDOM_CONFIRM && textId <= TEXT_SHOP_ITEM_RANDOM_CONFIRM_END){ + RandomizerCheck rc = OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf((RandomizerInf)((textId - TEXT_SHOP_ITEM_RANDOM_CONFIRM) + RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1)); + messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(rc, TEXT_SHOP_ITEM_RANDOM_CONFIRM); + // textId: TEXT_SCRUB_RANDOM + (randomizerInf - RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT) + } else if (textId == TEXT_SCRUB_RANDOM) { + EnDns* enDns = (EnDns*)GET_PLAYER(play)->targetActor; + RandomizerCheck rc = OTRGlobals::Instance->gRandomizer->GetCheckFromRandomizerInf((RandomizerInf)enDns->sohScrubIdentity.randomizerInf); + messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(rc, TEXT_SCRUB_RANDOM, TEXT_SCRUB_RANDOM_FREE, Randomizer_GetSettingValue(RSK_SCRUB_TEXT_HINT) == RO_GENERIC_OFF); } else if (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("RandomizeRupeeNames"), 1) && (textId == TEXT_BLUE_RUPEE || textId == TEXT_RED_RUPEE || textId == TEXT_PURPLE_RUPEE || textId == TEXT_HUGE_RUPEE)) { @@ -2624,27 +2625,32 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { // In rando, replace Navi's general overworld hints with rando-related gameplay tips } else if (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("RandoRelevantNavi"), 1) && textId >= TEXT_NAVI_DEKU_TREE_SUMMONS && textId <= TEXT_NAVI_TRY_TO_KEEP_MOVING) { u16 naviTextId = Random(0, NUM_NAVI_MESSAGES); - messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::NaviRandoMessageTableID, naviTextId); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::NaviRandoMessageTableID, naviTextId, MF_FORMATTED); } - else if (textId == TEXT_BEAN_SALESMAN_BUY_FOR_10 && ctx->GetOption(RSK_SHUFFLE_MAGIC_BEANS)) { - messageEntry = ctx->GetHint(RH_BEAN_SALESMAN)->GetHintMessage(MF_AUTO_FORMAT); + else if (textId == TEXT_BEAN_SALESMAN_BUY_FOR_10 && + (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_BEANS_ONLY) || + ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL))) { + messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(RC_ZR_MAGIC_BEAN_SALESMAN, TEXT_BEAN_SALESMAN_BUY_FOR_10, TEXT_NONE, Randomizer_GetSettingValue(RSK_MERCHANT_TEXT_HINT) == RO_GENERIC_OFF); } else if (textId == TEXT_BEAN_SALESMAN_BUY_FOR_100) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN_BUY_FOR_100); } - else if (textId == TEXT_GRANNYS_SHOP && !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP) && Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF && + else if (textId == TEXT_GRANNYS_SHOP && !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_GRANNYS_SHOP) && nonBeanMerchants && (ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) || INV_CONTENT(ITEM_CLAIM_CHECK) == ITEM_CLAIM_CHECK)){ - messageEntry = messageEntry = ctx->GetHint(RH_GRANNY)->GetHintMessage(MF_AUTO_FORMAT); + messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(RC_KAK_GRANNYS_SHOP, TEXT_GRANNYS_SHOP, TEXT_NONE, Randomizer_GetSettingValue(RSK_MERCHANT_TEXT_HINT) == RO_GENERIC_OFF); } - else if (textId == TEXT_MEDIGORON && Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF){ - messageEntry = messageEntry = ctx->GetHint(RH_MEDIGORON)->GetHintMessage(MF_AUTO_FORMAT); + else if (textId == TEXT_MEDIGORON && nonBeanMerchants){ + messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(RC_GC_MEDIGORON, TEXT_MEDIGORON, TEXT_NONE, Randomizer_GetSettingValue(RSK_MERCHANT_TEXT_HINT) == RO_GENERIC_OFF); } - else if (textId == TEXT_CARPET_SALESMAN_1 && !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN) && Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF){ - messageEntry = ctx->GetHint(RH_CARPET_SALESMAN)->GetHintMessage(MF_AUTO_FORMAT); + else if (textId == TEXT_CARPET_SALESMAN_1 && !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN) && nonBeanMerchants){ + if (Randomizer_GetSettingValue(RSK_MERCHANT_TEXT_HINT)){ + messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(RC_WASTELAND_BOMBCHU_SALESMAN, TEXT_CARPET_SALESMAN_1, TEXT_NONE, Randomizer_GetSettingValue(RSK_MERCHANT_TEXT_HINT) == RO_GENERIC_OFF); + } else { + messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(RC_WASTELAND_BOMBCHU_SALESMAN, TEXT_CARPET_SALESMAN_MYSTERIOUS, TEXT_NONE, Randomizer_GetSettingValue(RSK_MERCHANT_TEXT_HINT) == RO_GENERIC_OFF); + } } - else if (textId == TEXT_CARPET_SALESMAN_2 && !Flags_GetRandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN) && Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF){ - messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, textId); - Flags_SetRandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN);//set here so we can actually check if the text is run, not a good solution + else if (textId == TEXT_CARPET_SALESMAN_ARMS_DEALER){ + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, textId, MF_AUTO_FORMAT); } else if (textId == TEXT_SKULLTULA_PEOPLE_IM_CURSED) { actorParams = GET_PLAYER(play)->targetActor->params; if (actorParams == 1 && ctx->GetOption(RSK_KAK_10_SKULLS_HINT)){ @@ -2688,10 +2694,10 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_WARP_MINUET_OF_FOREST); } else if (textId == TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI || textId == TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, textId); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, textId, MF_AUTO_FORMAT); } else if (textId == TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_SHOOTING_GALLERY_MAN_COME_BACK_WITH_BOW, MF_AUTO_FORMAT); } else if (textId == TEXT_FIRE_TEMPLE_GORON_OWE_YOU_BIG_TIME || (textId >= TEXT_FIRE_TEMPLE_GORON_FALLING_DOORS_SECRET && textId <= TEXT_FIRE_TEMPLE_GORON_SOUNDS_DIFFERENT_SECRET)) { u16 choice = Random(0, NUM_GORON_MESSAGES); @@ -2762,7 +2768,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { messageEntry = ctx->GetHint(RH_HBA_HINT)->GetHintMessage(MF_AUTO_FORMAT, 3); } else if (textId == TEXT_CARPET_SALESMAN_CUSTOM_FAIL_TO_BUY){ - messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId, MF_AUTO_FORMAT); } else if (textId == TEXT_MASK_SHOP_SIGN && ctx->GetOption(RSK_MASK_SHOP_HINT)) { messageEntry = ctx->GetHint(RH_MASK_SHOP_HINT)->GetHintMessage(MF_AUTO_FORMAT); @@ -2786,23 +2792,23 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { // In vanilla, GS token count is incremented prior to the text box displaying // In rando we need to bump the token count by one to show the correct count s16 gsCount = gSaveContext.inventory.gsTokens + (IS_RANDO ? 1 : 0); - messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId, MF_FORMATTED); messageEntry.Replace("[[gsCount]]", std::to_string(gsCount)); } } else if ((IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("BetterBombchuShopping"), 0)) && (textId == TEXT_BUY_BOMBCHUS_10_DESC || textId == TEXT_BUY_BOMBCHUS_10_PROMPT)) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId, MF_FORMATTED); } else if (textId == TEXT_HEART_CONTAINER && CVarGetInteger(CVAR_ENHANCEMENT("InjectItemCounts"), 0)) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_CONTAINER); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_CONTAINER, MF_FORMATTED); messageEntry.Replace("[[heartContainerCount]]", std::to_string(gSaveContext.sohStats.heartContainers + 1)); } else if (textId == TEXT_HEART_PIECE && CVarGetInteger(CVAR_ENHANCEMENT("InjectItemCounts"), 0)) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_PIECE); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_PIECE, MF_FORMATTED); messageEntry.Replace("[[heartPieceCount]]", std::to_string(gSaveContext.sohStats.heartPieces + 1)); } else if (textId == TEXT_MARKET_GUARD_NIGHT && CVarGetInteger(CVAR_ENHANCEMENT("MarketSneak"), 0) && play->sceneNum == SCENE_MARKET_ENTRANCE_NIGHT) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_MARKET_GUARD_NIGHT); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_MARKET_GUARD_NIGHT, MF_FORMATTED); } if (textId == TEXT_FISHERMAN_LEAVE && CVarGetInteger(CVAR_ENHANCEMENT("QuitFishingAtDoor"), 0)) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_FISHERMAN_LEAVE); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_FISHERMAN_LEAVE, MF_FORMATTED); } font->charTexBuf[0] = (messageEntry.GetTextBoxType() << 4) | messageEntry.GetTextBoxPosition(); switch (gSaveContext.language) { diff --git a/soh/soh/z_message_OTR.cpp b/soh/soh/z_message_OTR.cpp index b695de579..215975662 100644 --- a/soh/soh/z_message_OTR.cpp +++ b/soh/soh/z_message_OTR.cpp @@ -189,8 +189,6 @@ extern "C" void OTRMessage_Init() "Holà! Holà!&Les cannes ne sortent pas d'ici!&Je suis sérieux!^Voulez-vous arrêter?&\x1B&%gOui&Non%w")); //TODO Used AI translation as placeholder CustomMessageManager::Instance->CreateMessage( customMessageTableID, TEXT_CARPET_SALESMAN_CUSTOM_FAIL_TO_BUY, - CustomMessage("I'm sorry I can't sell you&these fine specimens,&they need an %rexperienced owner%w.^" - "Come back when you have&had %gBombchus%w of your own.", - "", - "")); + CustomMessage("I'm sorry I can't sell you these fine specimens, they need an #experienced owner#.^" + "Come back when you have had #Bombchus# of your own.", {QM_RED, QM_GREEN})); } diff --git a/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c b/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c index 7e3f97856..09d312318 100644 --- a/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c +++ b/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c @@ -164,7 +164,7 @@ void EnDs_OfferOddPotion(EnDs* this, PlayState* play) { } s32 EnDs_CheckRupeesAndBottle() { - if (gSaveContext.rupees < 100) { + if (GameInteractor_Should(VB_GRANNY_SAY_INSUFFICIENT_RUPEES, gSaveContext.rupees < 100, NULL)) { return 0; } else if (GameInteractor_Should(VB_NEED_BOTTLE_FOR_GRANNYS_ITEM, Inventory_HasEmptyBottle() == 0, NULL)) { return 1; @@ -174,7 +174,7 @@ s32 EnDs_CheckRupeesAndBottle() { } void EnDs_GiveBluePotion(EnDs* this, PlayState* play) { - if (Actor_HasParent(&this->actor, play) || !GameInteractor_Should(VB_GIVE_ITEM_FROM_GRANNYS_SHOP, true, this)) { + if (Actor_HasParent(&this->actor, play)) { this->actor.parent = NULL; this->actionFunc = EnDs_Talk; } else { @@ -195,7 +195,9 @@ void EnDs_OfferBluePotion(EnDs* this, PlayState* play) { this->actionFunc = EnDs_TalkNoEmptyBottle; return; case 2: // have 100 rupees and empty bottle - Rupees_ChangeBy(-100); + if(GameInteractor_Should(VB_GRANNY_TAKE_MONEY, true, this)){ + Rupees_ChangeBy(-100); + } this->actor.flags &= ~ACTOR_FLAG_WILL_TALK; if (GameInteractor_Should(VB_GIVE_ITEM_FROM_GRANNYS_SHOP, true, this)) { @@ -203,9 +205,9 @@ void EnDs_OfferBluePotion(EnDs* this, PlayState* play) { Actor_OfferGetItem(&this->actor, play, GI_POTION_BLUE, 10000.0f, 50.0f); gSaveContext.pendingSale = itemEntry.itemId; gSaveContext.pendingSaleMod = itemEntry.modIndex; + this->actionFunc = EnDs_GiveBluePotion; } - - this->actionFunc = EnDs_GiveBluePotion; + return; } break; diff --git a/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.h b/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.h index fb3c62aa2..c1f807dfb 100644 --- a/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.h +++ b/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.h @@ -21,4 +21,8 @@ typedef struct EnDs { /* 0x01EC */ EnDsActionFunc actionFunc; } EnDs; // size = 0x01F0 +void EnDs_Talk(EnDs* actor, PlayState* play); +void EnDs_TalkAfterGiveOddPotion(EnDs* actor, PlayState* play); + + #endif diff --git a/soh/src/overlays/actors/ovl_En_Gm/z_en_gm.c b/soh/src/overlays/actors/ovl_En_Gm/z_en_gm.c index 2a54cf979..af1f26f19 100644 --- a/soh/src/overlays/actors/ovl_En_Gm/z_en_gm.c +++ b/soh/src/overlays/actors/ovl_En_Gm/z_en_gm.c @@ -245,15 +245,15 @@ void EnGm_ProcessChoiceIndex(EnGm* this, PlayState* play) { if (Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE && Message_ShouldAdvance(play)) { switch (play->msgCtx.choiceIndex) { case 0: // yes - if (gSaveContext.rupees < 200) { + if (GameInteractor_Should(VB_CHECK_RANDO_PRICE_OF_MEDIGORON, gSaveContext.rupees < 200, this)) { Message_ContinueTextbox(play, 0xC8); this->actionFunc = func_80A3DD7C; } else { if (GameInteractor_Should(VB_GIVE_ITEM_FROM_MEDIGORON, true, this)) { Actor_OfferGetItem(&this->actor, play, GI_SWORD_KNIFE, 415.0f, 10.0f); + this->actionFunc = func_80A3DF00; } - - this->actionFunc = func_80A3DF00; + } break; case 1: // no @@ -265,8 +265,7 @@ void EnGm_ProcessChoiceIndex(EnGm* this, PlayState* play) { } void func_80A3DF00(EnGm* this, PlayState* play) { - if (Actor_HasParent(&this->actor, play) || !GameInteractor_Should(VB_GIVE_ITEM_FROM_MEDIGORON, true, this)) { - Flags_SetRandomizerInf(RAND_INF_MERCHANTS_MEDIGORON); + if (Actor_HasParent(&this->actor, play)) { this->actor.parent = NULL; this->actionFunc = func_80A3DF60; } else { diff --git a/soh/src/overlays/actors/ovl_En_Gm/z_en_gm.h b/soh/src/overlays/actors/ovl_En_Gm/z_en_gm.h index 3652fc43a..f3f623ea0 100644 --- a/soh/src/overlays/actors/ovl_En_Gm/z_en_gm.h +++ b/soh/src/overlays/actors/ovl_En_Gm/z_en_gm.h @@ -24,4 +24,6 @@ typedef struct EnGm { /* 0x02C4 */ Vec3f talkPos; } EnGm; // size = 0x02D0 +void func_80A3DC44(EnGm* actor, PlayState* play); + #endif diff --git a/soh/src/overlays/actors/ovl_En_Js/z_en_js.c b/soh/src/overlays/actors/ovl_En_Js/z_en_js.c index a12dfec5e..ef6646bbd 100644 --- a/soh/src/overlays/actors/ovl_En_Js/z_en_js.c +++ b/soh/src/overlays/actors/ovl_En_Js/z_en_js.c @@ -128,11 +128,9 @@ void func_80A8910C(EnJs* this, PlayState* play) { } void func_80A89160(EnJs* this, PlayState* play) { - if (Actor_HasParent(&this->actor, play) || !GameInteractor_Should(VB_GIVE_ITEM_FROM_CARPET_SALESMAN, true, this)) { + if (Actor_HasParent(&this->actor, play)) { this->actor.parent = NULL; En_Js_SetupAction(this, func_80A8910C); - // Moved into the text handling to patch a text bug, not a great solution though - // Flags_SetRandomizerInf(RAND_INF_MERCHANTS_CARPET_SALESMAN); } else { GetItemEntry itemEntry = ItemTable_Retrieve(GI_BOMBCHUS_10); gSaveContext.pendingSale = itemEntry.itemId; @@ -145,17 +143,18 @@ void func_80A891C4(EnJs* this, PlayState* play) { if (Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE && Message_ShouldAdvance(play)) { switch (play->msgCtx.choiceIndex) { case 0: // yes - if (gSaveContext.rupees < 200) { + if (GameInteractor_Should(VB_CHECK_RANDO_PRICE_OF_CARPET_SALESMAN, gSaveContext.rupees < 200, this)) { Message_ContinueTextbox(play, 0x6075); func_80A89008(this); } else { - if (GameInteractor_Should(VB_GIVE_BOMBCHUS_FROM_CARPET_SALESMAN, true, this) || - (Actor_HasParent(&this->actor, play) || !GameInteractor_Should(VB_GIVE_ITEM_FROM_CARPET_SALESMAN, true, this))){ - Rupees_ChangeBy(-200); - En_Js_SetupAction(this, func_80A89160); - } else{ - Message_ContinueTextbox(play, 0x6073); - func_80A89008(this); + if (!GameInteractor_Should(VB_GIVE_ITEM_FROM_CARPET_SALESMAN, false, this)) { + if (GameInteractor_Should(VB_GIVE_BOMBCHUS_FROM_CARPET_SALESMAN, true, this) || Actor_HasParent(&this->actor, play)){ + Rupees_ChangeBy(-200); + En_Js_SetupAction(this, func_80A89160); + } else{ + Message_ContinueTextbox(play, 0x6073); + func_80A89008(this); + } } } break; diff --git a/soh/src/overlays/actors/ovl_En_Js/z_en_js.h b/soh/src/overlays/actors/ovl_En_Js/z_en_js.h index d496bb4c3..e5dcbd610 100644 --- a/soh/src/overlays/actors/ovl_En_Js/z_en_js.h +++ b/soh/src/overlays/actors/ovl_En_Js/z_en_js.h @@ -22,4 +22,6 @@ typedef struct EnJs { /* 0x028C */ EnJsActionFunc actionFunc; } EnJs; // size = 0x0290 +void func_80A890C0(EnJs* actor, PlayState* play); + #endif