diff --git a/libultraship/libultraship/ControlDeck.cpp b/libultraship/libultraship/ControlDeck.cpp index 7437afeee8..59f25b44f9 100644 --- a/libultraship/libultraship/ControlDeck.cpp +++ b/libultraship/libultraship/ControlDeck.cpp @@ -9,7 +9,6 @@ #include "Cvar.h" namespace Ship { - uint8_t* controllerBits; void ControlDeck::Init(uint8_t* bits) { ScanPhysicalDevices(); @@ -187,4 +186,9 @@ namespace Ship { std::shared_ptr ControlDeck::GetPhysicalDeviceFromVirtualSlot(int slot) { return GetPhysicalDevice(GetVirtualDevice(slot)); } + + uint8_t* ControlDeck::GetControllerBits() { + return controllerBits; + } + } \ No newline at end of file diff --git a/libultraship/libultraship/ControlDeck.h b/libultraship/libultraship/ControlDeck.h index 15cba08e96..025bfcde40 100644 --- a/libultraship/libultraship/ControlDeck.h +++ b/libultraship/libultraship/ControlDeck.h @@ -18,8 +18,10 @@ namespace Ship { size_t GetNumPhysicalDevices(); int GetVirtualDevice(int slot); size_t GetNumVirtualDevices(); + uint8_t* GetControllerBits(); private: - std::vector virtualDevices; + std::vector virtualDevices = {}; std::vector> physicalDevices = {}; + uint8_t* controllerBits = nullptr; }; } diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index 870bfd5325..3b3b534bd3 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -1760,9 +1760,30 @@ namespace SohImGui { needs_save = true; customWindows["Item Tracker"].enabled = CVar_GetS32("gItemTrackerEnabled", 0); } + InsertPadding(); + if (ImGui::Button(GetWindowButtonText("Item Tracker Settings", CVar_GetS32("gItemTrackerSettingsEnabled", 0)).c_str(), buttonSize)) + { + bool currentValue = CVar_GetS32("gItemTrackerSettingsEnabled", 0); + CVar_SetS32("gItemTrackerSettingsEnabled", !currentValue); + needs_save = true; + customWindows["Item Tracker Settings"].enabled = CVar_GetS32("gItemTrackerSettingsEnabled", 0); + } ImGui::PopStyleVar(3); ImGui::PopStyleColor(1); + PaddedSeparator(); + + if (ImGui::BeginMenu("Rando Enhancements")) + { + EnhancementCheckbox("Quest Item Fanfares", "gRandoQuestItemFanfares"); + Tooltip( + "Play unique fanfares when obtaining quest items\n" + "(medallions/stones/songs). Note that these fanfares\n" + "are longer than usual." + ); + ImGui::EndMenu(); + } + ImGui::EndMenu(); } diff --git a/libultraship/libultraship/Model.cpp b/libultraship/libultraship/Model.cpp index 9e37de177e..c59f38e8bf 100644 --- a/libultraship/libultraship/Model.cpp +++ b/libultraship/libultraship/Model.cpp @@ -2,7 +2,7 @@ namespace Ship { - Vertex::Vertex() + ModelVertex::ModelVertex() { pos = Vec3f(0, 0, 0); normal = Vec3f(0, 0, 0); @@ -10,7 +10,7 @@ namespace Ship uv = Vec2f(0, 0); } - Vertex::Vertex(BinaryReader* reader) + ModelVertex::ModelVertex(BinaryReader* reader) { pos = reader->ReadVec3f(); normal = reader->ReadVec3f(); @@ -36,7 +36,7 @@ namespace Ship uvCoords = reader->ReadUInt32(); boneWeights = reader->ReadUInt32(); - Vertex* vtxData = new Vertex[numVerts]; + ModelVertex* vtxData = new ModelVertex[numVerts]; uint32_t* indicesData = new uint32_t[numPolys]; if (vertices != 0) diff --git a/libultraship/libultraship/Model.h b/libultraship/libultraship/Model.h index f66ca7b846..241a2932ad 100644 --- a/libultraship/libultraship/Model.h +++ b/libultraship/libultraship/Model.h @@ -43,15 +43,15 @@ namespace Ship void ParseFileBinary(BinaryReader* reader, Resource* res) override; }; - struct Vertex + struct ModelVertex { Vec3f pos; Vec3f normal; Color3b color; Vec2f uv; - Vertex(); - Vertex(BinaryReader* reader); + ModelVertex(); + ModelVertex(BinaryReader* reader); }; class Model : public Resource @@ -62,7 +62,7 @@ namespace Ship uint32_t numVerts; uint32_t numPolys; - Vertex* vertices; + ModelVertex* vertices; Vec2f* boneWeights; uint32_t* indices; }; diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 043c05a461..7b39ad1803 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -174,6 +174,7 @@ source_group("Header Files\\soh\\Enhancements\\debugger" FILES ${Header_Files__s set(Header_Files__soh__Enhancements__randomizer "soh/Enhancements/randomizer/randomizer.h" "soh/Enhancements/randomizer/randomizer_item_tracker.h" + "soh/Enhancements/randomizer/adult_trade_shuffle.h" ) source_group("Header Files\\soh\\Enhancements\\randomizer" FILES ${Header_Files__soh__Enhancements__randomizer}) @@ -274,6 +275,7 @@ source_group("Source Files\\soh\\Enhancements\\debugger" FILES ${Source_Files__s set(Source_Files__soh__Enhancements__randomizer "soh/Enhancements/randomizer/randomizer.cpp" "soh/Enhancements/randomizer/randomizer_item_tracker.cpp" + "soh/Enhancements/randomizer/adult_trade_shuffle.c" ) source_group("Source Files\\soh\\Enhancements\\randomizer" FILES ${Source_Files__soh__Enhancements__randomizer}) diff --git a/soh/include/functions.h b/soh/include/functions.h index 086b989397..d31fa7903c 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -1057,6 +1057,7 @@ s32 Inventory_HasEmptyBottle(void); s32 Inventory_HasSpecificBottle(u8 bottleItem); void Inventory_UpdateBottleItem(GlobalContext* globalCtx, u8 item, u8 cButton); s32 Inventory_ConsumeFairy(GlobalContext* globalCtx); +bool Inventory_HatchPocketCucco(GlobalContext* globalCtx); void Interface_SetDoAction(GlobalContext* globalCtx, u16 action); void Interface_SetNaviCall(GlobalContext* globalCtx, u16 naviCallState); void Interface_LoadActionLabelB(GlobalContext* globalCtx, u16 action); diff --git a/soh/include/z64player.h b/soh/include/z64player.h index dcb7ade06f..72d28e7c2f 100644 --- a/soh/include/z64player.h +++ b/soh/include/z64player.h @@ -6,6 +6,8 @@ struct Player; +extern GetItemEntry sGetItemTable[195]; + typedef enum { /* 0 */ PLAYER_SWORD_NONE, /* 1 */ PLAYER_SWORD_KOKIRI, @@ -366,6 +368,7 @@ typedef enum { FLAG_SCENE_CLEAR, FLAG_SCENE_COLLECTIBLE, FLAG_EVENT_CHECK_INF, + FLAG_COW_MILKED } FlagType; typedef struct { @@ -627,9 +630,10 @@ typedef struct Player { /* 0x0A86 */ s8 unk_A86; /* 0x0A87 */ u8 unk_A87; /* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position - /* 0x0A94 */ PendingFlag pendingFlag; - /* 0x0AA0 */ u8 boomerangQuickRecall; // Has the player pressed the boomerang button while it's in the air still? - /* 0x0AA1 */ GetItemEntry getItemEntry; -} Player; // size = 0xAA9 + /* 0x0A89 */ bool pendingIceTrap; + /* 0x0A95 */ PendingFlag pendingFlag; + /* 0x0AA1 */ u8 boomerangQuickRecall; // Has the player pressed the boomerang button while it's in the air still? + /* 0x0AA2 */ GetItemEntry getItemEntry; +} Player; // size = 0xAAA #endif diff --git a/soh/include/z64save.h b/soh/include/z64save.h index 114de9fd47..9da18f72ef 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -175,7 +175,7 @@ typedef struct { /* 0x1422 */ s16 sunsSongState; // controls the effects of suns song /* 0x1424 */ s16 healthAccumulator; RandoSetting randoSettings[300]; - ItemLocationRando itemLocations[500]; + ItemLocationRando itemLocations[RC_MAX]; HintLocationRando hintLocations[50]; char childAltarText[250]; char adultAltarText[750]; @@ -184,7 +184,9 @@ typedef struct { u8 seedIcons[5]; u8 dungeonsDone[8]; u8 trialsDone[6]; + u8 cowsMilked[10]; u8 temporaryWeapon; + u16 adultTradeItems; } SaveContext; // size = 0x1428 typedef enum { diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index 08fae0ee46..bc56964fe5 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -30,4 +30,7 @@ typedef struct { #define GIMESSAGE_UNTRANSLATED(giid, iid, message) \ { giid, iid, message, message, message } +#define GIMESSAGE_NO_GERMAN(giid, iid, english, french) \ + { giid, iid, english, english, french } + #endif diff --git a/soh/soh/Enhancements/debugger/ImGuiHelpers.cpp b/soh/soh/Enhancements/debugger/ImGuiHelpers.cpp index 7fec0de144..d0ccab0eb7 100644 --- a/soh/soh/Enhancements/debugger/ImGuiHelpers.cpp +++ b/soh/soh/Enhancements/debugger/ImGuiHelpers.cpp @@ -20,3 +20,13 @@ void InsertHelpHoverText(const std::string& text) { ImGui::EndTooltip(); } } + +void PaddedSeparator(bool padTop, bool padBottom, float extraVerticalPadding) { + if (padTop) { + ImGui::Dummy(ImVec2(0.0f, extraVerticalPadding)); + } + ImGui::Separator(); + if (padBottom) { + ImGui::Dummy(ImVec2(0.0f, extraVerticalPadding)); + } +} diff --git a/soh/soh/Enhancements/debugger/ImGuiHelpers.h b/soh/soh/Enhancements/debugger/ImGuiHelpers.h index 7f01e45807..91df059aa8 100644 --- a/soh/soh/Enhancements/debugger/ImGuiHelpers.h +++ b/soh/soh/Enhancements/debugger/ImGuiHelpers.h @@ -6,3 +6,5 @@ void SetLastItemHoverText(const std::string& text); void InsertHelpHoverText(const std::string& text); + +void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalPadding = 0); diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 48c9c46959..c5cad88dd9 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -1,5 +1,6 @@ #include "debugSaveEditor.h" #include "../../util.h" +#include "../../OTRGlobals.h" #include "../libultraship/ImGuiImpl.h" #include "ImGuiHelpers.h" @@ -14,6 +15,7 @@ extern "C" { #include "variables.h" #include "functions.h" #include "macros.h" +#include "soh/Enhancements/randomizer/adult_trade_shuffle.h" extern GlobalContext* gGlobalCtx; #include "textures/icon_item_static/icon_item_static.h" @@ -525,6 +527,27 @@ void DrawInfoTab() { ImGui::PopItemWidth(); } +void DrawBGSItemFlag(uint8_t itemID) { + const ItemMapEntry& slotEntry = itemMapping[itemID]; + ImGui::Image(SohImGui::GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1)); + ImGui::SameLine(); + int tradeIndex = itemID - ITEM_POCKET_EGG; + bool hasItem = (gSaveContext.adultTradeItems & (1 << tradeIndex)) != 0; + bool shouldHaveItem = hasItem; + ImGui::Checkbox(("##adultTradeFlag" + std::to_string(itemID)).c_str(), &shouldHaveItem); + if (hasItem != shouldHaveItem) { + if (shouldHaveItem) { + gSaveContext.adultTradeItems |= (1 << tradeIndex); + if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_NONE) { + INV_CONTENT(ITEM_TRADE_ADULT) = ITEM_POCKET_EGG + tradeIndex; + } + } else { + gSaveContext.adultTradeItems &= ~(1 << tradeIndex); + Inventory_ReplaceItem(gGlobalCtx, itemID, Randomizer_GetNextAdultTradeItem()); + } + } +} + void DrawInventoryTab() { static bool restrictToValid = true; @@ -566,6 +589,9 @@ void DrawInventoryTab() { if (ImGui::BeginPopup(itemPopupPicker)) { if (ImGui::Button("##itemNonePicker", ImVec2(32.0f, 32.0f))) { gSaveContext.inventory.items[selectedIndex] = ITEM_NONE; + if (selectedIndex == SLOT_TRADE_ADULT) { + gSaveContext.adultTradeItems = 0; + } ImGui::CloseCurrentPopup(); } SetLastItemHoverText("None"); @@ -596,6 +622,13 @@ void DrawInventoryTab() { if (ImGui::ImageButton(SohImGui::GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 0)) { gSaveContext.inventory.items[selectedIndex] = slotEntry.id; + // Set adult trade item flag if you're playing adult trade shuffle in rando + if (gSaveContext.n64ddFlag && + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE); + selectedIndex == SLOT_TRADE_ADULT && + slotEntry.id >= ITEM_POCKET_EGG && slotEntry.id <= ITEM_CLAIM_CHECK) { + gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(slotEntry.id); + } ImGui::CloseCurrentPopup(); } SetLastItemHoverText(SohUtils::GetItemName(slotEntry.id)); @@ -632,6 +665,16 @@ void DrawInventoryTab() { ImGui::PopID(); } } + + // Trade quest flags are only used when shuffling the trade sequence, so + // don't show this if it isn't needed. + if (gSaveContext.n64ddFlag && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE) + && ImGui::TreeNode("Adult trade quest items")) { + for (int i = ITEM_POCKET_EGG; i <= ITEM_CLAIM_CHECK; i++) { + DrawBGSItemFlag(i); + } + ImGui::TreePop(); + } } // Draw a flag bitfield as an grid of checkboxes diff --git a/soh/soh/Enhancements/randomizer/3drando/item.hpp b/soh/soh/Enhancements/randomizer/3drando/item.hpp index a424dbf2b8..dbfb695b1e 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/item.hpp @@ -103,11 +103,11 @@ public: return false; } - if ((type == ITEMTYPE_BOSSKEY && getItemId != 0x9A) && (BossKeysanity.Is(BOSSKEYSANITY_VANILLA) || BossKeysanity.Is(BOSSKEYSANITY_OWN_DUNGEON))) { + if ((type == ITEMTYPE_BOSSKEY && getItemId != 0xAD) && (BossKeysanity.Is(BOSSKEYSANITY_VANILLA) || BossKeysanity.Is(BOSSKEYSANITY_OWN_DUNGEON))) { return false; } //Ganons Castle Boss Key - if (getItemId == 0x9A && (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA) || GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON))) { + if (getItemId == 0xAD && (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA) || GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON))) { return false; } diff --git a/soh/soh/Enhancements/randomizer/3drando/item_list.cpp b/soh/soh/Enhancements/randomizer/3drando/item_list.cpp index b76f247547..8cf49124ab 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_list.cpp @@ -229,11 +229,11 @@ void ItemTable_Init() { //English name itemTable[BUY_BOMBCHU_20] = Item(Text{"Buy Bombchu (20)", "Acheter: Missiles (20)", "Comprar bombchus (20)"}, ITEMTYPE_SHOP, 0x16, true, &BuyBombchus20, BOMBCHU_20, 180); itemTable[BUY_BOMBCHU_5] = Item(Text{"Buy Bombchu (5)", "Acheter: Missiles (5)", "Comprar bombchus (5)"}, ITEMTYPE_SHOP, 0x18, true, &BuyBombchus5, BOMBCHU_5, 60); itemTable[BUY_DEKU_SEEDS_30] = Item(Text{"Buy Deku Seeds (30)", "Acheter: Graines Mojo (30)", "Comprar semillas deku (30)"}, ITEMTYPE_SHOP, 0x1D, true, &BuySeed, DEKU_SEEDS_30, 30); - itemTable[SOLD_OUT] = Item(Text{"Sold Out", "Vendu", "Vendido"}, ITEMTYPE_SHOP, 0x26, false, &noVariable, NONE, 0); + itemTable[SOLD_OUT] = Item(Text{"Sold Out", "Rupture de stock", "Vendido"}, ITEMTYPE_SHOP, 0x26, false, &noVariable, NONE, 0); itemTable[BUY_BLUE_FIRE] = Item(Text{"Buy Blue Fire", "Acheter: Flamme Bleue", "Comprar fuego azul"}, ITEMTYPE_SHOP, 0x27, true, &BlueFireAccess, BOTTLE_WITH_BLUE_FIRE, 300); itemTable[BUY_BOTTLE_BUG] = Item(Text{"Buy Bottle Bug", "Acheter: Insecte en bouteille", "Comprar bichos"}, ITEMTYPE_SHOP, 0x28, true, &BugsAccess, BOTTLE_WITH_BUGS, 50); - itemTable[BUY_POE] = Item(Text{"Buy Poe", "Acheter: Esprit", "Comprar Poe"}, ITEMTYPE_SHOP, 0x2A, false, &noVariable, BOTTLE_WITH_BIG_POE, 30); - itemTable[BUY_FAIRYS_SPIRIT] = Item(Text{"Buy Fairy's Spirit", "Acheter: Esprit de Fée", "Comprar hada"}, ITEMTYPE_SHOP, 0x2B, true, &FairyAccess, BOTTLE_WITH_FAIRY, 50); + itemTable[BUY_POE] = Item(Text{"Buy Poe", "Acheter: Esprit", "Comprar Poe"}, ITEMTYPE_SHOP, 0x2A, false, &noVariable, BOTTLE_WITH_BIG_POE, 30); + itemTable[BUY_FAIRYS_SPIRIT] = Item(Text{"Buy Fairy's Spirit", "Acheter: Esprit de Fée", "Comprar hada"}, ITEMTYPE_SHOP, 0x2B, true, &FairyAccess, BOTTLE_WITH_FAIRY, 50); itemTable[BUY_ARROWS_10] = Item(Text{"Buy Arrows (10)", "Acheter: Flèches (10)", "Comprar flechas (10)"}, ITEMTYPE_SHOP, 0x2C, true, &BuyArrow, ARROWS_10, 20); itemTable[BUY_BOMBS_20] = Item(Text{"Buy Bombs (20)", "Acheter: Bombes (20)", "Comprar bombas (20)"}, ITEMTYPE_SHOP, 0x2D, true, &BuyBomb, BOMBS_20, 80); itemTable[BUY_BOMBS_30] = Item(Text{"Buy Bombs (30)", "Acheter: Bombes (30)", "Comprar bombas (30)"}, ITEMTYPE_SHOP, 0x2E, true, &BuyBomb, BOMBS_20, 120); diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp index 27101864bb..213b62f0ac 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp @@ -165,6 +165,11 @@ void LocationTable_Init() { //Zoras River locationTable[ZR_OPEN_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x09, "ZR Open Grotto Chest", ZR_OPEN_GROTTO_CHEST, RED_RUPEE, {Category::cZorasRiver, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); locationTable[ZR_MAGIC_BEAN_SALESMAN] = ItemLocation::Base (0x54, 0x16, "ZR Magic Bean Salesman", ZR_MAGIC_BEAN_SALESMAN, MAGIC_BEAN, {Category::cZorasRiver,}, SpoilerCollectionCheck::MagicBeans(0x54, 0x01), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_FROGS_ZELDAS_LULLABY] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs Zelda's Lullaby", ZR_FROGS_ZELDAS_LULLABY, PURPLE_RUPEE, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_FROGS_EPONAS_SONG] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs Epona's Song", ZR_FROGS_EPONAS_SONG, PURPLE_RUPEE, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_FROGS_SARIAS_SONG] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs Saria's Song", ZR_FROGS_SARIAS_SONG, PURPLE_RUPEE, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_FROGS_SUNS_SONG] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs Sun's Song", ZR_FROGS_SUNS_SONG, PURPLE_RUPEE, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_FROGS_SONG_OF_TIME] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs Song of Time", ZR_FROGS_SONG_OF_TIME, PURPLE_RUPEE, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); locationTable[ZR_FROGS_IN_THE_RAIN] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs in the Rain", ZR_FROGS_IN_THE_RAIN, PIECE_OF_HEART, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); locationTable[ZR_FROGS_OCARINA_GAME] = ItemLocation::Base (0x54, 0x76, "ZR Frogs Ocarina Game", ZR_FROGS_OCARINA_GAME, PIECE_OF_HEART, {Category::cZorasRiver, Category::cMinigame,}, SpoilerCollectionCheck::EventChkInf(0xD0), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); locationTable[ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH] = ItemLocation::Collectable(0x54, 0x04, "ZR Near Open Grotto Freestanding PoH", ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, PIECE_OF_HEART, {Category::cZorasRiver,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); @@ -1302,6 +1307,11 @@ std::vector overworldLocations = { //Zoras River ZR_OPEN_GROTTO_CHEST, ZR_MAGIC_BEAN_SALESMAN, + ZR_FROGS_ZELDAS_LULLABY, + ZR_FROGS_EPONAS_SONG, + ZR_FROGS_SARIAS_SONG, + ZR_FROGS_SUNS_SONG, + ZR_FROGS_SONG_OF_TIME, ZR_FROGS_IN_THE_RAIN, ZR_FROGS_OCARINA_GAME, ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index b7ed68ea65..ec03a0ebd6 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -729,6 +729,16 @@ void GenerateItemPool() { PlaceItemInLocation(WASTELAND_BOMBCHU_SALESMAN, BOMBCHU_10, false, true); } + if (ShuffleFrogSongRupees) { + AddItemToMainPool(PURPLE_RUPEE, 5); + } else { + PlaceItemInLocation(ZR_FROGS_ZELDAS_LULLABY, PURPLE_RUPEE, false, true); + PlaceItemInLocation(ZR_FROGS_EPONAS_SONG, PURPLE_RUPEE, false, true); + PlaceItemInLocation(ZR_FROGS_SARIAS_SONG, PURPLE_RUPEE, false, true); + PlaceItemInLocation(ZR_FROGS_SUNS_SONG, PURPLE_RUPEE, false, true); + PlaceItemInLocation(ZR_FROGS_SONG_OF_TIME, PURPLE_RUPEE, false, true); + } + if (ShuffleAdultTradeQuest) { AddItemToMainPool(POCKET_EGG); AddItemToMainPool(COJIRO); diff --git a/soh/soh/Enhancements/randomizer/3drando/keys.hpp b/soh/soh/Enhancements/randomizer/3drando/keys.hpp index 3e8d8f5cd1..0ce91d6a4d 100644 --- a/soh/soh/Enhancements/randomizer/3drando/keys.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/keys.hpp @@ -472,6 +472,11 @@ typedef enum { //ZORA'S_RIVER ZR_MAGIC_BEAN_SALESMAN, ZR_OPEN_GROTTO_CHEST, + ZR_FROGS_ZELDAS_LULLABY, + ZR_FROGS_EPONAS_SONG, + ZR_FROGS_SARIAS_SONG, + ZR_FROGS_SUNS_SONG, + ZR_FROGS_SONG_OF_TIME, ZR_FROGS_IN_THE_RAIN, ZR_FROGS_OCARINA_GAME, ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp index bff5d75631..3b257e16a5 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp @@ -31,6 +31,21 @@ void AreaTable_Init_ZorasDomain() { LocationAccess(ZR_FROGS_IN_THE_RAIN, {[]{return IsChild && CanPlay(SongOfStorms);}, /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SongOfStorms;}}), + LocationAccess(ZR_FROGS_ZELDAS_LULLABY, {[]{return IsChild && CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && ZeldasLullaby;}}), + LocationAccess(ZR_FROGS_EPONAS_SONG, {[]{return IsChild && CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && EponasSong;}}), + LocationAccess(ZR_FROGS_SARIAS_SONG, {[]{return IsChild && CanPlay(SariasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SariasSong;}}), + LocationAccess(ZR_FROGS_SUNS_SONG, {[]{return IsChild && CanPlay(SunsSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SunsSong;}}), + LocationAccess(ZR_FROGS_SONG_OF_TIME, {[]{return IsChild && CanPlay(SongOfTime);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SongOfTime;}}), LocationAccess(ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, {[]{return IsChild || CanUse(HOVER_BOOTS) || (IsAdult && LogicZoraRiverLower);}}), LocationAccess(ZR_NEAR_DOMAIN_FREESTANDING_POH, {[]{return IsChild || CanUse(HOVER_BOOTS) || (IsAdult && LogicZoraRiverUpper);}}), LocationAccess(ZR_GS_LADDER, {[]{return IsChild && AtNight && CanChildAttack && CanGetNightTimeGS;}}), diff --git a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp index edca583e51..328b862bd3 100644 --- a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp @@ -385,6 +385,13 @@ string_view merchantsHintsDesc = "These hints will make Medigoron and the "The Clearer Hints setting will affect how they\n" // "refer to the item."; // /*------------------------------ // +| SHUFFLE FROG SONG RUPEES | // +------------------------------*/ // +string_view frogSongRupeesDesc = "Enabling this adds 5 Purple Rupees to the item\n" // + "pool and shuffles the rewards from playing Zelda's\n" + "Lullaby, Epona's Song, Saria's Song, Sun's Song,\n" + "and Song of Time to the frogs in Zora's River.\n";// +/*------------------------------ // | SHUFFLE ADULT TRADE | // ------------------------------*/ // string_view adultTradeDesc = "Enabling this adds all of the adult trade quest\n"// @@ -586,6 +593,13 @@ string_view kingZoraSpeedRandom = "King Zora will move out of the way in 1 string_view completeMaskDesc = "Once the happy mask shop is opened, all masks\n" // "will be available to be borrowed."; // /*------------------------------ // +| ENABLE GLITCH CUTSCENES | // +------------------------------*/ // +string_view glitchCutscenesDesc = "The cutscenes of the Poes in Forest Temple and\n" // + "Darunia in Fire Temple will not be skipped.\n" // + "These cutscenes are only useful for glitched\n" // + "gameplay and can be safely skipped otherwise."; // +/*------------------------------ // | QUICK TEXT | // ------------------------------*/ // string_view quickTextDesc0 = "Quick text will be unchanged, requiring\n" // diff --git a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp index 396fdd24cb..cea8f419d6 100644 --- a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp @@ -126,6 +126,8 @@ extern string_view magicBeansDesc; extern string_view merchantsDesc; extern string_view merchantsHintsDesc; +extern string_view frogSongRupeesDesc; + extern string_view adultTradeDesc; extern string_view chestMinigameDesc; @@ -196,6 +198,8 @@ extern string_view kingZoraSpeedRandom; extern string_view completeMaskDesc; +extern string_view glitchCutscenesDesc; + extern string_view quickTextDesc0; extern string_view quickTextDesc1; extern string_view quickTextDesc2; diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 05fc10c4bb..71aa70b323 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -52,19 +52,19 @@ namespace Settings { // Setting name, Options, Setting Descriptions (assigned in setting_descriptions.cpp) Category (default: Setting),Default index (default: 0), Default hidden (default: false) //Open Settings Any option index past the last description will use the last description Option RandomizeOpen = Option::Bool("Randomize Settings", {"No","Yes"}, {openRandomize}, OptionCategory::Toggle); - Option OpenForest = Option::U8 ("Forest", {"Closed", "Open", "Closed Deku"}, {forestClosed, forestOpen, forestClosedDeku}, OptionCategory::Setting, OPENFOREST_OPEN); + Option OpenForest = Option::U8 ("Forest", {"Closed", "Closed Deku", "Open"}, {forestClosed, forestClosedDeku, forestOpen}, OptionCategory::Setting, OPENFOREST_CLOSED); Option OpenKakariko = Option::U8 ("Kakariko Gate", {"Closed", "Open"}, {kakGateClosed, kakGateOpen}); - Option OpenDoorOfTime = Option::U8 ("Door of Time", {"Open", "Closed", "Intended"}, {doorOfTimeOpen, doorOfTimeClosed, doorOfTimeIntended}); - Option ZorasFountain = Option::U8 ("Zora's Fountain", {"Normal", "Adult", "Open"}, {fountainNormal, fountainAdult, fountainOpen}); + Option OpenDoorOfTime = Option::U8 ("Door of Time", {"Closed", "Song only", "Open"}, {doorOfTimeIntended, doorOfTimeClosed, doorOfTimeOpen}); + Option ZorasFountain = Option::U8 ("Zora's Fountain", {"Closed", "Closed as child", "Open"}, {fountainNormal, fountainAdult, fountainOpen}); Option GerudoFortress = Option::U8 ("Gerudo Fortress", {"Normal", "Fast", "Open"}, {gerudoNormal, gerudoFast, gerudoOpen}); - Option Bridge = Option::U8 ("Rainbow Bridge", {"Open", "Vanilla", "Stones", "Medallions", "Rewards", "Dungeons", "Tokens"}, {bridgeOpen, bridgeVanilla, bridgeStones, bridgeMedallions, bridgeRewards, bridgeDungeons, bridgeTokens}, OptionCategory::Setting, RAINBOWBRIDGE_VANILLA); - Option BridgeStoneCount = Option::U8 (" Stone Count", {NumOpts(0, 3)}, {bridgeStoneCountDesc}, OptionCategory::Setting, 1, true); - Option BridgeMedallionCount= Option::U8 (" Medallion Count", {NumOpts(0, 6)}, {bridgeMedallionCountDesc}, OptionCategory::Setting, 1, true); - Option BridgeRewardCount = Option::U8 (" Reward Count", {NumOpts(0, 9)}, {bridgeRewardCountDesc}, OptionCategory::Setting, 1, true); - Option BridgeDungeonCount = Option::U8 (" Dungeon Count", {NumOpts(0, 8)}, {bridgeDungeonCountDesc}, OptionCategory::Setting, 1, true); - Option BridgeTokenCount = Option::U8 (" Token Count", {NumOpts(0, 100)}, {bridgeTokenCountDesc}, OptionCategory::Setting, 1, true); + Option Bridge = Option::U8 ("Rainbow Bridge", {"Vanilla", "Always open", "Stones", "Medallions", "Dungeon rewards", "Dungeons", "Tokens"}, {bridgeVanilla, bridgeOpen, bridgeStones, bridgeMedallions, bridgeRewards, bridgeDungeons, bridgeTokens}, OptionCategory::Setting, RAINBOWBRIDGE_VANILLA); + Option BridgeStoneCount = Option::U8 ("Stone Count", {NumOpts(0, 3)}, {bridgeStoneCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeMedallionCount= Option::U8 ("Medallion Count", {NumOpts(0, 6)}, {bridgeMedallionCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeRewardCount = Option::U8 ("Reward Count", {NumOpts(0, 9)}, {bridgeRewardCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeDungeonCount = Option::U8 ("Dungeon Count", {NumOpts(0, 8)}, {bridgeDungeonCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeTokenCount = Option::U8 ("Token Count", {NumOpts(0, 100)}, {bridgeTokenCountDesc}, OptionCategory::Setting, 1, true); Option RandomGanonsTrials = Option::Bool("Random Ganon's Trials", {"Off", "On"}, {randomGanonsTrialsDesc}, OptionCategory::Setting, ON); - Option GanonsTrialsCount = Option::U8 (" Trial Count", {NumOpts(0, 6)}, {ganonsTrialCountDesc}, OptionCategory::Setting, 1, true); + Option GanonsTrialsCount = Option::U8 ("Trial Count", {NumOpts(0, 6)}, {ganonsTrialCountDesc}, OptionCategory::Setting, 1, true); std::vector