From fe7476a377e49774a105f33be2ffcfb50dacc15c Mon Sep 17 00:00:00 2001 From: aMannus Date: Thu, 14 Dec 2023 12:19:39 +0100 Subject: [PATCH] Potsanity proof of concept --- soh/include/functions.h | 2 +- soh/include/z64actor.h | 3 ++ .../Enhancements/debugger/debugSaveEditor.h | 2 + .../randomizer/3drando/category.hpp | 1 + .../hint_list/hint_list_exclude_overworld.cpp | 5 +++ .../randomizer/3drando/item_pool.cpp | 11 +++++ .../location_access/locacc_castle_town.cpp | 5 ++- .../Enhancements/randomizer/3drando/logic.cpp | 4 ++ .../Enhancements/randomizer/3drando/logic.hpp | 1 + .../randomizer/3drando/spoiler_log.cpp | 4 ++ .../randomizer/3drando/spoiler_log.hpp | 1 + soh/soh/Enhancements/randomizer/location.h | 4 ++ .../Enhancements/randomizer/location_list.cpp | 5 +++ soh/soh/Enhancements/randomizer/option.cpp | 2 +- .../randomizer/option_descriptions.cpp | 2 + .../Enhancements/randomizer/randomizer.cpp | 19 +++++++++ soh/soh/Enhancements/randomizer/randomizer.h | 1 + .../Enhancements/randomizer/randomizerTypes.h | 16 ++++++-- .../randomizer/randomizer_check_objects.cpp | 1 + .../randomizer/randomizer_check_objects.h | 1 + .../randomizer/randomizer_check_tracker.cpp | 6 +++ .../Enhancements/randomizer/randomizer_inf.h | 2 + soh/soh/Enhancements/randomizer/settings.cpp | 7 +++- soh/soh/OTRGlobals.cpp | 4 ++ soh/soh/OTRGlobals.h | 1 + soh/src/code/z_actor.c | 4 +- soh/src/code/z_en_item00.c | 41 ++++++++++--------- .../actors/ovl_Obj_Tsubo/z_obj_tsubo.c | 32 +++++++++++++++ .../actors/ovl_Obj_Tsubo/z_obj_tsubo.h | 1 + 29 files changed, 158 insertions(+), 30 deletions(-) diff --git a/soh/include/functions.h b/soh/include/functions.h index 3a1aa8ae2..0c40f7270 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -457,7 +457,7 @@ u32 Actor_HasParent(Actor* actor, PlayState* play); // TODO: Rename the follwing 3 functions using whatever scheme we use when we rename func_8002F434 and func_8002F554. s32 GiveItemEntryWithoutActor(PlayState* play, GetItemEntry getItemEntry); s32 GiveItemEntryFromActor(Actor* actor, PlayState* play, GetItemEntry getItemEntry, f32 xzRange, f32 yRange); -void GiveItemEntryFromActorWithFixedRange(Actor* actor, PlayState* play, GetItemEntry getItemEntry); +s32 GiveItemEntryFromActorWithFixedRange(Actor* actor, PlayState* play, GetItemEntry getItemEntry); s32 func_8002F434(Actor* actor, PlayState* play, s32 getItemId, f32 xzRange, f32 yRange); void func_8002F554(Actor* actor, PlayState* play, s32 getItemId); void func_8002F580(Actor* actor, PlayState* play); diff --git a/soh/include/z64actor.h b/soh/include/z64actor.h index 7d4e313e7..f85f94c1c 100644 --- a/soh/include/z64actor.h +++ b/soh/include/z64actor.h @@ -7,6 +7,7 @@ #include "z64collision_check.h" #include "z64bgcheck.h" #include "soh/Enhancements/item-tables/ItemTableTypes.h" +#include "soh/Enhancements/randomizer/randomizerTypes.h" #include "z64actor_enum.h" #define ACTOR_NUMBER_MAX 2000 @@ -285,6 +286,8 @@ typedef struct EnItem00 { /* 0x160 */ ColliderCylinder collider; s16 ogParams; GetItemEntry randoGiEntry; + RandomizerCheck randoCheck; + RandomizerInf randoInf; } EnItem00; // size = 0x1AC // Only A_OBJ_SIGNPOST_OBLONG and A_OBJ_SIGNPOST_ARROW are used in room files. diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.h b/soh/soh/Enhancements/debugger/debugSaveEditor.h index 1daddbf17..244be1b65 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.h +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.h @@ -515,6 +515,8 @@ const std::vector flagTables = { { RAND_INF_BONGO_BONGO_SOUL, "RAND_INF_BONGO_BONGO_SOUL" }, { RAND_INF_TWINROVA_SOUL, "RAND_INF_TWINROVA_SOUL" }, { RAND_INF_GANON_SOUL, "RAND_INF_GANON_SOUL" }, + + { RAND_INF_SHUFFLE_POTS_MARKET_GUARD_HOUSE_CHILD_1, "RAND_INF_SHUFFLE_POTS_MARKET_GUARD_HOUSE_CHILD_1" }, } }, }; diff --git a/soh/soh/Enhancements/randomizer/3drando/category.hpp b/soh/soh/Enhancements/randomizer/3drando/category.hpp index f43b3ccba..5f3c9aff8 100644 --- a/soh/soh/Enhancements/randomizer/3drando/category.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/category.hpp @@ -17,6 +17,7 @@ enum class Category { cVanillaMap, cVanillaCompass, cAdultTrade, + cPot, }; enum class OptionCategory { diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp index 5e5a003ec..3f0d068ca 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp @@ -1356,4 +1356,9 @@ void HintTable_Init_Exclude_Overworld() { //obscure text Text{"a #cow in a luxurious hole# offers", /*french*/"la #vache dans une grotte luxueuse# donne", /*spanish*/"una #vaca de un lujoso hoyo# brinda"}, }); + + hintTable[RHT_SHUFFLE_POTS_MARKET_GUARD_HOUSE_1] = HintText::Exclude({ + //obscure text + Text{"a #pot in a room# holds", /*french*/"a #pot in a room# holds", /*spanish*/"a #pot in a room# holds"}, + }); } diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index 46d039f9b..f7c7346d1 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -574,6 +574,11 @@ static void PlaceVanillaCowMilk() { } } +static void PlaceVanillaPotContents() { + auto ctx = Rando::Context::GetInstance(); + ctx->PlaceItemInLocation(RC_MARKET_GUARD_HOUSE_CHILD_POT_1, RG_GREEN_RUPEE, false, true); +} + static void SetScarceItemPool() { ReplaceMaxItem(RG_PROGRESSIVE_BOMBCHUS, 3); ReplaceMaxItem(RG_BOMBCHU_5, 1); @@ -726,6 +731,12 @@ void GenerateItemPool() { PlaceVanillaCowMilk(); } + if (ctx->GetOption(RSK_SHUFFLE_POTS)) { + AddItemToMainPool(RG_GREEN_RUPEE); + } else { + PlaceVanillaPotContents(); + } + if (ctx->GetOption(RSK_SHUFFLE_MAGIC_BEANS)) { AddItemToMainPool(RG_MAGIC_BEAN_PACK); if (ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) { diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp index 53109e684..ff6ef257d 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp @@ -168,8 +168,9 @@ void AreaTable_Init_CastleTown() { areaTable[RR_MARKET_GUARD_HOUSE] = Area("Market Guard House", "Market Guard House", RA_NONE, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LocationAccess(RC_MARKET_10_BIG_POES, {[]{return IsAdult && BigPoeKill;}}), - LocationAccess(RC_MARKET_GS_GUARD_HOUSE, {[]{return IsChild;}}), + LocationAccess(RC_MARKET_10_BIG_POES, {[]{return IsAdult && BigPoeKill;}}), + LocationAccess(RC_MARKET_GS_GUARD_HOUSE, {[]{return IsChild;}}), + LocationAccess(RC_MARKET_GUARD_HOUSE_CHILD_POT_1, {[]{return CanBreakPots();}}), }, { //Exits Entrance(RR_MARKET_ENTRANCE, {[]{return true;}}), diff --git a/soh/soh/Enhancements/randomizer/3drando/logic.cpp b/soh/soh/Enhancements/randomizer/3drando/logic.cpp index 709f49cc4..7db4664c5 100644 --- a/soh/soh/Enhancements/randomizer/3drando/logic.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/logic.cpp @@ -503,6 +503,10 @@ namespace Logic { } } + bool CanBreakPots() { + return true; + } + uint8_t GetDifficultyValueFromString(Rando::Option& glitchOption) { return 0; } diff --git a/soh/soh/Enhancements/randomizer/3drando/logic.hpp b/soh/soh/Enhancements/randomizer/3drando/logic.hpp index 2477f9902..e006179c8 100644 --- a/soh/soh/Enhancements/randomizer/3drando/logic.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/logic.hpp @@ -380,6 +380,7 @@ bool CanPlay(bool song); bool CanUse(RandomizerGet itemName); bool HasProjectile(HasProjectileAge age); bool HasBossSoul(RandomizerGet itemName); +bool CanBreakPots(); bool SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmount); bool SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched); bool CanDoGlitch(GlitchType glitch); diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 6c9f83ab1..6f90effb9 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -118,6 +118,10 @@ void WriteIngameSpoilerLog() { if (!ctx->GetOption(RSK_SHUFFLE_COWS) && loc->IsCategory(Category::cCow)) { continue; } + // Shuffle Pots + else if (!ctx->GetOption(RSK_SHUFFLE_POTS) && loc->IsCategory(Category::cPot)) { + continue; + } // Merchants else if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_OFF) && loc->IsCategory(Category::cMerchant)) { continue; diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.hpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.hpp index 8ad3212f8..75632976d 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.hpp @@ -28,6 +28,7 @@ typedef enum { SPOILER_CHK_MERCHANT, SPOILER_CHK_GRAVEDIGGER, SPOILER_CHK_RANDOMIZER_INF, + SPOILER_CHK_POT, } SpoilerCollectionCheckType; // GetLocation groups for checks, used to group the checks by logical location diff --git a/soh/soh/Enhancements/randomizer/location.h b/soh/soh/Enhancements/randomizer/location.h index cd6e88f32..1a2869eb4 100644 --- a/soh/soh/Enhancements/randomizer/location.h +++ b/soh/soh/Enhancements/randomizer/location.h @@ -94,6 +94,10 @@ class SpoilerCollectionCheck { static auto RandomizerInf(const int8_t scene, const uint8_t flag) { return SpoilerCollectionCheck(SPOILER_CHK_RANDOMIZER_INF, scene, flag); } + + static auto Pot(const uint8_t scene, const uint8_t flag) { + return SpoilerCollectionCheck(SPOILER_CHK_POT, scene, flag); + } }; enum class LocationType { diff --git a/soh/soh/Enhancements/randomizer/location_list.cpp b/soh/soh/Enhancements/randomizer/location_list.cpp index be78d8acf..eca7e7061 100644 --- a/soh/soh/Enhancements/randomizer/location_list.cpp +++ b/soh/soh/Enhancements/randomizer/location_list.cpp @@ -1,6 +1,7 @@ #include "static_data.h" #define TWO_ACTOR_PARAMS(a, b) (abs(a) << 16) | abs(b) +#define THREE_ACTOR_PARAMS(a, b, c) (abs(a) << 10) | (abs(a) << 20) | abs(c) std::array Rando::StaticData::locationTable; @@ -207,6 +208,7 @@ std::vector Rando::StaticData::overworldLocations = { RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, + RC_MARKET_GUARD_HOUSE_CHILD_POT_1, // Market Shops RC_MARKET_BOMBCHU_SHOP_ITEM_1, @@ -1291,6 +1293,9 @@ void Rando::StaticData::InitLocationTable() { locationTable[RC_GV_COW] = Location::Base(RC_GV_COW, RCQUEST_BOTH, RCTYPE_COW, RCAREA_GERUDO_VALLEY, ACTOR_EN_COW, SCENE_GERUDO_VALLEY, 0x00, 0x15, "Cow", "GV Cow", RHT_GV_COW, RG_MILK, { Category::cCow }, SpoilerCollectionCheck::Cow(0x5A, 0x15), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); locationTable[RC_JABU_JABUS_BELLY_MQ_COW] = Location::Base(RC_JABU_JABUS_BELLY_MQ_COW, RCQUEST_MQ, RCTYPE_COW, RCAREA_JABU_JABUS_BELLY, ACTOR_EN_COW, SCENE_JABU_JABU, 0x00, 0x15, "MQ Cow", "Jabu Jabus Belly MQ Cow", RHT_JABU_JABUS_BELLY_MQ_COW, RG_MILK, { Category::cCow }, SpoilerCollectionCheck::Cow(0x02, 0x15), SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + // Pots Randomizer Check Randomizer Check Quest Type Area Actor ID Scene ID Params Flags Short Name Spoiler Name Hint Text Key Vanilla Item Categories Spoiler Collection Check Collection Check Group + locationTable[RC_MARKET_GUARD_HOUSE_CHILD_POT_1] = Location::Base(RC_MARKET_GUARD_HOUSE_CHILD_POT_1, RCQUEST_BOTH, RCTYPE_POT, RCAREA_MARKET, ACTOR_OBJ_TSUBO, SCENE_MARKET_GUARD_HOUSE, THREE_ACTOR_PARAMS(-80, 0, -7), 0x00, "Guard House Child Pot 1", "MK Guard House Child Pot 1", RHT_SHUFFLE_POTS_MARKET_GUARD_HOUSE_1, RG_GREEN_RUPEE, { Category::cPot }, SpoilerCollectionCheck::Pot(0x4D, 0x00), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + /*------------------------------- --- SHOPS --- 8 6 2 4 diff --git a/soh/soh/Enhancements/randomizer/option.cpp b/soh/soh/Enhancements/randomizer/option.cpp index a7b4340c9..a45f90985 100644 --- a/soh/soh/Enhancements/randomizer/option.cpp +++ b/soh/soh/Enhancements/randomizer/option.cpp @@ -414,7 +414,7 @@ bool OptionGroup::RenderImGui() const { // NOLINT(*-no-recursion) ImGui::Unindent(); } if (option->HasFlag(IMFLAG_SEPARATOR_BOTTOM)) { - UIWidgets::PaddedSeparator(); + UIWidgets::PaddedSeparator(false, true); } } } diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index 83f8b12a0..6d0c5e5c4 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -229,6 +229,8 @@ void Settings::CreateOptionDescriptions() { "\n" "The Gerudo Card is required to enter the Gerudo Training Grounds, opening " "the gate to Haunted Wasteland and the Horseback Archery minigame."; + mOptionDescriptions[RSK_SHUFFLE_POTS] = + "Freestanding pots will drop a randomized item the first time they're broken and collected. Pots will have a different appearance when they hold a randomized item."; mOptionDescriptions[RSK_SHOPSANITY] = "Off - All shop items will be the same as vanilla.\n" "\n" "0 Items - Vanilla shop items will be shuffled among different shops.\n" diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 6d1d76e30..0b9177c47 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1402,6 +1402,7 @@ std::map rcToRandomizerInf = { { RC_LH_ADULT_FISHING, RAND_INF_ADULT_FISHING }, { RC_MARKET_10_BIG_POES, RAND_INF_10_BIG_POES }, { RC_KAK_100_GOLD_SKULLTULA_REWARD, RAND_INF_KAK_100_GOLD_SKULLTULA_REWARD }, + { RC_MARKET_GUARD_HOUSE_CHILD_POT_1, RAND_INF_SHUFFLE_POTS_MARKET_GUARD_HOUSE_CHILD_1 }, }; Rando::Location* Randomizer::GetCheckObjectFromActor(s16 actorId, s16 sceneNum, s32 actorParams = 0x00) { @@ -1609,6 +1610,24 @@ CowIdentity Randomizer::IdentifyCow(s32 sceneNum, s32 posX, s32 posZ) { return cowIdentity; } +PotIdentity Randomizer::IdentifyPot(s32 sceneNum, s32 posX, s32 posY, s32 posZ) { + struct PotIdentity potIdentity; + + potIdentity.randomizerInf = RAND_INF_MAX; + potIdentity.randomizerCheck = RC_UNKNOWN_CHECK; + + s32 actorParams = THREE_ACTOR_PARAMS(posX, posY, posZ); + + Rando::Location* location = GetCheckObjectFromActor(ACTOR_OBJ_TSUBO, sceneNum, actorParams); + + if (location->GetRandomizerCheck() != RC_UNKNOWN_CHECK) { + potIdentity.randomizerInf = rcToRandomizerInf[location->GetRandomizerCheck()]; + potIdentity.randomizerCheck = location->GetRandomizerCheck(); + } + + return potIdentity; +} + u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) { return Rando::Context::GetInstance()->GetOption(randoSettingKey).GetSelectedOptionIndex(); } diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 9dab10b99..d4ad7707f 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -54,6 +54,7 @@ class Randomizer { ScrubIdentity IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); ShopItemIdentity IdentifyShopItem(s32 sceneNum, u8 slotIndex); CowIdentity IdentifyCow(s32 sceneNum, s32 posX, s32 posZ); + PotIdentity IdentifyPot(s32 sceneNum, s32 posX, s32 potY, s32 posZ); GetItemEntry GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogItemId, bool checkObtainability = true); GetItemEntry GetItemFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogItemId, bool checkObtainability = true); GetItemID GetItemIdFromRandomizerGet(RandomizerGet randoGet, GetItemID ogItemId); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 52a86f649..d27c70cf6 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -101,10 +101,11 @@ typedef enum { RCTYPE_CHEST_GAME, // todo replace this once we implement it, just using it to exclude for now RCTYPE_LINKS_POCKET, // todo this feels hacky RCTYPE_GOSSIP_STONE, - RCTYPE_SONG_LOCATION, // Song locations + RCTYPE_SONG_LOCATION, // Song locations RCTYPE_BOSS_HEART_OR_OTHER_REWARD, // Boss heart container or lesser dungeon rewards (lens, ice arrow) - RCTYPE_DUNGEON_REWARD, // Dungeon rewards (blue warps) - RCTYPE_OCARINA, // Ocarina locations + RCTYPE_DUNGEON_REWARD, // Dungeon rewards (blue warps) + RCTYPE_OCARINA, // Ocarina locations + RCTYPE_POT, // Shuffle Pots } RandomizerCheckType; typedef enum { RCQUEST_VANILLA, RCQUEST_MQ, RCQUEST_BOTH } RandomizerCheckQuest; @@ -746,6 +747,7 @@ typedef enum { RC_MARKET_BOMBCHU_SHOP_ITEM_6, RC_MARKET_BOMBCHU_SHOP_ITEM_7, RC_MARKET_BOMBCHU_SHOP_ITEM_8, + RC_MARKET_GUARD_HOUSE_CHILD_POT_1, RC_TOT_LIGHT_ARROWS_CUTSCENE, RC_TOT_MASTER_SWORD, RC_HC_MALON_EGG, @@ -3277,6 +3279,8 @@ typedef enum { RHT_CARPET_SALESMAN_DIALOG_THIRD, RHT_CARPET_SALESMAN_DIALOG_FOURTH, RHT_GRANNY_DIALOG, + // Shuffle Pots + RHT_SHUFFLE_POTS_MARKET_GUARD_HOUSE_1, RHT_MAX } RandomizerHintTextKey; @@ -3400,6 +3404,7 @@ typedef enum { RSK_SHUFFLE_COWS, RSK_SHUFFLE_WEIRD_EGG, RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD, + RSK_SHUFFLE_POTS, RSK_SHUFFLE_FROG_SONG_RUPEES, RSK_ITEM_POOL, RSK_ICE_TRAPS, @@ -3881,6 +3886,11 @@ typedef struct CowIdentity { RandomizerCheck randomizerCheck; } CowIdentity; +typedef struct PotIdentity { + RandomizerInf randomizerInf; + RandomizerCheck randomizerCheck; +} PotIdentity; + typedef enum { TRACKER_WINDOW_FLOATING, TRACKER_WINDOW_WINDOW diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp index ff0adf7a3..537f05e57 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp @@ -153,6 +153,7 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() { ((CVarGetInteger("gRandomizeShuffleTokens", RO_TOKENSANITY_OFF) == RO_TOKENSANITY_DUNGEONS) && RandomizerCheckObjects::AreaIsDungeon(location.GetArea()))) && (location.GetRCType() != RCTYPE_COW || CVarGetInteger("gRandomizeShuffleCows", RO_GENERIC_NO)) && + (location.GetRCType() != RCTYPE_POT || CVarGetInteger("gRandomizeShufflePotContents", RO_GENERIC_NO)) && (location.GetRCType() != RCTYPE_ADULT_TRADE || CVarGetInteger("gRandomizeShuffleAdultTrade", RO_GENERIC_NO)) && (location.GetRandomizerCheck() != RC_KF_KOKIRI_SWORD_CHEST || diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_objects.h b/soh/soh/Enhancements/randomizer/randomizer_check_objects.h index ab7e5538a..aea5d839c 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_objects.h +++ b/soh/soh/Enhancements/randomizer/randomizer_check_objects.h @@ -7,6 +7,7 @@ #include #define TWO_ACTOR_PARAMS(a, b) (abs(a) << 16) | abs(b) +#define THREE_ACTOR_PARAMS(a, b, c) (abs(a) << 10) | (abs(a) << 20) | abs(c) namespace RandomizerCheckObjects { bool AreaIsDungeon(RandomizerCheckArea area); diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index 5fdca02f5..7b53b093b 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -64,6 +64,7 @@ bool showKokiriSword; bool showMasterSword; bool showWeirdEgg; bool showGerudoCard; +bool showPots; bool showFrogSongRupees; bool showStartingMapsCompasses; bool showKeysanity; @@ -426,6 +427,7 @@ bool HasItemBeenCollected(RandomizerCheck rc) { case SpoilerCollectionCheckType::SPOILER_CHK_SCRUB: case SpoilerCollectionCheckType::SPOILER_CHK_RANDOMIZER_INF: case SpoilerCollectionCheckType::SPOILER_CHK_MASTER_SWORD: + case SpoilerCollectionCheckType::SPOILER_CHK_POT: return Flags_GetRandomizerInf(OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(rc)); case SpoilerCollectionCheckType::SPOILER_CHK_EVENT_CHK_INF: return gSaveContext.eventChkInf[flag / 16] & (0x01 << flag % 16); @@ -1030,6 +1032,9 @@ void LoadSettings() { showGerudoCard = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) == RO_GENERIC_YES : true; + showPots = IS_RANDO ? + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_POTS) == RO_GENERIC_YES + : true; showFrogSongRupees = IS_RANDO ? OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_FROG_SONG_RUPEES) == RO_GENERIC_YES : false; @@ -1132,6 +1137,7 @@ bool IsVisibleInCheckTracker(RandomizerCheck rc) { (showDungeonTokens && RandomizerCheckObjects::AreaIsDungeon(loc->GetArea())) ) && (loc->GetRCType() != RCTYPE_COW || showCows) && + (loc->GetRCType() != RCTYPE_POT || showPots) && (loc->GetRCType() != RCTYPE_ADULT_TRADE || showAdultTrade || rc == RC_KAK_ANJU_AS_ADULT || // adult trade checks that are always shuffled diff --git a/soh/soh/Enhancements/randomizer/randomizer_inf.h b/soh/soh/Enhancements/randomizer/randomizer_inf.h index d7e0c1dfe..dabe42852 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_inf.h +++ b/soh/soh/Enhancements/randomizer/randomizer_inf.h @@ -170,6 +170,8 @@ typedef enum { RAND_INF_TWINROVA_SOUL, RAND_INF_GANON_SOUL, + RAND_INF_SHUFFLE_POTS_MARKET_GUARD_HOUSE_CHILD_1, + // 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/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 114f2201a..41646d70b 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -105,6 +105,7 @@ void Settings::CreateOptions() { mOptions[RSK_SHUFFLE_OCARINA] = Option::Bool("Shuffle Ocarinas", "gRandomizeShuffleOcarinas", mOptionDescriptions[RSK_SHUFFLE_OCARINA]); mOptions[RSK_SHUFFLE_WEIRD_EGG] = Option::Bool("Shuffle Weird Egg", "gRandomizeShuffleWeirdEgg", mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG]); mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD] = Option::Bool("Shuffle Gerudo Membership Card", "gRandomizeShuffleGerudoToken", mOptionDescriptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD]); + mOptions[RSK_SHUFFLE_POTS] = Option::Bool("Shuffle Pot Contents", "gRandomizeShufflePotContents", mOptionDescriptions[RSK_SHUFFLE_POTS]); mOptions[RSK_SHUFFLE_MAGIC_BEANS] = Option::Bool("Shuffle Magic Beans", "gRandomizeShuffleBeans", mOptionDescriptions[RSK_SHUFFLE_MAGIC_BEANS]); mOptions[RSK_SHUFFLE_MERCHANTS] = Option::U8("Shuffle Merchants", {"Off", "On (No Hints)", "On (With Hints)"}, OptionCategory::Setting, "gRandomizeShuffleMerchants", mOptionDescriptions[RSK_SHUFFLE_MERCHANTS], WidgetType::Combobox, RO_SHUFFLE_MERCHANTS_OFF); mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES] = Option::Bool("Shuffle Frog Song Rupees", "gRandomizeShuffleFrogSongRupees", mOptionDescriptions[RSK_SHUFFLE_FROG_SONG_RUPEES]); @@ -614,7 +615,8 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_MASTER_SWORD], &mOptions[RSK_SHUFFLE_OCARINA], &mOptions[RSK_SHUFFLE_WEIRD_EGG], - &mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD] + &mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD], + &mOptions[RSK_SHUFFLE_POTS] }, false, WidgetContainerType::COLUMN); mOptionGroups[RSG_SHUFFLE_NPCS_IMGUI] = OptionGroup::SubGroup("Shuffle NPCs & Merchants", { &mOptions[RSK_SHOPSANITY], @@ -813,6 +815,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_OCARINA], &mOptions[RSK_SHUFFLE_WEIRD_EGG], &mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD], + &mOptions[RSK_SHUFFLE_POTS], &mOptions[RSK_SHUFFLE_MAGIC_BEANS], &mOptions[RSK_SHUFFLE_MERCHANTS], &mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES], @@ -1009,6 +1012,7 @@ void Settings::CreateOptions() { { "Shuffle Settings:Link's Pocket", RSK_LINKS_POCKET }, { "Shuffle Settings:Shuffle Songs", RSK_SHUFFLE_SONGS }, { "Shuffle Settings:Shuffle Gerudo Membership Card", RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD }, + { "Shuffle Settings:Shuffle Pot Contents", RSK_SHUFFLE_POTS }, { "Shuffle Settings:Shopsanity", RSK_SHOPSANITY }, { "Shuffle Settings:Shopsanity Prices", RSK_SHOPSANITY_PRICES }, { "Shuffle Settings:Affordable Prices", RSK_SHOPSANITY_PRICES_AFFORDABLE }, @@ -2060,6 +2064,7 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { } break; case RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD: + case RSK_SHUFFLE_POTS: case RSK_SHUFFLE_COWS: case RSK_SHUFFLE_ADULT_TRADE: case RSK_SHUFFLE_MAGIC_BEANS: diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index e4a5d7511..67424bec2 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1987,6 +1987,10 @@ extern "C" CowIdentity Randomizer_IdentifyCow(s32 sceneNum, s32 posX, s32 posZ) return OTRGlobals::Instance->gRandomizer->IdentifyCow(sceneNum, posX, posZ); } +extern "C" PotIdentity Randomizer_IdentifyPot(s32 sceneNum, s32 posX, s32 posY, s32 posZ) { + return OTRGlobals::Instance->gRandomizer->IdentifyPot(sceneNum, posX, posY, posZ); +} + extern "C" GetItemEntry ItemTable_Retrieve(int16_t getItemID) { GetItemEntry giEntry = ItemTableManager::Instance->RetrieveItemEntry(MOD_NONE, getItemID); return giEntry; diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index c9a6d3732..6d01f60ee 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -133,6 +133,7 @@ RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 sceneNum, s16 acto ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); ShopItemIdentity Randomizer_IdentifyShopItem(s32 sceneNum, u8 slotIndex); CowIdentity Randomizer_IdentifyCow(s32 sceneNum, s32 posX, s32 posZ); +PotIdentity Randomizer_IdentifyPot(s32 sceneNum, s32 posX, s32 posY, s32 posZ); void Randomizer_ParseSpoiler(const char* fileLoc); void Randomizer_LoadHintMessages(); void Randomizer_LoadMerchantMessages(); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 79a3c8ace..6d3de597d 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -2055,8 +2055,8 @@ s32 GiveItemEntryFromActor(Actor* actor, PlayState* play, GetItemEntry getItemEn * \param play the Global Context * \param getItemEntry the GetItemEntry for the item you want the player to receive. */ -void GiveItemEntryFromActorWithFixedRange(Actor* actor, PlayState* play, GetItemEntry getItemEntry) { - GiveItemEntryFromActor(actor, play, getItemEntry, 50.0f, 10.0f); +s32 GiveItemEntryFromActorWithFixedRange(Actor* actor, PlayState* play, GetItemEntry getItemEntry) { + return GiveItemEntryFromActor(actor, play, getItemEntry, 50.0f, 10.0f); } // TODO: Rename to GiveItemIdFromActor or similar diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index 42ea78f90..e5be29373 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -348,6 +348,7 @@ void EnItem00_Init(Actor* thisx, PlayState* play) { f32 shadowScale = 6.0f; s32 getItemId = GI_NONE; this->randoGiEntry = (GetItemEntry)GET_ITEM_NONE; + this->randoCheck = (RandomizerCheck)RC_UNKNOWN_CHECK; s16 spawnParam8000 = this->actor.params & 0x8000; s32 pad1; @@ -485,12 +486,11 @@ void EnItem00_Init(Actor* thisx, PlayState* play) { this->actor.shape.shadowAlpha = 180; this->actor.focus.pos = this->actor.world.pos; this->getItemId = GI_NONE; - RandomizerCheck randoCheck = - Randomizer_GetCheckFromActor(this->actor.id, play->sceneNum, this->ogParams); + this->randoCheck = Randomizer_GetCheckFromActor(this->actor.id, play->sceneNum, this->ogParams); + this->randoInf = RAND_INF_MAX; - if (IS_RANDO && randoCheck != RC_UNKNOWN_CHECK) { - this->randoGiEntry = - Randomizer_GetItemFromKnownCheck(randoCheck, getItemId); + if (IS_RANDO && this->randoCheck != RC_UNKNOWN_CHECK) { + this->randoGiEntry = Randomizer_GetItemFromKnownCheck(this->randoCheck, getItemId); this->randoGiEntry.getItemFrom = ITEM_FROM_FREESTANDING; } @@ -581,7 +581,10 @@ void EnItem00_Init(Actor* thisx, PlayState* play) { if (!IS_RANDO || this->randoGiEntry.getItemId == GI_NONE) { func_8002F554(&this->actor, play, getItemId); } else { - GiveItemEntryFromActorWithFixedRange(&this->actor, play, this->randoGiEntry); + if (GiveItemEntryFromActorWithFixedRange(&this->actor, play, this->randoGiEntry) && + this->randoInf != RAND_INF_MAX) { + Flags_SetRandomizerInf(this->randoInf); + } } } } @@ -734,7 +737,10 @@ void func_8001E5C8(EnItem00* this, PlayState* play) { if (!IS_RANDO) { func_8002F434(&this->actor, play, this->getItemId, 50.0f, 80.0f); } else { - GiveItemEntryFromActor(&this->actor, play, this->randoGiEntry, 50.0f, 80.0f); + if (GiveItemEntryFromActor(&this->actor, play, this->randoGiEntry, 50.0f, 80.0f) && + this->randoInf != RAND_INF_MAX) { + Flags_SetRandomizerInf(this->randoInf); + } } this->unk_15A++; } else { @@ -955,7 +961,10 @@ void EnItem00_Update(Actor* thisx, PlayState* play) { func_8002F554(&this->actor, play, getItemId); } else { getItemId = this->randoGiEntry.getItemId; - GiveItemEntryFromActorWithFixedRange(&this->actor, play, this->randoGiEntry); + if (GiveItemEntryFromActorWithFixedRange(&this->actor, play, this->randoGiEntry) && + this->randoInf != RAND_INF_MAX) { + Flags_SetRandomizerInf(this->randoInf); + } } } @@ -1363,12 +1372,8 @@ static const Vtx customDropVtx[] = { */ void EnItem00_DrawCollectible(EnItem00* this, PlayState* play) { if (IS_RANDO && (this->getItemId != GI_NONE || this->actor.params == ITEM00_SMALL_KEY)) { - RandomizerCheck randoCheck = - Randomizer_GetCheckFromActor(this->actor.id, play->sceneNum, this->ogParams); - - if (randoCheck != RC_UNKNOWN_CHECK) { - this->randoGiEntry = - Randomizer_GetItemFromKnownCheck(randoCheck, GI_NONE); + if (this->randoCheck != RC_UNKNOWN_CHECK) { + this->randoGiEntry = Randomizer_GetItemFromKnownCheck(this->randoCheck, GI_NONE); this->randoGiEntry.getItemFrom = ITEM_FROM_FREESTANDING; } @@ -1457,12 +1462,8 @@ void EnItem00_DrawHeartContainer(EnItem00* this, PlayState* play) { */ void EnItem00_DrawHeartPiece(EnItem00* this, PlayState* play) { if (IS_RANDO) { - RandomizerCheck randoCheck = - Randomizer_GetCheckFromActor(this->actor.id, play->sceneNum, this->ogParams); - - if (randoCheck != RC_UNKNOWN_CHECK) { - this->randoGiEntry = - Randomizer_GetItemFromKnownCheck(randoCheck, GI_NONE); + if (this->randoCheck != RC_UNKNOWN_CHECK) { + this->randoGiEntry = Randomizer_GetItemFromKnownCheck(this->randoCheck, GI_NONE); this->randoGiEntry.getItemFrom = ITEM_FROM_FREESTANDING; } diff --git a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c index 2346b34ff..f32021910 100644 --- a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c +++ b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c @@ -83,7 +83,29 @@ static InitChainEntry sInitChain[] = { ICHAIN_F32(uncullZoneScale, 100, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneDownward, 800, ICHAIN_STOP), }; +s8 ObjTsubo_HoldsRandomizedItem(ObjTsubo* this, PlayState* play) { + return Randomizer_GetSettingValue(RSK_SHUFFLE_POTS) && + !Flags_GetRandomizerInf(this->potIdentity.randomizerInf) && + this->potIdentity.randomizerCheck != RC_UNKNOWN_CHECK; +} + void ObjTsubo_SpawnCollectible(ObjTsubo* this, PlayState* play) { + + if (IS_RANDO && ObjTsubo_HoldsRandomizedItem(this, play)) { + GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(this->potIdentity.randomizerCheck, GI_NONE); + + EnItem00* actor = (EnItem00*)Item_DropCollectible2(play, &this->actor.world.pos, ITEM00_SMALL_KEY); + actor->randoCheck = this->potIdentity.randomizerCheck; + actor->randoGiEntry = getItemEntry; + actor->randoGiEntry.getItemFrom = ITEM_FROM_FREESTANDING; + actor->randoInf = this->potIdentity.randomizerInf; + actor->actor.velocity.y = 8.0f; + actor->actor.speedXZ = 2.0f; + actor->actor.gravity = -0.9f; + actor->actor.world.rot.y = Rand_CenteredFloat(65536.0f); + return; + } + s16 dropParams = this->actor.params & 0x1F; if ((dropParams >= ITEM00_RUPEE_GREEN) && (dropParams <= ITEM00_BOMBS_SPECIAL)) { @@ -145,6 +167,16 @@ void ObjTsubo_Init(Actor* thisx, PlayState* play) { ObjTsubo_SetupWaitForObject(this); osSyncPrintf("(dungeon keep 壷)(arg_data 0x%04x)\n", this->actor.params); } + if (IS_RANDO) { + this->potIdentity = Randomizer_IdentifyPot(play->sceneNum, (s16)this->actor.world.pos.x, + (s16)this->actor.world.pos.y, (s16)this->actor.world.pos.z); + + if (ObjTsubo_HoldsRandomizedItem(this, play)) { + this->actor.scale.x = 0.1f; + this->actor.scale.y = 0.1f; + this->actor.scale.z = 0.1f; + } + } } void ObjTsubo_Destroy(Actor* thisx, PlayState* play2) { diff --git a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.h b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.h index a83d43a47..74dbf6ebb 100644 --- a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.h +++ b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.h @@ -13,6 +13,7 @@ typedef struct ObjTsubo { /* 0x014C */ ObjTsuboActionFunc actionFunc; /* 0x0150 */ ColliderCylinder collider; /* 0x019C */ s8 objTsuboBankIndex; + /* */ PotIdentity potIdentity; } ObjTsubo; // size = 0x01A0 #endif