diff options
| author | mckinlee <mckinlee@ymail.com> | 2025-12-30 09:20:44 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-30 09:20:44 -0500 |
| commit | 14902f06c46b51e76aed63214fcc481dba5fd953 (patch) | |
| tree | 1d3e37b999b7040985558a3440122b9b883b6275 | |
| parent | f117e7384700ad217bfd13db77234b05daf041f4 (diff) | |
[Enhancement] Ammo Buyback (#1407)
* initial implementation
* feedback
* feedback 2
| -rw-r--r-- | mm/2s2h/BenGui/BenMenu.cpp | 16 | ||||
| -rw-r--r-- | mm/2s2h/Enhancements/Enhancements.h | 6 | ||||
| -rw-r--r-- | mm/2s2h/Enhancements/Items/AmmoBuyback.cpp | 408 | ||||
| -rw-r--r-- | mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h | 16 | ||||
| -rw-r--r-- | mm/src/code/z_message.c | 40 | ||||
| -rw-r--r-- | mm/src/code/z_message_nes.c | 22 |
6 files changed, 493 insertions, 15 deletions
diff --git a/mm/2s2h/BenGui/BenMenu.cpp b/mm/2s2h/BenGui/BenMenu.cpp index 66a5dd2a2..04d14a58c 100644 --- a/mm/2s2h/BenGui/BenMenu.cpp +++ b/mm/2s2h/BenGui/BenMenu.cpp @@ -57,6 +57,12 @@ static const std::vector<const char*> cremiaRewardOptions = { "Rupee", // CREMIA_REWARD_ALWAYS_RUPEE }; +static const std::vector<const char*> ammoBuybackOptions = { + "Vanilla", // AMMO_BUYBACK_VANILLA + "Full Price", // AMMO_BUYBACK_FULL_PRICE + "Half Price", // AMMO_BUYBACK_HALF_PRICE +}; + static const std::vector<const char*> gibdoTradeSequenceOptions = { "Vanilla", // GIBDO_TRADE_SEQUENCE_VANILLA "MM3D", // GIBDO_TRADE_SEQUENCE_MM3D @@ -1020,6 +1026,16 @@ void BenMenu::AddEnhancements() { "-Hug: Get the hugging cutscene\n" "-Rupee: Get the rupee reward") .ComboVec(&cremiaRewardOptions)); + AddWidget(path, "Ammo Buyback Options", WIDGET_CVAR_COMBOBOX) + .CVar("gEnhancements.Items.AmmoBuyback") + .Options(ComboboxOptions() + .Tooltip("Choose whether to allow selling ammo items (Arrows, Bombs, Bombchus, Deku Sticks, Deku " + "Nuts, Magic Beans, Powder Keg) " + "to the Curiosity Shop owner for Rupees.\n" + "-Vanilla: Ammo items cannot be sold\n" + "-Full Price: Sell at full value\n" + "-Half Price: Sell at half value (rounded up)") + .ComboVec(&ammoBuybackOptions)); AddWidget(path, "Accessibility", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Disable Screen Flash for Enemy Kills", WIDGET_CVAR_CHECKBOX) .CVar("gEnhancements.A11y.NoScreenFlashForEnemyKill") diff --git a/mm/2s2h/Enhancements/Enhancements.h b/mm/2s2h/Enhancements/Enhancements.h index 8b120dadf..13d8a5884 100644 --- a/mm/2s2h/Enhancements/Enhancements.h +++ b/mm/2s2h/Enhancements/Enhancements.h @@ -27,6 +27,12 @@ enum CremiaRewardsOptions { CREMIA_REWARD_ALWAYS_RUPEE, }; +enum AmmoBuybackOptions { + AMMO_BUYBACK_VANILLA, + AMMO_BUYBACK_FULL_PRICE, + AMMO_BUYBACK_HALF_PRICE, +}; + enum GibdoTradeSequenceOptions { GIBDO_TRADE_SEQUENCE_VANILLA, GIBDO_TRADE_SEQUENCE_MM3D, diff --git a/mm/2s2h/Enhancements/Items/AmmoBuyback.cpp b/mm/2s2h/Enhancements/Items/AmmoBuyback.cpp new file mode 100644 index 000000000..ded163021 --- /dev/null +++ b/mm/2s2h/Enhancements/Items/AmmoBuyback.cpp @@ -0,0 +1,408 @@ +#include <libultraship/bridge/consolevariablebridge.h> +#include "2s2h/GameInteractor/GameInteractor.h" +#include "2s2h/ShipInit.hpp" +#include "2s2h/CustomMessage/CustomMessage.h" +#include "2s2h/Enhancements/Enhancements.h" +#include "message_data_fmt_nes.h" + +extern "C" { +#include "overlays/actors/ovl_En_Fsn/z_en_fsn.h" + +void EnFsn_MakeOffer(EnFsn* thisx, PlayState* play); +void EnFsn_GiveItem(EnFsn* thisx, PlayState* play); +void EnFsn_StartBuying(EnFsn* thisx, PlayState* play); +void EnFsn_ResumeInteraction(EnFsn* enFsn, PlayState* play); +void Player_StartTalking(PlayState* play, Actor* actor); +void Player_StopCutscene(Player* player); +} + +#define CVAR_NAME "gEnhancements.Items.AmmoBuyback" +#define CVAR CVarGetInteger(CVAR_NAME, AMMO_BUYBACK_VANILLA) + +#define TEXT_ID_FSN_REJECTION 0x29CF // "Sorry, but I can't sell that here." +#define TEXT_ID_FSN_OFFER 0x29EF // Price offer dialogue +#define MAX_AMMO_SELL_QUANTITY 99 +#define STICK_THRESHOLD 30 +#define REPEAT_DELAY_INITIAL 10 +#define REPEAT_DELAY_CONTINUOUS 2 + +static struct { + EnFsn* actor = nullptr; + ItemId itemId = ITEM_NONE; + s16 quantity = 0; + s16 price = 0; + s16 lastRupeesSelected = 0; + bool isInputActive = false; +} sAmmoSale; + +static void Reset() { + sAmmoSale = {}; +} + +static s16 GetPricePerUnit(ItemId itemId) { + switch (itemId) { + case ITEM_BOW: + return 1; + case ITEM_BOMB: + return 3; + case ITEM_BOMBCHU: + return 4; + case ITEM_DEKU_STICK: + return 10; + case ITEM_DEKU_NUT: + return 3; + case ITEM_MAGIC_BEANS: + return 10; + case ITEM_POWDER_KEG: + return 50; + default: + return 0; + } +} + +static const char* GetNameForDialogue(ItemId itemId) { + switch (itemId) { + case ITEM_BOW: + return "%rArrows%w"; + case ITEM_BOMB: + return "%rBombs%w"; + case ITEM_BOMBCHU: + return "%rBombchus%w"; + case ITEM_DEKU_STICK: + return "%rDeku Sticks%w"; + case ITEM_DEKU_NUT: + return "%rDeku Nuts%w"; + case ITEM_MAGIC_BEANS: + return "%rMagic Beans%w"; + case ITEM_POWDER_KEG: + return "%rPowder Kegs%w"; + default: + return "%ritems%w"; + } +} + +static s16 GetSalePrice(ItemId itemId, s16 count) { + s16 totalPrice = count * GetPricePerUnit(itemId); + if (CVAR == AMMO_BUYBACK_HALF_PRICE) { + totalPrice = (totalPrice + 1) / 2; + } + return totalPrice; +} + +static bool IsItemAvailable(ItemId itemId) { + if (itemId == ITEM_POWDER_KEG) { + return INV_CONTENT(ITEM_POWDER_KEG) == ITEM_POWDER_KEG && AMMO(ITEM_POWDER_KEG) > 0; + } + if (itemId == ITEM_MAGIC_BEANS) { + return INV_CONTENT(ITEM_MAGIC_BEANS) == ITEM_MAGIC_BEANS && AMMO(ITEM_MAGIC_BEANS) > 0; + } + return Item_CheckObtainability(itemId) != ITEM_NONE; +} + +static void UpdateDigits(PlayState* play, s16 value) { + if (play->msgCtx.unk120C0 == 0) + return; + + char digits[3]; + // Layout: "XX0" where 3rd digit is hidden. + // Forces left alignment and matches internal *10 calc. + digits[0] = ((value / 10) % 10) + '0'; + digits[1] = (value % 10) + '0'; + digits[2] = '0'; + + // Writes digits and extra space to decodedBuffer + play->msgCtx.decodedBuffer.schar[play->msgCtx.unk120C0] = digits[0]; + play->msgCtx.decodedBuffer.schar[play->msgCtx.unk120C0 + 1] = digits[1]; + play->msgCtx.decodedBuffer.schar[play->msgCtx.unk120C0 + 2] = digits[2]; + play->msgCtx.decodedBuffer.schar[play->msgCtx.unk120C0 + 3] = ' '; + + // Render: [Tens] [Units] [Space] + Font_LoadCharNES(play, digits[0], play->msgCtx.unk120C4); + Font_LoadCharNES(play, digits[1], play->msgCtx.unk120C4 + (1 << 7)); + Font_LoadCharNES(play, ' ', play->msgCtx.unk120C4 + (2 << 7)); +} + +static bool UpdateInputState(bool isActive, bool* isHeld, s16* timer) { + if (!isActive) { + *isHeld = false; + *timer = 0; + return false; + } + if (!*isHeld) { + *isHeld = true; + *timer = REPEAT_DELAY_INITIAL; + return true; + } + if (*timer > 0) { + (*timer)--; + return false; + } + *timer = REPEAT_DELAY_CONTINUOUS; + return true; +} + +static void HandleStart(EnFsn* enFsn, PlayState* play) { + if (enFsn->price != 0 || enFsn->actor.textId != TEXT_ID_FSN_REJECTION) + return; + + Player* player = GET_PLAYER(play); + ItemId buttonItem = (ItemId)(IS_HELD_DPAD(player->heldItemButton) + ? DPAD_GET_CUR_FORM_BTN_ITEM(HELD_ITEM_TO_DPAD(player->heldItemButton)) + : GET_CUR_FORM_BTN_ITEM(player->heldItemButton)); + + if (GetPricePerUnit(buttonItem) > 0 && IsItemAvailable(buttonItem) && AMMO(buttonItem) > 0) { + sAmmoSale.actor = enFsn; + sAmmoSale.itemId = buttonItem; + sAmmoSale.lastRupeesSelected = 10; // Default for input mode + + // If player only has 1, skip inputs + s16 maxAllowed = MIN(AMMO(buttonItem), MAX_AMMO_SELL_QUANTITY); + + if (maxAllowed == 1) { + sAmmoSale.quantity = 1; + sAmmoSale.price = GetSalePrice(buttonItem, 1); + sAmmoSale.isInputActive = false; + enFsn->price = sAmmoSale.price; + } else { + sAmmoSale.quantity = 1; + sAmmoSale.price = 0; + sAmmoSale.isInputActive = true; + play->msgCtx.rupeesSelected = 10; + } + + enFsn->actionFunc = EnFsn_MakeOffer; + player->actor.textId = TEXT_ID_FSN_OFFER; + } +} + +static void HandleInput(EnFsn* enFsn, PlayState* play) { + static bool sStickHeldX = false, sStickHeldY = false; + static s16 sRepeatTimerX = 0, sRepeatTimerY = 0; + + MessageContext* msgCtx = &play->msgCtx; + Input* input = &play->state.input[0]; + + // Prevent input processing if the message system hasn't loaded our text yet + if (msgCtx->currentTextId != TEXT_ID_FSN_OFFER || msgCtx->unk120C0 == 0 || msgCtx->rupeesSelected < 10 || + msgCtx->msgMode == MSGMODE_NONE || msgCtx->msgMode == MSGMODE_TEXT_START || + msgCtx->msgMode == MSGMODE_TEXT_BOX_GROWING || msgCtx->msgMode == MSGMODE_TEXT_STARTING) { + return; + } + + s16 currentQuantity = (s16)(msgCtx->rupeesSelected / 10); + s16 newQuantity = currentQuantity; + s16 maxAllowed = MIN(AMMO(sAmmoSale.itemId), MAX_AMMO_SELL_QUANTITY); + + // Enforce cursor on visible digits (0=Tens, 1=Units) + if (msgCtx->unk120C2 > 1) + msgCtx->unk120C2 = 1; + + // Vertical Input (Quantity) + bool inputUp = CHECK_BTN_ALL(input->cur.button, BTN_DUP) || input->rel.stick_y >= STICK_THRESHOLD; + bool inputDown = CHECK_BTN_ALL(input->cur.button, BTN_DDOWN) || input->rel.stick_y <= -STICK_THRESHOLD; + s16 delta = (msgCtx->unk120C2 == 0) ? 10 : 1; + + if (inputUp) { + if (UpdateInputState(true, &sStickHeldY, &sRepeatTimerY)) + newQuantity += delta; + } else if (inputDown) { + if (UpdateInputState(true, &sStickHeldY, &sRepeatTimerY)) + newQuantity -= delta; + } else { + UpdateInputState(false, &sStickHeldY, &sRepeatTimerY); + } + + // Horizontal Input (Cursor) + bool inputRight = CHECK_BTN_ALL(input->cur.button, BTN_DRIGHT) || input->rel.stick_x >= STICK_THRESHOLD; + bool inputLeft = CHECK_BTN_ALL(input->cur.button, BTN_DLEFT) || input->rel.stick_x <= -STICK_THRESHOLD; + + if (inputRight) { + if (UpdateInputState(true, &sStickHeldX, &sRepeatTimerX)) { + msgCtx->unk120C2 = (msgCtx->unk120C2 >= 1) ? 1 : msgCtx->unk120C2 + 1; + Audio_PlaySfx(NA_SE_SY_CURSOR); + } + } else if (inputLeft) { + if (UpdateInputState(true, &sStickHeldX, &sRepeatTimerX)) { + msgCtx->unk120C2 = (msgCtx->unk120C2 <= 0) ? 0 : msgCtx->unk120C2 - 1; + Audio_PlaySfx(NA_SE_SY_CURSOR); + } + } else { + UpdateInputState(false, &sStickHeldX, &sRepeatTimerX); + } + + // Shortcuts + if (CHECK_BTN_ALL(input->press.button, BTN_Z)) + newQuantity = maxAllowed; + if (CHECK_BTN_ALL(input->press.button, BTN_R)) + newQuantity = 1; + + // Cleanup & Update + input->press.button &= ~(BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT); + input->cur.button &= ~(BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT); + input->rel.stick_x = 0; + input->rel.stick_y = 0; + + newQuantity = CLAMP(newQuantity, 1, maxAllowed); + + if (newQuantity != currentQuantity) { + msgCtx->rupeesSelected = newQuantity * 10; + UpdateDigits(play, newQuantity); + } + + if (newQuantity != (sAmmoSale.lastRupeesSelected / 10)) { + Audio_PlaySfx(NA_SE_SY_FSEL_CURSOR); + sAmmoSale.lastRupeesSelected = newQuantity * 10; + } + + if (Message_ShouldAdvance(play)) { + sAmmoSale.quantity = newQuantity; + sAmmoSale.price = GetSalePrice(sAmmoSale.itemId, newQuantity); + + enFsn->price = sAmmoSale.price; + sAmmoSale.isInputActive = false; + Message_StartTextbox(play, TEXT_ID_FSN_OFFER, &enFsn->actor); + } +} + +static void Resolve(EnFsn* enFsn, bool* shouldGiveItem) { + if (enFsn->actionFunc == EnFsn_GiveItem) { + *shouldGiveItem = false; + + Inventory_ChangeAmmo(sAmmoSale.itemId, -sAmmoSale.quantity); + Rupees_ChangeBy(sAmmoSale.price); + + enFsn->actor.parent = nullptr; + enFsn->actor.flags |= ACTOR_FLAG_TALK; + enFsn->actor.textId = 0; + enFsn->actionFunc = EnFsn_ResumeInteraction; + + Player* player = GET_PLAYER(gPlayState); + player->talkActor = &enFsn->actor; + player->talkActorDistance = enFsn->actor.xzDistToPlayer; + player->exchangeItemAction = PLAYER_IA_MINUS1; + player->getItemDrawIdPlusOne = 0; + player->getItemId = GI_NONE; + player->interactRangeActor = nullptr; + + Player_StopCutscene(player); + Player_StartTalking(gPlayState, &enFsn->actor); + + Reset(); + } +} + +static void HandleOfferResponse(EnFsn* enFsn, PlayState* play) { + if (sAmmoSale.isInputActive) + return; + + // Guard against these text states to prevent premature Reset + if (play->msgCtx.msgMode == MSGMODE_NONE || play->msgCtx.msgMode == MSGMODE_TEXT_START || + play->msgCtx.msgMode == MSGMODE_TEXT_BOX_GROWING || play->msgCtx.msgMode == MSGMODE_TEXT_STARTING) { + return; + } + + u8 talkState = Message_GetState(&play->msgCtx); + + // If choice was made (not 0/Yes), or text ended, reset + if ((talkState == TEXT_STATE_CHOICE && Message_ShouldAdvance(play) && play->msgCtx.choiceIndex != 0) || + talkState == TEXT_STATE_NONE) { + Reset(); + } +} + +static void DrawAmmoSelectionDigits() { + if (!sAmmoSale.isInputActive) + return; + + PlayState* play = gPlayState; + if (play->msgCtx.rupeesSelected < 10) { + play->msgCtx.rupeesSelected = 10; + sAmmoSale.lastRupeesSelected = 10; + } + UpdateDigits(play, play->msgCtx.rupeesSelected / 10); +} + +static void GenerateBuybackDialogue(u16* textId, bool* loadFromMessageTable) { + if (!sAmmoSale.actor) + return; + + if (sAmmoSale.isInputActive) { + // Custom Input Textbox + CustomMessage::Entry entry; + entry.textboxType = 6; + entry.textboxYPos = 1; + entry.msg = (char)MESSAGE_QUICKTEXT_ENABLE; + entry.msg += std::string("How many ") + GetNameForDialogue(sAmmoSale.itemId) + "? " + (char)MESSAGE_NEWLINE + + (char)MESSAGE_INPUT_BANK + (char)MESSAGE_NEWLINE + "Set the amount with " + + (char)MESSAGE_CONTROL_PAD + " and" + (char)MESSAGE_NEWLINE + "press " + (char)MESSAGE_BTN_A + + " to decide." + (char)MESSAGE_END; + + CustomMessage::LoadCustomMessageIntoFont(entry); + *loadFromMessageTable = false; + } else { + // Offer Textbox with Price Injection + auto entry = CustomMessage::LoadVanillaMessageTableEntry(*textId); + entry.autoFormat = false; + CustomMessage::Replace(&entry.msg, std::string(1, (char)MESSAGE_HELD_ITEM_PRICE), + std::to_string(sAmmoSale.price) + " Rupees"); + CustomMessage::LoadCustomMessageIntoFont(entry); + *loadFromMessageTable = false; + } +} + +static void UpdateBuybackInteraction(Actor* actor) { + EnFsn* enFsn = (EnFsn*)actor; + PlayState* play = gPlayState; + + if (enFsn->actionFunc == EnFsn_StartBuying) { + HandleStart(enFsn, play); + return; + } + if (sAmmoSale.actor != enFsn) + return; + if (sAmmoSale.isInputActive) + HandleInput(enFsn, play); + if (enFsn->actionFunc == EnFsn_MakeOffer) + HandleOfferResponse(enFsn, play); +} + +static void OnFsnDestroy(Actor* actor) { + if (sAmmoSale.actor == (EnFsn*)actor) + Reset(); +} + +static void BlockAmmoBuybackInput() { + if (!gPlayState || (GameState*)gPlayState != gGameState) + return; + + if (sAmmoSale.isInputActive) { + Input* input = &gPlayState->state.input[0]; + input->press.button &= ~(BTN_B | BTN_CUP); + input->cur.button &= ~(BTN_B | BTN_CUP); + } +} + +static void RegisterAmmoBuyback() { + COND_HOOK(OnInterfaceDrawStart, CVAR != AMMO_BUYBACK_VANILLA, DrawAmmoSelectionDigits); + COND_ID_HOOK(OnOpenText, TEXT_ID_FSN_OFFER, CVAR != AMMO_BUYBACK_VANILLA, GenerateBuybackDialogue); + COND_ID_HOOK(OnActorUpdate, ACTOR_EN_FSN, CVAR != AMMO_BUYBACK_VANILLA, UpdateBuybackInteraction); + COND_ID_HOOK(OnActorDestroy, ACTOR_EN_FSN, CVAR != AMMO_BUYBACK_VANILLA, OnFsnDestroy); + COND_HOOK(OnGameStateMainStart, CVAR != AMMO_BUYBACK_VANILLA, BlockAmmoBuybackInput); + + COND_VB_SHOULD(VB_MSG_LOAD_RUPEES_TEXT, CVAR != AMMO_BUYBACK_VANILLA, { + if (sAmmoSale.isInputActive) + *should = false; + }); + + COND_VB_SHOULD(VB_MSG_PLAY_INPUT_COUNT_SOUND, sAmmoSale.isInputActive, { *should = false; }); + + COND_VB_SHOULD(VB_GIVE_ITEM_FROM_OFFER, CVAR != AMMO_BUYBACK_VANILLA, { + GetItemId* item = va_arg(args, GetItemId*); + Actor* actor = va_arg(args, Actor*); + if (sAmmoSale.actor != nullptr && sAmmoSale.actor == (EnFsn*)actor) { + Resolve((EnFsn*)actor, should); + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterAmmoBuyback, { CVAR_NAME }); diff --git a/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h b/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h index 725b84053..a4bbe1793 100644 --- a/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h +++ b/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h @@ -1194,6 +1194,22 @@ typedef enum { // true // ``` // #### `args` + // - None + VB_MSG_LOAD_RUPEES_TEXT, + + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - None + VB_MSG_PLAY_INPUT_COUNT_SOUND, + + // #### `result` + // ```c + // true + // ``` + // #### `args` // - `*Actor` // - `s16` (item ID) VB_MSG_SCRIPT_DEL_ITEM, diff --git a/mm/src/code/z_message.c b/mm/src/code/z_message.c index 4ce98b5bd..0be1e96e8 100644 --- a/mm/src/code/z_message.c +++ b/mm/src/code/z_message.c @@ -688,7 +688,9 @@ void func_80148D64(PlayState* play) { } Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); - Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + if (GameInteractor_Should(VB_MSG_PLAY_INPUT_COUNT_SOUND, true)) { + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + } } else if (msgCtx->stickAdjY >= 30) { msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2]++; if (msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] > '9') { @@ -696,7 +698,9 @@ void func_80148D64(PlayState* play) { } Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); - Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + if (GameInteractor_Should(VB_MSG_PLAY_INPUT_COUNT_SOUND, true)) { + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + } } else if ((msgCtx->stickAdjX >= 30) && !sAnalogStickHeld) { sAnalogStickHeld = true; msgCtx->unk120C2++; @@ -732,7 +736,9 @@ void func_80149048(PlayState* play) { } Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); - Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + if (GameInteractor_Should(VB_MSG_PLAY_INPUT_COUNT_SOUND, true)) { + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + } } else if (msgCtx->stickAdjY >= 30) { msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2]++; if (msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] > '9') { @@ -740,7 +746,9 @@ void func_80149048(PlayState* play) { } Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); - Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + if (GameInteractor_Should(VB_MSG_PLAY_INPUT_COUNT_SOUND, true)) { + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + } } msgCtx->rupeesSelected = (msgCtx->decodedBuffer.schar[msgCtx->unk120C0] - '0') * 10; @@ -758,7 +766,9 @@ void func_801491DC(PlayState* play) { msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + '0'; Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); - Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + if (GameInteractor_Should(VB_MSG_PLAY_INPUT_COUNT_SOUND, true)) { + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + } } else if (msgCtx->stickAdjY >= 30) { msgCtx->unk12054[msgCtx->unk120C2]++; if (msgCtx->unk12054[msgCtx->unk120C2] > 5) { @@ -767,7 +777,9 @@ void func_801491DC(PlayState* play) { msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + '0'; Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); - Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + if (GameInteractor_Should(VB_MSG_PLAY_INPUT_COUNT_SOUND, true)) { + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + } } else if ((msgCtx->stickAdjX >= 30) && !sAnalogStickHeld) { sAnalogStickHeld = true; msgCtx->unk120C2++; @@ -801,7 +813,9 @@ void func_80149454(PlayState* play) { msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + '0'; Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); - Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + if (GameInteractor_Should(VB_MSG_PLAY_INPUT_COUNT_SOUND, true)) { + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + } } else if (msgCtx->stickAdjY >= 30) { msgCtx->unk12054[msgCtx->unk120C2]++; if (msgCtx->unk12054[msgCtx->unk120C2] > 9) { @@ -810,7 +824,9 @@ void func_80149454(PlayState* play) { msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + '0'; Font_LoadCharNES(play, msgCtx->decodedBuffer.schar[msgCtx->unk120C0 + msgCtx->unk120C2], msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); - Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + if (GameInteractor_Should(VB_MSG_PLAY_INPUT_COUNT_SOUND, true)) { + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + } } else if ((msgCtx->stickAdjX >= 30) && !sAnalogStickHeld) { sAnalogStickHeld = true; msgCtx->unk120C2++; @@ -844,7 +860,9 @@ void func_801496C8(PlayState* play) { msgCtx->decodedBuffer.wchar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + 0x824F; Font_LoadChar(play, msgCtx->decodedBuffer.wchar[msgCtx->unk120C0 + msgCtx->unk120C2], msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); - Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + if (GameInteractor_Should(VB_MSG_PLAY_INPUT_COUNT_SOUND, true)) { + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + } } else if (msgCtx->stickAdjY >= 30) { msgCtx->unk12054[msgCtx->unk120C2]++; if (msgCtx->unk12054[msgCtx->unk120C2] >= 4) { @@ -853,7 +871,9 @@ void func_801496C8(PlayState* play) { msgCtx->decodedBuffer.wchar[msgCtx->unk120C0 + msgCtx->unk120C2] = msgCtx->unk12054[msgCtx->unk120C2] + 0x824F; Font_LoadChar(play, msgCtx->decodedBuffer.wchar[msgCtx->unk120C0 + msgCtx->unk120C2], msgCtx->unk120C4 + (msgCtx->unk120C2 << 7)); - Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + if (GameInteractor_Should(VB_MSG_PLAY_INPUT_COUNT_SOUND, true)) { + Audio_PlaySfx(NA_SE_SY_RUPY_COUNT); + } } else if ((msgCtx->stickAdjX >= 30) && !sAnalogStickHeld) { sAnalogStickHeld = true; msgCtx->unk120C2++; diff --git a/mm/src/code/z_message_nes.c b/mm/src/code/z_message_nes.c index 3cdd9a5fb..79f6e7477 100644 --- a/mm/src/code/z_message_nes.c +++ b/mm/src/code/z_message_nes.c @@ -4,6 +4,7 @@ #include "assets/interface/message_texture_static/message_texture_static.h" #include <stdio.h> #include <libultraship/bridge/consolevariablebridge.h> +#include "2s2h/GameInteractor/GameInteractor.h" f32 sNESFontWidths[160] = { 8.0f, 8.0f, 6.0f, 9.0f, 9.0f, 14.0f, 12.0f, 3.0f, 7.0f, 7.0f, 7.0f, 9.0f, 4.0f, 6.0f, 4.0f, 9.0f, @@ -1291,7 +1292,9 @@ void Message_DecodeNES(PlayState* play) { Message_LoadCharNES(play, digits[i] + '0', &charTexIndex, &spA4, decodedBufPos); decodedBufPos++; } - Message_LoadLocalizedRupeesNES(play, &decodedBufPos, &charTexIndex, &spA4); + if (GameInteractor_Should(VB_MSG_LOAD_RUPEES_TEXT, true)) { + Message_LoadLocalizedRupeesNES(play, &decodedBufPos, &charTexIndex, &spA4); + } } else if (curChar == MESSAGE_RUPEES_SELECTED) { digits[0] = digits[1] = 0; digits[2] = msgCtx->rupeesSelected; @@ -1316,7 +1319,9 @@ void Message_DecodeNES(PlayState* play) { decodedBufPos++; } } - Message_LoadRupeesNES(play, &decodedBufPos, &charTexIndex, &spA4, msgCtx->rupeesSelected); + if (GameInteractor_Should(VB_MSG_LOAD_RUPEES_TEXT, true)) { + Message_LoadRupeesNES(play, &decodedBufPos, &charTexIndex, &spA4, msgCtx->rupeesSelected); + } } else if (curChar == MESSAGE_RUPEES_TOTAL) { digits[0] = digits[1] = digits[2] = 0; digits[3] = msgCtx->rupeesTotal; @@ -1344,7 +1349,9 @@ void Message_DecodeNES(PlayState* play) { decodedBufPos++; } } - Message_LoadRupeesNES(play, &decodedBufPos, &charTexIndex, &spA4, msgCtx->rupeesTotal); + if (GameInteractor_Should(VB_MSG_LOAD_RUPEES_TEXT, true)) { + Message_LoadRupeesNES(play, &decodedBufPos, &charTexIndex, &spA4, msgCtx->rupeesTotal); + } } else if (curChar == MESSAGE_TIME_UNTIL_MOON_CRASH) { Message_LoadTimeNES(play, curChar, &charTexIndex, &spA4, &decodedBufPos); } else if (curChar == MESSAGE_STRAY_FAIRIES) { @@ -1499,7 +1506,10 @@ void Message_DecodeNES(PlayState* play) { Message_LoadCharNES(play, digits[i] + '0', &charTexIndex, &spA4, decodedBufPos); decodedBufPos++; } - Message_LoadPluralRupeesNES(play, &decodedBufPos, &charTexIndex, &spA4); + if (GameInteractor_Should(VB_MSG_LOAD_RUPEES_TEXT, true)) { + Message_LoadPluralRupeesNES(play, &decodedBufPos, &charTexIndex, &spA4); + } + } else if (curChar == MESSAGE_INPUT_BOMBER_CODE) { decodedBufPos++; msgCtx->unk120BE = spC6; @@ -1674,7 +1684,9 @@ void Message_DecodeNES(PlayState* play) { spA4 += 16.0f * msgCtx->textCharScale; } } - Message_LoadPluralRupeesNES(play, &decodedBufPos, &charTexIndex, &spA4); + if (GameInteractor_Should(VB_MSG_LOAD_RUPEES_TEXT, true)) { + Message_LoadPluralRupeesNES(play, &decodedBufPos, &charTexIndex, &spA4); + } } else if (curChar == MESSAGE_BOMBER_CODE) { for (i = 0; i < 5; i++) { //! @bug OoB read & write for i == 4, digits array is only 4 elements |
