From 9f63aaae9974440db6f67b9e11b50587a3009bd4 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sun, 21 Aug 2022 16:14:41 -0500 Subject: [PATCH 01/62] Initial work towards scrubsanity, got affordable prices mostly functional Write and read prices from spoiler, move IdentifyScrub up to Randomizer In a semi working state Fix bug when going from c to cpp Kill scrubs before they spawn if already purchased Woopsie from rebase Update soh/soh/OTRGlobals.cpp --- soh/include/z64save.h | 1 + .../Enhancements/randomizer/3drando/fill.cpp | 13 + .../randomizer/3drando/item_location.cpp | 50 +++ .../randomizer/3drando/item_location.hpp | 17 +- .../randomizer/3drando/settings.cpp | 1 + .../randomizer/3drando/spoiler_log.cpp | 15 +- .../Enhancements/randomizer/randomizer.cpp | 321 +++++++++++++++++- soh/soh/Enhancements/randomizer/randomizer.h | 2 + .../Enhancements/randomizer/randomizerTypes.h | 10 + soh/soh/OTRGlobals.cpp | 22 +- soh/soh/OTRGlobals.h | 1 + soh/soh/SaveManager.cpp | 12 + soh/src/code/z_sram.c | 6 + soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c | 72 ++-- soh/src/overlays/actors/ovl_En_Dns/z_en_dns.h | 1 + .../actors/ovl_En_Shopnuts/z_en_shopnuts.c | 9 + 16 files changed, 492 insertions(+), 61 deletions(-) diff --git a/soh/include/z64save.h b/soh/include/z64save.h index 9da18f72ef..d219fd17f6 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -185,6 +185,7 @@ typedef struct { u8 dungeonsDone[8]; u8 trialsDone[6]; u8 cowsMilked[10]; + u8 scrubsPurchased[35]; u8 temporaryWeapon; u16 adultTradeItems; } SaveContext; // size = 0x1428 diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index 14bf594c2e..b78e3f6301 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -1039,6 +1039,19 @@ int Fill() { //Fast fill for the rest of the pool std::vector remainingPool = FilterAndEraseFromPool(ItemPool, [](const auto i) { return true; }); FastFill(remainingPool, GetAllEmptyLocations(), false); + + // Add prices for scrubsanity + if (Scrubsanity.Is(SCRUBSANITY_AFFORDABLE)) { + for (size_t i = 0; i < ScrubLocations.size(); i++) { + Location(ScrubLocations[i])->SetScrubsanityPrice(10); + } + } else if (Scrubsanity.Is(SCRUBSANITY_RANDOM_PRICES)) { + for (size_t i = 0; i < ScrubLocations.size(); i++) { + int randomPrice = GetRandomScrubPrice(); + Location(ScrubLocations[i])->SetScrubsanityPrice(randomPrice); + } + } + GeneratePlaythrough(); //Successful placement, produced beatable result if(playthroughBeatable && !placementFailure) { diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp index 08d191740d..0a4405c785 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp @@ -1011,6 +1011,56 @@ std::vector> ShopLocationLists = { GC_ShopLocations, }; +//List of scrubs, used for pricing the scrubs +std::vector ScrubLocations = { + LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, + LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, + LW_DEKU_SCRUB_NEAR_BRIDGE, + LW_DEKU_SCRUB_GROTTO_REAR, + LW_DEKU_SCRUB_GROTTO_FRONT, + SFM_DEKU_SCRUB_GROTTO_REAR, + SFM_DEKU_SCRUB_GROTTO_FRONT, + HF_DEKU_SCRUB_GROTTO, + LH_DEKU_SCRUB_GROTTO_LEFT, + LH_DEKU_SCRUB_GROTTO_RIGHT, + LH_DEKU_SCRUB_GROTTO_CENTER, + GV_DEKU_SCRUB_GROTTO_REAR, + GV_DEKU_SCRUB_GROTTO_FRONT, + COLOSSUS_DEKU_SCRUB_GROTTO_REAR, + COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, + GC_DEKU_SCRUB_GROTTO_LEFT, + GC_DEKU_SCRUB_GROTTO_RIGHT, + GC_DEKU_SCRUB_GROTTO_CENTER, + DMC_DEKU_SCRUB, + DMC_DEKU_SCRUB_GROTTO_LEFT, + DMC_DEKU_SCRUB_GROTTO_RIGHT, + DMC_DEKU_SCRUB_GROTTO_CENTER, + ZR_DEKU_SCRUB_GROTTO_REAR, + ZR_DEKU_SCRUB_GROTTO_FRONT, + LLR_DEKU_SCRUB_GROTTO_LEFT, + LLR_DEKU_SCRUB_GROTTO_RIGHT, + LLR_DEKU_SCRUB_GROTTO_CENTER, + DEKU_TREE_MQ_DEKU_SCRUB, + DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, + DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, + DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, + DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + JABU_JABUS_BELLY_DEKU_SCRUB, + GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, + GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, + GANONS_CASTLE_DEKU_SCRUB_RIGHT, + GANONS_CASTLE_DEKU_SCRUB_LEFT, + GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, + GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, +}; + //List of gossip stone locations for hints std::vector gossipStoneLocations = { DMC_GOSSIP_STONE, diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.hpp b/soh/soh/Enhancements/randomizer/3drando/item_location.hpp index 823cd88ef5..efe1a62576 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_location.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.hpp @@ -257,8 +257,8 @@ public: } void SetPrice(uint16_t price_) { - //don't override price if the price was set for shopsanity - if (hasShopsanityPrice) { + //don't override price if the price was set for shopsanity/scrubsanity + if (hasShopsanityPrice || hasScrubsanityPrice) { return; } price = price_; @@ -269,10 +269,19 @@ public: hasShopsanityPrice = true; } + void SetScrubsanityPrice(uint16_t price_) { + price = price_; + hasScrubsanityPrice = true; + } + bool HasShopsanityPrice() const { return hasShopsanityPrice; } + bool HasScrubsanityPrice() const { + return hasScrubsanityPrice; + } + bool IsExcluded() const { return excludedOption.Value(); } @@ -426,6 +435,7 @@ public: isHintable = false; price = 0; hasShopsanityPrice = false; + hasScrubsanityPrice = false; hidden = false; } @@ -451,6 +461,7 @@ private: bool isHintable = false; uint32_t parentRegion = NONE; bool hasShopsanityPrice = false; + bool hasScrubsanityPrice = false; bool hidden = false; }; @@ -467,6 +478,8 @@ ItemLocation* Location(uint32_t locKey); extern std::vector> ShopLocationLists; +extern std::vector ScrubLocations; + extern std::vector gossipStoneLocations; extern std::vector dungeonRewardLocations; diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 51eaff18be..c7e06b8124 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2532,6 +2532,7 @@ namespace Settings { ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]); ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]); Tokensanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_TOKENS]); + Scrubsanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SCRUBS]); ShuffleCows.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_COWS]); ShuffleKokiriSword.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_KOKIRI_SWORD]); ShuffleOcarinas.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_OCARINA]); diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 22d1f196d6..562671fd11 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -675,15 +675,14 @@ static void WriteHints(int language) { static void WriteAllLocations(int language) { for (const uint32_t key : allLocations) { ItemLocation* location = Location(key); + std::string placedItemName = language == 2 ? location->GetPlacedItemName().french : location->GetPlacedItemName().english; - switch (language) { - case 0: - default: - jsonData["locations"][location->GetName()] = location->GetPlacedItemName().english; - break; - case 2: - jsonData["locations"][location->GetName()] = location->GetPlacedItemName().french; - break; + // Eventually check for other things here like fake name + if (location->HasScrubsanityPrice() || location->HasShopsanityPrice()) { + jsonData["locations"][location->GetName()]["item"] = placedItemName; + jsonData["locations"][location->GetName()]["price"] = location->GetPrice();; + } else { + jsonData["locations"][location->GetName()] = placedItemName; } } } diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 60c198ed4e..299d418c8a 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -81,6 +81,7 @@ Sprite* Randomizer::GetSeedTexture(uint8_t index) { Randomizer::~Randomizer() { this->randoSettings.clear(); this->itemLocations.clear(); + this->scrubPrices.clear(); } std::unordered_map getItemIdToItemId = { @@ -523,6 +524,7 @@ std::unordered_map SpoilerfileSettingNameToEn { "Open Settings:Random Ganon's Trials", RSK_RANDOM_TRIALS }, { "Open Settings:Trial Count", RSK_TRIAL_COUNT }, { "Shuffle Settings:Shuffle Gerudo Card", RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD }, + { "Shuffle Settings:Scrub Shuffle", RSK_SHUFFLE_SCRUBS }, { "Shuffle Settings:Shuffle Cows", RSK_SHUFFLE_COWS }, { "Shuffle Settings:Tokensanity", RSK_SHUFFLE_TOKENS }, { "Shuffle Settings:Shuffle Adult Trade", RSK_SHUFFLE_ADULT_TRADE }, @@ -749,6 +751,17 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { numericValueString = it.value(); gSaveContext.randoSettings[index].value = std::stoi(numericValueString); break; + case RSK_SHUFFLE_SCRUBS: + if(it.value() == "Off") { + gSaveContext.randoSettings[index].value = 0; + } else if(it.value() == "Affordable") { + gSaveContext.randoSettings[index].value = 1; + } else if(it.value() == "Expensive") { + gSaveContext.randoSettings[index].value = 2; + } else if(it.value() == "Random Prices") { + gSaveContext.randoSettings[index].value = 3; + } + break; case RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD: case RSK_SHUFFLE_COWS: case RSK_SHUFFLE_ADULT_TRADE: @@ -1079,9 +1092,11 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent for (auto itemit = itemJson.begin(); itemit != itemJson.end(); ++itemit) { // todo handle prices if (itemit.key() == "item") { - gSaveContext.itemLocations[index].check = SpoilerfileCheckNameToEnum[it.key()]; gSaveContext.itemLocations[index].get = SpoilerfileGetNameToEnum[itemit.value()]; + } else if (itemit.key() == "price") { + scrubPrices[gSaveContext.itemLocations[index].check] = itemit.value(); + // TODO: Handle shop prices } } } else { @@ -1565,6 +1580,281 @@ std::string Randomizer::GetGanonHintText() const { return ganonHintText; } +ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData) { + struct ScrubIdentity scrubIdentity; + + scrubIdentity.scrubId = -1; + scrubIdentity.randomizerCheck = RC_UNKNOWN_CHECK; + scrubIdentity.getItemId = GI_NONE; + scrubIdentity.itemPrice = -1; + scrubIdentity.isShuffled = GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) > 0; + + switch (actorParams) { + case 0x00: + scrubIdentity.getItemId = GI_NUTS_5_2; + break; + case 0x01: + scrubIdentity.getItemId = GI_STICKS_1; + break; + case 0x02: + scrubIdentity.getItemId = GI_HEART_PIECE; + break; + case 0x03: + scrubIdentity.getItemId = GI_SEEDS_30; + break; + case 0x04: + scrubIdentity.getItemId = GI_SHIELD_DEKU; + break; + case 0x05: + scrubIdentity.getItemId = GI_BOMBS_5; + break; + case 0x06: + scrubIdentity.getItemId = GI_ARROWS_LARGE; + break; + case 0x07: + scrubIdentity.getItemId = GI_POTION_RED; + break; + case 0x08: + scrubIdentity.getItemId = GI_POTION_GREEN; + break; + case 0x09: + scrubIdentity.getItemId = GI_STICK_UPGRADE_20; + break; + case 0x0A: + scrubIdentity.getItemId = GI_NUT_UPGRADE_30; + break; + } + + // TODO: Handle MQ scrubs + switch (sceneNum) { + case SCENE_DDAN: // Dodongo's Cavern + switch (actorParams) { + case 0x00: + scrubIdentity.scrubId = 0x00; + scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT; + break; + case 0x01: + scrubIdentity.scrubId = 0x01; + scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS; + break; + case 0x03: + case 0x06: + scrubIdentity.scrubId = 0x02; + scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT; + break; + case 0x04: + scrubIdentity.scrubId = 0x03; + scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY; + break; + } + break; + case SCENE_BDAN: // Jabu Jabu's Belly + switch (actorParams) { + case 0x00: + scrubIdentity.scrubId = 0x04; + scrubIdentity.randomizerCheck = RC_JABU_JABUS_BELLY_DEKU_SCRUB; + break; + } + break; + case SCENE_GANONTIKA: // Ganon's Castle + switch (actorParams) { + case 0x05: + scrubIdentity.scrubId = 0x05; + scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT; + break; + case 0x03: + case 0x06: + scrubIdentity.scrubId = 0x06; + scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT; + break; + case 0x07: + scrubIdentity.scrubId = 0x07; + scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT; + break; + case 0x08: + scrubIdentity.scrubId = 0x08; + scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_LEFT; + break; + } + break; + case SCENE_KAKUSIANA: // Grotto + // Ugly, but the best way we can identify which grotto we are in, same method 3DRando uses, but we'll need to account for entrance rando + switch (respawnData) { + case 0xE6: // Hyrule Field Scrub Grotto + switch (actorParams) { + case 0x02: + scrubIdentity.scrubId = 0x09; + scrubIdentity.randomizerCheck = RC_HF_DEKU_SCRUB_GROTTO; + scrubIdentity.isShuffled = true; + break; + } + break; + case 0xEB: // ZR Scrub Grotto + switch (actorParams) { + case 0x07: + scrubIdentity.scrubId = 0x0A; + scrubIdentity.randomizerCheck = RC_ZR_DEKU_SCRUB_GROTTO_REAR; + break; + case 0x08: + scrubIdentity.scrubId = 0x0B; + scrubIdentity.randomizerCheck = RC_ZR_DEKU_SCRUB_GROTTO_FRONT; + break; + } + break; + case 0xEE: // Sacred Forest Meadow Scrub Grotto + switch (actorParams) { + case 0x07: + scrubIdentity.scrubId = 0x0C; + scrubIdentity.randomizerCheck = RC_SFM_DEKU_SCRUB_GROTTO_REAR; + break; + case 0x08: + scrubIdentity.scrubId = 0x0D; + scrubIdentity.randomizerCheck = RC_SFM_DEKU_SCRUB_GROTTO_FRONT; + break; + } + break; + case 0xEF: // Lake Hylia Scrub Grotto + switch (actorParams) { + case 0x00: + scrubIdentity.scrubId = 0x0E; + scrubIdentity.randomizerCheck = RC_LH_DEKU_SCRUB_GROTTO_LEFT; + break; + case 0x05: + scrubIdentity.scrubId = 0x0F; + scrubIdentity.randomizerCheck = RC_LH_DEKU_SCRUB_GROTTO_RIGHT; + break; + case 0x03: + case 0x06: + scrubIdentity.scrubId = 0x10; + scrubIdentity.randomizerCheck = RC_LH_DEKU_SCRUB_GROTTO_CENTER; + break; + } + break; + case 0xF0: // Gerudo Valley Scrub Grotto + switch (actorParams) { + case 0x07: + scrubIdentity.scrubId = 0x11; + scrubIdentity.randomizerCheck = RC_GV_DEKU_SCRUB_GROTTO_REAR; + break; + case 0x08: + scrubIdentity.scrubId = 0x12; + scrubIdentity.randomizerCheck = RC_GV_DEKU_SCRUB_GROTTO_FRONT; + break; + } + break; + case 0xF5: // Lost Woods Scrub Grotto + switch (actorParams) { + case 0x03: + case 0x06: + scrubIdentity.scrubId = 0x13; + scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_GROTTO_REAR; + break; + case 0x0A: + scrubIdentity.scrubId = 0x14; + scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_GROTTO_FRONT; + scrubIdentity.isShuffled = true; + break; + } + break; + case 0xF9: // Death Mountain Crater Scrub Grotto + switch (actorParams) { + case 0x00: + scrubIdentity.scrubId = 0x15; + scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB_GROTTO_LEFT; + break; + case 0x05: + scrubIdentity.scrubId = 0x16; + scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB_GROTTO_RIGHT; + break; + case 0x03: + case 0x06: + scrubIdentity.scrubId = 0x17; + scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB_GROTTO_CENTER; + break; + } + break; + case 0xFB: // Gerudo City Scrub Grotto + switch (actorParams) { + case 0x00: + scrubIdentity.scrubId = 0x18; + scrubIdentity.randomizerCheck = RC_GC_DEKU_SCRUB_GROTTO_LEFT; + break; + case 0x05: + scrubIdentity.scrubId = 0x19; + scrubIdentity.randomizerCheck = RC_GC_DEKU_SCRUB_GROTTO_RIGHT; + break; + case 0x03: + case 0x06: + scrubIdentity.scrubId = 0x1A; + scrubIdentity.randomizerCheck = RC_GC_DEKU_SCRUB_GROTTO_CENTER; + break; + } + break; + case 0xFC: // Lon Lon Ranch Scrub Grotto + switch (actorParams) { + case 0x00: + scrubIdentity.scrubId = 0x1B; + scrubIdentity.randomizerCheck = RC_LLR_DEKU_SCRUB_GROTTO_LEFT; + break; + case 0x05: + scrubIdentity.scrubId = 0x1C; + scrubIdentity.randomizerCheck = RC_LLR_DEKU_SCRUB_GROTTO_RIGHT; + break; + case 0x03: + case 0x06: + scrubIdentity.scrubId = 0x1D; + scrubIdentity.randomizerCheck = RC_LLR_DEKU_SCRUB_GROTTO_CENTER; + break; + } + break; + case 0xFD: // Desert Colossus Scrub Grotto + switch (actorParams) { + case 0x07: + scrubIdentity.scrubId = 0x1E; + scrubIdentity.randomizerCheck = RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR; + break; + case 0x08: + scrubIdentity.scrubId = 0x1F; + scrubIdentity.randomizerCheck = RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT; + break; + } + break; + } + break; + case SCENE_SPOT10: // Lost woods + switch (actorParams) { + case 0x00: + scrubIdentity.scrubId = 0x20; + scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT; + break; + case 0x01: + scrubIdentity.scrubId = 0x21; + scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT; + break; + case 0x09: + scrubIdentity.scrubId = 0x22; + scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_NEAR_BRIDGE; + scrubIdentity.isShuffled = true; + break; + } + break; + case SCENE_SPOT17: // Death Mountain Crater + switch (actorParams) { + case 0x05: + scrubIdentity.scrubId = 0x23; + scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB; + break; + } + break; + } + + if (scrubPrices.find(scrubIdentity.randomizerCheck) != scrubPrices.end()) { + scrubIdentity.itemPrice = scrubPrices[scrubIdentity.randomizerCheck]; + } + + return scrubIdentity; +} + u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) { return this->randoSettings[randoSettingKey]; } @@ -2158,10 +2448,6 @@ RandomizerCheck Randomizer::GetCheckFromActor(s16 sceneNum, s16 actorId, s16 act break; case 62: switch (actorParams) { - case 2: - return RC_HF_DEKU_SCRUB_GROTTO; - case 10: - return RC_LW_DEKU_SCRUB_GROTTO_FRONT; case 22988: return RC_KF_STORMS_GROTTO_CHEST; case -22988: @@ -2426,8 +2712,6 @@ RandomizerCheck Randomizer::GetCheckFromActor(s16 sceneNum, s16 actorId, s16 act break; case 91: switch (actorParams) { - case 9: - return RC_LW_DEKU_SCRUB_NEAR_BRIDGE; case 14365: return RC_LW_GOSSIP_STONE; case 27905: @@ -2592,6 +2876,7 @@ void GenerateRandomizerImgui() { cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS] = CVar_GetS32("gRandomizeShuffleDungeonReward", 0); cvarSettings[RSK_SHUFFLE_SONGS] = CVar_GetS32("gRandomizeShuffleSongs", 0); cvarSettings[RSK_SHUFFLE_TOKENS] = CVar_GetS32("gRandomizeShuffleTokens", 0); + cvarSettings[RSK_SHUFFLE_SCRUBS] = CVar_GetS32("gRandomizeShuffleScrubs", 0); cvarSettings[RSK_SHUFFLE_COWS] = CVar_GetS32("gRandomizeShuffleCows", 0); cvarSettings[RSK_SHUFFLE_ADULT_TRADE] = CVar_GetS32("gRandomizeShuffleAdultTrade", 0); cvarSettings[RSK_SKIP_CHILD_ZELDA] = CVar_GetS32("gRandomizeSkipChildZelda", 0); @@ -3108,11 +3393,20 @@ void DrawRandoEditor(bool& open) { "expected to be collected after getting Sun's Song."); PaddedSeparator(); - // Shuffle Cows - SohImGui::EnhancementCheckbox(Settings::ShuffleCows.GetName().c_str(), "gRandomizeShuffleCows"); - InsertHelpHoverText( - "Cows give a randomized item from the pool upon performing Epona's Song in front of them."); - PaddedSeparator(); + // Shuffle Scrubs + ImGui::Text(Settings::Scrubsanity.GetName().c_str()); + InsertHelpHoverText( + "Off - Scrubs will not be shuffled.\n" + "\n" + "Affordable - Scrubs will be shuffled and their item will cost 10 rupees.\n" + ); + SohImGui::EnhancementCombobox("gRandomizeShuffleScrubs", randoShuffleScrubs, 4, 0); + PaddedSeparator(); + + // Shuffle Cows + SohImGui::EnhancementCheckbox(Settings::ShuffleCows.GetName().c_str(), "gRandomizeShuffleCows"); + InsertHelpHoverText("Cows give a randomized item from the pool upon performing Epona's Song in front of them."); + PaddedSeparator(); // Shuffle Adult Trade Quest SohImGui::EnhancementCheckbox(Settings::ShuffleAdultTradeQuest.GetName().c_str(), @@ -3699,8 +3993,7 @@ void CreateGetItemMessages(std::vector messageEntries) { void CreateScrubMessages() { CustomMessageManager* customMessageManager = CustomMessageManager::Instance; customMessageManager->AddCustomMessageTable(Randomizer::scrubMessageTableID); - const std::vector prices = { 10, 40 }; - for (u8 price : prices) { + for (u32 price = 0; price <= 95; price += 5) { customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, price, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, "\x12\x38\x82\All right! You win! In return for&sparing me, I will sell you a&%gmysterious item%w!&%r" + diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 15394fbcb4..98c2efa5f7 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -16,6 +16,7 @@ class Randomizer { std::string ganonHintText; std::string ganonText; std::unordered_map randoSettings; + std::unordered_map scrubPrices; s16 GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId); s16 GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId); void ParseRandomizerSettingsFile(const char* spoilerFileName); @@ -45,6 +46,7 @@ class Randomizer { std::string GetAdultAltarText() const; std::string GetGanonText() const; std::string GetGanonHintText() const; + ScrubIdentity IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); s16 GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); s16 GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); static void CreateCustomMessages(); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 21635278ca..79d0db0601 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1,6 +1,7 @@ #pragma once #include +#include "z64item.h" // This should probably go in a less rando-specific location // but the best location will probably be in the modding engine @@ -987,6 +988,7 @@ typedef enum { RSK_SHUFFLE_DUNGEON_REWARDS, RSK_SHUFFLE_SONGS, RSK_SHUFFLE_TOKENS, + RSK_SHUFFLE_SCRUBS, RSK_SHUFFLE_COWS, RSK_SHUFFLE_WEIRD_EGG, RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD, @@ -1015,3 +1017,11 @@ typedef enum { RSK_SKULLS_SUNS_SONG, RSK_SHUFFLE_ADULT_TRADE } RandomizerSettingKey; + +typedef struct ScrubIdentity { + int32_t scrubId; + RandomizerCheck randomizerCheck; + GetItemID getItemId; + int32_t itemPrice; + bool isShuffled; +} ScrubIdentity; \ No newline at end of file diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 805e866daf..af727a8123 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1568,18 +1568,12 @@ extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 sceneNum, s16 actorI return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams); } -extern "C" CustomMessageEntry Randomizer_GetScrubMessage(u16 scrubTextId) { - int price = 0; - switch (scrubTextId) { - case TEXT_SCRUB_POH: - price = 10; - break; - case TEXT_SCRUB_STICK_UPGRADE: - case TEXT_SCRUB_NUT_UPGRADE: - price = 40; - break; - } - return CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, price); +extern "C" ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData) { + return OTRGlobals::Instance->gRandomizer->IdentifyScrub(sceneNum, actorParams, respawnData); +} + +extern "C" CustomMessageEntry Randomizer_GetScrubMessage(s16 itemPrice) { + return CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, itemPrice); } extern "C" CustomMessageEntry Randomizer_GetAltarMessage() { @@ -1703,8 +1697,8 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { } else { messageEntry = Randomizer_GetGanonHintText(); } - } else if (textId == TEXT_SCRUB_POH || textId == TEXT_SCRUB_STICK_UPGRADE || textId == TEXT_SCRUB_NUT_UPGRADE) { - messageEntry = Randomizer_GetScrubMessage(textId); + } else if (textId >= 0x9000 && textId <= 0x905F) { + messageEntry = Randomizer_GetScrubMessage((textId & ((1 << 8) - 1))); } } if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) { diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 069707cd90..75f375fa73 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -96,6 +96,7 @@ Sprite* GetSeedTexture(uint8_t index); void Randomizer_LoadSettings(const char* spoilerFileName); u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum); +ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); void Randomizer_LoadHintLocations(const char* spoilerFileName); void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent); GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 9f93a777db..4621c5e93c 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -768,6 +768,10 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadArray("cowsMilked", ARRAY_COUNT(gSaveContext.cowsMilked), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.cowsMilked[i]); }); + + SaveManager::Instance->LoadArray("scrubsPurchased", ARRAY_COUNT(gSaveContext.scrubsPurchased), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.scrubsPurchased[i]); + }); } void SaveManager::LoadBaseVersion2() { @@ -932,6 +936,10 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadArray("cowsMilked", ARRAY_COUNT(gSaveContext.cowsMilked), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.cowsMilked[i]); }); + + SaveManager::Instance->LoadArray("scrubsPurchased", ARRAY_COUNT(gSaveContext.scrubsPurchased), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.scrubsPurchased[i]); + }); } void SaveManager::SaveBase() { @@ -1092,6 +1100,10 @@ void SaveManager::SaveBase() { SaveManager::Instance->SaveArray("cowsMilked", ARRAY_COUNT(gSaveContext.cowsMilked), [](size_t i) { SaveManager::Instance->SaveData("", gSaveContext.cowsMilked[i]); }); + + SaveManager::Instance->SaveArray("scrubsPurchased", ARRAY_COUNT(gSaveContext.scrubsPurchased), [](size_t i) { + SaveManager::Instance->SaveData("", gSaveContext.scrubsPurchased[i]); + }); } void SaveManager::SaveArray(const std::string& name, const size_t size, SaveArrayFunc func) { diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 8d23e42eb3..4b362f0705 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -7,6 +7,7 @@ #define NUM_DUNGEONS 8 #define NUM_TRIALS 6 #define NUM_COWS 10 +#define NUM_SCRUBS 35 /** * Initialize new save. @@ -717,6 +718,11 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.cowsMilked[i] = 0; } + // Sets all scrubs to not purchased when generating a rando save. + for (u8 i = 0; i < NUM_SCRUBS; i++) { + gSaveContext.scrubsPurchased[i] = 0; + } + // Set Cutscene flags to skip them gSaveContext.eventChkInf[0xC] |= 0x10; // returned to tot with medallions gSaveContext.eventChkInf[0xC] |= 0x20; //sheik at tot pedestal diff --git a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c index d3a9243566..878e8eeed1 100644 --- a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c +++ b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c @@ -15,6 +15,7 @@ void EnDns_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnDns_Update(Actor* thisx, GlobalContext* globalCtx); void EnDns_Draw(Actor* thisx, GlobalContext* globalCtx); +u32 EnDns_RandomizerPurchaseableCheck(EnDns* this); u32 func_809EF5A4(EnDns* this); u32 func_809EF658(EnDns* this); u32 func_809EF70C(EnDns* this); @@ -24,6 +25,7 @@ u32 func_809EF854(EnDns* this); u32 func_809EF8F4(EnDns* this); u32 func_809EF9A4(EnDns* this); +void EnDns_RandomizerPurchase(EnDns* this); void func_809EF9F8(EnDns* this); void func_809EFA28(EnDns* this); void func_809EFA58(EnDns* this); @@ -155,7 +157,6 @@ void EnDns_Init(Actor* thisx, GlobalContext* globalCtx) { Collider_InitCylinder(globalCtx, &this->collider); Collider_SetCylinderType1(globalCtx, &this->collider, &this->actor, &sCylinderInit); ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 35.0f); - this->actor.textId = D_809F040C[this->actor.params]; Actor_SetScale(&this->actor, 0.01f); this->actor.colChkInfo.mass = MASS_IMMOVABLE; this->maintainCollider = 1; @@ -164,7 +165,24 @@ void EnDns_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.speedXZ = 0.0f; this->actor.velocity.y = 0.0f; this->actor.gravity = -1.0f; + this->actor.textId = D_809F040C[this->actor.params]; this->dnsItemEntry = sItemEntries[this->actor.params]; + if (gSaveContext.n64ddFlag) { + s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1); + this->scrubIdentity = Randomizer_IdentifyScrub(globalCtx->sceneNum, this->actor.params, respawnData); + + if (Randomizer_GetSettingValue(RSK_SHUFFLE_SCRUBS) == 1 || Randomizer_GetSettingValue(RSK_SHUFFLE_SCRUBS) == 3 && this->scrubIdentity.itemPrice != -1) { + this->dnsItemEntry->itemPrice = this->scrubIdentity.itemPrice; + } + + if (this->scrubIdentity.isShuffled) { + this->dnsItemEntry->getItemId = this->scrubIdentity.getItemId; + this->dnsItemEntry->purchaseableCheck = EnDns_RandomizerPurchaseableCheck; + this->dnsItemEntry->setRupeesAndFlags = EnDns_RandomizerPurchase; + this->dnsItemEntry->itemAmount = 1; + this->actor.textId = 0x9000 + this->dnsItemEntry->itemPrice; + } + } this->actionFunc = EnDns_SetupWait; } @@ -185,6 +203,13 @@ void EnDns_ChangeAnim(EnDns* this, u8 index) { /* Item give checking functions */ +u32 EnDns_RandomizerPurchaseableCheck(EnDns* this) { + if (gSaveContext.rupees < this->dnsItemEntry->itemPrice || gSaveContext.scrubsPurchased[this->scrubIdentity.scrubId] == 1) { + return 0; + } + return 4; +} + u32 func_809EF5A4(EnDns* this) { if ((CUR_CAPACITY(UPG_NUTS) != 0) && (AMMO(ITEM_NUT) >= CUR_CAPACITY(UPG_NUTS))) { return 1; @@ -281,6 +306,10 @@ u32 func_809EF9A4(EnDns* this) { } /* Paying and flagging functions */ +void EnDns_RandomizerPurchase(EnDns* this) { + Rupees_ChangeBy(-this->dnsItemEntry->itemPrice); + gSaveContext.scrubsPurchased[this->scrubIdentity.scrubId] = 1; +} void func_809EF9F8(EnDns* this) { Rupees_ChangeBy(-this->dnsItemEntry->itemPrice); @@ -369,31 +398,25 @@ void EnDns_Talk(EnDns* this, GlobalContext* globalCtx) { } void func_809EFDD0(EnDns* this, GlobalContext* globalCtx) { - if (this->actor.params == 0x9) { - if (gSaveContext.n64ddFlag) { - GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(GI_STICK_UPGRADE_30, this->actor.id, this->actor.params, globalCtx->sceneNum); - GiveItemEntryFromActor(&this->actor, globalCtx, getItemEntry, 130.0f, 100.0f); - } else if (CUR_UPG_VALUE(UPG_STICKS) < 2) { - func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_20, 130.0f, 100.0f); + if (!gSaveContext.n64ddFlag || !this->scrubIdentity.isShuffled) { + if (this->actor.params == 0x9) { + if (CUR_UPG_VALUE(UPG_STICKS) < 2) { + func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_20, 130.0f, 100.0f); + } else { + func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_30, 130.0f, 100.0f); + } + } else if (this->actor.params == 0xA) { + if (CUR_UPG_VALUE(UPG_NUTS) < 2) { + func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_30, 130.0f, 100.0f); + } else { + func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_40, 130.0f, 100.0f); + } } else { - func_8002F434(&this->actor, globalCtx, GI_STICK_UPGRADE_30, 130.0f, 100.0f); - } - } else if (this->actor.params == 0xA) { - if (gSaveContext.n64ddFlag) { - GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(GI_NUT_UPGRADE_40, this->actor.id, this->actor.params, globalCtx->sceneNum); - GiveItemEntryFromActor(&this->actor, globalCtx, getItemEntry, 130.0f, 100.0f); - } else if (CUR_UPG_VALUE(UPG_NUTS) < 2) { - func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_30, 130.0f, 100.0f); - } else { - func_8002F434(&this->actor, globalCtx, GI_NUT_UPGRADE_40, 130.0f, 100.0f); + func_8002F434(&this->actor, globalCtx, this->dnsItemEntry->getItemId, 130.0f, 100.0f); } } else { - if (!gSaveContext.n64ddFlag) { - func_8002F434(&this->actor, globalCtx, this->dnsItemEntry->getItemId, 130.0f, 100.0f); - } else { - GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(this->dnsItemEntry->getItemId, this->actor.id, this->actor.params, globalCtx->sceneNum); - GiveItemEntryFromActor(&this->actor, globalCtx, getItemEntry, 130.0f, 100.0f); - } + GetItemEntry itemEntry = Randomizer_GetItemFromKnownCheck(this->scrubIdentity.randomizerCheck, this->scrubIdentity.getItemId); + GiveItemEntryFromActor(&this->actor, globalCtx, itemEntry, 130.0f, 100.0f); } } @@ -489,6 +512,9 @@ void EnDns_Update(Actor* thisx, GlobalContext* globalCtx) { this->dustTimer++; this->actor.textId = D_809F040C[this->actor.params]; + if (gSaveContext.n64ddFlag && this->scrubIdentity.isShuffled) { + this->actor.textId = 0x9000 + this->dnsItemEntry->itemPrice; + } Actor_SetFocus(&this->actor, 60.0f); Actor_SetScale(&this->actor, 0.01f); SkelAnime_Update(&this->skelAnime); diff --git a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.h b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.h index 90bd3d0955..4dab2bf398 100644 --- a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.h +++ b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.h @@ -32,6 +32,7 @@ typedef struct EnDns { /* 0x02BD */ u8 dropCollectible; /* 0x02C0 */ DnsItemEntry* dnsItemEntry; /* 0x02C4 */ f32 yInitPos; + /* */ ScrubIdentity scrubIdentity; } EnDns; // size = 0x02C8 #endif diff --git a/soh/src/overlays/actors/ovl_En_Shopnuts/z_en_shopnuts.c b/soh/src/overlays/actors/ovl_En_Shopnuts/z_en_shopnuts.c index 2b1f6a12e7..6655b3aea2 100644 --- a/soh/src/overlays/actors/ovl_En_Shopnuts/z_en_shopnuts.c +++ b/soh/src/overlays/actors/ovl_En_Shopnuts/z_en_shopnuts.c @@ -69,6 +69,15 @@ void EnShopnuts_Init(Actor* thisx, GlobalContext* globalCtx) { CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sColChkInfoInit); Collider_UpdateCylinder(&this->actor, &this->collider); + if (gSaveContext.n64ddFlag) { + s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1); + ScrubIdentity scrubIdentity = Randomizer_IdentifyScrub(globalCtx->sceneNum, this->actor.params, respawnData); + + if (scrubIdentity.isShuffled && gSaveContext.scrubsPurchased[scrubIdentity.scrubId] == 1) { + Actor_Kill(&this->actor); + } + } + if (((this->actor.params == 0x0002) && (gSaveContext.itemGetInf[0] & 0x800)) || ((this->actor.params == 0x0009) && (gSaveContext.infTable[25] & 4)) || ((this->actor.params == 0x000A) && (gSaveContext.infTable[25] & 8))) { From c6c08522e6ac7b0538e8f43ec4190748ab2901ba Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Wed, 24 Aug 2022 10:19:41 -0500 Subject: [PATCH 02/62] Custom message for free items --- soh/soh/Enhancements/randomizer/randomizer.cpp | 10 ++++++++-- soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 299d418c8a..b7a8dc45d0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1678,7 +1678,6 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa } break; case SCENE_KAKUSIANA: // Grotto - // Ugly, but the best way we can identify which grotto we are in, same method 3DRando uses, but we'll need to account for entrance rando switch (respawnData) { case 0xE6: // Hyrule Field Scrub Grotto switch (actorParams) { @@ -3993,7 +3992,14 @@ void CreateGetItemMessages(std::vector messageEntries) { void CreateScrubMessages() { CustomMessageManager* customMessageManager = CustomMessageManager::Instance; customMessageManager->AddCustomMessageTable(Randomizer::scrubMessageTableID); - for (u32 price = 0; price <= 95; price += 5) { + customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, 0, + { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, + "\x12\x38\x82\All right! You win! In return for&sparing me, I will give you a&%gmysterious 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 %gmysteriösen&Gegenstand%w geben! Bitte nimm ihn!\x07\x10\xA3", + "\x12\x38\x82\D'accord! Vous avez gagné! En échange&de m'épargner, je vous donnerai un &%gobjet mystérieux%w! S'il vous plaît,&prenez-le!\x07\x10\xA3", + }); + + for (u32 price = 5; price <= 95; price += 5) { customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, price, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, "\x12\x38\x82\All right! You win! In return for&sparing me, I will sell you a&%gmysterious item%w!&%r" + diff --git a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c index 878e8eeed1..d2c42794eb 100644 --- a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c +++ b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c @@ -168,6 +168,7 @@ void EnDns_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.textId = D_809F040C[this->actor.params]; this->dnsItemEntry = sItemEntries[this->actor.params]; if (gSaveContext.n64ddFlag) { + // Ugly, but the best way we can identify which grotto we are in, same method 3DRando uses, but we'll need to account for entrance rando s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1); this->scrubIdentity = Randomizer_IdentifyScrub(globalCtx->sceneNum, this->actor.params, respawnData); From b7e3a72f85d3a8173f4da4479e09bc9c1ba9b04a Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Wed, 24 Aug 2022 11:00:02 -0500 Subject: [PATCH 03/62] Fix issue from bad merge and a few other small things --- .../Enhancements/randomizer/randomizer.cpp | 27 ++++++++++--------- .../Enhancements/randomizer/randomizerTypes.h | 2 +- soh/soh/OTRGlobals.cpp | 23 ++++++++-------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index c73c6885d1..3f61e2513a 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3394,6 +3394,16 @@ void DrawRandoEditor(bool& open) { SohImGui::EnhancementCombobox("gRandomizeShuffleSongs", randoShuffleSongs, 3, 0); PaddedSeparator(); + // Shuffle Scrubs + ImGui::Text(Settings::Scrubsanity.GetName().c_str()); + InsertHelpHoverText( + "Off - Scrubs will not be shuffled.\n" + "\n" + "Affordable - Scrubs will be shuffled and their item will cost 10 rupees.\n" + ); + SohImGui::EnhancementCombobox("gRandomizeShuffleScrubs", randoShuffleScrubs, 4, 0); + PaddedSeparator(); + // Shuffle Tokens ImGui::Text(Settings::Tokensanity.GetName().c_str()); InsertHelpHoverText("Shuffles Golden Skulltula Tokens into the item pool. This means " @@ -3414,20 +3424,11 @@ void DrawRandoEditor(bool& open) { "expected to be collected after getting Sun's Song."); PaddedSeparator(); - // Shuffle Scrubs - ImGui::Text(Settings::Scrubsanity.GetName().c_str()); - InsertHelpHoverText( - "Off - Scrubs will not be shuffled.\n" - "\n" - "Affordable - Scrubs will be shuffled and their item will cost 10 rupees.\n" - ); - SohImGui::EnhancementCombobox("gRandomizeShuffleScrubs", randoShuffleScrubs, 4, 0); - PaddedSeparator(); - // Shuffle Cows - SohImGui::EnhancementCheckbox(Settings::ShuffleCows.GetName().c_str(), "gRandomizeShuffleCows"); - InsertHelpHoverText("Cows give a randomized item from the pool upon performing Epona's Song in front of them."); - PaddedSeparator(); + // Shuffle Cows + SohImGui::EnhancementCheckbox(Settings::ShuffleCows.GetName().c_str(), "gRandomizeShuffleCows"); + InsertHelpHoverText("Cows give a randomized item from the pool upon performing Epona's Song in front of them."); + PaddedSeparator(); // Shuffle Adult Trade Quest SohImGui::EnhancementCheckbox(Settings::ShuffleAdultTradeQuest.GetName().c_str(), diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 79d0db0601..02adad1a58 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1024,4 +1024,4 @@ typedef struct ScrubIdentity { GetItemID getItemId; int32_t itemPrice; bool isShuffled; -} ScrubIdentity; \ No newline at end of file +} ScrubIdentity; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index c5c7a33ec3..4a1307d115 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1578,18 +1578,17 @@ extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 sceneNum, s16 actorI return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams); } -extern "C" CustomMessageEntry Randomizer_GetScrubMessage(u16 scrubTextId) { - int price = 0; - switch (scrubTextId) { - case TEXT_SCRUB_POH: - price = 10; - break; - case TEXT_SCRUB_STICK_UPGRADE: - case TEXT_SCRUB_NUT_UPGRADE: - price = 40; - break; - } - return CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, price); +extern "C" ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData) { + return OTRGlobals::Instance->gRandomizer->IdentifyScrub(sceneNum, actorParams, respawnData); +} + +extern "C" CustomMessageEntry Randomizer_GetScrubMessage(s16 itemPrice) { + return CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, itemPrice); +} + +extern "C" CustomMessageEntry Randomizer_GetNaviMessage() { + u16 naviTextId = rand() % NUM_NAVI_MESSAGES; + return CustomMessageManager::Instance->RetrieveMessage(Randomizer::NaviRandoMessageTableID, naviTextId); } extern "C" CustomMessageEntry Randomizer_GetAltarMessage() { From fe7aedc80d5e53b7c1b3ccc2b507b465bdb208a4 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 24 Aug 2022 15:44:31 -0400 Subject: [PATCH 04/62] Adds getItemEntry for Magic Bean Pack --- .../Enhancements/randomizer/randomizer.cpp | 170 +++++++++++------- soh/src/code/z_parameter.c | 15 +- 2 files changed, 120 insertions(+), 65 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index d13792714a..5b6012e1a5 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3878,72 +3878,119 @@ void Randomizer::CreateCustomMessages() { const std::vector getItemMessages = { GIMESSAGE(RG_ICE_TRAP, ITEM_NONE, "\x08\x06\x30You are a %bFOWL%w!\x0E\x20", "\x08\x06\x15 Du bist ein %bDUMMKOPF%w!\x0E\x20", "\x08\x06\x50%bIDIOT%w\x0E\x20"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, - "You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!", - "Vous obtenez une %rBouteille avec&une Flamme Bleue%w! Utilisez-la&pour faire fondre la %rGlace&Rouge%w!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, "You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!", + "Vous obtenez une %rBouteille avec&une Flamme Bleue%w! Utilisez-la&pour faire fondre la %rGlace&Rouge%w!"), GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BIG_POE, ITEM_BIG_POE, - "You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!", - "Vous obtenez une %rBouteille avec&une Âme%w! Vendez-la au Marchand&d'Âme"), + "You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!", + "Vous obtenez une %rBouteille avec&une Âme%w! Vendez-la au Marchand&d'Âme"), GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BLUE_POTION, ITEM_POTION_BLUE, - "You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!", - "Vous obtenez une %rBouteille avec&une Potion Bleue%w! Buvez-la pour&restaurer votre %rénergie vitale%w&ainsi que votre %gmagie%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_FISH, ITEM_FISH, - "You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!", - "Vous obtenez une %rBouteille avec&un Poisson%w! Il a l'air délicieux!&Il paraîtrait que %bJabu-Jabu %wen&serait friand!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BUGS, ITEM_BUG, - "You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!", - "Vous obtenez une %rBouteille avec&des Insectes%w! Ils adorent creuser&dans la terre meuble!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_FAIRY, ITEM_FAIRY, - "You got a %rFairy in a Bottle%w!&Use it wisely!", - "Vous obtenez une %rBouteille avec&une Fée%w! Faites-en bon usage!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, - "You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!", - "Vous obtenez une %rBouteille avec&une Potion Rouge%w! Buvez-la pour&restaurer votre %rénergie vitale%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN, - "You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!", - "Vous obtenez une %rBouteille avec&une Potion Verte%w! Buvez-la pour&restaurer votre %gmagie%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_POE, ITEM_POE, - "You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this...", - "Vous obtenez une %rBouteille avec&un Esprit%w! Ça intéresserait&peut-être le vendeur d'Âme "), + "You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!", + "Vous obtenez une %rBouteille avec&une Potion Bleue%w! Buvez-la pour&restaurer votre " + "%rénergie vitale%w&ainsi que votre %gmagie%w!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_FISH, ITEM_FISH, + "You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!", + "Vous obtenez une %rBouteille avec&un Poisson%w! Il a l'air délicieux!&Il paraîtrait que %bJabu-Jabu " + "%wen&serait friand!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_BUGS, ITEM_BUG, "You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!", + "Vous obtenez une %rBouteille avec&des Insectes%w! Ils adorent creuser&dans la terre meuble!"), + GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_FAIRY, ITEM_FAIRY, "You got a %rFairy in a Bottle%w!&Use it wisely!", + "Vous obtenez une %rBouteille avec&une Fée%w! Faites-en bon usage!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, + "You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!", + "Vous obtenez une %rBouteille avec&une Potion Rouge%w! Buvez-la pour&restaurer votre %rénergie vitale%w!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN, + "You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!", + "Vous obtenez une %rBouteille avec&une Potion Verte%w! Buvez-la pour&restaurer votre %gmagie%w!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_POE, ITEM_POE, + "You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this...", + "Vous obtenez une %rBouteille avec&un Esprit%w! Ça intéresserait&peut-être le vendeur d'Âme "), - GIMESSAGE_NO_GERMAN(RG_GERUDO_FORTRESS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yThieves Hideout &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yRepaire des Voleurs%w!"), - GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %gForest Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %gTemple de la Forêt%w!"), - GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rFire Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %rTemple du Feu%w!"), - GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %bWater Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %bTemple de l'Eau%w!"), - GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %ySpirit Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yTemple de l'Esprit%w!"), - GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pShadow Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %pTemple de l'Ombre%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pBottom of the &Well %wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %Puits%w!"), - GIMESSAGE_NO_GERMAN(RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yGerudo Training &Grounds %wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yGymnase Gerudo%w!"), - GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rGanon's Castle &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %Château de Ganon%w!"), + GIMESSAGE_NO_GERMAN(RG_GERUDO_FORTRESS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yThieves Hideout &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %yRepaire des Voleurs%w!"), + GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %gForest Temple &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rFire Temple &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %bWater Temple &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %ySpirit Temple &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pShadow Temple &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_SMALL_KEY, ITEM_KEY_SMALL, + "You found a %pBottom of the &Well %wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %Puits%w!"), + GIMESSAGE_NO_GERMAN(RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, ITEM_KEY_SMALL, + "You found a %yGerudo Training &Grounds %wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %yGymnase Gerudo%w!"), + GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rGanon's Castle &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %Château de Ganon%w!"), - GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %gForest Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%gTemple de la Forêt%w!"), - GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rFire Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%rTemple du Feu%w!"), - GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %bWater Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%bTemple de l'Eau%w!"), - GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %ySpirit Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%yTemple de l'Esprit%w!"), - GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %pShadow Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%pTemple de l'Ombre%w!"), - GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rGanon's Castle &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%rChâteau de Ganon%w!"), - - GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_MAP, ITEM_DUNGEON_MAP, "You found the %gDeku Tree &%wMap!", "Vous obtenez la %rCarte %wde&l'%gArbre Mojo%w!"), - GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %rDodongo's Cavern &%wMap!", "Vous obtenez la %rCarte %wde la&%rCaverne Dodongo%w!"), - GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_MAP, ITEM_DUNGEON_MAP, "You found the %bJabu Jabu's Belly &%wMap!", "Vous obtenez la %rCarte %wdu &%bVentre de Jabu-Jabu%w!"), - GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %gForest Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%gTemple de la Forêt%w!"), - GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %rFire Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%rTemple du Feu%w!"), - GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %bWater Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%bTemple de l'Eau%w!"), - GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %ySpirit Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%yTemple de l'Esprit%w!"), - GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %pShadow Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%pTemple de l'Ombre%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_MAP, ITEM_DUNGEON_MAP, "You found the %pBottom of the &Well %wMap!", "Vous obtenez la %rCarte %wdu &%pPuits%w!"), - GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %cIce Cavern &%wMap!", "Vous obtenez la %rCarte %wde &la %cCaverne Polaire%w!"), + GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %gForest Temple &%wBoss Key!", + "Vous obtenez la %rClé d'or %wdu&%gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rFire Temple &%wBoss Key!", + "Vous obtenez la %rClé d'or %wdu&%rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %bWater Temple &%wBoss Key!", + "Vous obtenez la %rClé d'or %wdu&%bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %ySpirit Temple &%wBoss Key!", + "Vous obtenez la %rClé d'or %wdu&%yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %pShadow Temple &%wBoss Key!", + "Vous obtenez la %rClé d'or %wdu&%pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rGanon's Castle &%wBoss Key!", + "Vous obtenez la %rClé d'or %wdu&%rChâteau de Ganon%w!"), - GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_COMPASS, ITEM_COMPASS, "You found the %gDeku Tree &%wCompass!", "Vous obtenez la %rBoussole %wde&l'%gArbre Mojo%w!"), - GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_COMPASS, ITEM_COMPASS, "You found the %rDodongo's Cavern &%wCompass!", "Vous obtenez la %rBoussole %wde la&%rCaverne Dodongo%w!"), - GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_COMPASS, ITEM_COMPASS, "You found the %bJabu Jabu's Belly &%wCompass!", "Vous obtenez la %rBoussole %wdu &%bVentre de Jabu-Jabu%w!"), - GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %gForest Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%gTemple de la Forêt%w!"), - GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %rFire Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%rTemple du Feu%w!"), - GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %bWater Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%bTemple de l'Eau%w!"), - GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %ySpirit Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%yTemple de l'Esprit%w!"), - GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %pShadow Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%pTemple de l'Ombre%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_COMPASS, ITEM_COMPASS, "You found the %pBottom of the &Well %wCompass!", "Vous obtenez la %rBoussole %wdu &%pPuits%w!"), - GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_COMPASS, ITEM_COMPASS, "You found the %cIce Cavern &%wCompass!", "Vous obtenez la %rBoussole %wde &la %cCaverne Polaire%w!"), + GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_MAP, ITEM_DUNGEON_MAP, "You found the %gDeku Tree &%wMap!", + "Vous obtenez la %rCarte %wde&l'%gArbre Mojo%w!"), + GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %rDodongo's Cavern &%wMap!", + "Vous obtenez la %rCarte %wde la&%rCaverne Dodongo%w!"), + GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_MAP, ITEM_DUNGEON_MAP, "You found the %bJabu Jabu's Belly &%wMap!", + "Vous obtenez la %rCarte %wdu &%bVentre de Jabu-Jabu%w!"), + GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %gForest Temple &%wMap!", + "Vous obtenez la %rCarte %wdu &%gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %rFire Temple &%wMap!", + "Vous obtenez la %rCarte %wdu &%rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %bWater Temple &%wMap!", + "Vous obtenez la %rCarte %wdu &%bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %ySpirit Temple &%wMap!", + "Vous obtenez la %rCarte %wdu &%yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %pShadow Temple &%wMap!", + "Vous obtenez la %rCarte %wdu &%pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_MAP, ITEM_DUNGEON_MAP, "You found the %pBottom of the &Well %wMap!", + "Vous obtenez la %rCarte %wdu &%pPuits%w!"), + GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %cIce Cavern &%wMap!", + "Vous obtenez la %rCarte %wde &la %cCaverne Polaire%w!"), + + GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_COMPASS, ITEM_COMPASS, "You found the %gDeku Tree &%wCompass!", + "Vous obtenez la %rBoussole %wde&l'%gArbre Mojo%w!"), + GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_COMPASS, ITEM_COMPASS, "You found the %rDodongo's Cavern &%wCompass!", + "Vous obtenez la %rBoussole %wde la&%rCaverne Dodongo%w!"), + GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_COMPASS, ITEM_COMPASS, "You found the %bJabu Jabu's Belly &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%bVentre de Jabu-Jabu%w!"), + GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %gForest Temple &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %rFire Temple &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %bWater Temple &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %ySpirit Temple &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %pShadow Temple &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_COMPASS, ITEM_COMPASS, + "You found the %pBottom of the &Well %wCompass!", + "Vous obtenez la %rBoussole %wdu &%pPuits%w!"), + GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_COMPASS, ITEM_COMPASS, "You found the %cIce Cavern &%wCompass!", + "Vous obtenez la %rBoussole %wde &la %cCaverne Polaire%w!"), + GIMESSAGE(RG_MAGIC_BEAN_PACK, ITEM_BEAN, + "You got a %rPack of Magic Beans%w!&Find a suitable spot for a garden&and plant them. Then, wait for&something fun to happen!", + "Du hast eine %rPackung&Magic Beans%w! Finde&einen geeigneten Platz fur einen&Garten und pflanze sie. Dann^warte auf etwas Lustiges passiert!", + "Vous avez un %rPack de&haricots magiques%w ! Trouvez&un endroit convenable pour un&jardin et plantez-les.^Ensuite, attendez quelque&chose d'amusant doit arriver !") }; CreateGetItemMessages(getItemMessages); CreateScrubMessages(); @@ -4043,6 +4090,7 @@ void InitRandoItemTable() { GET_ITEM(RG_SHADOW_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_SHADOW_TEMPLE_COMPASS), GET_ITEM(RG_BOTTOM_OF_THE_WELL_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_BOTTOM_OF_THE_WELL_COMPASS), GET_ITEM(RG_ICE_CAVERN_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_ICE_CAVERN_COMPASS), + GET_ITEM(RG_MAGIC_BEAN_PACK, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_MAGIC_BEAN_PACK) }; ItemTableManager::Instance->AddItemTable(MOD_RANDOMIZER); for (int i = 0; i < ARRAY_COUNT(extendedVanillaGetItemTable); i++) { diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index bc8fa8149f..acad4d8743 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2177,6 +2177,14 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { return RG_NONE; } + if (item == RG_MAGIC_BEAN_PACK) { + if (gSaveContext.inventory.items[SLOT(ITEM_BEAN)] == ITEM_NONE) { + INV_CONTENT(ITEM_BEAN) = ITEM_BEAN; + AMMO(ITEM_BEAN) = 10; + BEANS_BOUGHT = 10; + } + } + if (item == RG_DOUBLE_DEFENSE) { gSaveContext.doubleDefense = true; gSaveContext.inventory.defenseHearts = 20; @@ -2223,9 +2231,9 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { } } } else if ((item >= RG_FOREST_TEMPLE_SMALL_KEY && item <= RG_GANONS_CASTLE_SMALL_KEY) || - (item >= RG_FOREST_TEMPLE_BOSS_KEY && item <= RG_GANONS_CASTLE_BOSS_KEY) || - (item >= RG_DEKU_TREE_MAP && item <= RG_ICE_CAVERN_MAP) || - (item >= RG_DEKU_TREE_COMPASS && item <= RG_ICE_CAVERN_COMPASS)) { + (item >= RG_FOREST_TEMPLE_BOSS_KEY && item <= RG_GANONS_CASTLE_BOSS_KEY) || + (item >= RG_DEKU_TREE_MAP && item <= RG_ICE_CAVERN_MAP) || + (item >= RG_DEKU_TREE_COMPASS && item <= RG_ICE_CAVERN_COMPASS)) { int mapIndex = gSaveContext.mapIndex; switch (item) { case RG_DEKU_TREE_MAP: @@ -2323,7 +2331,6 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { return temp; } - u8 Item_CheckObtainability(u8 item) { s16 i; s16 slot = SLOT(item); From adf465c1a05f8179dc6cf6a56f53334ba72bc927 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 24 Aug 2022 17:20:45 -0400 Subject: [PATCH 05/62] Sets up Magic Bean Salesman to sell a rando check for 60 rupees. --- .../Enhancements/randomizer/randomizerTypes.h | 3 ++- soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c | 21 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 21635278ca..14e5ae34aa 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1013,5 +1013,6 @@ typedef enum { RSK_COMPLETE_MASK_QUEST, RSK_ENABLE_GLITCH_CUTSCENES, RSK_SKULLS_SUNS_SONG, - RSK_SHUFFLE_ADULT_TRADE + RSK_SHUFFLE_ADULT_TRADE, + RSK_SHUFFLE_MAGIC_BEANS } RandomizerSettingKey; diff --git a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c index 04919761ef..dc4dc61ca5 100644 --- a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c +++ b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c @@ -125,11 +125,19 @@ void EnMs_Talk(EnMs* this, GlobalContext* globalCtx) { } else if (Message_ShouldAdvance(globalCtx)) { switch (globalCtx->msgCtx.choiceIndex) { case 0: // yes - if (gSaveContext.rupees < sPrices[BEANS_BOUGHT]) { + if (gSaveContext.rupees < + ((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) + ? 60 + : sPrices[BEANS_BOUGHT])) { Message_ContinueTextbox(globalCtx, 0x4069); // not enough rupees text return; } - func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f); + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) { + GiveItemEntryFromActor(&this->actor, globalCtx, + Randomizer_GetItemFromKnownCheck(RC_ZR_MAGIC_BEAN_SALESMAN, GI_BEAN), 90.0f, 10.0f); + } else { + func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f); + } this->actionFunc = EnMs_Sell; return; case 1: // no @@ -142,11 +150,16 @@ void EnMs_Talk(EnMs* this, GlobalContext* globalCtx) { void EnMs_Sell(EnMs* this, GlobalContext* globalCtx) { if (Actor_HasParent(&this->actor, globalCtx)) { - Rupees_ChangeBy(-sPrices[BEANS_BOUGHT]); + Rupees_ChangeBy((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? 60 : -sPrices[BEANS_BOUGHT]); this->actor.parent = NULL; this->actionFunc = EnMs_TalkAfterPurchase; } else { - func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f); + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) { + GiveItemEntryFromActor(&this->actor, globalCtx, + Randomizer_GetItemFromKnownCheck(RC_ZR_MAGIC_BEAN_SALESMAN, GI_BEAN), 90.0f, 10.0f); + } else { + func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f); + } } } From c4de29b7f1aeeeb96a1337b1020b7558c0e21022 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 24 Aug 2022 17:24:50 -0400 Subject: [PATCH 06/62] Correctly sets `BEANS_BOUGHT` as a "flag" for the bean salesman --- soh/src/code/z_parameter.c | 1 - soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index acad4d8743..7548c0fa70 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2181,7 +2181,6 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { if (gSaveContext.inventory.items[SLOT(ITEM_BEAN)] == ITEM_NONE) { INV_CONTENT(ITEM_BEAN) = ITEM_BEAN; AMMO(ITEM_BEAN) = 10; - BEANS_BOUGHT = 10; } } diff --git a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c index dc4dc61ca5..5c8a1807b8 100644 --- a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c +++ b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c @@ -157,6 +157,7 @@ void EnMs_Sell(EnMs* this, GlobalContext* globalCtx) { if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) { GiveItemEntryFromActor(&this->actor, globalCtx, Randomizer_GetItemFromKnownCheck(RC_ZR_MAGIC_BEAN_SALESMAN, GI_BEAN), 90.0f, 10.0f); + BEANS_BOUGHT = 10; } else { func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f); } From db6a39719501c76bc256896be73ed67ac78454b9 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 24 Aug 2022 17:58:01 -0400 Subject: [PATCH 07/62] Adds new text for the bean salesman --- soh/soh/Enhancements/randomizer/randomizer.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 5b6012e1a5..69da8fa034 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3734,6 +3734,17 @@ void CreateScrubMessages() { std::to_string(price) + " Rubis%w!\x07\x10\xA3" }); } + customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, 0x405E, + { + TEXTBOX_TYPE_BLACK, + TEXTBOX_POS_BOTTOM, + "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" + "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" + "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" + "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + }); } void CreateRupeeMessages() { From 80863fc7f287af134334cc8d2edbc9a4ed8494af Mon Sep 17 00:00:00 2001 From: Kenix3 Date: Wed, 24 Aug 2022 22:11:33 -0400 Subject: [PATCH 08/62] Moves class member functions from headers to compilation units. --- libultraship/libultraship/CMakeLists.txt | 1 + libultraship/libultraship/Console.cpp | 16 +++++ libultraship/libultraship/Console.h | 9 ++- libultraship/libultraship/ControlDeck.h | 2 +- libultraship/libultraship/Controller.cpp | 12 ++++ libultraship/libultraship/Controller.h | 14 ++--- libultraship/libultraship/DummyController.cpp | 61 +++++++++++++++++++ libultraship/libultraship/DummyController.h | 38 +++++------- libultraship/libultraship/Hooks.cpp | 5 ++ .../libultraship/KeyboardController.cpp | 26 +++++++- .../libultraship/KeyboardController.h | 20 ++---- libultraship/libultraship/ResourceMgr.cpp | 13 ++++ libultraship/libultraship/ResourceMgr.h | 9 +-- libultraship/libultraship/SDLController.cpp | 23 +++++++ libultraship/libultraship/SDLController.h | 32 ++++------ libultraship/libultraship/Window.cpp | 48 +++++++++++++++ libultraship/libultraship/Window.h | 24 ++++---- 17 files changed, 266 insertions(+), 87 deletions(-) create mode 100644 libultraship/libultraship/DummyController.cpp create mode 100644 libultraship/libultraship/Hooks.cpp diff --git a/libultraship/libultraship/CMakeLists.txt b/libultraship/libultraship/CMakeLists.txt index 8f365162d9..b599936601 100644 --- a/libultraship/libultraship/CMakeLists.txt +++ b/libultraship/libultraship/CMakeLists.txt @@ -87,6 +87,7 @@ set(Source_Files__Controller "KeyboardController.cpp" "KeyboardController.h" "UltraController.h" + "DummyController.cpp" "DummyController.h" ) diff --git a/libultraship/libultraship/Console.cpp b/libultraship/libultraship/Console.cpp index 846e6e0a0d..65ec3ea816 100644 --- a/libultraship/libultraship/Console.cpp +++ b/libultraship/libultraship/Console.cpp @@ -389,4 +389,20 @@ namespace Ship { Commands[command] = entry; } } + + std::string Console::GetCurrentChannel() { + return currentChannel; + } + + bool Console::IsOpened() { + return opened; + } + + void Console::Close() { + opened = false; + } + + void Console::Open() { + opened = true; + } } \ No newline at end of file diff --git a/libultraship/libultraship/Console.h b/libultraship/libultraship/Console.h index 4f846a2c50..91aebb907b 100644 --- a/libultraship/libultraship/Console.h +++ b/libultraship/libultraship/Console.h @@ -93,10 +93,9 @@ namespace Ship { void Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, ...); bool HasCommand(const std::string& command); void AddCommand(const std::string& command, CommandEntry entry); - - std::string GetCurrentChannel() { return currentChannel; } - bool IsOpened() { return opened; } - void Close() { opened = false; } - void Open() { opened = true; } + std::string GetCurrentChannel(); + bool IsOpened(); + void Close(); + void Open(); }; } \ No newline at end of file diff --git a/libultraship/libultraship/ControlDeck.h b/libultraship/libultraship/ControlDeck.h index d925020c46..e0e85f27ae 100644 --- a/libultraship/libultraship/ControlDeck.h +++ b/libultraship/libultraship/ControlDeck.h @@ -21,7 +21,7 @@ namespace Ship { 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/Controller.cpp b/libultraship/libultraship/Controller.cpp index c1d32c2a9c..ef2ebe943d 100644 --- a/libultraship/libultraship/Controller.cpp +++ b/libultraship/libultraship/Controller.cpp @@ -112,4 +112,16 @@ namespace Ship { std::shared_ptr Controller::getProfile(int32_t virtualSlot) { return profiles[virtualSlot]; } + + std::shared_ptr Controller::GetAttachment() { + return Attachment; + } + + bool Controller::IsRumbling() { + return isRumbling; + } + + std::string Controller::GetGuid() { + return GUID; + } } diff --git a/libultraship/libultraship/Controller.h b/libultraship/libultraship/Controller.h index 76d1c46afb..5cd5b86544 100644 --- a/libultraship/libultraship/Controller.h +++ b/libultraship/libultraship/Controller.h @@ -40,7 +40,6 @@ namespace Ship { public: virtual ~Controller() = default; Controller(); - void Read(OSContPad* pad, int32_t virtualSlot); virtual void ReadFromSource(int32_t virtualSlot) = 0; virtual void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) = 0; virtual bool Connected() const = 0; @@ -49,8 +48,12 @@ namespace Ship { virtual void CreateDefaultBinding(int32_t virtualSlot) = 0; virtual void ClearRawPress() = 0; virtual int32_t ReadRawPress() = 0; + virtual const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) = 0; + virtual const std::string GetControllerName() = 0; + void Read(OSContPad* pad, int32_t virtualSlot); void SetButtonMapping(int32_t virtualSlot, int32_t n64Button, int32_t dwScancode); - std::shared_ptr GetAttachment() { return Attachment; } + std::shared_ptr GetAttachment(); + std::shared_ptr getProfile(int32_t virtualSlot); int8_t& getLeftStickX(int32_t virtualSlot); int8_t& getLeftStickY(int32_t virtualSlot); int8_t& getRightStickX(int32_t virtualSlot); @@ -58,11 +61,8 @@ namespace Ship { int32_t& getPressedButtons(int32_t virtualSlot); float& getGyroX(int32_t virtualSlot); float& getGyroY(int32_t virtualSlot); - std::shared_ptr getProfile(int32_t virtualSlot); - bool IsRumbling() { return isRumbling; } - std::string GetGuid() { return GUID; } - virtual const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) = 0; - virtual const std::string GetControllerName() = 0; + bool IsRumbling(); + std::string GetGuid(); protected: std::shared_ptr Attachment; diff --git a/libultraship/libultraship/DummyController.cpp b/libultraship/libultraship/DummyController.cpp new file mode 100644 index 0000000000..fba77edb1d --- /dev/null +++ b/libultraship/libultraship/DummyController.cpp @@ -0,0 +1,61 @@ +#include "DummyController.h" + +namespace Ship { + DummyController::DummyController(const std::string& CUID, const std::string& KeyName, bool Connected) { + GUID = CUID; + isConnected = Connected; + ButtonName = KeyName; + } + + void DummyController::ReadFromSource(int32_t virtualSlot) { + + } + + const std::string DummyController::GetControllerName() { + return GUID; + } + + const std::string DummyController::GetButtonName(int32_t virtualSlot, int32_t n64Button) { + return ButtonName; + } + + void DummyController::WriteToSource(int32_t virtualSlot, ControllerCallback* controller){ + + } + + bool DummyController::Connected() const { + return isConnected; + } + + bool DummyController::CanRumble() const { + return false; + } + + bool DummyController::CanGyro() const { + return false; + } + + void DummyController::CreateDefaultBinding(int32_t slot) { + + } + + std::string DummyController::GetControllerType() { + return "Unk"; + } + + std::string DummyController::GetConfSection() { + return "Unk"; + } + + std::string DummyController::GetBindingConfSection() { + return "Unk"; + } + + void DummyController::ClearRawPress() { + + } + + int32_t DummyController::ReadRawPress() { + return -1; + } +} diff --git a/libultraship/libultraship/DummyController.h b/libultraship/libultraship/DummyController.h index 7e71b7033a..c66d83c3d8 100644 --- a/libultraship/libultraship/DummyController.h +++ b/libultraship/libultraship/DummyController.h @@ -7,31 +7,25 @@ namespace Ship { class DummyController final : public Controller { public: - DummyController(const std::string& CUID, const std::string& KeyName, bool Connected) { - GUID = CUID; - isConnected = Connected; - ButtonName = KeyName; - } - + DummyController(const std::string& CUID, const std::string& KeyName, bool Connected); std::map, int32_t> ReadButtonPress(); - void ReadFromSource(int32_t slot) override {} - const std::string GetControllerName() override { return GUID; } - const std::string GetButtonName(int slot, int n64Button) override { return ButtonName; } - void WriteToSource(int32_t slot, ControllerCallback* controller) override { } - bool Connected() const override { return isConnected; } - bool CanRumble() const override { return false; } - bool CanGyro() const override { return false; } - - void ClearRawPress() override {} - int32_t ReadRawPress() override { return -1; } - bool HasPadConf() const { return true; } - std::optional GetPadConfSection() { return "Unk"; } - void CreateDefaultBinding(int32_t slot) override {} + void ReadFromSource(int32_t virtualSlot) override; + const std::string GetControllerName() override; + const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override; + void WriteToSource(int32_t slot, ControllerCallback* controller) override; + bool Connected() const override; + bool CanRumble() const override; + bool CanGyro() const override; + void ClearRawPress() override; + int32_t ReadRawPress() override; + bool HasPadConf() const; + std::optional GetPadConfSection(); + void CreateDefaultBinding(int32_t virtualSlot) override; protected: std::string ButtonName; bool isConnected = false; - std::string GetControllerType() { return "Unk"; } - std::string GetConfSection() { return "Unk"; } - std::string GetBindingConfSection() { return "Unk"; } + std::string GetControllerType(); + std::string GetConfSection(); + std::string GetBindingConfSection(); }; } \ No newline at end of file diff --git a/libultraship/libultraship/Hooks.cpp b/libultraship/libultraship/Hooks.cpp new file mode 100644 index 0000000000..577801743f --- /dev/null +++ b/libultraship/libultraship/Hooks.cpp @@ -0,0 +1,5 @@ +#include "Hooks.h" + +namespace Ship { + +} diff --git a/libultraship/libultraship/KeyboardController.cpp b/libultraship/libultraship/KeyboardController.cpp index ff0b72b70e..88fb0f8979 100644 --- a/libultraship/libultraship/KeyboardController.cpp +++ b/libultraship/libultraship/KeyboardController.cpp @@ -7,7 +7,7 @@ #endif #include "Hooks.h" - + #include "Window.h" namespace Ship { @@ -100,4 +100,28 @@ namespace Ship { const std::string KeyboardController::GetControllerName() { return "Keyboard"; } + + bool KeyboardController::Connected() const { + return true; + } + + bool KeyboardController::CanRumble() const { + return false; + } + + bool KeyboardController::CanGyro() const { + return false; + } + + void KeyboardController::ClearRawPress() { + lastKey = -1; + } + + void KeyboardController::SetLastScancode(int32_t key) { + lastScancode = key; + } + + int32_t KeyboardController::GetLastScancode() { + return lastScancode; + } } diff --git a/libultraship/libultraship/KeyboardController.h b/libultraship/libultraship/KeyboardController.h index 345e34718e..6e2a9f5f5a 100644 --- a/libultraship/libultraship/KeyboardController.h +++ b/libultraship/libultraship/KeyboardController.h @@ -9,26 +9,18 @@ namespace Ship { void ReadFromSource(int32_t virtualSlot) override; void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) override; - bool Connected() const override { return true; } - bool CanRumble() const override { return false; } - bool CanGyro() const override { return false; } const std::string GetControllerName() override; const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override; bool PressButton(int32_t dwScancode); bool ReleaseButton(int32_t dwScancode); - - void ClearRawPress() override { - lastKey = -1; - } - + bool Connected() const override; + bool CanRumble() const override; + bool CanGyro() const override; + void ClearRawPress() override; int32_t ReadRawPress() override; void ReleaseAllButtons(); - - void SetLastScancode(int32_t key) { - lastScancode = key; - } - - int32_t GetLastScancode() { return lastScancode; } + void SetLastScancode(int32_t key); + int32_t GetLastScancode(); void CreateDefaultBinding(int32_t virtualSlot) override; protected: diff --git a/libultraship/libultraship/ResourceMgr.cpp b/libultraship/libultraship/ResourceMgr.cpp index 4ca77708a3..0bf34ffe80 100644 --- a/libultraship/libultraship/ResourceMgr.cpp +++ b/libultraship/libultraship/ResourceMgr.cpp @@ -333,4 +333,17 @@ namespace Ship { const std::string* ResourceMgr::HashToString(uint64_t Hash) const { return OTR->HashToString(Hash); } + + std::shared_ptr ResourceMgr::GetArchive() { + return OTR; + } + + std::shared_ptr ResourceMgr::GetContext() { + return Context; + } + + std::shared_ptr ResourceMgr::LoadResource(const std::string& FilePath) { + return LoadResource(FilePath.c_str()); + } + } diff --git a/libultraship/libultraship/ResourceMgr.h b/libultraship/libultraship/ResourceMgr.h index e0b0c07cfb..f98b8cb8ba 100644 --- a/libultraship/libultraship/ResourceMgr.h +++ b/libultraship/libultraship/ResourceMgr.h @@ -23,20 +23,17 @@ namespace Ship { bool IsRunning(); bool DidLoadSuccessfully(); - std::shared_ptr GetArchive() { return OTR; } - std::shared_ptr GetContext() { return Context; } - + std::shared_ptr GetArchive(); + std::shared_ptr GetContext(); const std::string* HashToString(uint64_t Hash) const; - void InvalidateResourceCache(); - uint32_t GetGameVersion(); void SetGameVersion(uint32_t newGameVersion); std::shared_ptr LoadFileAsync(const std::string& FilePath); std::shared_ptr LoadFile(const std::string& FilePath); std::shared_ptr GetCachedFile(const char* FilePath) const; std::shared_ptr LoadResource(const char* FilePath); - std::shared_ptr LoadResource(const std::string& FilePath) { return LoadResource(FilePath.c_str()); } + std::shared_ptr LoadResource(const std::string& FilePath); std::variant, std::shared_ptr> LoadResourceAsync(const char* FilePath); std::shared_ptr>> CacheDirectory(const std::string& SearchMask); std::shared_ptr>> CacheDirectoryAsync(const std::string& SearchMask); diff --git a/libultraship/libultraship/SDLController.cpp b/libultraship/libultraship/SDLController.cpp index d0bb8e1f78..8811b94cb1 100644 --- a/libultraship/libultraship/SDLController.cpp +++ b/libultraship/libultraship/SDLController.cpp @@ -12,6 +12,10 @@ extern "C" uint8_t __osMaxControllers; namespace Ship { + SDLController::SDLController(int32_t physicalSlot) : Controller(), Cont(nullptr), physicalSlot(physicalSlot) { + + } + bool SDLController::Open() { const auto NewCont = SDL_GameControllerOpen(physicalSlot); @@ -450,4 +454,23 @@ namespace Ship { profile->GyroData[DRIFT_Y] = 0.0f; profile->GyroData[GYRO_SENSITIVITY] = 1.0f; } + + bool SDLController::Connected() const { + return Cont != nullptr; + } + + bool SDLController::CanGyro() const { + return supportsGyro; + } + + bool SDLController::CanRumble() const { +#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18) + return SDL_GameControllerHasRumble(Cont); +#endif + return false; + } + + void SDLController::ClearRawPress() { + + } } diff --git a/libultraship/libultraship/SDLController.h b/libultraship/libultraship/SDLController.h index e9c696dac7..111070843a 100644 --- a/libultraship/libultraship/SDLController.h +++ b/libultraship/libultraship/SDLController.h @@ -5,6 +5,19 @@ namespace Ship { class SDLController : public Controller { public: + SDLController(int32_t physicalSlot); + void ReadFromSource(int32_t virtualSlot) override; + const std::string GetControllerName() override; + const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override; + void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) override; + bool Connected() const override; + bool CanGyro() const override; + bool CanRumble() const override; + bool Open(); + void ClearRawPress() override; + int32_t ReadRawPress() override; + + protected: inline static const char* AxisNames[] = { "Left Stick X", "Left Stick Y", @@ -15,25 +28,6 @@ namespace Ship { "Start Button" }; - SDLController(int32_t physicalSlot) : Controller(), Cont(nullptr), physicalSlot(physicalSlot) { } - void ReadFromSource(int32_t virtualSlot) override; - const std::string GetControllerName() override; - const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override; - void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) override; - bool Connected() const override { return Cont != nullptr; } - bool CanGyro() const override { return supportsGyro; } - bool CanRumble() const override { -#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18) - return SDL_GameControllerHasRumble(Cont); -#endif - return false; - } - - bool Open(); - void ClearRawPress() override {} - int32_t ReadRawPress() override; - - protected: void CreateDefaultBinding(int32_t virtualSlot) override; private: diff --git a/libultraship/libultraship/Window.cpp b/libultraship/libultraship/Window.cpp index 666c1e0c00..b9e84fd60d 100644 --- a/libultraship/libultraship/Window.cpp +++ b/libultraship/libultraship/Window.cpp @@ -581,4 +581,52 @@ namespace Ship { saveFile.close(); } + + bool Window::IsFullscreen() { + return bIsFullscreen; + } + + uint32_t Window::GetMenuBar() { + return dwMenubar; + } + + void Window::SetMenuBar(uint32_t dwMenuBar) { + this->dwMenubar = dwMenuBar; + } + + std::string Window::GetName() { + return Name; + } + + std::shared_ptr Window::GetControlDeck() { + return ControllerApi; + } + + std::shared_ptr Window::GetAudioPlayer() { + return APlayer; + } + + std::shared_ptr Window::GetResourceManager() { + return ResMan; + } + + std::shared_ptr Window::GetConfig() { + return Config; + } + + std::shared_ptr Window::GetLogger() { + return Logger; + } + + const char* Window::GetKeyName(int32_t scancode) { + return WmApi->get_key_name(scancode); + } + + int32_t Window::GetLastScancode() { + return lastScancode; + } + + void Window::SetLastScancode(int32_t scanCode) { + lastScancode = scanCode; + } } diff --git a/libultraship/libultraship/Window.h b/libultraship/libultraship/Window.h index 6a0e688997..b70587bf58 100644 --- a/libultraship/libultraship/Window.h +++ b/libultraship/libultraship/Window.h @@ -36,20 +36,20 @@ namespace Ship { void ToggleFullscreen(); void SetFullscreen(bool bIsFullscreen); void ShowCursor(bool hide); - bool IsFullscreen() { return bIsFullscreen; } uint32_t GetCurrentWidth(); uint32_t GetCurrentHeight(); - uint32_t GetMenuBar() { return dwMenubar; } - void SetMenuBar(uint32_t dwMenuBar) { this->dwMenubar = dwMenuBar; } - std::string GetName() { return Name; } - std::shared_ptr GetControlDeck() { return ControllerApi; }; - std::shared_ptr GetAudioPlayer() { return APlayer; } - std::shared_ptr GetResourceManager() { return ResMan; } - std::shared_ptr GetConfig() { return Config; } - std::shared_ptr GetLogger() { return Logger; } - const char* GetKeyName(int32_t scancode) { return WmApi->get_key_name(scancode); } - int32_t GetLastScancode() { return lastScancode; } - void SetLastScancode(int32_t scanCode) { lastScancode = scanCode; } + bool IsFullscreen(); + uint32_t GetMenuBar(); + void SetMenuBar(uint32_t dwMenuBar); + std::string GetName(); + std::shared_ptr GetControlDeck(); + std::shared_ptr GetAudioPlayer(); + std::shared_ptr GetResourceManager(); + std::shared_ptr GetConfig(); + std::shared_ptr GetLogger(); + const char* GetKeyName(int32_t scancode); + int32_t GetLastScancode(); + void SetLastScancode(int32_t scanCode); protected: Window() = default; From cc6e4238cf6eb143265de6b22c36efad584157e1 Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 25 Aug 2022 08:49:15 +0200 Subject: [PATCH 09/62] Fixes BGS on skull tokens --- soh/src/code/z_parameter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 9d95bb0bc9..e2aa0fe463 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1644,6 +1644,7 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { if (item == ITEM_SWORD_BGS) { gSaveContext.swordHealth = 8; + gSaveContext.bgsFlag = 1; if (ALL_EQUIP_VALUE(EQUIP_SWORD) == 0xF ||(gSaveContext.n64ddFlag && ALL_EQUIP_VALUE(EQUIP_SWORD) == 0xE)) { // In rando, when buying Giant's Knife, also check From 2626f6c7e3523ede1356e08755e29254bb9ff25f Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 25 Aug 2022 09:34:46 +0200 Subject: [PATCH 10/62] Fixed Winner PoH on skulltula's --- soh/src/overlays/actors/ovl_En_Si/z_en_si.c | 33 ++++++++++++++------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c index 36fc46abb3..1cfe31f6ff 100644 --- a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c +++ b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c @@ -17,7 +17,8 @@ s32 func_80AFB748(EnSi* this, GlobalContext* globalCtx); void func_80AFB768(EnSi* this, GlobalContext* globalCtx); void func_80AFB89C(EnSi* this, GlobalContext* globalCtx); void func_80AFB950(EnSi* this, GlobalContext* globalCtx); -void Randomizer_GrantSkullReward(EnSi* this, GlobalContext* globalCtx); +void Randomizer_GetSkullReward(EnSi* this, GlobalContext* globalCtx); +void Randomizer_GiveSkullReward(EnSi* this, GlobalContext* globalCtx); s32 textId = 0xB4; s32 giveItemId = ITEM_SKULL_TOKEN; @@ -99,21 +100,25 @@ void func_80AFB768(EnSi* this, GlobalContext* globalCtx) { if (this->collider.base.ocFlags2 & OC2_HIT_PLAYER) { this->collider.base.ocFlags2 &= ~OC2_HIT_PLAYER; + if (gSaveContext.n64ddFlag) { - Randomizer_GrantSkullReward(this, globalCtx); + Randomizer_GetSkullReward(this, globalCtx); } else { Item_Give(globalCtx, giveItemId); } if ((CVar_GetS32("gSkulltulaFreeze", 0) != 1 || giveItemId != ITEM_SKULL_TOKEN) && getItemId != RG_ICE_TRAP) { player->actor.freezeTimer = 20; } + Message_StartTextbox(globalCtx, textId, NULL); if (gSaveContext.n64ddFlag && getItemId != RG_ICE_TRAP) { + Randomizer_GiveSkullReward(this, globalCtx); Audio_PlayFanfare_Rando(getItem); } else { Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET); } + player->getItemEntry = (GetItemEntry)GET_ITEM_NONE; this->actionFunc = func_80AFB950; } else { @@ -133,16 +138,20 @@ void func_80AFB89C(EnSi* this, GlobalContext* globalCtx) { if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) { if (gSaveContext.n64ddFlag) { - Randomizer_GrantSkullReward(this, globalCtx); + Randomizer_GetSkullReward(this, globalCtx); } else { Item_Give(globalCtx, giveItemId); } + Message_StartTextbox(globalCtx, textId, NULL); + if (gSaveContext.n64ddFlag && getItemId != RG_ICE_TRAP) { + Randomizer_GiveSkullReward(this, globalCtx); Audio_PlayFanfare_Rando(getItem); } else { Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET); } + player->getItemEntry = (GetItemEntry)GET_ITEM_NONE; this->actionFunc = func_80AFB950; } @@ -190,7 +199,7 @@ void EnSi_Draw(Actor* thisx, GlobalContext* globalCtx) { } } -void Randomizer_GrantSkullReward(EnSi* this, GlobalContext* globalCtx) { +void Randomizer_GetSkullReward(EnSi* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum); @@ -201,12 +210,16 @@ void Randomizer_GrantSkullReward(EnSi* this, GlobalContext* globalCtx) { } else { textId = getItem.textId; giveItemId = getItem.itemId; - if (getItem.modIndex == MOD_NONE) { - Item_Give(globalCtx, giveItemId); - } else if (getItem.modIndex == MOD_RANDOMIZER) { - Randomizer_Item_Give(globalCtx, getItem); - } } - // player->getItemId = getItemId; +} + +void Randomizer_GiveSkullReward(EnSi* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + if (getItem.modIndex == MOD_NONE) { + Item_Give(globalCtx, giveItemId); + } else if (getItem.modIndex == MOD_RANDOMIZER) { + Randomizer_Item_Give(globalCtx, getItem); + } player->getItemEntry = getItem; } From bc5ec248895cbee43ab9a06f5bcc9ddff6932d0d Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 25 Aug 2022 09:54:08 +0200 Subject: [PATCH 11/62] Ice trap fix --- soh/src/overlays/actors/ovl_En_Si/z_en_si.c | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c index 1cfe31f6ff..2764a498f3 100644 --- a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c +++ b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c @@ -205,6 +205,7 @@ void Randomizer_GetSkullReward(EnSi* this, GlobalContext* globalCtx) { getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum); getItemId = getItem.getItemId; if (getItemId == RG_ICE_TRAP) { + player->getItemEntry = getItem; player->pendingIceTrap = true; textId = 0xF8; } else { From ef1b662bf4eac3ae5d3d9c3d57ef10c46f4341f3 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 09:42:15 -0400 Subject: [PATCH 12/62] Finishes wiring up bean salesman settings and text. --- soh/soh/Enhancements/custom-message/CustomMessageTypes.h | 3 ++- soh/soh/Enhancements/randomizer/3drando/settings.cpp | 1 + soh/soh/Enhancements/randomizer/randomizer.cpp | 8 ++++++++ soh/soh/OTRGlobals.cpp | 2 ++ soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c | 3 ++- 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index b38b5fc801..d82cd84a97 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -15,7 +15,8 @@ typedef enum { TEXT_BLUE_RUPEE = 0xCC, TEXT_RED_RUPEE = 0xF0, TEXT_PURPLE_RUPEE = 0xF1, - TEXT_HUGE_RUPEE = 0xF2 + TEXT_HUGE_RUPEE = 0xF2, + TEXT_BEAN_SALESEMAN = 0x405E } TextIDs; #ifdef __cplusplus diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 51eaff18be..7df0be90a6 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2551,6 +2551,7 @@ namespace Settings { ShuffleFrogSongRupees.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_FROG_SONG_RUPEES]); ShuffleAdultTradeQuest.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_ADULT_TRADE]); + ShuffleMagicBeans.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_MAGIC_BEANS]); // the checkbox works because 0 is "Off" and 1 is "Fairy Ocarina" StartingOcarina.SetSelectedIndex(cvarSettings[RSK_STARTING_OCARINA]); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 69da8fa034..5285279223 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -548,6 +548,7 @@ std::unordered_map SpoilerfileSettingNameToEn { "Shuffle Settings:Shuffle Cows", RSK_SHUFFLE_COWS }, { "Shuffle Settings:Tokensanity", RSK_SHUFFLE_TOKENS }, { "Shuffle Settings:Shuffle Adult Trade", RSK_SHUFFLE_ADULT_TRADE }, + { "Shuffle Settings:Shuffle Magic Beans", RSK_SHUFFLE_MAGIC_BEANS}, { "Start with Deku Shield", RSK_STARTING_DEKU_SHIELD }, { "Start with Kokiri Sword", RSK_STARTING_KOKIRI_SWORD }, { "Start with Fairy Ocarina", RSK_STARTING_OCARINA }, @@ -774,6 +775,7 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { case RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD: case RSK_SHUFFLE_COWS: case RSK_SHUFFLE_ADULT_TRADE: + case RSK_SHUFFLE_MAGIC_BEANS: case RSK_RANDOM_TRIALS: case RSK_STARTING_DEKU_SHIELD: case RSK_STARTING_KOKIRI_SWORD: @@ -2616,6 +2618,7 @@ void GenerateRandomizerImgui() { cvarSettings[RSK_SHUFFLE_TOKENS] = CVar_GetS32("gRandomizeShuffleTokens", 0); cvarSettings[RSK_SHUFFLE_COWS] = CVar_GetS32("gRandomizeShuffleCows", 0); cvarSettings[RSK_SHUFFLE_ADULT_TRADE] = CVar_GetS32("gRandomizeShuffleAdultTrade", 0); + cvarSettings[RSK_SHUFFLE_MAGIC_BEANS] = CVar_GetS32("gRandomizeShuffleBeans", 0); cvarSettings[RSK_SKIP_CHILD_ZELDA] = CVar_GetS32("gRandomizeSkipChildZelda", 0); // if we skip child zelda, we start with zelda's letter, and malon starts @@ -3149,6 +3152,11 @@ void DrawRandoEditor(bool& open) { "If disabled, only the Claim Check will be found in the pool."); PaddedSeparator(); + SohImGui::EnhancementCheckbox(Settings::ShuffleMagicBeans.GetName().c_str(), "gRandomizeShuffleBeans"); + InsertHelpHoverText("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."); + PaddedSeparator(); + if (CVar_GetS32("gRandomizeStartingKokiriSword", 0) == 0) { // Shuffle Kokiri Sword SohImGui::EnhancementCheckbox(Settings::ShuffleKokiriSword.GetName().c_str(), diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 18d20ee00d..f2d3c4844a 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1727,6 +1727,8 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { // In rando, replace Navi's general overworld hints with rando-related gameplay tips } else if (CVar_GetS32("gRandoRelevantNavi", 1) && textId >= 0x0140 && textId <= 0x015F) { messageEntry = Randomizer_GetNaviMessage(); + } else if (Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS) && textId == TEXT_BEAN_SALESEMAN) { + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, TEXT_BEAN_SALESEMAN); } } if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) { diff --git a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c index 5c8a1807b8..d90e54244b 100644 --- a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c +++ b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c @@ -152,7 +152,8 @@ void EnMs_Sell(EnMs* this, GlobalContext* globalCtx) { if (Actor_HasParent(&this->actor, globalCtx)) { Rupees_ChangeBy((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? 60 : -sPrices[BEANS_BOUGHT]); this->actor.parent = NULL; - this->actionFunc = EnMs_TalkAfterPurchase; + this->actionFunc = + (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? EnMs_Wait : EnMs_TalkAfterPurchase; } else { if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) { GiveItemEntryFromActor(&this->actor, globalCtx, From 5842beeb55d447b28af2204bb002fe633dfda06b Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 10:11:35 -0400 Subject: [PATCH 13/62] Fixes Bean Pack item from chest. --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 5285279223..0f37eee73e 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1198,8 +1198,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case RG_MAGIC_BEAN: return GI_BEAN; - case RG_MAGIC_BEAN_PACK: - return GI_BEAN; //todo make it 10 of them case RG_WEIRD_EGG: return GI_WEIRD_EGG; From 90067be13216a3234224a21ed1c193e8e78e9c81 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 11:19:17 -0400 Subject: [PATCH 14/62] Fixes Dungeon Rewards from Song from Impa (#1311) --- soh/src/code/z_sram.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 6ab65e3cbc..952ce8e3ce 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -701,7 +701,9 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { s32 giid = getItem.getItemId; if (getItem.modIndex == MOD_NONE) { - if (giid == GI_RUPEE_GREEN || giid == GI_RUPEE_BLUE || giid == GI_RUPEE_RED || + if (getItem.itemId >= ITEM_MEDALLION_FOREST && getItem.itemId <= ITEM_ZORA_SAPPHIRE) { + GiveLinkDungeonReward(getItem.getItemId); + } else if (giid == GI_RUPEE_GREEN || giid == GI_RUPEE_BLUE || giid == GI_RUPEE_RED || giid == GI_RUPEE_PURPLE || giid == GI_RUPEE_GOLD) { GiveLinkRupeesByGetItemId(giid); } else if (giid == GI_BOMBCHUS_10 || giid == GI_BOMBCHUS_5 || giid == GI_BOMBCHUS_20) { From 69157640f6e6792e20f74fa9c71dd2a0b3f961d0 Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 25 Aug 2022 17:34:45 +0200 Subject: [PATCH 15/62] Removed BGS flag in Item_Give() --- soh/src/code/z_parameter.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index e2aa0fe463..b47c866222 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1642,13 +1642,16 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { } else if ((item >= ITEM_SWORD_KOKIRI) && (item <= ITEM_SWORD_BGS)) { gSaveContext.inventory.equipment |= gBitFlags[item - ITEM_SWORD_KOKIRI] << gEquipShifts[EQUIP_SWORD]; + // Both Giant's Knife and Biggoron Sword have the same Item ID, so this part handles both of them if (item == ITEM_SWORD_BGS) { gSaveContext.swordHealth = 8; - gSaveContext.bgsFlag = 1; - if (ALL_EQUIP_VALUE(EQUIP_SWORD) == 0xF - ||(gSaveContext.n64ddFlag && ALL_EQUIP_VALUE(EQUIP_SWORD) == 0xE)) { // In rando, when buying Giant's Knife, also check - gSaveContext.inventory.equipment ^= 8 << gEquipShifts[EQUIP_SWORD]; // for 0xE in case we don't have Kokiri Sword + // In rando, when buying Giant's Knife, also check + // for 0xE in case we don't have Kokiri Sword + if (ALL_EQUIP_VALUE(EQUIP_SWORD) == 0xF || (gSaveContext.n64ddFlag && ALL_EQUIP_VALUE(EQUIP_SWORD) == 0xE)) { + + gSaveContext.inventory.equipment ^= 8 << gEquipShifts[EQUIP_SWORD]; + if (gSaveContext.equips.buttonItems[0] == ITEM_SWORD_KNIFE) { gSaveContext.equips.buttonItems[0] = ITEM_SWORD_BGS; Interface_LoadItemIcon1(globalCtx, 0); From c22951353e56e39338a62bf2f42d84036e72ba85 Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 25 Aug 2022 18:04:52 +0200 Subject: [PATCH 16/62] Renamed function --- soh/src/overlays/actors/ovl_En_Si/z_en_si.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c index 2764a498f3..aa07c14509 100644 --- a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c +++ b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c @@ -17,7 +17,7 @@ s32 func_80AFB748(EnSi* this, GlobalContext* globalCtx); void func_80AFB768(EnSi* this, GlobalContext* globalCtx); void func_80AFB89C(EnSi* this, GlobalContext* globalCtx); void func_80AFB950(EnSi* this, GlobalContext* globalCtx); -void Randomizer_GetSkullReward(EnSi* this, GlobalContext* globalCtx); +void Randomizer_UpdateSkullReward(EnSi* this, GlobalContext* globalCtx); void Randomizer_GiveSkullReward(EnSi* this, GlobalContext* globalCtx); s32 textId = 0xB4; @@ -102,7 +102,7 @@ void func_80AFB768(EnSi* this, GlobalContext* globalCtx) { this->collider.base.ocFlags2 &= ~OC2_HIT_PLAYER; if (gSaveContext.n64ddFlag) { - Randomizer_GetSkullReward(this, globalCtx); + Randomizer_UpdateSkullReward(this, globalCtx); } else { Item_Give(globalCtx, giveItemId); } @@ -138,7 +138,7 @@ void func_80AFB89C(EnSi* this, GlobalContext* globalCtx) { if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) { if (gSaveContext.n64ddFlag) { - Randomizer_GetSkullReward(this, globalCtx); + Randomizer_UpdateSkullReward(this, globalCtx); } else { Item_Give(globalCtx, giveItemId); } @@ -199,7 +199,7 @@ void EnSi_Draw(Actor* thisx, GlobalContext* globalCtx) { } } -void Randomizer_GetSkullReward(EnSi* this, GlobalContext* globalCtx) { +void Randomizer_UpdateSkullReward(EnSi* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum); From 00838cb5b60a123c4d06f220840e559f805b886a Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 12:39:34 -0400 Subject: [PATCH 17/62] Adds french text for the bean salesman --- soh/soh/Enhancements/randomizer/randomizer.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 0f37eee73e..452112552a 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3740,16 +3740,18 @@ void CreateScrubMessages() { std::to_string(price) + " Rubis%w!\x07\x10\xA3" }); } - customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, 0x405E, + customMessageManager->CreateMessage( + Randomizer::scrubMessageTableID, 0x405E, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, - "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" - "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" - "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" - "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " + "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " + "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "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 un&" + "%gobjet mystérieux%w pour 60 Rubis?\x1B&%gOui&Non%w", }); } From 6ab13f389b9e4371d0dd1dec08d1cdec719d3328 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 12:43:19 -0400 Subject: [PATCH 18/62] Fixes salesman to properly take 60 rupees from you. --- soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c index d90e54244b..9f67a21fc2 100644 --- a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c +++ b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c @@ -150,7 +150,7 @@ void EnMs_Talk(EnMs* this, GlobalContext* globalCtx) { void EnMs_Sell(EnMs* this, GlobalContext* globalCtx) { if (Actor_HasParent(&this->actor, globalCtx)) { - Rupees_ChangeBy((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? 60 : -sPrices[BEANS_BOUGHT]); + Rupees_ChangeBy((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? -60 : -sPrices[BEANS_BOUGHT]); this->actor.parent = NULL; this->actionFunc = (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? EnMs_Wait : EnMs_TalkAfterPurchase; From efd4ceb636a5c953a633c7ea703799e866f90b9f Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 12:46:08 -0400 Subject: [PATCH 19/62] Colors keywords in bean salesman text. --- soh/soh/Enhancements/randomizer/randomizer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 452112552a..66ecbc7d94 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3745,11 +3745,11 @@ void CreateScrubMessages() { { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, - "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " + "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " + "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "J'ai essayé d'être un vendeur de&haricots magiques, mais j'étais&mauvais au niveau du marketing et&ça me " + "J'ai essayé d'être un vendeur de&%rharicots magiques%w, mais j'étais&mauvais au niveau du marketing et&ça me " "courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&" "%gobjet mystérieux%w pour 60 Rubis?\x1B&%gOui&Non%w", }); From 49b48fb7a4db1d334a62c9cc6d3241e81a5c8848 Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 25 Aug 2022 19:56:34 +0200 Subject: [PATCH 20/62] Fix BGS and maps/keys textboxes --- soh/src/overlays/actors/ovl_En_Si/z_en_si.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c index aa07c14509..87a3b854c6 100644 --- a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c +++ b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c @@ -205,13 +205,13 @@ void Randomizer_UpdateSkullReward(EnSi* this, GlobalContext* globalCtx) { getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum); getItemId = getItem.getItemId; if (getItemId == RG_ICE_TRAP) { - player->getItemEntry = getItem; player->pendingIceTrap = true; textId = 0xF8; } else { textId = getItem.textId; giveItemId = getItem.itemId; } + player->getItemEntry = getItem; } void Randomizer_GiveSkullReward(EnSi* this, GlobalContext* globalCtx) { @@ -222,5 +222,7 @@ void Randomizer_GiveSkullReward(EnSi* this, GlobalContext* globalCtx) { } else if (getItem.modIndex == MOD_RANDOMIZER) { Randomizer_Item_Give(globalCtx, getItem); } - player->getItemEntry = getItem; + if (getItem.getItemId == GI_SWORD_BGS) { + gSaveContext.bgsFlag = true; + } } From 29b9f0b37e586543d036a7f6ee58d5484b8d2167 Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 25 Aug 2022 19:58:05 +0200 Subject: [PATCH 21/62] Comment --- soh/src/overlays/actors/ovl_En_Si/z_en_si.c | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c index 87a3b854c6..39e1195f54 100644 --- a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c +++ b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c @@ -222,6 +222,7 @@ void Randomizer_GiveSkullReward(EnSi* this, GlobalContext* globalCtx) { } else if (getItem.modIndex == MOD_RANDOMIZER) { Randomizer_Item_Give(globalCtx, getItem); } + // RANDOTOD: Move this into Item_Give() or some other more central location if (getItem.getItemId == GI_SWORD_BGS) { gSaveContext.bgsFlag = true; } From c2fed1a382e82080a9607ec9dc10cdee92ffdf0d Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 14:16:43 -0400 Subject: [PATCH 22/62] Fixes Lost Woods Bridge Ice Trap in Rando (#1313) --- soh/src/code/z_play.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 7ab9905a74..6b311fd4cb 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -255,10 +255,10 @@ void GivePlayerRandoRewardSariaGift(GlobalContext* globalCtx, RandomizerCheck ch if (gSaveContext.entranceIndex == 0x05E0) { GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(check, RG_ZELDAS_LULLABY); - if ((!Flags_GetEventChkInf(0xC1) || (player->getItemId == getItemEntry.getItemId && getItemEntry.getItemId != GI_ICE_TRAP)) && - player != NULL && !Player_InBlockingCsMode(globalCtx, player)) { + if (!Flags_GetEventChkInf(0xC1) && player != NULL && !Player_InBlockingCsMode(globalCtx, player)) { GiveItemEntryWithoutActor(globalCtx, getItemEntry); - Flags_SetEventChkInf(0xC1); + player->pendingFlag.flagType = FLAG_EVENT_CHECK_INF; + player->pendingFlag.flagID = 0xC1; } } } From 3da197f0cdd7ef7f6bcf6c651f73e75a97a25503 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 14:39:12 -0400 Subject: [PATCH 23/62] Removes some magic numbers --- soh/soh/Enhancements/custom-message/CustomMessageTypes.h | 2 +- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- soh/soh/OTRGlobals.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index d82cd84a97..dff85f4155 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -16,7 +16,7 @@ typedef enum { TEXT_RED_RUPEE = 0xF0, TEXT_PURPLE_RUPEE = 0xF1, TEXT_HUGE_RUPEE = 0xF2, - TEXT_BEAN_SALESEMAN = 0x405E + TEXT_BEAN_SALESMAN = 0x405E } TextIDs; #ifdef __cplusplus diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 66ecbc7d94..72533c3c4f 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3741,7 +3741,7 @@ void CreateScrubMessages() { }); } customMessageManager->CreateMessage( - Randomizer::scrubMessageTableID, 0x405E, + Randomizer::scrubMessageTableID, TEXT_BEAN_SALESMAN, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index f2d3c4844a..59d0bbad96 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1727,8 +1727,8 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { // In rando, replace Navi's general overworld hints with rando-related gameplay tips } else if (CVar_GetS32("gRandoRelevantNavi", 1) && textId >= 0x0140 && textId <= 0x015F) { messageEntry = Randomizer_GetNaviMessage(); - } else if (Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS) && textId == TEXT_BEAN_SALESEMAN) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, TEXT_BEAN_SALESEMAN); + } else if (Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS) && textId == TEXT_BEAN_SALESMAN) { + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, TEXT_BEAN_SALESMAN); } } if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) { From 1e31d108e6b7620db11d8d90f540569a71d42ed2 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Thu, 25 Aug 2022 13:49:02 -0500 Subject: [PATCH 24/62] Various changes from feedback, and use new randomizerInf table --- soh/include/z64save.h | 1 - .../Enhancements/randomizer/3drando/fill.cpp | 2 +- .../randomizer/3drando/spoiler_log.cpp | 12 ++- .../Enhancements/randomizer/randomizer.cpp | 91 ++++++++++--------- soh/soh/Enhancements/randomizer/randomizer.h | 2 +- .../Enhancements/randomizer/randomizerTypes.h | 3 +- .../Enhancements/randomizer/randomizer_inf.h | 37 ++++++++ soh/soh/SaveManager.cpp | 12 --- soh/src/code/z_sram.c | 5 - soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c | 8 +- .../actors/ovl_En_Shopnuts/z_en_shopnuts.c | 2 +- 11 files changed, 106 insertions(+), 69 deletions(-) diff --git a/soh/include/z64save.h b/soh/include/z64save.h index 7db9f3c145..14da6a2fce 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -184,7 +184,6 @@ typedef struct { char ganonText[250]; u8 seedIcons[5]; u16 randomizerInf[2]; - u8 scrubsPurchased[35]; u8 temporaryWeapon; u16 adultTradeItems; } SaveContext; // size = 0x1428 diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index b78e3f6301..e23f9633d6 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -1040,7 +1040,7 @@ int Fill() { std::vector remainingPool = FilterAndEraseFromPool(ItemPool, [](const auto i) { return true; }); FastFill(remainingPool, GetAllEmptyLocations(), false); - // Add prices for scrubsanity + //Add prices for scrubsanity, this is unique to SoH because we write/read scrub prices to/from the spoilerfile. if (Scrubsanity.Is(SCRUBSANITY_AFFORDABLE)) { for (size_t i = 0; i < ScrubLocations.size(); i++) { Location(ScrubLocations[i])->SetScrubsanityPrice(10); diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 29d57292ca..98ce64ef1a 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -673,12 +673,20 @@ static void WriteHints(int language) { static void WriteAllLocations(int language) { for (const uint32_t key : allLocations) { ItemLocation* location = Location(key); - std::string placedItemName = language == 2 ? location->GetPlacedItemName().french : location->GetPlacedItemName().english; + std::string placedItemName; + + switch (language) { + case 0: + default: + location->GetPlacedItemName().english; + case 2: + location->GetPlacedItemName().french; + } // Eventually check for other things here like fake name if (location->HasScrubsanityPrice() || location->HasShopsanityPrice()) { jsonData["locations"][location->GetName()]["item"] = placedItemName; - jsonData["locations"][location->GetName()]["price"] = location->GetPrice();; + jsonData["locations"][location->GetName()]["price"] = location->GetPrice(); } else { jsonData["locations"][location->GetName()] = placedItemName; } diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 23c0f45dca..2e73b3ed0d 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -104,7 +104,7 @@ Sprite* Randomizer::GetSeedTexture(uint8_t index) { Randomizer::~Randomizer() { this->randoSettings.clear(); this->itemLocations.clear(); - this->scrubPrices.clear(); + this->randomizerMerchantPrices.clear(); } std::unordered_map getItemIdToItemId = { @@ -1118,8 +1118,7 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent gSaveContext.itemLocations[index].check = SpoilerfileCheckNameToEnum[it.key()]; gSaveContext.itemLocations[index].get = SpoilerfileGetNameToEnum[itemit.value()]; } else if (itemit.key() == "price") { - scrubPrices[gSaveContext.itemLocations[index].check] = itemit.value(); - // TODO: Handle shop prices + randomizerMerchantPrices[gSaveContext.itemLocations[index].check] = itemit.value(); } } } else { @@ -1606,12 +1605,12 @@ std::string Randomizer::GetGanonHintText() const { ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData) { struct ScrubIdentity scrubIdentity; - scrubIdentity.scrubId = -1; scrubIdentity.randomizerCheck = RC_UNKNOWN_CHECK; scrubIdentity.getItemId = GI_NONE; scrubIdentity.itemPrice = -1; scrubIdentity.isShuffled = GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) > 0; + // Based on z_en_dns.c 93-113 switch (actorParams) { case 0x00: scrubIdentity.getItemId = GI_NUTS_5_2; @@ -1653,20 +1652,20 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case SCENE_DDAN: // Dodongo's Cavern switch (actorParams) { case 0x00: - scrubIdentity.scrubId = 0x00; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT; scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT; break; case 0x01: - scrubIdentity.scrubId = 0x01; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS; scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS; break; case 0x03: case 0x06: - scrubIdentity.scrubId = 0x02; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT; scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT; break; case 0x04: - scrubIdentity.scrubId = 0x03; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY; scrubIdentity.randomizerCheck = RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY; break; } @@ -1674,7 +1673,7 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case SCENE_BDAN: // Jabu Jabu's Belly switch (actorParams) { case 0x00: - scrubIdentity.scrubId = 0x04; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_JABU_JABUS_BELLY_DEKU_SCRUB; scrubIdentity.randomizerCheck = RC_JABU_JABUS_BELLY_DEKU_SCRUB; break; } @@ -1682,20 +1681,20 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case SCENE_GANONTIKA: // Ganon's Castle switch (actorParams) { case 0x05: - scrubIdentity.scrubId = 0x05; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT; scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT; break; case 0x03: case 0x06: - scrubIdentity.scrubId = 0x06; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT; scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT; break; case 0x07: - scrubIdentity.scrubId = 0x07; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_RIGHT; scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT; break; case 0x08: - scrubIdentity.scrubId = 0x08; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_LEFT; scrubIdentity.randomizerCheck = RC_GANONS_CASTLE_DEKU_SCRUB_LEFT; break; } @@ -1705,7 +1704,7 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case 0xE6: // Hyrule Field Scrub Grotto switch (actorParams) { case 0x02: - scrubIdentity.scrubId = 0x09; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO; scrubIdentity.randomizerCheck = RC_HF_DEKU_SCRUB_GROTTO; scrubIdentity.isShuffled = true; break; @@ -1714,11 +1713,11 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case 0xEB: // ZR Scrub Grotto switch (actorParams) { case 0x07: - scrubIdentity.scrubId = 0x0A; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_REAR; scrubIdentity.randomizerCheck = RC_ZR_DEKU_SCRUB_GROTTO_REAR; break; case 0x08: - scrubIdentity.scrubId = 0x0B; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_FRONT; scrubIdentity.randomizerCheck = RC_ZR_DEKU_SCRUB_GROTTO_FRONT; break; } @@ -1726,11 +1725,11 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case 0xEE: // Sacred Forest Meadow Scrub Grotto switch (actorParams) { case 0x07: - scrubIdentity.scrubId = 0x0C; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_REAR; scrubIdentity.randomizerCheck = RC_SFM_DEKU_SCRUB_GROTTO_REAR; break; case 0x08: - scrubIdentity.scrubId = 0x0D; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_FRONT; scrubIdentity.randomizerCheck = RC_SFM_DEKU_SCRUB_GROTTO_FRONT; break; } @@ -1738,16 +1737,16 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case 0xEF: // Lake Hylia Scrub Grotto switch (actorParams) { case 0x00: - scrubIdentity.scrubId = 0x0E; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_LEFT; scrubIdentity.randomizerCheck = RC_LH_DEKU_SCRUB_GROTTO_LEFT; break; case 0x05: - scrubIdentity.scrubId = 0x0F; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_RIGHT; scrubIdentity.randomizerCheck = RC_LH_DEKU_SCRUB_GROTTO_RIGHT; break; case 0x03: case 0x06: - scrubIdentity.scrubId = 0x10; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_CENTER; scrubIdentity.randomizerCheck = RC_LH_DEKU_SCRUB_GROTTO_CENTER; break; } @@ -1755,11 +1754,11 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case 0xF0: // Gerudo Valley Scrub Grotto switch (actorParams) { case 0x07: - scrubIdentity.scrubId = 0x11; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_REAR; scrubIdentity.randomizerCheck = RC_GV_DEKU_SCRUB_GROTTO_REAR; break; case 0x08: - scrubIdentity.scrubId = 0x12; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_FRONT; scrubIdentity.randomizerCheck = RC_GV_DEKU_SCRUB_GROTTO_FRONT; break; } @@ -1768,11 +1767,11 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa switch (actorParams) { case 0x03: case 0x06: - scrubIdentity.scrubId = 0x13; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_REAR; scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_GROTTO_REAR; break; case 0x0A: - scrubIdentity.scrubId = 0x14; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_FRONT; scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_GROTTO_FRONT; scrubIdentity.isShuffled = true; break; @@ -1781,16 +1780,16 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case 0xF9: // Death Mountain Crater Scrub Grotto switch (actorParams) { case 0x00: - scrubIdentity.scrubId = 0x15; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_LEFT; scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB_GROTTO_LEFT; break; case 0x05: - scrubIdentity.scrubId = 0x16; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_RIGHT; scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB_GROTTO_RIGHT; break; case 0x03: case 0x06: - scrubIdentity.scrubId = 0x17; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_CENTER; scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB_GROTTO_CENTER; break; } @@ -1798,16 +1797,16 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case 0xFB: // Gerudo City Scrub Grotto switch (actorParams) { case 0x00: - scrubIdentity.scrubId = 0x18; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_LEFT; scrubIdentity.randomizerCheck = RC_GC_DEKU_SCRUB_GROTTO_LEFT; break; case 0x05: - scrubIdentity.scrubId = 0x19; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_RIGHT; scrubIdentity.randomizerCheck = RC_GC_DEKU_SCRUB_GROTTO_RIGHT; break; case 0x03: case 0x06: - scrubIdentity.scrubId = 0x1A; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_CENTER; scrubIdentity.randomizerCheck = RC_GC_DEKU_SCRUB_GROTTO_CENTER; break; } @@ -1815,16 +1814,16 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case 0xFC: // Lon Lon Ranch Scrub Grotto switch (actorParams) { case 0x00: - scrubIdentity.scrubId = 0x1B; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_LEFT; scrubIdentity.randomizerCheck = RC_LLR_DEKU_SCRUB_GROTTO_LEFT; break; case 0x05: - scrubIdentity.scrubId = 0x1C; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_RIGHT; scrubIdentity.randomizerCheck = RC_LLR_DEKU_SCRUB_GROTTO_RIGHT; break; case 0x03: case 0x06: - scrubIdentity.scrubId = 0x1D; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_CENTER; scrubIdentity.randomizerCheck = RC_LLR_DEKU_SCRUB_GROTTO_CENTER; break; } @@ -1832,11 +1831,11 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case 0xFD: // Desert Colossus Scrub Grotto switch (actorParams) { case 0x07: - scrubIdentity.scrubId = 0x1E; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_REAR; scrubIdentity.randomizerCheck = RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR; break; case 0x08: - scrubIdentity.scrubId = 0x1F; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT; scrubIdentity.randomizerCheck = RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT; break; } @@ -1846,15 +1845,15 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case SCENE_SPOT10: // Lost woods switch (actorParams) { case 0x00: - scrubIdentity.scrubId = 0x20; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT; scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT; break; case 0x01: - scrubIdentity.scrubId = 0x21; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT; scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT; break; case 0x09: - scrubIdentity.scrubId = 0x22; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_BRIDGE; scrubIdentity.randomizerCheck = RC_LW_DEKU_SCRUB_NEAR_BRIDGE; scrubIdentity.isShuffled = true; break; @@ -1863,15 +1862,15 @@ ScrubIdentity Randomizer::IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respa case SCENE_SPOT17: // Death Mountain Crater switch (actorParams) { case 0x05: - scrubIdentity.scrubId = 0x23; + scrubIdentity.randomizerInf = RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB; scrubIdentity.randomizerCheck = RC_DMC_DEKU_SCRUB; break; } break; } - if (scrubPrices.find(scrubIdentity.randomizerCheck) != scrubPrices.end()) { - scrubIdentity.itemPrice = scrubPrices[scrubIdentity.randomizerCheck]; + if (randomizerMerchantPrices.find(scrubIdentity.randomizerCheck) != randomizerMerchantPrices.end()) { + scrubIdentity.itemPrice = randomizerMerchantPrices[scrubIdentity.randomizerCheck]; } return scrubIdentity; @@ -3398,9 +3397,13 @@ void DrawRandoEditor(bool& open) { // Shuffle Scrubs ImGui::Text(Settings::Scrubsanity.GetName().c_str()); InsertHelpHoverText( - "Off - Scrubs will not be shuffled.\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 have random items.\n" "\n" "Affordable - Scrubs will be shuffled and their item will cost 10 rupees.\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" ); SohImGui::EnhancementCombobox("gRandomizeShuffleScrubs", randoShuffleScrubs, 4, 0); PaddedSeparator(); @@ -4019,6 +4022,8 @@ void CreateGetItemMessages(std::vector messageEntries) { } } +// Currently these are generated at runtime, one for each price between 0-95. We're soon going to migrate this +// to being generated at save load, with only messages specific to each scrub. void CreateScrubMessages() { CustomMessageManager* customMessageManager = CustomMessageManager::Instance; customMessageManager->AddCustomMessageTable(Randomizer::scrubMessageTableID); diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 209ced506c..c5df36e2c9 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -19,7 +19,7 @@ class Randomizer { std::string ganonHintText; std::string ganonText; std::unordered_map randoSettings; - std::unordered_map scrubPrices; + std::unordered_map randomizerMerchantPrices; s16 GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId); s16 GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId); void ParseRandomizerSettingsFile(const char* spoilerFileName); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 02adad1a58..0cbbb1eaf4 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -2,6 +2,7 @@ #include #include "z64item.h" +#include "randomizer_inf.h" // This should probably go in a less rando-specific location // but the best location will probably be in the modding engine @@ -1019,7 +1020,7 @@ typedef enum { } RandomizerSettingKey; typedef struct ScrubIdentity { - int32_t scrubId; + RandomizerInf randomizerInf; RandomizerCheck randomizerCheck; GetItemID getItemId; int32_t itemPrice; diff --git a/soh/soh/Enhancements/randomizer/randomizer_inf.h b/soh/soh/Enhancements/randomizer/randomizer_inf.h index e5f41a5d3d..c55e2d2ec0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_inf.h +++ b/soh/soh/Enhancements/randomizer/randomizer_inf.h @@ -29,6 +29,43 @@ typedef enum { RAND_INF_COWS_MILKED_JABU_JABUS_BELLY_MQ_COW, RAND_INF_COWS_MILKED_HF_COW_GROTTO_GOSSIP_STONE, + RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, + RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, + RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, + RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, + RAND_INF_SCRUBS_PURCHASED_JABU_JABUS_BELLY_DEKU_SCRUB, + RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, + RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, + RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_RIGHT, + RAND_INF_SCRUBS_PURCHASED_GANONS_CASTLE_DEKU_SCRUB_LEFT, + RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO, + RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_REAR, + RAND_INF_SCRUBS_PURCHASED_ZR_DEKU_SCRUB_GROTTO_FRONT, + RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_REAR, + RAND_INF_SCRUBS_PURCHASED_SFM_DEKU_SCRUB_GROTTO_FRONT, + RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_LEFT, + RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_RIGHT, + RAND_INF_SCRUBS_PURCHASED_LH_DEKU_SCRUB_GROTTO_CENTER, + RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_REAR, + RAND_INF_SCRUBS_PURCHASED_GV_DEKU_SCRUB_GROTTO_FRONT, + RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_REAR, + RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_GROTTO_FRONT, + RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_LEFT, + RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_RIGHT, + RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB_GROTTO_CENTER, + RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_LEFT, + RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_RIGHT, + RAND_INF_SCRUBS_PURCHASED_GC_DEKU_SCRUB_GROTTO_CENTER, + RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_LEFT, + RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_RIGHT, + RAND_INF_SCRUBS_PURCHASED_LLR_DEKU_SCRUB_GROTTO_CENTER, + RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_REAR, + RAND_INF_SCRUBS_PURCHASED_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, + RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, + RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, + RAND_INF_SCRUBS_PURCHASED_LW_DEKU_SCRUB_NEAR_BRIDGE, + RAND_INF_SCRUBS_PURCHASED_DMC_DEKU_SCRUB, + // If you add anything to this list, you need to update the size of randomizerInf in z64save.h to be ceil(RAND_INF_MAX / 16) RAND_INF_MAX, diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 092ad3eade..8d8e7cd77c 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -761,10 +761,6 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); }); - - SaveManager::Instance->LoadArray("scrubsPurchased", ARRAY_COUNT(gSaveContext.scrubsPurchased), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.scrubsPurchased[i]); - }); } void SaveManager::LoadBaseVersion2() { @@ -922,10 +918,6 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); }); - - SaveManager::Instance->LoadArray("scrubsPurchased", ARRAY_COUNT(gSaveContext.scrubsPurchased), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.scrubsPurchased[i]); - }); } void SaveManager::SaveBase() { @@ -1079,10 +1071,6 @@ void SaveManager::SaveBase() { SaveManager::Instance->SaveArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { SaveManager::Instance->SaveData("", gSaveContext.randomizerInf[i]); }); - - SaveManager::Instance->SaveArray("scrubsPurchased", ARRAY_COUNT(gSaveContext.scrubsPurchased), [](size_t i) { - SaveManager::Instance->SaveData("", gSaveContext.scrubsPurchased[i]); - }); } void SaveManager::SaveArray(const std::string& name, const size_t size, SaveArrayFunc func) { diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 270fd87a83..a5f35bcaa0 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -709,11 +709,6 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.randomizerInf[i] = 0; } - // Sets all scrubs to not purchased when generating a rando save. - for (u8 i = 0; i < NUM_SCRUBS; i++) { - gSaveContext.scrubsPurchased[i] = 0; - } - // Set Cutscene flags to skip them gSaveContext.eventChkInf[0xC] |= 0x10; // returned to tot with medallions gSaveContext.eventChkInf[0xC] |= 0x20; //sheik at tot pedestal diff --git a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c index d2c42794eb..5b6f097d01 100644 --- a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c +++ b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c @@ -181,6 +181,8 @@ void EnDns_Init(Actor* thisx, GlobalContext* globalCtx) { this->dnsItemEntry->purchaseableCheck = EnDns_RandomizerPurchaseableCheck; this->dnsItemEntry->setRupeesAndFlags = EnDns_RandomizerPurchase; this->dnsItemEntry->itemAmount = 1; + // Currently the textID is simply identified by the item price since that is the only thing + // unique to it, later on this will change to identifying by scrubIdentity.randomizerInf this->actor.textId = 0x9000 + this->dnsItemEntry->itemPrice; } } @@ -205,7 +207,7 @@ void EnDns_ChangeAnim(EnDns* this, u8 index) { /* Item give checking functions */ u32 EnDns_RandomizerPurchaseableCheck(EnDns* this) { - if (gSaveContext.rupees < this->dnsItemEntry->itemPrice || gSaveContext.scrubsPurchased[this->scrubIdentity.scrubId] == 1) { + if (gSaveContext.rupees < this->dnsItemEntry->itemPrice || Flags_GetRandomizerInf(this->scrubIdentity.randomizerInf)) { return 0; } return 4; @@ -309,7 +311,7 @@ u32 func_809EF9A4(EnDns* this) { /* Paying and flagging functions */ void EnDns_RandomizerPurchase(EnDns* this) { Rupees_ChangeBy(-this->dnsItemEntry->itemPrice); - gSaveContext.scrubsPurchased[this->scrubIdentity.scrubId] = 1; + Flags_SetRandomizerInf(this->scrubIdentity.randomizerInf); } void func_809EF9F8(EnDns* this) { @@ -514,6 +516,8 @@ void EnDns_Update(Actor* thisx, GlobalContext* globalCtx) { this->dustTimer++; this->actor.textId = D_809F040C[this->actor.params]; if (gSaveContext.n64ddFlag && this->scrubIdentity.isShuffled) { + // Currently the textID is simply identified by the item price since that is the only thing + // unique to it, later on this will change to identifying by scrubIdentity.randomizerInf this->actor.textId = 0x9000 + this->dnsItemEntry->itemPrice; } Actor_SetFocus(&this->actor, 60.0f); diff --git a/soh/src/overlays/actors/ovl_En_Shopnuts/z_en_shopnuts.c b/soh/src/overlays/actors/ovl_En_Shopnuts/z_en_shopnuts.c index 6655b3aea2..70a4c8e10f 100644 --- a/soh/src/overlays/actors/ovl_En_Shopnuts/z_en_shopnuts.c +++ b/soh/src/overlays/actors/ovl_En_Shopnuts/z_en_shopnuts.c @@ -73,7 +73,7 @@ void EnShopnuts_Init(Actor* thisx, GlobalContext* globalCtx) { s16 respawnData = gSaveContext.respawn[RESPAWN_MODE_RETURN].data & ((1 << 8) - 1); ScrubIdentity scrubIdentity = Randomizer_IdentifyScrub(globalCtx->sceneNum, this->actor.params, respawnData); - if (scrubIdentity.isShuffled && gSaveContext.scrubsPurchased[scrubIdentity.scrubId] == 1) { + if (scrubIdentity.isShuffled && Flags_GetRandomizerInf(scrubIdentity.randomizerInf)) { Actor_Kill(&this->actor); } } From c76ff719f47ff61bcbb01a1a28d96835d8b51138 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Thu, 25 Aug 2022 13:53:04 -0500 Subject: [PATCH 25/62] Fix issue in spoiler generation --- soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 98ce64ef1a..cc6f996f07 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -679,8 +679,10 @@ static void WriteAllLocations(int language) { case 0: default: location->GetPlacedItemName().english; + break; case 2: location->GetPlacedItemName().french; + break; } // Eventually check for other things here like fake name From dc9eeb18d95ab0a7625121103029787e1b9ca1b7 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Thu, 25 Aug 2022 15:38:41 -0500 Subject: [PATCH 26/62] Increase size of randomizerInf --- soh/include/z64save.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/include/z64save.h b/soh/include/z64save.h index 14da6a2fce..6ad6eeb170 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -183,7 +183,7 @@ typedef struct { char ganonHintText[150]; char ganonText[250]; u8 seedIcons[5]; - u16 randomizerInf[2]; + u16 randomizerInf[4]; u8 temporaryWeapon; u16 adultTradeItems; } SaveContext; // size = 0x1428 From 5043309c63f3d25afdf2e73951dfb0fe3e647da6 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 16:43:57 -0400 Subject: [PATCH 27/62] Adds basic german text for bean salesman --- soh/soh/Enhancements/randomizer/randomizer.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 72533c3c4f..2557d84a79 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3745,12 +3745,11 @@ void CreateScrubMessages() { { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, - "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " - "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " - "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "J'ai essayé d'être un vendeur de&%rharicots magiques%w, mais j'étais&mauvais au niveau du marketing et&ça me " - "courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&" + "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth " + "beans!^Anyway, want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "Möchten Sie einen geheimnisvollen& Gegenstand für 60 Rubine?\x1B&%gJa&Nein%w", + "J'ai essayé d'être un vendeur de&%rharicots magiques%w, mais j'étais&mauvais au niveau du marketing et&ça " + "me courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&" "%gobjet mystérieux%w pour 60 Rubis?\x1B&%gOui&Non%w", }); } From 0bcc5b13105a20e2518919a10bf4c0766f52f869 Mon Sep 17 00:00:00 2001 From: briaguya Date: Thu, 25 Aug 2022 17:27:37 -0400 Subject: [PATCH 28/62] no more blank spoilers --- .../randomizer/3drando/spoiler_log.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index cc6f996f07..b5aaf1aeb3 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -676,13 +676,13 @@ static void WriteAllLocations(int language) { std::string placedItemName; switch (language) { - case 0: - default: - location->GetPlacedItemName().english; - break; - case 2: - location->GetPlacedItemName().french; - break; + case 0: + default: + placedItemName = location->GetPlacedItemName().english; + break; + case 2: + placedItemName = location->GetPlacedItemName().french; + break; } // Eventually check for other things here like fake name From 866cb3166bff7b885d03d6da111b43ee12b9433a Mon Sep 17 00:00:00 2001 From: briaguya Date: Thu, 25 Aug 2022 17:28:46 -0400 Subject: [PATCH 29/62] formatting --- .../randomizer/3drando/spoiler_log.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index b5aaf1aeb3..597951f536 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -676,13 +676,13 @@ static void WriteAllLocations(int language) { std::string placedItemName; switch (language) { - case 0: - default: - placedItemName = location->GetPlacedItemName().english; - break; - case 2: - placedItemName = location->GetPlacedItemName().french; - break; + case 0: + default: + placedItemName = location->GetPlacedItemName().english; + break; + case 2: + placedItemName = location->GetPlacedItemName().french; + break; } // Eventually check for other things here like fake name From 0107699a6b307fbce3a81293fe7f6620cb5eb6c3 Mon Sep 17 00:00:00 2001 From: briaguya Date: Thu, 25 Aug 2022 17:29:09 -0400 Subject: [PATCH 30/62] more formatting --- soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 597951f536..48ed607d2b 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -678,11 +678,11 @@ static void WriteAllLocations(int language) { switch (language) { case 0: default: - placedItemName = location->GetPlacedItemName().english; - break; + placedItemName = location->GetPlacedItemName().english; + break; case 2: - placedItemName = location->GetPlacedItemName().french; - break; + placedItemName = location->GetPlacedItemName().french; + break; } // Eventually check for other things here like fake name From 71e7fb9d70cfe588de5bd2838e49d8d0c8fd32a2 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 18:02:00 -0400 Subject: [PATCH 31/62] Merge rando-next and rename scrub message table to merchant message table --- soh/soh/Enhancements/randomizer/randomizer.cpp | 14 +++++++------- soh/soh/Enhancements/randomizer/randomizer.h | 2 +- soh/soh/OTRGlobals.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index ac0072e3df..4fd2a123da 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -32,7 +32,7 @@ u8 generated; const std::string Randomizer::getItemMessageTableID = "Randomizer"; const std::string Randomizer::hintMessageTableID = "RandomizerHints"; -const std::string Randomizer::scrubMessageTableID = "RandomizerScrubs"; +const std::string Randomizer::merchantMessageTableID = "RandomizerScrubs"; const std::string Randomizer::rupeeMessageTableID = "RandomizerRupees"; const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi"; @@ -4030,10 +4030,10 @@ void CreateGetItemMessages(std::vector messageEntries) { // Currently these are generated at runtime, one for each price between 0-95. We're soon going to migrate this // to being generated at save load, with only messages specific to each scrub. -void CreateScrubMessages() { +void CreateMerchantMessages() { CustomMessageManager* customMessageManager = CustomMessageManager::Instance; - customMessageManager->AddCustomMessageTable(Randomizer::scrubMessageTableID); - customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, 0, + customMessageManager->AddCustomMessageTable(Randomizer::merchantMessageTableID); + customMessageManager->CreateMessage(Randomizer::merchantMessageTableID, 0, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, "\x12\x38\x82\All right! You win! In return for&sparing me, I will give you a&%gmysterious 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 %gmysteriösen&Gegenstand%w geben! Bitte nimm ihn!\x07\x10\xA3", @@ -4041,7 +4041,7 @@ void CreateScrubMessages() { }); for (u32 price = 5; price <= 95; price += 5) { - customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, price, + customMessageManager->CreateMessage(Randomizer::merchantMessageTableID, price, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, "\x12\x38\x82\All right! You win! In return for&sparing me, I will sell you a&%gmysterious item%w!&%r" + std::to_string(price) + " Rupees%w it is!\x07\x10\xA3", @@ -4053,7 +4053,7 @@ void CreateScrubMessages() { }); } customMessageManager->CreateMessage( - Randomizer::scrubMessageTableID, TEXT_BEAN_SALESMAN, + Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, @@ -4323,7 +4323,7 @@ void Randomizer::CreateCustomMessages() { "Vous avez un %rPack de&haricots magiques%w ! Trouvez&un endroit convenable pour un&jardin et plantez-les.^Ensuite, attendez quelque&chose d'amusant doit arriver !") }; CreateGetItemMessages(getItemMessages); - CreateScrubMessages(); + CreateMerchantMessages(); CreateRupeeMessages(); CreateNaviRandoMessages(); } diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index c5df36e2c9..8b467a699e 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -34,7 +34,7 @@ class Randomizer { static const std::string getItemMessageTableID; static const std::string hintMessageTableID; - static const std::string scrubMessageTableID; + static const std::string merchantMessageTableID; static const std::string rupeeMessageTableID; static const std::string NaviRandoMessageTableID; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index e55f4d9fa4..d6f20e9a45 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1583,7 +1583,7 @@ extern "C" ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, } extern "C" CustomMessageEntry Randomizer_GetScrubMessage(s16 itemPrice) { - return CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, itemPrice); + return CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, itemPrice); } extern "C" CustomMessageEntry Randomizer_GetNaviMessage() { @@ -1722,7 +1722,7 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { } else if (CVar_GetS32("gRandoRelevantNavi", 1) && textId >= 0x0140 && textId <= 0x015F) { messageEntry = Randomizer_GetNaviMessage(); } else if (Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS) && textId == TEXT_BEAN_SALESMAN) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, TEXT_BEAN_SALESMAN); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN); } } if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) { From 4a51ab31872468f0624ac56fad4d9c265e4a29ce Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 20:42:34 -0400 Subject: [PATCH 32/62] Fixes bug where Bean Pack was also granting blue potion --- soh/src/code/z_parameter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index be3bf82537..1c0a2db875 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2186,6 +2186,7 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { INV_CONTENT(ITEM_BEAN) = ITEM_BEAN; AMMO(ITEM_BEAN) = 10; } + return RG_NONE; } if (item == RG_DOUBLE_DEFENSE) { From 9148fa5aecac359d73df84875e0e93b6fd9208dd Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 20:48:28 -0400 Subject: [PATCH 33/62] Adds custom particles to Freestanding Bean Pack item. --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- soh/src/code/z_en_item00.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 4fd2a123da..b3120c3c2d 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -4059,7 +4059,7 @@ void CreateMerchantMessages() { TEXTBOX_POS_BOTTOM, "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth " "beans!^Anyway, want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "Möchten Sie einen geheimnisvollen& Gegenstand für 60 Rubine?\x1B&%gJa&Nein%w", + "Möchten Sie einen geheimnisvollen&Gegenstand für 60 Rubine?\x1B&%gJa&Nein%w", "J'ai essayé d'être un vendeur de&%rharicots magiques%w, mais j'étais&mauvais au niveau du marketing et&ça " "me courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&" "%gobjet mystérieux%w pour 60 Rubis?\x1B&%gOui&Non%w", diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index 89e1c9df7f..95375ea484 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -1290,6 +1290,7 @@ void EnItem00_CustomItemsParticles(Actor* Parent, GlobalContext* globalCtx, GetI switch (giEntry.itemId) { case RG_MAGIC_SINGLE: case RG_MAGIC_DOUBLE: + case RG_MAGIC_BEAN_PACK: color_slot = 0; break; case RG_DOUBLE_DEFENSE: From 53531c4481123e448f731f01d5152ac0bd5cf049 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Fri, 26 Aug 2022 01:17:51 -0400 Subject: [PATCH 34/62] Cleanup --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- soh/src/code/z_parameter.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index b3120c3c2d..2d7798e208 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -32,7 +32,7 @@ u8 generated; const std::string Randomizer::getItemMessageTableID = "Randomizer"; const std::string Randomizer::hintMessageTableID = "RandomizerHints"; -const std::string Randomizer::merchantMessageTableID = "RandomizerScrubs"; +const std::string Randomizer::merchantMessageTableID = "RandomizerMerchants"; const std::string Randomizer::rupeeMessageTableID = "RandomizerRupees"; const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi"; diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 1c0a2db875..73044df27e 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2182,7 +2182,7 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { } if (item == RG_MAGIC_BEAN_PACK) { - if (gSaveContext.inventory.items[SLOT(ITEM_BEAN)] == ITEM_NONE) { + if (INV_CONTENT(ITEM_BEAN) == ITEM_NONE) { INV_CONTENT(ITEM_BEAN) = ITEM_BEAN; AMMO(ITEM_BEAN) = 10; } From 83abf5776668a43d836fae1d0102a0bf32152f34 Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 26 Aug 2022 23:51:36 +0200 Subject: [PATCH 35/62] Add skull token to links pocket --- soh/src/code/z_sram.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index f351232299..92dd215c46 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -309,6 +309,11 @@ void GiveLinkDekuNutUpgrade(GetItemID giid) { } } +void GiveLinkSkullToken() { + gSaveContext.inventory.questItems |= gBitFlags[QUEST_SKULL_TOKEN]; + gSaveContext.inventory.gsTokens++; +} + void GiveLinkMagic(GetItemID giid) { if (giid == RG_MAGIC_SINGLE) { gSaveContext.magicLevel = 1; @@ -849,6 +854,8 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { GiveLinkDekuStickUpgrade(giid); } else if (giid == GI_NUT_UPGRADE_30 || giid == GI_NUT_UPGRADE_40) { GiveLinkDekuNutUpgrade(giid); + } else if (giid == GI_SKULL_TOKEN) { + GiveLinkSkullToken(); } else { s32 iid = getItem.itemId; if (iid != -1) INV_CONTENT(iid) = iid; From 9f47099232a810d30e39360f9ad08d2b23d18912 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Fri, 26 Aug 2022 21:17:12 -0400 Subject: [PATCH 36/62] Properly handles starting link with adult trade items. --- soh/src/code/z_sram.c | 50 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 92dd215c46..d53055c932 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -4,6 +4,7 @@ #include #include #include +#include "soh/Enhancements/randomizer/adult_trade_shuffle.h" #define NUM_DUNGEONS 8 #define NUM_TRIALS 6 @@ -513,6 +514,53 @@ void GiveLinkDungeonItem(GetItemID getItemId) { } } +void GiveLinkAdultTradeItem(GetItemID giid) { + ItemID item; + switch (giid) { + case GI_POCKET_EGG: + item = ITEM_POCKET_EGG; + break; + case GI_POCKET_CUCCO: + item = ITEM_POCKET_CUCCO; + break; + case GI_COJIRO: + item = ITEM_COJIRO; + break; + case GI_ODD_MUSHROOM: + item = ITEM_ODD_MUSHROOM; + break; + case GI_ODD_POTION: + item = ITEM_ODD_POTION; + break; + case GI_SAW: + item = ITEM_SAW; + break; + case GI_SWORD_BROKEN: + item = ITEM_SWORD_BROKEN; + break; + case GI_PRESCRIPTION: + item = ITEM_PRESCRIPTION; + break; + case GI_FROG: + item = ITEM_FROG; + break; + case GI_EYEDROPS: + item = ITEM_EYEDROPS; + break; + case GI_CLAIM_CHECK: + item = ITEM_CLAIM_CHECK; + break; + } + if ((item == ITEM_SAW) && CVar_GetS32("gDekuNutUpgradeFix", 0) == 0) { + gSaveContext.itemGetInf[1] |= 0x8000; + } + + if (item >= ITEM_POCKET_EGG) { + gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(item); + } + INV_CONTENT(item) = item; +} + void GiveLinksPocketMedallion() { GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_LINKS_POCKET, RG_NONE); @@ -856,6 +904,8 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { GiveLinkDekuNutUpgrade(giid); } else if (giid == GI_SKULL_TOKEN) { GiveLinkSkullToken(); + } else if (giid >= GI_POCKET_EGG && giid <= GI_CLAIM_CHECK) { + GiveLinkAdultTradeItem(giid); } else { s32 iid = getItem.itemId; if (iid != -1) INV_CONTENT(iid) = iid; From 62aeac51b9b9d86be0ab5cae1510cecadd0d92ff Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Fri, 26 Aug 2022 22:14:49 -0400 Subject: [PATCH 37/62] ACTUALLY fixes adult trade items on save init this time. --- soh/src/code/z_sram.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index d53055c932..4bbbe726a4 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -558,7 +558,7 @@ void GiveLinkAdultTradeItem(GetItemID giid) { if (item >= ITEM_POCKET_EGG) { gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(item); } - INV_CONTENT(item) = item; + INV_CONTENT(ITEM_TRADE_ADULT) = item; } void GiveLinksPocketMedallion() { @@ -788,6 +788,11 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.eventChkInf[3] |= 0x800; gSaveContext.eventChkInf[12] |= 1; + // shuffle adult trade quest + if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { + gSaveContext.adultTradeItems = 0; + } + // Give Link's pocket item GiveLinksPocketMedallion(); @@ -904,7 +909,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { GiveLinkDekuNutUpgrade(giid); } else if (giid == GI_SKULL_TOKEN) { GiveLinkSkullToken(); - } else if (giid >= GI_POCKET_EGG && giid <= GI_CLAIM_CHECK) { + } else if (giid >= GI_POCKET_EGG && giid <= GI_CLAIM_CHECK || giid == GI_COJIRO) { GiveLinkAdultTradeItem(giid); } else { s32 iid = getItem.itemId; @@ -1022,11 +1027,6 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { } } - // shuffle adult trade quest - if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { - gSaveContext.adultTradeItems = 0; - } - // complete mask quest if (Randomizer_GetSettingValue(RSK_COMPLETE_MASK_QUEST)) { gSaveContext.itemGetInf[3] |= 0x100; // Sold Keaton Mask From 7fbb381db74a0aa2405866b99f7daa31fae431a8 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 02:25:13 -0400 Subject: [PATCH 38/62] Changes Malon's behavior to so she won't leave Hyrule Castle until you've obtained her item. --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index 88c5b07245..5e6b363b5a 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -90,7 +90,16 @@ static void* sEyeTextures[] = { gMalonChildEyeClosedTex, }; +bool Randomizer_ObtainedMalonHCReward() { + return Flags_GetEventChkInf(0x12); +} + u16 EnMa1_GetText(GlobalContext* globalCtx, Actor* thisx) { + // Special case for Malon Hyrule Castle Text. Placing it here at the beginning + // has the added benefit of circumventing mask text if wearing bunny hood. + if (gSaveContext.n64ddFlag && globalCtx->sceneNum == SCENE_SPOT15) { + return Randomizer_ObtainedMalonHCReward() ? 0x2044 : 0x2043; + } u16 faceReaction = Text_GetFaceReaction(globalCtx, 0x17); if (faceReaction != 0) { @@ -195,7 +204,8 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { !(gSaveContext.eventChkInf[1] & 0x10) && !(gSaveContext.infTable[8] & 0x800)) { return 1; } - if ((globalCtx->sceneNum == SCENE_SPOT15) && !(gSaveContext.eventChkInf[1] & 0x10)) { + if ((globalCtx->sceneNum == SCENE_SPOT15) && (!(gSaveContext.eventChkInf[1] & 0x10) || + (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()))) { if (gSaveContext.infTable[8] & 0x800) { return 1; } else { @@ -209,7 +219,7 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { if (globalCtx->sceneNum != SCENE_SPOT20) { return 0; } - if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10)) { + if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10) && ((gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()) || !gSaveContext.n64ddFlag)) { return 1; } return 0; @@ -290,7 +300,7 @@ void EnMa1_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.targetMode = 6; this->unk_1E8.unk_00 = 0; - if (!(gSaveContext.eventChkInf[1] & 0x10) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || + if (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F))) { this->actionFunc = func_80AA0D88; EnMa1_ChangeAnim(this, ENMA1_ANIM_2); @@ -322,9 +332,11 @@ void func_80AA0D88(EnMa1* this, GlobalContext* globalCtx) { } } - if ((globalCtx->sceneNum == SCENE_SPOT15) && (gSaveContext.eventChkInf[1] & 0x10)) { - Actor_Kill(&this->actor); - } else if (!(gSaveContext.eventChkInf[1] & 0x10) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { + if ((globalCtx->sceneNum == SCENE_SPOT15) && (gSaveContext.eventChkInf[1] & 0x10) && (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward())) { + if (!gSaveContext.n64ddFlag) { + Actor_Kill(&this->actor); + } + } else if ((!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward())) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { if (this->unk_1E8.unk_00 == 2) { this->actionFunc = func_80AA0EA0; globalCtx->msgCtx.stateTimer = 4; From bf1b327a955faa356a56e7ae02db13bf386628c5 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 02:50:44 -0400 Subject: [PATCH 39/62] Cleanup and Documentation --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index 5e6b363b5a..d7dbea1f55 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -200,10 +200,14 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { if (!LINK_IS_CHILD) { return 0; } + // Causes Malon to appear in the market if you haven't met her yet. if (((globalCtx->sceneNum == SCENE_MARKET_NIGHT) || (globalCtx->sceneNum == SCENE_MARKET_DAY)) && !(gSaveContext.eventChkInf[1] & 0x10) && !(gSaveContext.infTable[8] & 0x800)) { return 1; } + // Causes Malon to appear at Hyrule Castle if you've met her already and either we're vanilla and Talon hasn't + // left Hyrule Castle, or if we're randomized and haven't obtained her check. If we haven't met Malon yet, this + // sets the flag for meeting her. if ((globalCtx->sceneNum == SCENE_SPOT15) && (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()))) { if (gSaveContext.infTable[8] & 0x800) { @@ -213,13 +217,18 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { return 0; } } + // Malon asleep in her bed if Talon has left Hyrule Castle and it is nighttime. if ((globalCtx->sceneNum == SCENE_SOUKO) && IS_NIGHT && (gSaveContext.eventChkInf[1] & 0x10)) { return 1; } + // Don't spawn Malon if none of the above are true and we are not in Lon Lon Ranch. if (globalCtx->sceneNum != SCENE_SPOT20) { return 0; } - if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10) && ((gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()) || !gSaveContext.n64ddFlag)) { + // If we've gotten this far, we're in Lon Lon Ranch. Spawn Malon if it is daytime, Talon has left Hyrule Castle, and + // either we are not randomized, or we are and we have received Malon's item at Hyrule Castle. + if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10) && + ((gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()) || !gSaveContext.n64ddFlag)) { return 1; } return 0; @@ -300,10 +309,14 @@ void EnMa1_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.targetMode = 6; this->unk_1E8.unk_00 = 0; + // If Talon has not left Hyrule Castle, we are randomized and ahve not obtained Malon's HC Check, we are not randomized + // and have Epona's Song, or we are randomized and have obtained Malon's Epona's Song Check. This sets Malon's idle + // singing animation in such a way that she has dialog but does not give items or respond to the Ocarina. if (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F))) { this->actionFunc = func_80AA0D88; EnMa1_ChangeAnim(this, ENMA1_ANIM_2); + // If none of the above conditions were true, set Malon up to teach Epona's Song. } else { if (gSaveContext.n64ddFlag) { // Skip straight to "let's sing it together" textbox in the ranch gSaveContext.eventChkInf[1] |= 0x40; @@ -332,10 +345,15 @@ void func_80AA0D88(EnMa1* this, GlobalContext* globalCtx) { } } - if ((globalCtx->sceneNum == SCENE_SPOT15) && (gSaveContext.eventChkInf[1] & 0x10) && (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward())) { + // If we're at Hyrule Castle, and either Talon has left or we're randomized and have obtained Malon's HC Check + if ((globalCtx->sceneNum == SCENE_SPOT15) && ((!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()))) { + // Only kill Malon's Actor here in vanilla. If we're in rando and speak to her we don't want her to pop + // out of existence immediately. The init function will properly kill her actor on the next scene load. if (!gSaveContext.n64ddFlag) { Actor_Kill(&this->actor); } + // If Talon has not run away, or we're randomized and have not received Malon's HC Check, or we're + // not randomized and have obtained Epona's Song, put Malon in the state to give Link the HC reward. } else if ((!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward())) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { if (this->unk_1E8.unk_00 == 2) { this->actionFunc = func_80AA0EA0; From 928a39fe9e21f43a2e322a9cdf06bed98c04b6fe Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 09:30:49 -0400 Subject: [PATCH 40/62] More Cleanup --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index d7dbea1f55..eaf4b14192 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -309,9 +309,11 @@ void EnMa1_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.targetMode = 6; this->unk_1E8.unk_00 = 0; - // If Talon has not left Hyrule Castle, we are randomized and ahve not obtained Malon's HC Check, we are not randomized - // and have Epona's Song, or we are randomized and have obtained Malon's Epona's Song Check. This sets Malon's idle - // singing animation in such a way that she has dialog but does not give items or respond to the Ocarina. + // To avoid missing a check, we want Malon to have the actionFunc for singing, but not reacting to Ocarina, if any of + // the following are true. + // 1. Talon has not left Hyrule Castle. + // 2. We are Randomized and have not obtained Malon's Weird Egg Check. + // 3. We are not Randomized and have obtained Epona's Song if (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F))) { this->actionFunc = func_80AA0D88; @@ -345,15 +347,15 @@ void func_80AA0D88(EnMa1* this, GlobalContext* globalCtx) { } } - // If we're at Hyrule Castle, and either Talon has left or we're randomized and have obtained Malon's HC Check - if ((globalCtx->sceneNum == SCENE_SPOT15) && ((!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()))) { - // Only kill Malon's Actor here in vanilla. If we're in rando and speak to her we don't want her to pop - // out of existence immediately. The init function will properly kill her actor on the next scene load. - if (!gSaveContext.n64ddFlag) { - Actor_Kill(&this->actor); - } - // If Talon has not run away, or we're randomized and have not received Malon's HC Check, or we're - // not randomized and have obtained Epona's Song, put Malon in the state to give Link the HC reward. + // We want to Kill Malon's Actor outside of randomizer when Talon is freed. In Randomizer we don't kill Malon's + // Actor here, otherwise if we wake up Talon first and then get her check she will spontaneously + // disappear. + if ((globalCtx->sceneNum == SCENE_SPOT15) && (!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[1] & 0x10)) { + Actor_Kill(&this->actor); + // We want Malon to give the Weird Egg Check (see function below) in the following situations: + // 1. Talon as not left Hyrule Castle (Vanilla) OR + // 2. We haven't obtained Malon's Weird Egg Check (Randomizer only) OR + // 3. We have Epona's Song? (Vanilla only, not sure why it's here but I didn't write that one) } else if ((!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward())) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { if (this->unk_1E8.unk_00 == 2) { this->actionFunc = func_80AA0EA0; From 1bf8423f75bd0b7abe77787831c1863b08105e6b Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 14:19:37 -0400 Subject: [PATCH 41/62] Reimplements selecting different amounts of Ganon's Trials. --- soh/include/functions.h | 1 + soh/include/macros.h | 1 + .../randomizer/3drando/settings.cpp | 18 +++--- .../randomizer/3drando/spoiler_log.cpp | 59 ++++++++++++------- .../Enhancements/randomizer/randomizer.cpp | 56 +++++++++++++++--- soh/soh/Enhancements/randomizer/randomizer.h | 6 +- soh/soh/OTRGlobals.cpp | 8 +++ soh/soh/OTRGlobals.h | 2 + soh/src/code/z_actor.c | 4 ++ soh/src/code/z_sram.c | 10 +++- .../actors/ovl_Demo_Kekkai/z_demo_kekkai.c | 28 ++++++++- .../ovl_Object_Kankyo/z_object_kankyo.c | 21 +++++++ .../ovl_file_choose/z_file_choose.c | 1 + 13 files changed, 174 insertions(+), 41 deletions(-) diff --git a/soh/include/functions.h b/soh/include/functions.h index 9047b6d3f2..7d8b309a58 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -561,6 +561,7 @@ s32 Flags_GetInfTable(s32 flag); void Flags_SetInfTable(s32 flag); s32 Flags_GetRandomizerInf(RandomizerInf flag); void Flags_SetRandomizerInf(RandomizerInf flag); +void Flags_UnsetRandomizerInf(RandomizerInf flag); u16 func_80037C30(GlobalContext* globalCtx, s16 arg1); s32 func_80037D98(GlobalContext* globalCtx, Actor* actor, s16 arg2, s32* arg3); s32 func_80038290(GlobalContext* globalCtx, Actor* actor, Vec3s* arg2, Vec3s* arg3, Vec3f arg4); diff --git a/soh/include/macros.h b/soh/include/macros.h index 1822cb1d69..bcfb3fce5f 100644 --- a/soh/include/macros.h +++ b/soh/include/macros.h @@ -260,5 +260,6 @@ extern GraphicsContext* __gfxCtx; #define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1) +#define NUM_TRIALS 6 #endif diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index fc02dfd6a4..9e496598e0 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2519,15 +2519,15 @@ namespace Settings { BridgeTokenCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_TOKEN_COUNT]); RandomGanonsTrials.SetSelectedIndex(cvarSettings[RSK_RANDOM_TRIALS]); // RANDTODO: Switch this back once Ganon's Trials Count is properly implemented. - //GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); - switch (cvarSettings[RSK_TRIAL_COUNT]) { - case 0: - GanonsTrialsCount.SetSelectedIndex(6); - break; - case 1: - GanonsTrialsCount.SetSelectedIndex(0); - break; - } + GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); + // switch (cvarSettings[RSK_TRIAL_COUNT]) { + // case 0: + // GanonsTrialsCount.SetSelectedIndex(6); + // break; + // case 1: + // GanonsTrialsCount.SetSelectedIndex(0); + // break; + // } ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]); ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]); diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 48ed607d2b..332fbb9e16 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -501,27 +501,46 @@ static void WriteMasterQuestDungeons(tinyxml2::XMLDocument& spoilerLog) { } } -// Writes the required trails to the spoiler log, if there are any. -static void WriteRequiredTrials(tinyxml2::XMLDocument& spoilerLog) { - auto parentNode = spoilerLog.NewElement("required-trials"); - - for (const auto* trial : Trial::trialList) { - if (trial->IsSkipped()) { - continue; +// Writes the required trials to the spoiler log, if there are any. +static void WriteRequiredTrials() { + for (const auto& trial : Trial::trialList) { + if (trial->IsRequired()) { + std::string trialName; + switch (gSaveContext.language) { + case LANGUAGE_FRA: + trialName = trial->GetName().GetFrench(); + break; + case LANGUAGE_ENG: + default: + trialName = trial->GetName().GetEnglish(); + break; + } + jsonData["requiredTrials"].push_back(RemoveLineBreaks(trialName)); + } } - - auto node = parentNode->InsertNewChildElement("trial"); - // PURPLE TODO: LOCALIZATION - std::string name = trial->GetName().GetEnglish(); - name[0] = toupper(name[0]); // Capitalize T in "The" - node->SetAttribute("name", name.c_str()); - } - - if (!parentNode->NoChildren()) { - spoilerLog.RootElement()->InsertEndChild(parentNode); - } } +// Writes the required trails to the spoiler log, if there are any. +// static void WriteRequiredTrials(tinyxml2::XMLDocument& spoilerLog) { +// auto parentNode = spoilerLog.NewElement("required-trials"); + +// for (const auto* trial : Trial::trialList) { +// if (trial->IsSkipped()) { +// continue; +// } + +// auto node = parentNode->InsertNewChildElement("trial"); +// // PURPLE TODO: LOCALIZATION +// std::string name = trial->GetName().GetEnglish(); +// name[0] = toupper(name[0]); // Capitalize T in "The" +// node->SetAttribute("name", name.c_str()); +// } + +// if (!parentNode->NoChildren()) { +// spoilerLog.RootElement()->InsertEndChild(parentNode); +// } +// } + // Writes the intended playthrough to the spoiler log, separated into spheres. static void WritePlaythrough() { // auto playthroughNode = spoilerLog.NewElement("playthrough"); @@ -723,7 +742,7 @@ const char* SpoilerLog_Write(int language) { // WriteEnabledGlitches(spoilerLog); //} //WriteMasterQuestDungeons(spoilerLog); - //WriteRequiredTrials(spoilerLog); + WriteRequiredTrials(); WritePlaythrough(); //WriteWayOfTheHeroLocation(spoilerLog); @@ -773,7 +792,7 @@ bool PlacementLog_Write() { WriteEnabledTricks(placementLog); WriteEnabledGlitches(placementLog); WriteMasterQuestDungeons(placementLog); - WriteRequiredTrials(placementLog); + //WriteRequiredTrials(placementLog); placementtxt = "\n" + placementtxt; diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 2d7798e208..6dff5a627f 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -107,6 +107,21 @@ Randomizer::~Randomizer() { this->randomizerMerchantPrices.clear(); } +std::unordered_map spoilerFileTrialToEnum = { + { "the Forest Trial", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, + { "l'épreuve de la forêt", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, + { "the Fire Trial", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, + { "l'épreuve du feu", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, + { "the Water Trial", RAND_INF_TRIALS_DONE_WATER_TRIAL }, + { "l'épreuve de l'eau", RAND_INF_TRIALS_DONE_WATER_TRIAL }, + { "the Spirit Trial", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, + { "l'épreuve de l'esprit", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, + { "the Shadow Trial", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, + { "l'épreuve de l'ombre", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, + { "the Light Trial", RAND_INF_TRIALS_DONE_LIGHT_TRIAL }, + { "l'épreuve de la lumière", RAND_INF_TRIALS_DONE_LIGHT_TRIAL } +}; + std::unordered_map getItemIdToItemId = { { GI_BOW, ITEM_BOW }, { GI_ARROW_FIRE, ITEM_ARROW_FIRE }, @@ -673,6 +688,12 @@ void Randomizer::LoadItemLocations(const char* spoilerFileName, bool silent) { itemLocations[RC_UNKNOWN_CHECK] = RG_NONE; } +void Randomizer::LoadRequiredTrials(const char* spoilerFileName) { + if (strcmp(spoilerFileName, "") != 0) { + ParseRequiredTrialsFile(spoilerFileName); + } +} + void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { std::ifstream spoilerFileStream(sanitize(spoilerFileName)); if (!spoilerFileStream) @@ -1091,6 +1112,25 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { } } +void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) { + std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + if (!spoilerFileStream) { + return; + } + + try { + json spoilerFileJson; + spoilerFileStream >> spoilerFileJson; + json trialsJson = spoilerFileJson["requiredTrials"]; + + for (auto it = trialsJson.begin(); it != trialsJson.end(); it++) { + this->trialsRequired[spoilerFileTrialToEnum[it.value()]] = true; + } + } catch (const std::exception& e) { + return; + } +} + void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent) { std::ifstream spoilerFileStream(sanitize(spoilerFileName)); if (!spoilerFileStream) @@ -1141,6 +1181,10 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent } } +bool Randomizer::IsTrialRequired(RandomizerInf trial) { + return this->trialsRequired.contains(trial); +} + s16 Randomizer::GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) { s16 itemId = GetItemFromActor(actorId, actorParams, sceneNum, ogId); return itemId; @@ -3355,21 +3399,17 @@ void DrawRandoEditor(bool& open) { PaddedSeparator(); // Random Ganon's Trials - /* ImGui::Text("Random Ganon's Trials"); + SohImGui::EnhancementCheckbox("Random Ganon's Trials", "gRandomizeGanonTrial"); InsertHelpHoverText("Sets a random number or required trials to enter\nGanon's Tower."); - SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 2, 0); if (CVar_GetS32("gRandomizeGanonTrial", 0) == 0) { - ImGui::PopItemWidth(); SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 0, 6, "", 6); InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); - RANDTODO: Switch back to slider when pre-completing some of Ganon's Trials is properly implemnted. } - */ - SohImGui::EnhancementCheckbox("Skip Ganon's Trials", "gRandomizeGanonTrialCount"); - InsertHelpHoverText( - "Sets whether or not Ganon's Castle Trials are required to enter Ganon's Tower."); + // SohImGui::EnhancementCheckbox("Skip Ganon's Trials", "gRandomizeGanonTrialCount"); + // InsertHelpHoverText( + // "Sets whether or not Ganon's Castle Trials are required to enter Ganon's Tower."); } // COLUMN 2 - Shuffle Settings diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 8b467a699e..2c87a5b036 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -14,6 +14,7 @@ class Randomizer { private: std::unordered_map itemLocations; std::unordered_map hintLocations; + std::unordered_map trialsRequired; std::string childAltarText; std::string adultAltarText; std::string ganonHintText; @@ -24,6 +25,7 @@ class Randomizer { s16 GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId); void ParseRandomizerSettingsFile(const char* spoilerFileName); void ParseHintLocationsFile(const char* spoilerFileName); + void ParseRequiredTrialsFile(const char* spoilerFileName); void ParseItemLocationsFile(const char* spoilerFileName, bool silent); bool IsItemVanilla(RandomizerGet randoGet); @@ -44,7 +46,9 @@ class Randomizer { bool SpoilerFileExists(const char* spoilerFileName); void LoadRandomizerSettings(const char* spoilerFileName); void LoadHintLocations(const char* spoilerFileName); - void LoadItemLocations(const char* spoilerFileName, bool silent); + void LoadRequiredTrials(const char* spoilerFileName); + void LoadItemLocations(const char* spoilerFileName,bool silent); + bool IsTrialRequired(RandomizerInf trial); u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey); RandomizerCheck GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams); std::string GetChildAltarText() const; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index d6f20e9a45..7d7a86268f 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1562,10 +1562,18 @@ extern "C" void Randomizer_LoadHintLocations(const char* spoilerFileName) { OTRGlobals::Instance->gRandomizer->LoadHintLocations(spoilerFileName); } +extern "C" void Randomizer_LoadRequiredTrials(const char* spoilerFileName) { + OTRGlobals::Instance->gRandomizer->LoadRequiredTrials(spoilerFileName); +} + extern "C" void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent) { OTRGlobals::Instance->gRandomizer->LoadItemLocations(spoilerFileName, silent); } +extern "C" bool Randomizer_IsTrialRequired(RandomizerInf trial) { + return OTRGlobals::Instance->gRandomizer->IsTrialRequired(trial); +} + extern "C" bool SpoilerFileExists(const char* spoilerFileName) { return OTRGlobals::Instance->gRandomizer->SpoilerFileExists(spoilerFileName); } diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 3266b16ebf..f81afdaeac 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -98,7 +98,9 @@ u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum); ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); void Randomizer_LoadHintLocations(const char* spoilerFileName); +void Randomizer_LoadRequiredTrials(const char* spoilerFileName); void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent); +bool Randomizer_IsTrialRequired(RandomizerInf trial); GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 5d7add53a8..0f4808494c 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -4719,6 +4719,10 @@ void Flags_SetRandomizerInf(RandomizerInf flag) { gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); } +void Flags_UnsetRandomizerInf(RandomizerInf flag) { + gSaveContext.randomizerInf[flag >> 4] &= ~(flag & 0xF); +} + u32 func_80035BFC(GlobalContext* globalCtx, s16 arg1) { u16 retTextId = 0; diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 4bbbe726a4..c8befa586a 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -7,7 +7,6 @@ #include "soh/Enhancements/randomizer/adult_trade_shuffle.h" #define NUM_DUNGEONS 8 -#define NUM_TRIALS 6 #define NUM_COWS 10 #define NUM_SCRUBS 35 @@ -762,6 +761,15 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.randomizerInf[i] = 0; } + // Set all trials to cleared if trial count is random or anything other than 6 + if (Randomizer_GetSettingValue(RSK_RANDOM_TRIALS) || (Randomizer_GetSettingValue(RSK_TRIAL_COUNT) != 6)) { + for (u16 i = RAND_INF_TRIALS_DONE_LIGHT_TRIAL; i <= RAND_INF_TRIALS_DONE_SHADOW_TRIAL; i++) { + if (!Randomizer_IsTrialRequired(i)) { + Flags_SetRandomizerInf(i); + } + } + } + // Set Cutscene flags to skip them gSaveContext.eventChkInf[0xC] |= 0x10; // returned to tot with medallions gSaveContext.eventChkInf[0xC] |= 0x20; //sheik at tot pedestal diff --git a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c index adc534a2d4..dab59262c6 100644 --- a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c +++ b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c @@ -64,12 +64,33 @@ static u8 sEnergyColors[] = { /* Forest prim */ 255, 255, 170, /* env */ 0, 200, 0, }; +// Translates from the barrier's actor params to their corresponding randInf flags. +RandomizerInf trialParamToRandInf(u16 params) { + switch (params) { + case KEKKAI_LIGHT: + return RAND_INF_TRIALS_DONE_LIGHT_TRIAL; + case KEKKAI_FOREST: + return RAND_INF_TRIALS_DONE_FOREST_TRIAL; + case KEKKAI_FIRE: + return RAND_INF_TRIALS_DONE_FIRE_TRIAL; + case KEKKAI_WATER: + return RAND_INF_TRIALS_DONE_WATER_TRIAL; + case KEKKAI_SPIRIT: + return RAND_INF_TRIALS_DONE_SPIRIT_TRIAL; + case KEKKAI_SHADOW: + return RAND_INF_TRIALS_DONE_SHADOW_TRIAL; + } +} + s32 DemoKekkai_CheckEventFlag(s32 params) { static s32 eventFlags[] = { 0xC3, 0xBC, 0xBF, 0xBE, 0xBD, 0xAD, 0xBB }; if ((params < KEKKAI_TOWER) || (params > KEKKAI_FOREST)) { return true; } + if (gSaveContext.n64ddFlag) { + return Flags_GetRandomizerInf(trialParamToRandInf(params)); + } return Flags_GetEventChkInf(eventFlags[params]); } @@ -128,8 +149,7 @@ void DemoKekkai_Init(Actor* thisx, GlobalContext* globalCtx) { this->collider2.dim.yShift = 300; if (gSaveContext.n64ddFlag) { - int trialsToComplete = Randomizer_GetSettingValue(RSK_TRIAL_COUNT); - if (trialsToComplete <= TrialsDoneCount()) { + if (TrialsDoneCount() == NUM_TRIALS) { Actor_Kill(thisx); return; } @@ -141,6 +161,10 @@ void DemoKekkai_Init(Actor* thisx, GlobalContext* globalCtx) { case KEKKAI_SHADOW: case KEKKAI_SPIRIT: case KEKKAI_FOREST: + if (gSaveContext.n64ddFlag && Flags_GetRandomizerInf(trialParamToRandInf(thisx->params))) { + Actor_Kill(thisx); + return; + } this->energyAlpha = 1.0f; this->orbScale = 1.0f; Actor_SetScale(thisx, 0.1f); diff --git a/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c b/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c index 22b7969644..6aff361444 100644 --- a/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c +++ b/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c @@ -135,6 +135,27 @@ void ObjectKankyo_Init(Actor* thisx, GlobalContext* globalCtx) { this->effects[5].size = 0.0f; } + if (gSaveContext.n64ddFlag) { + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_FOREST_TRIAL)) { + this->effects[0].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_WATER_TRIAL)) { + this->effects[1].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_SHADOW_TRIAL)) { + this->effects[2].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_FIRE_TRIAL)) { + this->effects[3].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_LIGHT_TRIAL)) { + this->effects[4].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_SPIRIT_TRIAL)) { + this->effects[5].size = 0.0f; + } + } + if (gSaveContext.cutsceneTrigger != 0) { if (gSaveContext.entranceIndex == 0x0538) { this->effects[0].size = 0.1f; diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 75cc7ca27b..f363751ee2 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -433,6 +433,7 @@ void FileChoose_UpdateMainMenu(GameState* thisx) { const char* fileLoc = CVar_GetString("gSpoilerLog", ""); Randomizer_LoadSettings(fileLoc); Randomizer_LoadHintLocations(fileLoc); + Randomizer_LoadRequiredTrials(fileLoc); Randomizer_LoadItemLocations(fileLoc, silent); fileSelectSpoilerFileLoaded = true; } From ff0ef4a6b472e9e11692b03cb24073826f27fab0 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 14:27:02 -0400 Subject: [PATCH 42/62] ImGui/Commented out code cleanup. --- soh/soh/Enhancements/randomizer/3drando/settings.cpp | 10 ---------- soh/soh/Enhancements/randomizer/randomizer.cpp | 6 +----- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 9e496598e0..cb9820cec0 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2518,17 +2518,7 @@ namespace Settings { BridgeDungeonCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_DUNGEON_COUNT]); BridgeTokenCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_TOKEN_COUNT]); RandomGanonsTrials.SetSelectedIndex(cvarSettings[RSK_RANDOM_TRIALS]); - // RANDTODO: Switch this back once Ganon's Trials Count is properly implemented. GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); - // switch (cvarSettings[RSK_TRIAL_COUNT]) { - // case 0: - // GanonsTrialsCount.SetSelectedIndex(6); - // break; - // case 1: - // GanonsTrialsCount.SetSelectedIndex(0); - // break; - // } - ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]); ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]); Tokensanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_TOKENS]); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 6dff5a627f..11335d2757 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3399,17 +3399,13 @@ void DrawRandoEditor(bool& open) { PaddedSeparator(); // Random Ganon's Trials - ImGui::Text("Random Ganon's Trials"); SohImGui::EnhancementCheckbox("Random Ganon's Trials", "gRandomizeGanonTrial"); - InsertHelpHoverText("Sets a random number or required trials to enter\nGanon's Tower."); + InsertHelpHoverText("Sets a random number or required trials to enter Ganon's Tower."); if (CVar_GetS32("gRandomizeGanonTrial", 0) == 0) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 0, 6, "", 6); InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); } - // SohImGui::EnhancementCheckbox("Skip Ganon's Trials", "gRandomizeGanonTrialCount"); - // InsertHelpHoverText( - // "Sets whether or not Ganon's Castle Trials are required to enter Ganon's Tower."); } // COLUMN 2 - Shuffle Settings From 3d8b8066dadd584de71d17ba017ed6989d00041f Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 14:33:38 -0400 Subject: [PATCH 43/62] More comment cleanup --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index eaf4b14192..c2a19e6217 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -205,16 +205,15 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { !(gSaveContext.eventChkInf[1] & 0x10) && !(gSaveContext.infTable[8] & 0x800)) { return 1; } - // Causes Malon to appear at Hyrule Castle if you've met her already and either we're vanilla and Talon hasn't - // left Hyrule Castle, or if we're randomized and haven't obtained her check. If we haven't met Malon yet, this - // sets the flag for meeting her. - if ((globalCtx->sceneNum == SCENE_SPOT15) && (!(gSaveContext.eventChkInf[1] & 0x10) || - (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()))) { - if (gSaveContext.infTable[8] & 0x800) { - return 1; - } else { - gSaveContext.infTable[8] |= 0x800; - return 0; + if ((globalCtx->sceneNum == SCENE_SPOT15) && // if we're at hyrule castle + (!(gSaveContext.eventChkInf[1] & 0x10) || // and talon hasn't left + (gSaveContext.n64ddFlag && + !Randomizer_ObtainedMalonHCReward()))) { // or we're rando'd and haven't gotten malon's HC check + if (gSaveContext.infTable[8] & 0x800) { // if we've met malon + return 1; // make her appear at the castle + } else { // if we haven't met malon + gSaveContext.infTable[8] |= 0x800; // set the flag for meeting malon + return 0; // don't make her appear at the castle } } // Malon asleep in her bed if Talon has left Hyrule Castle and it is nighttime. From 4d8bfa97c0914d79c0b3e5bc8916aa6ff8656a2e Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 15:51:14 -0400 Subject: [PATCH 44/62] UI Changes (dropdown and slider rather than checkbox and slider) --- .../Enhancements/randomizer/3drando/settings.cpp | 12 ++++++++++-- soh/soh/Enhancements/randomizer/randomizer.cpp | 16 +++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index cb9820cec0..cb91e53341 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2517,8 +2517,16 @@ namespace Settings { BridgeRewardCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_REWARD_COUNT]); BridgeDungeonCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_DUNGEON_COUNT]); BridgeTokenCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_TOKEN_COUNT]); - RandomGanonsTrials.SetSelectedIndex(cvarSettings[RSK_RANDOM_TRIALS]); - GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); + if (cvarSettings[RSK_RANDOM_TRIALS] == 2) { + RandomGanonsTrials.SetSelectedIndex(1); + } else { + RandomGanonsTrials.SetSelectedIndex(0); + } + if (cvarSettings[RSK_RANDOM_TRIALS] == 0) { + GanonsTrialsCount.SetSelectedIndex(0); + } else { + GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); + } ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]); ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]); Tokensanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_TOKENS]); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 11335d2757..af83fe8e4f 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3025,7 +3025,7 @@ void DrawRandoEditor(bool& open) { const char* randoGerudoFortress[3] = { "Normal", "Fast", "Open" }; const char* randoRainbowBridge[7] = { "Vanilla", "Always open", "Stones", "Medallions", "Dungeon rewards", "Dungeons", "Tokens" }; - const char* randoGanonsTrial[2] = { "Off", "On" }; + const char* randoGanonsTrial[3] = { "Skip", "Set Number", "Random Number" }; // World Settings const char* randoStartingAge[3] = { "Child", "Adult", "Random" }; @@ -3399,12 +3399,18 @@ void DrawRandoEditor(bool& open) { PaddedSeparator(); // Random Ganon's Trials - SohImGui::EnhancementCheckbox("Random Ganon's Trials", "gRandomizeGanonTrial"); - InsertHelpHoverText("Sets a random number or required trials to enter Ganon's Tower."); - if (CVar_GetS32("gRandomizeGanonTrial", 0) == 0) { + ImGui::Text("Ganon's Trials"); + InsertHelpHoverText("Sets the number of Ganon's Trials required to dispel the barrier\n\n" + "Skip - No Trials are required and the barrier is already dispelled.\n\n" + "Set Number - Select a number of trials that will be required from the" + "slider below. Which specific trials you need to complete will be random.\n\n" + "Random Number - A Random number and set of trials will be required."); + SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 3, 0); + if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 0, 6, "", 6); - InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); + InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower." + "The specific trials you need to complete will be randomly selected."); } } From dbd8909d2634d73e8da63d0ecb51ec4c3fa8b510 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 15:53:57 -0400 Subject: [PATCH 45/62] Forgot to limit slider from 1-6 rather than 0-6 --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index af83fe8e4f..4dea6642cb 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3408,7 +3408,7 @@ void DrawRandoEditor(bool& open) { SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 3, 0); if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", - "gRandomizeGanonTrialCount", 0, 6, "", 6); + "gRandomizeGanonTrialCount", 1, 6, "", 6); InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower." "The specific trials you need to complete will be randomly selected."); } From 404a637ebd2df655dd0d052ee4f419d23fa3f800 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 15:56:11 -0400 Subject: [PATCH 46/62] Removes added function that went unused. --- soh/include/functions.h | 1 - soh/src/code/z_actor.c | 4 ---- 2 files changed, 5 deletions(-) diff --git a/soh/include/functions.h b/soh/include/functions.h index 7d8b309a58..9047b6d3f2 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -561,7 +561,6 @@ s32 Flags_GetInfTable(s32 flag); void Flags_SetInfTable(s32 flag); s32 Flags_GetRandomizerInf(RandomizerInf flag); void Flags_SetRandomizerInf(RandomizerInf flag); -void Flags_UnsetRandomizerInf(RandomizerInf flag); u16 func_80037C30(GlobalContext* globalCtx, s16 arg1); s32 func_80037D98(GlobalContext* globalCtx, Actor* actor, s16 arg2, s32* arg3); s32 func_80038290(GlobalContext* globalCtx, Actor* actor, Vec3s* arg2, Vec3s* arg3, Vec3f arg4); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 0f4808494c..5d7add53a8 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -4719,10 +4719,6 @@ void Flags_SetRandomizerInf(RandomizerInf flag) { gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); } -void Flags_UnsetRandomizerInf(RandomizerInf flag) { - gSaveContext.randomizerInf[flag >> 4] &= ~(flag & 0xF); -} - u32 func_80035BFC(GlobalContext* globalCtx, s16 arg1) { u16 retTextId = 0; From 6aaef2179bbe26485973ab6552a9b22e514f12c6 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 18:26:25 -0400 Subject: [PATCH 47/62] More Cleanup --- .../randomizer/3drando/spoiler_log.cpp | 21 ------------------- .../Enhancements/randomizer/randomizer.cpp | 3 +-- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 332fbb9e16..63230c2d1d 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -520,27 +520,6 @@ static void WriteRequiredTrials() { } } -// Writes the required trails to the spoiler log, if there are any. -// static void WriteRequiredTrials(tinyxml2::XMLDocument& spoilerLog) { -// auto parentNode = spoilerLog.NewElement("required-trials"); - -// for (const auto* trial : Trial::trialList) { -// if (trial->IsSkipped()) { -// continue; -// } - -// auto node = parentNode->InsertNewChildElement("trial"); -// // PURPLE TODO: LOCALIZATION -// std::string name = trial->GetName().GetEnglish(); -// name[0] = toupper(name[0]); // Capitalize T in "The" -// node->SetAttribute("name", name.c_str()); -// } - -// if (!parentNode->NoChildren()) { -// spoilerLog.RootElement()->InsertEndChild(parentNode); -// } -// } - // Writes the intended playthrough to the spoiler log, separated into spheres. static void WritePlaythrough() { // auto playthroughNode = spoilerLog.NewElement("playthrough"); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 4dea6642cb..a433f0b3cf 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3409,8 +3409,7 @@ void DrawRandoEditor(bool& open) { if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 1, 6, "", 6); - InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower." - "The specific trials you need to complete will be randomly selected."); + InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); } } From fafd90482b37cd54e30fea7f5f38fe44864c5c3b Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 18:42:36 -0400 Subject: [PATCH 48/62] Refactor of some old rando code to use new functions. --- .../actors/ovl_Demo_Kekkai/z_demo_kekkai.c | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c index dab59262c6..6d0b51db23 100644 --- a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c +++ b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c @@ -271,27 +271,10 @@ void DemoKekkai_TrialBarrierDispel(Actor* thisx, GlobalContext* globalCtx) { DemoKekkai* this = (DemoKekkai*)thisx; if (gSaveContext.n64ddFlag) { - switch (thisx->params) { - case KEKKAI_WATER: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_WATER_TRIAL); - break; - case KEKKAI_LIGHT: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_LIGHT_TRIAL); - break; - case KEKKAI_FIRE: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_FIRE_TRIAL); - break; - case KEKKAI_SHADOW: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_SHADOW_TRIAL); - break; - case KEKKAI_SPIRIT: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_SPIRIT_TRIAL); - break; - case KEKKAI_FOREST: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_FOREST_TRIAL); - break; - } - Flags_SetEventChkInf(eventFlags[thisx->params]); + Flags_SetRandomizerInf(trialParamToRandInf(thisx->params)); + // May or may not be needed. Not sure if needed for anything + // that randoInf isn't already covering. Leaving it for safety. + Flags_SetEventChkInf(eventFlags[thisx->params]); } if (globalCtx->csCtx.frames == csFrames[this->actor.params]) { From 9c43f7225b97aa38b14cdfdfdc146f4135980f19 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 18:45:21 -0400 Subject: [PATCH 49/62] Adds captilization to French spoilerfile strings. --- soh/soh/Enhancements/randomizer/3drando/trial.cpp | 12 ++++++------ soh/soh/Enhancements/randomizer/randomizer.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/trial.cpp b/soh/soh/Enhancements/randomizer/3drando/trial.cpp index 1659673c97..e9ee31317b 100644 --- a/soh/soh/Enhancements/randomizer/3drando/trial.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/trial.cpp @@ -7,12 +7,12 @@ TrialInfo::TrialInfo(Text name_) TrialInfo::~TrialInfo() = default; - TrialInfo ForestTrial = TrialInfo(Text{"the Forest Trial", /*french*/"l'épreuve de la forêt", /*spanish*/"la prueba del bosque"}); - TrialInfo FireTrial = TrialInfo(Text{"the Fire Trial", /*french*/"l'épreuve du feu", /*spanish*/"la prueba del fuego"}); - TrialInfo WaterTrial = TrialInfo(Text{"the Water Trial", /*french*/"l'épreuve de l'eau", /*spanish*/"la prueba del agua"}); - TrialInfo SpiritTrial = TrialInfo(Text{"the Spirit Trial", /*french*/"l'épreuve de l'esprit", /*spanish*/"la prueba del espíritu"}); - TrialInfo ShadowTrial = TrialInfo(Text{"the Shadow Trial", /*french*/"l'épreuve de l'ombre", /*spanish*/"la prueba de las sombras"}); - TrialInfo LightTrial = TrialInfo(Text{"the Light Trial", /*french*/"l'épreuve de la lumière", /*spanish*/"la prueba de la luz"}); + TrialInfo ForestTrial = TrialInfo(Text{"the Forest Trial", /*french*/"l'épreuve de la Forêt", /*spanish*/"la prueba del bosque"}); + TrialInfo FireTrial = TrialInfo(Text{"the Fire Trial", /*french*/"l'épreuve du Feu", /*spanish*/"la prueba del fuego"}); + TrialInfo WaterTrial = TrialInfo(Text{"the Water Trial", /*french*/"l'épreuve de l'Eau", /*spanish*/"la prueba del agua"}); + TrialInfo SpiritTrial = TrialInfo(Text{"the Spirit Trial", /*french*/"l'épreuve de l'Esprit", /*spanish*/"la prueba del espíritu"}); + TrialInfo ShadowTrial = TrialInfo(Text{"the Shadow Trial", /*french*/"l'épreuve de l'Ombre", /*spanish*/"la prueba de las sombras"}); + TrialInfo LightTrial = TrialInfo(Text{"the Light Trial", /*french*/"l'épreuve de la Lumière", /*spanish*/"la prueba de la luz"}); const TrialArray trialList = { &ForestTrial, diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index a433f0b3cf..8f4ef7d3b9 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -109,17 +109,17 @@ Randomizer::~Randomizer() { std::unordered_map spoilerFileTrialToEnum = { { "the Forest Trial", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, - { "l'épreuve de la forêt", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, + { "l'épreuve de la Forêt", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, { "the Fire Trial", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, - { "l'épreuve du feu", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, + { "l'épreuve du Feu", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, { "the Water Trial", RAND_INF_TRIALS_DONE_WATER_TRIAL }, - { "l'épreuve de l'eau", RAND_INF_TRIALS_DONE_WATER_TRIAL }, + { "l'épreuve de l'Eau", RAND_INF_TRIALS_DONE_WATER_TRIAL }, { "the Spirit Trial", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, - { "l'épreuve de l'esprit", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, + { "l'épreuve de l'Esprit", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, { "the Shadow Trial", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, - { "l'épreuve de l'ombre", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, + { "l'épreuve de l'Ombre", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, { "the Light Trial", RAND_INF_TRIALS_DONE_LIGHT_TRIAL }, - { "l'épreuve de la lumière", RAND_INF_TRIALS_DONE_LIGHT_TRIAL } + { "l'épreuve de la Lumière", RAND_INF_TRIALS_DONE_LIGHT_TRIAL } }; std::unordered_map getItemIdToItemId = { From 0de1cd96b1f466a8f24a57efbefdeecd5e2db181 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sun, 28 Aug 2022 22:57:41 -0400 Subject: [PATCH 50/62] Fixes keys, maps, and compasses on develop-zhora rando. --- .../Enhancements/randomizer/randomizer.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 8f4ef7d3b9..a6d6b0e4b0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1619,6 +1619,41 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_BUY_BOMBS_535: case RG_BUY_RED_POTION_40: case RG_BUY_RED_POTION_50: + case RG_FOREST_TEMPLE_SMALL_KEY: + case RG_FIRE_TEMPLE_SMALL_KEY: + case RG_WATER_TEMPLE_SMALL_KEY: + case RG_SPIRIT_TEMPLE_SMALL_KEY: + case RG_SHADOW_TEMPLE_SMALL_KEY: + case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: + case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: + case RG_GERUDO_FORTRESS_SMALL_KEY: + case RG_GANONS_CASTLE_SMALL_KEY: + case RG_FOREST_TEMPLE_BOSS_KEY: + case RG_FIRE_TEMPLE_BOSS_KEY: + case RG_WATER_TEMPLE_BOSS_KEY: + case RG_SPIRIT_TEMPLE_BOSS_KEY: + case RG_SHADOW_TEMPLE_BOSS_KEY: + case RG_GANONS_CASTLE_BOSS_KEY: + case RG_DEKU_TREE_COMPASS: + case RG_DODONGOS_CAVERN_COMPASS: + case RG_JABU_JABUS_BELLY_COMPASS: + case RG_FOREST_TEMPLE_COMPASS: + case RG_FIRE_TEMPLE_COMPASS: + case RG_WATER_TEMPLE_COMPASS: + case RG_SPIRIT_TEMPLE_COMPASS: + case RG_SHADOW_TEMPLE_COMPASS: + case RG_BOTTOM_OF_THE_WELL_COMPASS: + case RG_ICE_CAVERN_COMPASS: + case RG_DEKU_TREE_MAP: + case RG_DODONGOS_CAVERN_MAP: + case RG_JABU_JABUS_BELLY_MAP: + case RG_FOREST_TEMPLE_MAP: + case RG_FIRE_TEMPLE_MAP: + case RG_WATER_TEMPLE_MAP: + case RG_SPIRIT_TEMPLE_MAP: + case RG_SHADOW_TEMPLE_MAP: + case RG_BOTTOM_OF_THE_WELL_MAP: + case RG_ICE_CAVERN_MAP: return true; default: return false; From 760eaa4d97de5ebaa38ad9213f4301f73f6dd08d Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sun, 28 Aug 2022 23:01:21 -0400 Subject: [PATCH 51/62] Adds randotodo comment as a note to adapt for the keysanity situation. --- soh/soh/Enhancements/randomizer/randomizer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index a6d6b0e4b0..1bb2a1ab93 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1619,6 +1619,7 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_BUY_BOMBS_535: case RG_BUY_RED_POTION_40: case RG_BUY_RED_POTION_50: + //RANDO TODO: Fix this to return false if keysanity is on. case RG_FOREST_TEMPLE_SMALL_KEY: case RG_FIRE_TEMPLE_SMALL_KEY: case RG_WATER_TEMPLE_SMALL_KEY: From 35d651f06e62149768397a2f53078a0ef01a8293 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sun, 28 Aug 2022 23:54:13 -0400 Subject: [PATCH 52/62] When shuffled to Own Dungeon or below, give vanilla keys, maps, and compasses. --- .../Enhancements/randomizer/randomizer.cpp | 78 ++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 1bb2a1ab93..a9fe62d9a0 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1409,7 +1409,66 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { return GI_BOTTLE; case RG_BOTTLE_WITH_MILK: return GI_MILK_BOTTLE; - + + case RG_DEKU_TREE_MAP: + case RG_DODONGOS_CAVERN_MAP: + case RG_JABU_JABUS_BELLY_MAP: + case RG_FOREST_TEMPLE_MAP: + case RG_FIRE_TEMPLE_MAP: + case RG_WATER_TEMPLE_MAP: + case RG_SPIRIT_TEMPLE_MAP: + case RG_SHADOW_TEMPLE_MAP: + case RG_BOTTOM_OF_THE_WELL_MAP: + case RG_ICE_CAVERN_MAP: + if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) < 3) { + return GI_MAP; + } else { + return randoGet; + } + + case RG_DEKU_TREE_COMPASS: + case RG_DODONGOS_CAVERN_COMPASS: + case RG_JABU_JABUS_BELLY_COMPASS: + case RG_FOREST_TEMPLE_COMPASS: + case RG_FIRE_TEMPLE_COMPASS: + case RG_WATER_TEMPLE_COMPASS: + case RG_SPIRIT_TEMPLE_COMPASS: + case RG_SHADOW_TEMPLE_COMPASS: + case RG_BOTTOM_OF_THE_WELL_COMPASS: + case RG_ICE_CAVERN_COMPASS: + if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) < 3) { + return GI_COMPASS; + } else { + return randoGet; + } + + case RG_FOREST_TEMPLE_BOSS_KEY: + case RG_FIRE_TEMPLE_BOSS_KEY: + case RG_WATER_TEMPLE_BOSS_KEY: + case RG_SPIRIT_TEMPLE_BOSS_KEY: + case RG_SHADOW_TEMPLE_BOSS_KEY: + case RG_GANONS_CASTLE_BOSS_KEY: + if (GetRandoSettingValue(RSK_BOSS_KEYSANITY) < 3) { + return GI_KEY_BOSS; + } else { + return randoGet; + } + + case RG_FOREST_TEMPLE_SMALL_KEY: + case RG_FIRE_TEMPLE_SMALL_KEY: + case RG_WATER_TEMPLE_SMALL_KEY: + case RG_SPIRIT_TEMPLE_SMALL_KEY: + case RG_SHADOW_TEMPLE_SMALL_KEY: + case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: + case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: + case RG_GERUDO_FORTRESS_SMALL_KEY: + case RG_GANONS_CASTLE_SMALL_KEY: + if (GetRandoSettingValue(RSK_KEYSANITY) < 3) { + return GI_KEY_SMALL; + } else { + return randoGet; + } + // todo test this with keys in own dungeon case RG_TREASURE_GAME_SMALL_KEY: return GI_DOOR_KEY; @@ -1619,7 +1678,7 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_BUY_BOMBS_535: case RG_BUY_RED_POTION_40: case RG_BUY_RED_POTION_50: - //RANDO TODO: Fix this to return false if keysanity is on. + return true; case RG_FOREST_TEMPLE_SMALL_KEY: case RG_FIRE_TEMPLE_SMALL_KEY: case RG_WATER_TEMPLE_SMALL_KEY: @@ -1629,12 +1688,24 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: case RG_GERUDO_FORTRESS_SMALL_KEY: case RG_GANONS_CASTLE_SMALL_KEY: + if (GetRandoSettingValue(RSK_KEYSANITY) > 2) { + return false; + } + return true; case RG_FOREST_TEMPLE_BOSS_KEY: case RG_FIRE_TEMPLE_BOSS_KEY: case RG_WATER_TEMPLE_BOSS_KEY: case RG_SPIRIT_TEMPLE_BOSS_KEY: case RG_SHADOW_TEMPLE_BOSS_KEY: + if (GetRandoSettingValue(RSK_BOSS_KEYSANITY) > 2) { + return false; + } + return true; case RG_GANONS_CASTLE_BOSS_KEY: + if (GetRandoSettingValue(RSK_GANONS_BOSS_KEY) > 2) { + return false; + } + return true; case RG_DEKU_TREE_COMPASS: case RG_DODONGOS_CAVERN_COMPASS: case RG_JABU_JABUS_BELLY_COMPASS: @@ -1655,6 +1726,9 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_SHADOW_TEMPLE_MAP: case RG_BOTTOM_OF_THE_WELL_MAP: case RG_ICE_CAVERN_MAP: + if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) > 2) { + return false; + } return true; default: return false; From 0a27714b8edb65775d4989e170a472fd3ab348f2 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 00:09:44 -0400 Subject: [PATCH 53/62] Adds missing case for RSK_GERUDO_KEYS from spoilerfile parsing. --- .../Enhancements/randomizer/randomizer.cpp | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index a9fe62d9a0..2ed1888e40 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -875,6 +875,19 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { gSaveContext.randoSettings[index].value = 3; } break; + case RSK_GERUDO_KEYS: + if (it.value() == "Vanilla") { + gSaveContext.randoSettings[index].value = 0; + } + if (it.value() == "Any Dungeon") { + gSaveContext.randoSettings[index].value = 1; + } + if (it.value() == "Overworld") { + gSaveContext.randoSettings[index].value = 2; + } + if (it.value() == "Anywhere") { + gSaveContext.randoSettings[index].value = 3; + } case RSK_KEYSANITY: if(it.value() == "Start With") { gSaveContext.randoSettings[index].value = 0; @@ -1461,13 +1474,18 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case RG_SHADOW_TEMPLE_SMALL_KEY: case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: - case RG_GERUDO_FORTRESS_SMALL_KEY: case RG_GANONS_CASTLE_SMALL_KEY: if (GetRandoSettingValue(RSK_KEYSANITY) < 3) { return GI_KEY_SMALL; } else { return randoGet; } + case RG_GERUDO_FORTRESS_SMALL_KEY: + if (GetRandoSettingValue(RSK_GERUDO_KEYS) == 0) { + return GI_KEY_SMALL; + } else { + return randoGet; + } // todo test this with keys in own dungeon case RG_TREASURE_GAME_SMALL_KEY: @@ -1686,12 +1704,16 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_SHADOW_TEMPLE_SMALL_KEY: case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: - case RG_GERUDO_FORTRESS_SMALL_KEY: case RG_GANONS_CASTLE_SMALL_KEY: if (GetRandoSettingValue(RSK_KEYSANITY) > 2) { return false; } return true; + case RG_GERUDO_FORTRESS_SMALL_KEY: + if (GetRandoSettingValue(RSK_GERUDO_KEYS != 0)) { + return false + } + return true; case RG_FOREST_TEMPLE_BOSS_KEY: case RG_FIRE_TEMPLE_BOSS_KEY: case RG_WATER_TEMPLE_BOSS_KEY: From a84262dbf7a9bd8658bd027e31f13c8a6aac5b43 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 00:11:10 -0400 Subject: [PATCH 54/62] Bit of cleanup --- soh/soh/Enhancements/randomizer/randomizer.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 2ed1888e40..7d552ce900 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -878,14 +878,11 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { case RSK_GERUDO_KEYS: if (it.value() == "Vanilla") { gSaveContext.randoSettings[index].value = 0; - } - if (it.value() == "Any Dungeon") { + } else if (it.value() == "Any Dungeon") { gSaveContext.randoSettings[index].value = 1; - } - if (it.value() == "Overworld") { + } else if (it.value() == "Overworld") { gSaveContext.randoSettings[index].value = 2; - } - if (it.value() == "Anywhere") { + } else if (it.value() == "Anywhere") { gSaveContext.randoSettings[index].value = 3; } case RSK_KEYSANITY: From f44c588a2c24aa3ffc2de533b1553bd6c595d821 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 01:03:21 -0400 Subject: [PATCH 55/62] Oops --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 7d552ce900..01bb061756 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1708,7 +1708,7 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { return true; case RG_GERUDO_FORTRESS_SMALL_KEY: if (GetRandoSettingValue(RSK_GERUDO_KEYS != 0)) { - return false + return false; } return true; case RG_FOREST_TEMPLE_BOSS_KEY: From 51dbee365a6c3efd366a15c79e0814e242756a45 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 01:04:13 -0400 Subject: [PATCH 56/62] Oops part 2 --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 01bb061756..b4129eba14 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1707,7 +1707,7 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { } return true; case RG_GERUDO_FORTRESS_SMALL_KEY: - if (GetRandoSettingValue(RSK_GERUDO_KEYS != 0)) { + if (GetRandoSettingValue(RSK_GERUDO_KEYS) != 0) { return false; } return true; From b9aee7085edda009c07e9876e3ed88994e6b0e20 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 19:12:19 -0400 Subject: [PATCH 57/62] Adds note to key colors enhancement about this change. --- libultraship/libultraship/ImGuiImpl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index d430bc7699..c74d126fb6 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -2011,7 +2011,9 @@ namespace SohImGui { ); PaddedEnhancementCheckbox("Key Colors Match Dungeon", "gRandoMatchKeyColors", true, false); Tooltip( - "Matches the color of small keys and boss keys to the dungeon they belong to. This helps identify keys from afar and adds a little bit of flair."); + "Matches the color of small keys and boss keys to the dungeon they belong to. " + "This helps identify keys from afar and adds a little bit of flair.\n\nThis only " + "applies to seeds with keys and boss keys shuffled to Any Dungeon, Overworld, or Anywhere."); PaddedEnhancementCheckbox("Quest Item Fanfares", "gRandoQuestItemFanfares", true, false); Tooltip( "Play unique fanfares when obtaining quest items " From 99674ff88c0ef9669d3782a7003d533a7d5e2f1b Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 29 Aug 2022 19:19:01 -0400 Subject: [PATCH 58/62] Readds missing workaround for spirit temple and ganon's castle keys. --- soh/src/code/z_parameter.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 73044df27e..265c69aced 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1690,12 +1690,35 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { } return ITEM_NONE; } else if (item == ITEM_KEY_SMALL) { - if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { - gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; - return ITEM_NONE; + // Small key exceptions for rando with keysanity off. + if (gSaveContext.n64ddFlag) { + if (globalCtx->sceneNum == 10) { // ganon's tower -> ganon's castle + if (gSaveContext.inventory.dungeonKeys[13] < 0) { + gSaveContext.inventory.dungeonKeys[13] = 1; + return ITEM_NONE; + } else { + gSaveContext.inventory.dungeonKeys[13]++; + return ITEM_NONE; + } + } + + if (globalCtx->sceneNum == 92) { // Desert Colossus -> Spirit Temple. + if (gSaveContext.inventory.dungeonKeys[6] < 0) { + gSaveContext.inventory.dungeonKeys[6] = 1; + return ITEM_NONE; + } else { + gSaveContext.inventory.dungeonKeys[6]++; + return ITEM_NONE; + } + } } else { - gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]++; - return ITEM_NONE; + if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { + gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; + return ITEM_NONE; + } else { + gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]++; + return ITEM_NONE; + } } } else if ((item == ITEM_QUIVER_30) || (item == ITEM_BOW)) { if (CUR_UPG_VALUE(UPG_QUIVER) == 0) { From 3856d1b0a745aede9f6e1ce409d31ee66cc3bdf3 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Tue, 30 Aug 2022 11:00:47 -0400 Subject: [PATCH 59/62] Fixed small key case that was behind an else and shouldn't have been --- soh/src/code/z_parameter.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 265c69aced..f8df81f342 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1711,14 +1711,12 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { return ITEM_NONE; } } + if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { + gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; + return ITEM_NONE; } else { - if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { - gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; - return ITEM_NONE; - } else { - gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]++; - return ITEM_NONE; - } + gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]++; + return ITEM_NONE; } } else if ((item == ITEM_QUIVER_30) || (item == ITEM_BOW)) { if (CUR_UPG_VALUE(UPG_QUIVER) == 0) { From 60257b98a4ae4e392ef2c049255b367a6ef34ee8 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Tue, 30 Aug 2022 11:21:29 -0400 Subject: [PATCH 60/62] Oops. Missed closing bracket. --- soh/src/code/z_parameter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index f8df81f342..8d26f36586 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1711,6 +1711,7 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { return ITEM_NONE; } } + } if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; return ITEM_NONE; From 042d6f3865fd187642eb8aa48f8c01f9d5b6c399 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 31 Aug 2022 10:57:59 -0400 Subject: [PATCH 61/62] Fixes a few bugs related to chests. --- soh/src/overlays/actors/ovl_player_actor/z_player.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 2631e39b99..2ac6e0fc25 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -6108,7 +6108,7 @@ s32 func_8083E5A8(Player* this, GlobalContext* globalCtx) { } GetItemEntry giEntry; - if (this->getItemEntry.objectId == OBJECT_INVALID) { + if (this->getItemEntry.objectId == OBJECT_INVALID || (this->getItemId != this->getItemEntry.getItemId)) { giEntry = ItemTable_Retrieve(this->getItemId); } else { giEntry = this->getItemEntry; @@ -6165,7 +6165,7 @@ s32 func_8083E5A8(Player* this, GlobalContext* globalCtx) { } } else if (CHECK_BTN_ALL(sControlInput->press.button, BTN_A) && !(this->stateFlags1 & PLAYER_STATE1_11) && !(this->stateFlags2 & PLAYER_STATE2_10)) { - if (this->getItemId != GI_NONE && this->getItemEntry.objectId != OBJECT_INVALID) { + if (this->getItemId != GI_NONE) { GetItemEntry giEntry; if (this->getItemEntry.objectId == OBJECT_INVALID) { giEntry = ItemTable_Retrieve(-this->getItemId); @@ -9687,8 +9687,8 @@ void func_808473D4(GlobalContext* globalCtx, Player* this) { else if ((!(this->stateFlags1 & PLAYER_STATE1_11) || (heldActor == NULL)) && (interactRangeActor != NULL) && ((!sp1C && (this->getItemId == GI_NONE)) || - ((this->getItemId < 0 && this->getItemEntry.getItemId < 0) && !(this->stateFlags1 & PLAYER_STATE1_27)))) { - if (this->getItemId < 0 && this->getItemEntry.getItemId < 0) { + (this->getItemId < 0 && !(this->stateFlags1 & PLAYER_STATE1_27)))) { + if (this->getItemId < 0) { doAction = DO_ACTION_OPEN; } else if ((interactRangeActor->id == ACTOR_BG_TOKI_SWD) && LINK_IS_ADULT) { doAction = DO_ACTION_DROP; From 1f12caa5c9e02f108560ffe3f73f624ce42f4422 Mon Sep 17 00:00:00 2001 From: briaguya Date: Wed, 31 Aug 2022 18:15:09 -0400 Subject: [PATCH 62/62] fix oot ice trap check optimization issues --- soh/soh/OTRGlobals.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 7d7a86268f..8867862602 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1652,15 +1652,14 @@ extern "C" GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomi return ItemTable_RetrieveEntry(getItemModIndex, itemID); } -extern "C" bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor) { - return gSaveContext.n64ddFlag && (actor->parent != NULL) && - Randomizer_GetItemFromKnownCheck(randomizerCheck, ogId).getItemId == RG_ICE_TRAP; -} - extern "C" bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId) { return gSaveContext.n64ddFlag && Randomizer_GetItemFromKnownCheck(randomizerCheck, ogId).getItemId == RG_ICE_TRAP; } +extern "C" bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor) { + return Randomizer_ItemIsIceTrap(randomizerCheck, ogId) && actor->parent != NULL; +} + extern "C" CustomMessageEntry Randomizer_GetCustomGetItemMessage(Player* player) { s16 giid; if (player->getItemEntry.objectId != OBJECT_INVALID) {