summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett Cox <garrettjcox@gmail.com>2026-01-20 19:26:50 -0600
committerGitHub <noreply@github.com>2026-01-20 19:26:50 -0600
commitd7bd6f9c7df615cd1b41a5b482e2589a6a03cca0 (patch)
treee7ef22b8eb223bd5cd58310f1c85ae6837e5b2dd
parentf237dd2930e60a2128a0a80d4783318025dd8f1d (diff)
Implement sarias song hint item (#1161)
-rw-r--r--mm/2s2h/CustomMessage/CustomMessage.cpp55
-rw-r--r--mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTrackerSettings.cpp1
-rw-r--r--mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h16
-rw-r--r--mm/2s2h/Rando/DrawItem.cpp2
-rw-r--r--mm/2s2h/Rando/Logic/GeneratePools.cpp3
-rw-r--r--mm/2s2h/Rando/Menu.cpp7
-rw-r--r--mm/2s2h/Rando/MiscBehavior/MiscBehavior.cpp1
-rw-r--r--mm/2s2h/Rando/MiscBehavior/MiscBehavior.h1
-rw-r--r--mm/2s2h/Rando/MiscBehavior/SariasSongHint.cpp133
-rw-r--r--mm/2s2h/Rando/StaticData/Items.cpp5
-rw-r--r--mm/2s2h/Rando/StaticData/Options.cpp1
-rw-r--r--mm/2s2h/Rando/Types.h1
-rw-r--r--mm/src/code/z_message.c10
13 files changed, 221 insertions, 15 deletions
diff --git a/mm/2s2h/CustomMessage/CustomMessage.cpp b/mm/2s2h/CustomMessage/CustomMessage.cpp
index ff3a16152..3bc6c5f1f 100644
--- a/mm/2s2h/CustomMessage/CustomMessage.cpp
+++ b/mm/2s2h/CustomMessage/CustomMessage.cpp
@@ -65,37 +65,70 @@ void CustomMessage::AddLineBreaks(std::string* msg) {
for (size_t i = 0; i < msg->size(); ++i) {
char currentChar = (*msg)[i];
- if ((uint8_t)currentChar >= 0x20 && (uint8_t)currentChar < 0x20 + ARRAY_COUNTU(sNESFontWidths)) {
- currentLineWidth += sNESFontWidths[(uint8_t)currentChar - 0x20];
- }
-
- // Increment for existing new liens
+ // Handle existing newlines
if (currentChar == 0x11) {
currentLineWidth = 0.0f;
lastSpaceIndex = std::string::npos;
++currentLineCount;
+ continue;
+ }
+
+ // Handle existing box breaks
+ if (currentChar == 0x10) {
+ currentLineWidth = 0.0f;
+ lastSpaceIndex = std::string::npos;
+ currentLineCount = 0;
+ continue;
}
+ // Track spaces for word wrapping
if (currentChar == ' ') {
lastSpaceIndex = i;
}
- if (currentLineWidth > MAX_TEXTBOX_WIDTH) {
+
+ // Calculate width for printable characters
+ float charWidth = 0.0f;
+ if ((uint8_t)currentChar >= 0x20 && (uint8_t)currentChar < 0x20 + ARRAY_COUNTU(sNESFontWidths)) {
+ charWidth = sNESFontWidths[(uint8_t)currentChar - 0x20];
+ }
+
+ // Check if adding this character would exceed width
+ if (currentLineWidth + charWidth > MAX_TEXTBOX_WIDTH) {
if (lastSpaceIndex != std::string::npos) {
+ // Break at the last space
(*msg)[lastSpaceIndex] = 0x11;
- i = lastSpaceIndex;
+
+ // Recalculate width from after the space to current position
+ currentLineWidth = 0.0f;
+ for (size_t j = lastSpaceIndex + 1; j < i; ++j) {
+ char c = (*msg)[j];
+ if ((uint8_t)c >= 0x20 && (uint8_t)c < 0x20 + ARRAY_COUNTU(sNESFontWidths)) {
+ currentLineWidth += sNESFontWidths[(uint8_t)c - 0x20];
+ }
+ }
+ // Add current character's width
+ currentLineWidth += charWidth;
+
+ lastSpaceIndex = std::string::npos;
} else {
+ // No space found, force break before current character
msg->insert(i, 1, 0x11);
+ currentLineWidth = charWidth; // Current char is now first on new line
+ ++i; // Skip the inserted newline character
}
- currentLineWidth = 0.0f;
- lastSpaceIndex = std::string::npos;
++currentLineCount;
if (currentLineCount >= MAX_LINES_PER_PAGE) {
- // Replace the added new line for a box break instead
- (*msg)[i] = 0x10;
+ // Find the newline we just added and replace it with box break
+ size_t newlinePos = (lastSpaceIndex != std::string::npos) ? lastSpaceIndex : i - 1;
+ (*msg)[newlinePos] = 0x10;
currentLineCount = 0;
+ lastSpaceIndex = std::string::npos;
}
+ } else {
+ // Character fits on current line
+ currentLineWidth += charWidth;
}
}
}
diff --git a/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTrackerSettings.cpp b/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTrackerSettings.cpp
index 59e9045ba..285c935b4 100644
--- a/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTrackerSettings.cpp
+++ b/mm/2s2h/Enhancements/Trackers/ItemTracker/ItemTrackerSettings.cpp
@@ -288,6 +288,7 @@ void LoadAvailableWindows() {
{ TRACKER_ITEM_RANDO, RI_SONG_DOUBLE_TIME },
{ TRACKER_ITEM_RANDO, RI_SONG_INVERTED_TIME },
{ TRACKER_ITEM_RANDO, RI_SONG_SUN },
+ { TRACKER_ITEM_RANDO, RI_SONG_SARIA },
},
});
diff --git a/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h b/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h
index 6dbb8e53e..a1c657d1b 100644
--- a/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h
+++ b/mm/2s2h/GameInteractor/GameInteractor_VanillaBehavior.h
@@ -1259,6 +1259,22 @@ typedef enum {
// #### `result`
// ```c
+ // false
+ // ```
+ // #### `args`
+ // - None
+ VB_MSG_CAPTURE_MSGMODE_TEXT_DONE,
+
+ // #### `result`
+ // ```c
+ // false
+ // ```
+ // #### `args`
+ // - None
+ VB_MSG_CAPTURE_MSGMODE_TEXT_CLOSING_OCARINA_ACTION,
+
+ // #### `result`
+ // ```c
// true
// ```
// #### `args`
diff --git a/mm/2s2h/Rando/DrawItem.cpp b/mm/2s2h/Rando/DrawItem.cpp
index 6328f8172..c4592e464 100644
--- a/mm/2s2h/Rando/DrawItem.cpp
+++ b/mm/2s2h/Rando/DrawItem.cpp
@@ -101,6 +101,7 @@ void DrawSong(RandoItemId randoItemId) {
case RI_SONG_STORMS:
gDPSetEnvColor(POLY_XLU_DISP++, 146, 146, 146, 255);
break;
+ case RI_SONG_SARIA:
case RI_SONG_SONATA:
gDPSetEnvColor(POLY_XLU_DISP++, 98, 255, 98, 255);
break;
@@ -488,6 +489,7 @@ void Rando::DrawItem(RandoItemId randoItemId, RandoCheckId randoCheckId, Actor*
case RI_SONG_STORMS:
case RI_SONG_SUN:
case RI_SONG_HEALING:
+ case RI_SONG_SARIA:
case RI_SONG_SOARING:
case RI_SONG_SONATA:
case RI_SONG_ELEGY:
diff --git a/mm/2s2h/Rando/Logic/GeneratePools.cpp b/mm/2s2h/Rando/Logic/GeneratePools.cpp
index f90ed3e2a..a08738d24 100644
--- a/mm/2s2h/Rando/Logic/GeneratePools.cpp
+++ b/mm/2s2h/Rando/Logic/GeneratePools.cpp
@@ -217,6 +217,9 @@ void GeneratePools(RandoSaveInfo& saveInfo, std::vector<RandoCheckId>& checkPool
if (saveInfo.randoSaveOptions[RO_SHUFFLE_SONG_INVERTED_TIME] == RO_GENERIC_YES) {
itemPool.push_back(RI_SONG_INVERTED_TIME);
}
+ if (saveInfo.randoSaveOptions[RO_SHUFFLE_SONG_SARIA] == RO_GENERIC_YES) {
+ itemPool.push_back(RI_SONG_SARIA);
+ }
// Shuffle Triforce Pieces into the Pool
if (saveInfo.randoSaveOptions[RO_SHUFFLE_TRIFORCE_PIECES] == RO_GENERIC_YES) {
diff --git a/mm/2s2h/Rando/Menu.cpp b/mm/2s2h/Rando/Menu.cpp
index 1fa5865bf..50bd2921f 100644
--- a/mm/2s2h/Rando/Menu.cpp
+++ b/mm/2s2h/Rando/Menu.cpp
@@ -234,6 +234,7 @@ static RegisterShipInitFunc refreshMetricsInit(RefreshMetrics, {
"gRando.Options.RO_SHUFFLE_SNOWBALL_DROPS",
"gRando.Options.RO_SHUFFLE_SONG_DOUBLE_TIME",
"gRando.Options.RO_SHUFFLE_SONG_INVERTED_TIME",
+ "gRando.Options.RO_SHUFFLE_SONG_SARIA",
"gRando.Options.RO_SHUFFLE_SONG_SUN",
"gRando.Options.RO_SHUFFLE_SWIM",
"gRando.Options.RO_SHUFFLE_TINGLE_SHOPS",
@@ -439,6 +440,12 @@ static void DrawItemsTab() {
CVarCheckbox("Song of Double Time", Rando::StaticData::Options[RO_SHUFFLE_SONG_DOUBLE_TIME].cvar);
CVarCheckbox("Inverted Song of Time", Rando::StaticData::Options[RO_SHUFFLE_SONG_INVERTED_TIME].cvar);
CVarCheckbox("Sun's Song", Rando::StaticData::Options[RO_SHUFFLE_SONG_SUN].cvar);
+ CVarCheckbox(
+ "Saria's Song", Rando::StaticData::Options[RO_SHUFFLE_SONG_SARIA].cvar,
+ CheckboxOptions(
+ { { .tooltip = "Adds Saria's Song to the item pool, playing it will give you a hint to a progressive item "
+ "that is reachable in logic, weighted towards things like bow, bomb, and transformation "
+ "masks. The song is one time use, you will lose it after using it." } }));
CVarCheckbox("Deku Stick Bag", "gPlaceholderBool",
CheckboxOptions({ { .disabled = true, .disabledTooltip = "Coming Soon" } }));
CVarCheckbox("Deku Nut Bag", "gPlaceholderBool",
diff --git a/mm/2s2h/Rando/MiscBehavior/MiscBehavior.cpp b/mm/2s2h/Rando/MiscBehavior/MiscBehavior.cpp
index abef38721..fad880ca4 100644
--- a/mm/2s2h/Rando/MiscBehavior/MiscBehavior.cpp
+++ b/mm/2s2h/Rando/MiscBehavior/MiscBehavior.cpp
@@ -16,6 +16,7 @@ void Rando::MiscBehavior::OnFileLoad() {
Rando::MiscBehavior::CheckQueueReset();
Rando::MiscBehavior::InitKaleidoItemPage();
Rando::MiscBehavior::InitOfferGetItemBehavior();
+ Rando::MiscBehavior::SariasSongHint();
COND_HOOK(OnFlagSet, IS_RANDO, Rando::MiscBehavior::OnFlagSet);
COND_HOOK(OnSceneFlagSet, IS_RANDO, Rando::MiscBehavior::OnSceneFlagSet);
diff --git a/mm/2s2h/Rando/MiscBehavior/MiscBehavior.h b/mm/2s2h/Rando/MiscBehavior/MiscBehavior.h
index d0f93f436..372dd1893 100644
--- a/mm/2s2h/Rando/MiscBehavior/MiscBehavior.h
+++ b/mm/2s2h/Rando/MiscBehavior/MiscBehavior.h
@@ -22,6 +22,7 @@ void OnFlagSet(FlagType flagType, u32 flag);
void OnSceneFlagSet(s16 sceneId, FlagType flagType, u32 flag);
void OnSceneInit(s16 sceneId, s8 spawnNum);
void OfferTrapItem();
+void SariasSongHint();
} // namespace MiscBehavior
diff --git a/mm/2s2h/Rando/MiscBehavior/SariasSongHint.cpp b/mm/2s2h/Rando/MiscBehavior/SariasSongHint.cpp
new file mode 100644
index 000000000..bde8d62ed
--- /dev/null
+++ b/mm/2s2h/Rando/MiscBehavior/SariasSongHint.cpp
@@ -0,0 +1,133 @@
+#include "2s2h/CustomMessage/CustomMessage.h"
+#include "MiscBehavior.h"
+#include "2s2h/ShipUtils.h"
+#include <set>
+#include "2s2h/Rando/Logic/Logic.h"
+
+extern "C" {
+#include <variables.h>
+#include <z64ocarina.h>
+s32 Message_ShouldAdvanceSilent(PlayState* play);
+extern s16 sOcarinaSongFanfares[17];
+extern s16 sLastPlayedSong;
+}
+
+static int playedSariasSongState = 0;
+
+std::set<RandoItemId> priorityItems = {
+ RI_BOW, RI_HOOKSHOT, RI_MASK_BLAST, RI_BOMB_BAG_20, RI_MASK_DEKU, RI_MASK_GORON,
+ RI_MASK_ZORA, RI_MASK_FIERCE_DEITY, RI_SONG_SONATA, RI_SONG_LULLABY, RI_SONG_NOVA, RI_SONG_SOARING,
+};
+
+RandoCheckId GetProgressiveCheckInLogic() {
+ std::unordered_map<RandoRegionId, Rando::Logic::RegionTimeState> regionTimeStates =
+ Rando::Logic::InitializeRegionTimeStates(RR_MAX);
+ std::set<RandoRegionId> reachableRegions = {};
+ // Get connected entrances from starting & warp points
+ Rando::Logic::FindReachableRegions(RR_MAX, reachableRegions, regionTimeStates);
+ // Get connected regions from current entrance (TODO: Make this optional)
+ Rando::Logic::FindReachableRegions(Rando::Logic::GetRegionIdFromEntrance(gSaveContext.save.entrance),
+ reachableRegions, regionTimeStates);
+
+ std::vector<RandoCheckId> priorityChecks = {};
+ std::vector<RandoCheckId> otherChecks = {};
+
+ for (RandoRegionId regionId : reachableRegions) {
+ auto& randoRegion = Rando::Logic::Regions[regionId];
+ for (auto& [randoCheckId, accessLogicFunc] : randoRegion.checks) {
+ if (accessLogicFunc.first() && RANDO_SAVE_CHECKS[randoCheckId].shuffled &&
+ !RANDO_SAVE_CHECKS[randoCheckId].obtained) {
+ RandoItemId itemId = Rando::ConvertItem(RANDO_SAVE_CHECKS[randoCheckId].randoItemId, randoCheckId);
+ auto type = Rando::StaticData::Items[itemId].randoItemType;
+
+ if (priorityItems.contains(itemId)) {
+ priorityChecks.push_back(randoCheckId);
+ } else if (type == RITYPE_MAJOR || type == RITYPE_MASK) {
+ otherChecks.push_back(randoCheckId);
+ }
+ }
+ }
+ }
+
+ // First, we try to return a priority check if one is available, in order of the priority items list.
+ // If no priority checks are available, we return a random major/mask check.
+ return priorityChecks.empty()
+ ? (otherChecks.empty() ? RC_UNKNOWN : otherChecks[Ship_Random(0, otherChecks.size() - 1)])
+ : priorityChecks[0];
+}
+
+void Rando::MiscBehavior::SariasSongHint() {
+ bool shouldRegister = IS_RANDO && RANDO_SAVE_OPTIONS[RO_SHUFFLE_SONG_SARIA];
+
+ // Fix vanilla issue where saria's song plays the majoras lair fanfare
+ if (shouldRegister) {
+ sOcarinaSongFanfares[OCARINA_SONG_SARIAS] = NA_BGM_SARIAS_SONG;
+ } else {
+ sOcarinaSongFanfares[OCARINA_SONG_SARIAS] = NA_BGM_MAJORAS_LAIR;
+ }
+
+ COND_VB_SHOULD(VB_SONG_AVAILABLE_TO_PLAY, shouldRegister, {
+ uint8_t* songIndex = va_arg(args, uint8_t*);
+ // If the currently played song is Sun's Song, set it to be available to be played.
+ if (*songIndex == OCARINA_SONG_SARIAS && CHECK_QUEST_ITEM(QUEST_SONG_SARIA)) {
+ *should = true;
+ playedSariasSongState = 1;
+ }
+ });
+
+ COND_VB_SHOULD(VB_MSG_CAPTURE_MSGMODE_TEXT_DONE, shouldRegister, {
+ if (playedSariasSongState && gPlayState->msgCtx.ocarinaMode == OCARINA_MODE_PROCESS_RESTRICTED_SONG) {
+ *should = true;
+
+ if (Message_ShouldAdvanceSilent(gPlayState)) {
+ if (gPlayState->msgCtx.choiceIndex == 0) {
+ playedSariasSongState = 2;
+ Audio_PlaySfx(NA_SE_SY_DECIDE);
+ Message_ContinueTextbox(gPlayState, 0x1B95);
+ } else {
+ playedSariasSongState = 0;
+ Audio_PlaySfx(NA_SE_SY_DECIDE);
+ Message_CloseTextbox(gPlayState);
+ gPlayState->msgCtx.ocarinaMode = OCARINA_MODE_END;
+ }
+ }
+ }
+ });
+
+ COND_VB_SHOULD(VB_MSG_CAPTURE_MSGMODE_TEXT_CLOSING_OCARINA_ACTION, shouldRegister, {
+ MessageContext* msgCtx = &gPlayState->msgCtx;
+
+ if (sLastPlayedSong == OCARINA_SONG_SARIAS) {
+ *should = true;
+ Message_StartTextbox(gPlayState, 0x1B95, NULL);
+ gPlayState->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_RESTRICTED_SONG;
+ }
+ });
+
+ COND_ID_HOOK(OnOpenText, 0x1B95, shouldRegister, [](u16* textId, bool* loadFromMessageTable) {
+ CustomMessage::Entry entry;
+ if (playedSariasSongState == 1) {
+ entry.nextMessageID = 0x1B95;
+ entry.msg = "Call out to an old friend for help? You can only do this once.\x02\x11\xC2Yes\x11No";
+ } else if (playedSariasSongState == 2) {
+ RandoCheckId randoCheckId = GetProgressiveCheckInLogic();
+ entry.textboxType = TEXTBOX_TYPE_2;
+
+ if (randoCheckId == RC_UNKNOWN) {
+ entry.msg = "... You call out but there is no response ...";
+ } else {
+ entry.msg = "%g... Link? Is that you? Where have you been..?! Zelda has been worried sick about you! "
+ "... You need my help?\x10 Alright but just this once. Search %y{{location}}%g, you will "
+ "find what you need. Hurry now!";
+ CustomMessage::Replace(&entry.msg, "{{location}}",
+ Ship_GetSceneName(Rando::StaticData::Checks[randoCheckId].sceneId));
+ Rando::RemoveItem(RI_SONG_SARIA);
+ }
+
+ playedSariasSongState = 0;
+ }
+
+ CustomMessage::LoadCustomMessageIntoFont(entry);
+ *loadFromMessageTable = false;
+ });
+}
diff --git a/mm/2s2h/Rando/StaticData/Items.cpp b/mm/2s2h/Rando/StaticData/Items.cpp
index fb3ad9824..c6dde1b36 100644
--- a/mm/2s2h/Rando/StaticData/Items.cpp
+++ b/mm/2s2h/Rando/StaticData/Items.cpp
@@ -173,6 +173,7 @@ std::map<RandoItemId, RandoStaticItem> Items = {
RI(RI_SONG_LULLABY, "the", "Goron Lullaby", RITYPE_MAJOR, ITEM_SONG_LULLABY, GI_NONE, GID_NONE),
RI(RI_SONG_NOVA, "the", "New Wave Bossa Nova", RITYPE_MAJOR, ITEM_SONG_NOVA, GI_NONE, GID_NONE),
RI(RI_SONG_OATH, "the", "Oath to Order", RITYPE_MAJOR, ITEM_SONG_OATH, GI_NONE, GID_NONE),
+ RI(RI_SONG_SARIA, "", "Saria's Song", RITYPE_MAJOR, ITEM_SONG_SARIA, GI_NONE, GID_NONE),
RI(RI_SONG_SOARING, "the", "Song of Soaring", RITYPE_MAJOR, ITEM_SONG_SOARING, GI_NONE, GID_NONE),
RI(RI_SONG_SONATA, "the", "Sonata of Awakening", RITYPE_MAJOR, ITEM_SONG_SONATA, GI_NONE, GID_NONE),
RI(RI_SONG_STORMS, "the", "Song of Storms", RITYPE_MAJOR, ITEM_SONG_STORMS, GI_NONE, GID_NONE),
@@ -282,7 +283,7 @@ std::map<StartingItemCategory, std::vector<RandoItemId>> StartingItemsMap = {
RI_PROGRESSIVE_WALLET,
RI_SONG_TIME, RI_SONG_HEALING, RI_SONG_EPONA, RI_SONG_SOARING, RI_SONG_STORMS,
RI_SONG_SONATA, RI_PROGRESSIVE_LULLABY, RI_SONG_NOVA, RI_SONG_ELEGY, RI_SONG_OATH,
- RI_SONG_DOUBLE_TIME, RI_SONG_INVERTED_TIME, RI_SONG_SUN
+ RI_SONG_DOUBLE_TIME, RI_SONG_INVERTED_TIME, RI_SONG_SUN, RI_SONG_SARIA,
} },
{ STARTING_ITEMS_TRADE,
{ RI_MOONS_TEAR, RI_DEED_LAND, RI_DEED_SWAMP, RI_DEED_MOUNTAIN, RI_DEED_OCEAN, RI_ROOM_KEY, RI_LETTER_TO_MAMA,
@@ -510,6 +511,8 @@ const char* GetIconTexturePath(RandoItemId randoItemId) {
case RI_SONG_DOUBLE_TIME:
case RI_SONG_INVERTED_TIME:
return (const char*)gItemIcons[ITEM_SONG_TIME];
+ case RI_SONG_SARIA:
+ return (const char*)gItemIcons[ITEM_SONG_SARIA];
default:
break;
}
diff --git a/mm/2s2h/Rando/StaticData/Options.cpp b/mm/2s2h/Rando/StaticData/Options.cpp
index a863f39ee..0aa955749 100644
--- a/mm/2s2h/Rando/StaticData/Options.cpp
+++ b/mm/2s2h/Rando/StaticData/Options.cpp
@@ -54,6 +54,7 @@ std::map<RandoOptionId, RandoStaticOption> Options = {
RO(RO_SHUFFLE_SNOWBALL_DROPS, RO_GENERIC_OFF),
RO(RO_SHUFFLE_SONG_DOUBLE_TIME, RO_GENERIC_OFF),
RO(RO_SHUFFLE_SONG_INVERTED_TIME, RO_GENERIC_OFF),
+ RO(RO_SHUFFLE_SONG_SARIA, RO_GENERIC_OFF),
RO(RO_SHUFFLE_SONG_SUN, RO_GENERIC_OFF),
RO(RO_SHUFFLE_SWIM, RO_GENERIC_OFF),
RO(RO_SHUFFLE_TINGLE_SHOPS, RO_GENERIC_OFF),
diff --git a/mm/2s2h/Rando/Types.h b/mm/2s2h/Rando/Types.h
index 15caa3748..3f105bea0 100644
--- a/mm/2s2h/Rando/Types.h
+++ b/mm/2s2h/Rando/Types.h
@@ -2985,6 +2985,7 @@ typedef enum {
RO_SHUFFLE_SNOWBALL_DROPS,
RO_SHUFFLE_SONG_DOUBLE_TIME,
RO_SHUFFLE_SONG_INVERTED_TIME,
+ RO_SHUFFLE_SONG_SARIA,
RO_SHUFFLE_SONG_SUN,
RO_SHUFFLE_SWIM,
RO_SHUFFLE_TINGLE_SHOPS,
diff --git a/mm/src/code/z_message.c b/mm/src/code/z_message.c
index af383621c..04efc6f8c 100644
--- a/mm/src/code/z_message.c
+++ b/mm/src/code/z_message.c
@@ -5819,8 +5819,10 @@ void Message_Update(PlayState* play) {
break;
}
- if ((msgCtx->textboxEndType == TEXTBOX_ENDTYPE_TWO_CHOICE) &&
- (play->msgCtx.ocarinaMode == OCARINA_MODE_ACTIVE)) {
+ if (GameInteractor_Should(VB_MSG_CAPTURE_MSGMODE_TEXT_DONE, false)) {
+ // no-op
+ } else if ((msgCtx->textboxEndType == TEXTBOX_ENDTYPE_TWO_CHOICE) &&
+ (play->msgCtx.ocarinaMode == OCARINA_MODE_ACTIVE)) {
if (Message_ShouldAdvance(play)) {
if (msgCtx->choiceIndex == 0) {
play->msgCtx.ocarinaMode = OCARINA_MODE_WARP;
@@ -6042,7 +6044,9 @@ void Message_Update(PlayState* play) {
if (msgCtx->ocarinaAction != OCARINA_ACTION_CHECK_NOTIME_DONE) {
s16 pad;
- if (sLastPlayedSong == OCARINA_SONG_TIME) {
+ if (GameInteractor_Should(VB_MSG_CAPTURE_MSGMODE_TEXT_CLOSING_OCARINA_ACTION, false)) {
+ // no-op
+ } else if (sLastPlayedSong == OCARINA_SONG_TIME) {
if (interfaceCtx->restrictions.songOfTime == 0) {
Message_StartTextbox(play, 0x1B8A, NULL);
play->msgCtx.ocarinaMode = OCARINA_MODE_PROCESS_SOT;