From cb215ede878fa8c135a3f2bcf202f59e8893957e Mon Sep 17 00:00:00 2001 From: OtherBlue <93625085+OtherBlue@users.noreply.github.com> Date: Mon, 22 Jun 2026 02:09:41 -0300 Subject: [PATCH] Custom Bottle Contents (#6780) --- .../object_custom_equip/object_custom_equip.h | 37 ++++++++++++++ soh/soh/Enhancements/customequipment.cpp | 50 +++++++++++++++++++ .../vanilla-behavior/GIVanillaBehavior.h | 10 ++++ soh/src/code/z_player_lib.c | 10 ++-- 4 files changed, 104 insertions(+), 3 deletions(-) diff --git a/soh/assets/objects/object_custom_equip/object_custom_equip.h b/soh/assets/objects/object_custom_equip/object_custom_equip.h index f86061a9a5..0e1c6e761f 100644 --- a/soh/assets/objects/object_custom_equip/object_custom_equip.h +++ b/soh/assets/objects/object_custom_equip/object_custom_equip.h @@ -143,6 +143,43 @@ static const ALIGN_ASSET(2) char gCustomChildGoronFPSHandDL[] = dgCustomChildGor #define dgCustomChildZoraFPSHandDL "__OTR__objects/object_custom_equip/gCustomChildZoraFPSHandDL" static const ALIGN_ASSET(2) char gCustomChildZoraFPSHandDL[] = dgCustomChildZoraFPSHandDL; +#define dgCustomBottleDL "__OTR__objects/object_custom_equip/gCustomBottleDL" +static const ALIGN_ASSET(2) char gCustomBottleDL[] = dgCustomBottleDL; +#define dgCustomBottleRedPotionDL "__OTR__objects/object_custom_equip/gCustomBottleRedPotionDL" +static const ALIGN_ASSET(2) char gCustomBottleRedPotionDL[] = dgCustomBottleRedPotionDL; + +#define dgCustomBottleGreenPotionDL "__OTR__objects/object_custom_equip/gCustomBottleGreenPotionDL" +static const ALIGN_ASSET(2) char gCustomBottleGreenPotionDL[] = dgCustomBottleGreenPotionDL; + +#define dgCustomBottleBluePotionDL "__OTR__objects/object_custom_equip/gCustomBottleBluePotionDL" +static const ALIGN_ASSET(2) char gCustomBottleBluePotionDL[] = dgCustomBottleBluePotionDL; + +#define dgCustomBottleFairyDL "__OTR__objects/object_custom_equip/gCustomBottleFairyDL" +static const ALIGN_ASSET(2) char gCustomBottleFairyDL[] = dgCustomBottleFairyDL; + +#define dgCustomBottleFishDL "__OTR__objects/object_custom_equip/gCustomBottleFishDL" +static const ALIGN_ASSET(2) char gCustomBottleFishDL[] = dgCustomBottleFishDL; + +#define dgCustomBottleMilkDL "__OTR__objects/object_custom_equip/gCustomBottleMilkDL" +static const ALIGN_ASSET(2) char gCustomBottleMilkDL[] = dgCustomBottleMilkDL; + +#define dgCustomBottleMilkHalfDL "__OTR__objects/object_custom_equip/gCustomBottleMilkHalfDL" +static const ALIGN_ASSET(2) char gCustomBottleMilkHalfDL[] = dgCustomBottleMilkHalfDL; + +#define dgCustomBottleLetterDL "__OTR__objects/object_custom_equip/gCustomBottleLetterDL" +static const ALIGN_ASSET(2) char gCustomBottleLetterDL[] = dgCustomBottleLetterDL; + +#define dgCustomBottleBlueFireDL "__OTR__objects/object_custom_equip/gCustomBottleBlueFireDL" +static const ALIGN_ASSET(2) char gCustomBottleBlueFireDL[] = dgCustomBottleBlueFireDL; + +#define dgCustomBottleBugDL "__OTR__objects/object_custom_equip/gCustomBottleBugDL" +static const ALIGN_ASSET(2) char gCustomBottleBugDL[] = dgCustomBottleBugDL; + +#define dgCustomBottleBigPoeDL "__OTR__objects/object_custom_equip/gCustomBottleBigPoeDL" +static const ALIGN_ASSET(2) char gCustomBottleBigPoeDL[] = dgCustomBottleBigPoeDL; + +#define dgCustomBottlePoeDL "__OTR__objects/object_custom_equip/gCustomBottlePoeDL" +static const ALIGN_ASSET(2) char gCustomBottlePoeDL[] = dgCustomBottlePoeDL; #endif // OBJECTS_OBJECT_CUSTOM_EQUIP_H diff --git a/soh/soh/Enhancements/customequipment.cpp b/soh/soh/Enhancements/customequipment.cpp index 4038c5bc85..be622330d1 100644 --- a/soh/soh/Enhancements/customequipment.cpp +++ b/soh/soh/Enhancements/customequipment.cpp @@ -202,6 +202,22 @@ static bool IsScalingAdultItemAsChild() { CVarGetInteger(CVAR_ENHANCEMENT("ScaleAdultEquipmentAsChild"), 0) && !LINK_IS_ADULT; } +const char* bottleContentDLs[] = { + nullptr, // 0: PLAYER_IA_BOTTLE (empty - no custom content needed) + gCustomBottleFishDL, // 1: PLAYER_IA_BOTTLE_FISH + gCustomBottleBlueFireDL, // 2: PLAYER_IA_BOTTLE_FIRE + gCustomBottleBugDL, // 3: PLAYER_IA_BOTTLE_BUG + gCustomBottlePoeDL, // 4: PLAYER_IA_BOTTLE_POE + gCustomBottleBigPoeDL, // 5: PLAYER_IA_BOTTLE_BIG_POE + gCustomBottleLetterDL, // 6: PLAYER_IA_BOTTLE_RUTOS_LETTER + gCustomBottleRedPotionDL, // 7: PLAYER_IA_BOTTLE_POTION_RED + gCustomBottleBluePotionDL, // 8: PLAYER_IA_BOTTLE_POTION_BLUE + gCustomBottleGreenPotionDL, // 9: PLAYER_IA_BOTTLE_POTION_GREEN + gCustomBottleMilkDL, // 10: PLAYER_IA_BOTTLE_MILK_FULL + gCustomBottleMilkHalfDL, // 11: PLAYER_IA_BOTTLE_MILK_HALF + gCustomBottleFairyDL, // 12: PLAYER_IA_BOTTLE_FAIRY +}; + static void RegisterCustomEquipment() { // World (gameplay) character COND_VB_SHOULD(VB_PLAYER_OVERRIDE_LIMB_DRAW, CVarGetInteger(CVAR_SETTING("AltAssets"), 1), { @@ -603,6 +619,40 @@ static void RegisterCustomEquipment() { gSPDisplayList(play->state.gfxCtx->polyOpa.p++, resolvedChain); } }); + + COND_VB_SHOULD(VB_PLAYER_DRAW_BOTTLE, CVarGetInteger(CVAR_SETTING("AltAssets"), 1), { + Player* player = va_arg(args, Player*); + PlayState* play = va_arg(args, PlayState*); + const char* contentDL = nullptr; + Gfx* resolvedContent = nullptr; + Gfx* resolvedBottle = LoadCustomGfx(gCustomBottleDL); + if (resolvedBottle) { + *should = false; + gSPDisplayList(play->state.gfxCtx->polyXlu.p++, resolvedBottle); + + if (player->itemAction >= PLAYER_IA_BOTTLE && + player->itemAction < PLAYER_IA_BOTTLE + std::size(bottleContentDLs)) { + contentDL = bottleContentDLs[player->itemAction - PLAYER_IA_BOTTLE]; + } + + if (contentDL) { + resolvedContent = LoadCustomGfx(contentDL); + } + + if (resolvedContent) { + gSPDisplayList(play->state.gfxCtx->polyOpa.p++, resolvedContent); + } + } + }); + + COND_VB_SHOULD(VB_PLAYER_UPDATE_BOTTLE_HELD, CVarGetInteger(CVAR_SETTING("AltAssets"), 1), { + Player* player = va_arg(args, Player*); + const bool isFullMilk = player->itemAction == PLAYER_IA_BOTTLE_MILK_FULL; + if (isFullMilk) { + *should = false; + player->itemAction = PLAYER_IA_BOTTLE_MILK_HALF; + } + }); } static RegisterShipInitFunc initFunc(RegisterCustomEquipment, { CVAR_SETTING("AltAssets") }); diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index db841e8745..4af469cbc4 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -2003,6 +2003,11 @@ typedef enum { // - `*int32_t` (arrowType) VB_PLAYER_ARROW_MAGIC_CONSUMPTION, + // #### `args` + // - `void*` player (Player*) + // - `PlayState*` play + VB_PLAYER_DRAW_BOTTLE, + // #### `args` // - `s32` limbIndex // - `Gfx**` dList (write to *dList to replace the resolved display list) @@ -2018,6 +2023,11 @@ typedef enum { // - `PlayState*` play VB_PLAYER_OVERRIDE_LIMB_DRAW_PAUSE, + // #### `args` + // - `*Player` + // - `*PlayState` + VB_PLAYER_UPDATE_BOTTLE_HELD, + // #### `result` // ```c // item == ITEM_SAW diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index 63684cc5f9..a440c9348a 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -693,7 +693,9 @@ void Player_UpdateBottleHeld(PlayState* play, Player* this, s32 item, s32 action this->heldItemAction = actionParam; } - this->itemAction = actionParam; + if (GameInteractor_Should(VB_PLAYER_UPDATE_BOTTLE_HELD, true, this)) { + this->itemAction = actionParam; + } } void Player_ReleaseLockOn(Player* this) { @@ -1833,8 +1835,10 @@ void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList, Ve OPEN_DISPS(play->state.gfxCtx); gSPMatrix(POLY_XLU_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gDPSetEnvColor(POLY_XLU_DISP++, bottleColor->r, bottleColor->g, bottleColor->b, 0); - gSPDisplayList(POLY_XLU_DISP++, sBottleDLists[(gSaveContext.linkAge)]); + if (GameInteractor_Should(VB_PLAYER_DRAW_BOTTLE, true, this, play)) { + gDPSetEnvColor(POLY_XLU_DISP++, bottleColor->r, bottleColor->g, bottleColor->b, 0); + gSPDisplayList(POLY_XLU_DISP++, sBottleDLists[gSaveContext.linkAge]); + } CLOSE_DISPS(play->state.gfxCtx); }