diff --git a/mm/2s2h/BenGui/BenMenu.cpp b/mm/2s2h/BenGui/BenMenu.cpp index 4dd8c419c7..6bf1775e73 100644 --- a/mm/2s2h/BenGui/BenMenu.cpp +++ b/mm/2s2h/BenGui/BenMenu.cpp @@ -1188,6 +1188,18 @@ void BenMenu::AddEnhancements() { "- Always: Always show the search balls.") .DefaultIndex(DekuGuardSearchBallsOptions::DEKU_GUARD_SEARCH_BALLS_NIGHT_ONLY) .ComboMap(dekuGuardSearchBallsOptions)); + AddWidget(path, "Gibdo Trade Sequence Options", WIDGET_CVAR_COMBOBOX) + .CVar("gEnhancements.Cheats.GibdoTradeSequence") + .Options( + ComboboxOptions() + .Tooltip( + "Changes the way the Gibdo Trade Sequence works\n" + "-Vanilla: Works normally\n" + "-MM3D: Gibdos will only take one quantity of the item they request, as they do in MM3D. The Gibdo " + "requesting a blue potion will also accept a red potion.\n" + "-No trade: Gibdos will vanish without taking items") + .DefaultIndex(GibdoTradeSequenceOptions::GIBDO_TRADE_SEQUENCE_VANILLA) + .ComboMap(gibdoTradeSequenceOptions)); path.column = 2; AddWidget(path, "Damage Multiplier", WIDGET_CVAR_COMBOBOX) diff --git a/mm/2s2h/BenGui/BenMenu.h b/mm/2s2h/BenGui/BenMenu.h index 551fe915de..7927b225c3 100644 --- a/mm/2s2h/BenGui/BenMenu.h +++ b/mm/2s2h/BenGui/BenMenu.h @@ -39,6 +39,12 @@ static const std::unordered_map cremiaRewardOptions = { { CREMIA_REWARD_ALWAYS_RUPEE, "Rupee" }, }; +static const std::unordered_map gibdoTradeSequenceOptions = { + { GIBDO_TRADE_SEQUENCE_VANILLA, "Vanilla" }, + { GIBDO_TRADE_SEQUENCE_MM3D, "MM3D" }, + { GIBDO_TRADE_SEQUENCE_NO_TRADE, "No trade" }, +}; + static const std::unordered_map clockTypeOptions = { { CLOCK_TYPE_ORIGINAL, "Original" }, { CLOCK_TYPE_3DS, "MM3D style" }, diff --git a/mm/2s2h/Enhancements/DifficultyOptions/GibdoTradeSequenceOptions.cpp b/mm/2s2h/Enhancements/DifficultyOptions/GibdoTradeSequenceOptions.cpp new file mode 100644 index 0000000000..e5e3762a20 --- /dev/null +++ b/mm/2s2h/Enhancements/DifficultyOptions/GibdoTradeSequenceOptions.cpp @@ -0,0 +1,71 @@ +#include +#include "2s2h/GameInteractor/GameInteractor.h" +#include "2s2h/Enhancements/Enhancements.h" +#include "2s2h/ShipInit.hpp" +#include + +#define CVAR_NAME "gEnhancements.Cheats.GibdoTradeSequence" +#define CVAR CVarGetInteger(CVAR_NAME, GIBDO_TRADE_SEQUENCE_VANILLA) + +extern "C" { +#include "functions.h" +#include "variables.h" +#include "overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.h" + +// redefinition +typedef struct { + /* 0x0 */ PlayerItemAction itemAction; + /* 0x4 */ ItemId item; + /* 0x8 */ s32 amount; + /* 0xC */ s16 isBottledItem; +} EnTalkGibudRequestedItem; // size = 0x10 +} + +static EnTalkGibudRequestedItem redPotionRequestedItem = { PLAYER_IA_BOTTLE_POTION_RED, ITEM_POTION_RED, 1, true }; + +void RegisterGibdoTradeSequenceOptions() { + COND_VB_SHOULD(VB_GIBDO_TRADE_SEQUENCE_SUFFICIENT_QUANTITY_PRESENTED, CVAR != GIBDO_TRADE_SEQUENCE_VANILLA, { + ItemId requestedItemId = (ItemId)va_arg(args, int); + if (AMMO(requestedItemId) >= 1) { + *should = true; + } + }); + + COND_VB_SHOULD(VB_GIBDO_TRADE_SEQUENCE_ACCEPT_RED_POTION, CVAR == GIBDO_TRADE_SEQUENCE_MM3D, { + PlayerItemAction requestedItemAction = (PlayerItemAction)va_arg(args, int); + PlayerItemAction presentedItemAction = (PlayerItemAction)va_arg(args, int); + + EnTalkGibudRequestedItem** requestedItem = va_arg(args, EnTalkGibudRequestedItem**); + + if (requestedItemAction == PLAYER_IA_BOTTLE_POTION_BLUE && + presentedItemAction == + PLAYER_IA_BOTTLE_POTION_RED) { // If requested blue potion, but presented red potion, switch out + // requested item from blue potion to red potion. + *should = true; + *requestedItem = &redPotionRequestedItem; + } + }); + + COND_VB_SHOULD(VB_GIBDO_TRADE_SEQUENCE_TAKE_MORE_THAN_ONE_ITEM, CVAR != GIBDO_TRADE_SEQUENCE_VANILLA, { + *should = false; + + EnTalkGibudRequestedItem* requestedItem = va_arg(args, EnTalkGibudRequestedItem*); + if (CVAR == GIBDO_TRADE_SEQUENCE_MM3D) { + Inventory_ChangeAmmo(requestedItem->item, -1); + } + }); + + COND_VB_SHOULD(VB_GIBDO_TRADE_SEQUENCE_DO_TRADE, CVAR == GIBDO_TRADE_SEQUENCE_NO_TRADE, { + *should = false; + + EnTalkGibud* gibudCtx = va_arg(args, EnTalkGibud*); + bool doEndTradeMessage = va_arg(args, bool); + + if (doEndTradeMessage) { + Message_StartTextbox(gPlayState, 0x138A, &gibudCtx->actor); + gibudCtx->textId = 0x138A; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterGibdoTradeSequenceOptions, { CVAR_NAME }); \ No newline at end of file diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 2ee05bba1c..cfda54a430 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -27,6 +27,12 @@ enum CremiaRewardsOptions { CREMIA_REWARD_ALWAYS_RUPEE, }; +enum GibdoTradeSequenceOptions { + GIBDO_TRADE_SEQUENCE_VANILLA, + GIBDO_TRADE_SEQUENCE_MM3D, + GIBDO_TRADE_SEQUENCE_NO_TRADE, +}; + enum DekuGuardSearchBallsOptions { DEKU_GUARD_SEARCH_BALLS_NIGHT_ONLY, DEKU_GUARD_SEARCH_BALLS_NEVER, diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index 434e9f28bc..5fa2e81bfa 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -94,6 +94,10 @@ typedef enum { VB_GORON_ROLL_DISABLE_SPIKE_MODE, VB_DEKU_LINK_SPIN_ON_LAST_HOP, VB_CLAMP_ANIMATION_SPEED, + VB_GIBDO_TRADE_SEQUENCE_SUFFICIENT_QUANTITY_PRESENTED, + VB_GIBDO_TRADE_SEQUENCE_ACCEPT_RED_POTION, + VB_GIBDO_TRADE_SEQUENCE_TAKE_MORE_THAN_ONE_ITEM, + VB_GIBDO_TRADE_SEQUENCE_DO_TRADE, } GIVanillaBehavior; typedef enum { diff --git a/mm/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.c b/mm/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.c index 2bfa81c840..3fc9f62b36 100644 --- a/mm/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.c +++ b/mm/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.c @@ -3,7 +3,7 @@ * Overlay: ovl_En_Talk_Gibud * Description: Gibdos requesting items Beneath the Well */ - +#include "2s2h/GameInteractor/GameInteractor.h" #include "z_en_talk_gibud.h" #include "z64rumble.h" @@ -713,10 +713,12 @@ void EnTalkGibud_GetNextTextBoxId(EnTalkGibud* this, PlayState* play) { s32 EnTalkGibud_PresentedItemMatchesRequest(EnTalkGibud* this, PlayState* play, PlayerItemAction presentedItemAction) { EnTalkGibudRequestedItem* requestedItem = &sRequestedItemTable[this->requestedItemIndex]; - + GameInteractor_Should(VB_GIBDO_TRADE_SEQUENCE_ACCEPT_RED_POTION, false, requestedItem->itemAction, + presentedItemAction, &requestedItem); if (requestedItem->itemAction == presentedItemAction) { if (!requestedItem->isBottledItem) { - if (AMMO(requestedItem->item) >= requestedItem->amount) { + if (GameInteractor_Should(VB_GIBDO_TRADE_SEQUENCE_SUFFICIENT_QUANTITY_PRESENTED, + AMMO(requestedItem->item) >= requestedItem->amount, requestedItem->item)) { return EN_TALK_GIBUD_REQUESTED_ITEM_MET; } else { return EN_TALK_GIBUD_REQUESTED_ITEM_NOT_ENOUGH_AMMO; @@ -782,8 +784,10 @@ void EnTalkGibud_SetupPassiveIdle(EnTalkGibud* this) { void EnTalkGibud_PassiveIdle(EnTalkGibud* this, PlayState* play) { if (Actor_ProcessTalkRequest(&this->actor, &play->state)) { this->isTalking = true; - Message_StartTextbox(play, 0x1388, &this->actor); - this->textId = 0x1388; + if (GameInteractor_Should(VB_GIBDO_TRADE_SEQUENCE_DO_TRADE, true, this, true)) { + Message_StartTextbox(play, 0x1388, &this->actor); + this->textId = 0x1388; + } Actor_PlaySfx(&this->actor, NA_SE_EN_REDEAD_AIM); EnTalkGibud_SetupTalk(this); } else if (this->actor.xzDistToPlayer < 100.0f && !(this->collider.base.acFlags & AC_HIT)) { @@ -828,10 +832,17 @@ void EnTalkGibud_Talk(EnTalkGibud* this, PlayState* play) { if (this->textId == 0x138A) { // Remove the requested item/amount from the player's inventory requestedItem = &sRequestedItemTable[this->requestedItemIndex]; - if (!requestedItem->isBottledItem) { - Inventory_ChangeAmmo(requestedItem->item, -requestedItem->amount); - } else { - Player_UpdateBottleHeld(play, player, ITEM_BOTTLE, PLAYER_IA_BOTTLE_EMPTY); + if (GameInteractor_Should(VB_GIBDO_TRADE_SEQUENCE_DO_TRADE, true, this, + false)) { // We don't want to try to change their inventory if they don't + // need to trade anything + if (!requestedItem->isBottledItem) { + if (GameInteractor_Should(VB_GIBDO_TRADE_SEQUENCE_TAKE_MORE_THAN_ONE_ITEM, true, + requestedItem)) { + Inventory_ChangeAmmo(requestedItem->item, -requestedItem->amount); + } + } else { + Player_UpdateBottleHeld(play, player, ITEM_BOTTLE, PLAYER_IA_BOTTLE_EMPTY); + } } player->stateFlags1 |= PLAYER_STATE1_20; player->stateFlags1 |= PLAYER_STATE1_20000000;