Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement] Add Gibdo Trade Sequence Options #917

Merged
12 changes: 12 additions & 0 deletions mm/2s2h/BenGui/BenMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions mm/2s2h/BenGui/BenMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ static const std::unordered_map<int32_t, const char*> cremiaRewardOptions = {
{ CREMIA_REWARD_ALWAYS_RUPEE, "Rupee" },
};

static const std::unordered_map<int32_t, const char*> gibdoTradeSequenceOptions = {
{ GIBDO_TRADE_SEQUENCE_VANILLA, "Vanilla" },
{ GIBDO_TRADE_SEQUENCE_MM3D, "MM3D" },
{ GIBDO_TRADE_SEQUENCE_NO_TRADE, "No trade" },
};

static const std::unordered_map<int32_t, const char*> clockTypeOptions = {
{ CLOCK_TYPE_ORIGINAL, "Original" },
{ CLOCK_TYPE_3DS, "MM3D style" },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include <libultraship/bridge.h>
#include "2s2h/GameInteractor/GameInteractor.h"
#include "2s2h/Enhancements/Enhancements.h"
#include "2s2h/ShipInit.hpp"
#include <stdarg.h>

#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**);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be a nested pointer? I think you can get away with just the top level pointer and changing it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The top-level pointer requestedItem points to the sRequestedItemTable entry that contains the blue potion. If I passed requestedItem by copy to the hook, that would leave with the ability to alter the vanilla table, which I definitely want to avoid. If I had altered the table, and the player switched back to Vanilla behavior, the gibdo would only take a red potion, and not a blue one. So I definitely don't want to change what's already there, I found that the cleanest solution is to just pass a pointer to that pointer and change what it is pointing to, which would be our own entry.


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 });
6 changes: 6 additions & 0 deletions mm/2s2h/Enhancements/Enhancements.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions mm/2s2h/GameInteractor/GameInteractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
29 changes: 20 additions & 9 deletions mm/src/overlays/actors/ovl_En_Talk_Gibud/z_en_talk_gibud.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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;
Expand Down
Loading