From 43510e5ad9f0fd6c6b720a0cb65eb6b232449690 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Mon, 24 Mar 2025 17:21:09 -0400 Subject: [PATCH] Fix Skull Tokens from Chests locking you in place (#5198) * temp fix for chest skulltulas * Implement way to load a vanilla message into a CustomMessage * dynamically inserts autodismiss text code to skulltula text. --- .../custom-message/CustomMessageManager.cpp | 38 +++++++++++++++++++ .../custom-message/CustomMessageManager.h | 2 + .../Enhancements/randomizer/hook_handlers.cpp | 5 ++- soh/soh/OTRGlobals.cpp | 8 +++- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp index 4d4d27b3f..1b993dab2 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp +++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.cpp @@ -114,6 +114,44 @@ CustomMessage::CustomMessage(Text text, TextBoxType type_,TextBoxPosition positi messages[LANGUAGE_FRA] = text.GetFrench(); } +typedef struct { + u16 textId; + u8 typePos; + const char* segment; + u32 msgSize; +} MessageTableEntry; + +extern "C" MessageTableEntry* sNesMessageEntryTablePtr; +extern "C" MessageTableEntry* sGerMessageEntryTablePtr; +extern "C" MessageTableEntry* sFraMessageEntryTablePtr; + +CustomMessage CustomMessage::LoadVanillaMessageTableEntry(uint16_t textId) { + const char* foundSeg; + const char* nextSeg; + MessageTableEntry* msgEntry = sNesMessageEntryTablePtr; + u16 bufferId = textId; + CustomMessage msg; + if (gSaveContext.language == LANGUAGE_GER) { + msgEntry = sGerMessageEntryTablePtr; + } else if (gSaveContext.language == LANGUAGE_FRA) { + msgEntry = sFraMessageEntryTablePtr; + } + while (msgEntry->textId != 0xFFFF) { + if (msgEntry->textId == bufferId) { + TextBoxPosition position = static_cast(msgEntry->typePos & 0xF); + TextBoxType type = static_cast(msgEntry->typePos >> 4); + // uint8_t icon = msgEntry->segment[1]; + std::string message = std::string(msgEntry->segment , msgEntry->msgSize); + msg = CustomMessage(message, type, position); + // msg.Format(static_cast(icon)); + return msg; + } + msgEntry++; + } + return CustomMessage(); +} + + const std::string CustomMessage::GetEnglish(MessageFormat format) const { return GetForLanguage(LANGUAGE_ENG, format); } diff --git a/soh/soh/Enhancements/custom-message/CustomMessageManager.h b/soh/soh/Enhancements/custom-message/CustomMessageManager.h index e8a969064..0720d8ac4 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageManager.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageManager.h @@ -47,6 +47,8 @@ class CustomMessage { CustomMessage(std::string english_, std::vector colors_, std::vector capital_ = {}, TextBoxType type_ = TEXTBOX_TYPE_BLACK, TextBoxPosition position_ = TEXTBOX_POS_BOTTOM); CustomMessage(Text text, TextBoxType type_ = TEXTBOX_TYPE_BLACK, TextBoxPosition position_ = TEXTBOX_POS_BOTTOM); + static CustomMessage LoadVanillaMessageTableEntry(uint16_t textId); + static std::string MESSAGE_END() ; static std::string ITEM_OBTAINED(uint8_t x) ; static std::string NEWLINE() ; diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 9a7a28806..2d40459ea 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -236,6 +236,7 @@ void RandomizerOnFlagSetHandler(int16_t flagType, int16_t flag) { RandomizerCheck rc = GetRandomizerCheckFromFlag(flagType, flag); if (rc == RC_UNKNOWN_CHECK) return; + if (flagType == FLAG_GS_TOKEN && Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_OFF)) return; auto loc = Rando::Context::GetInstance()->GetItemLocation(rc); if (loc == nullptr || loc->HasObtained() || loc->GetPlacedRandomizerGet() == RG_NONE) return; @@ -1610,7 +1611,6 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l case VB_GIVE_ITEM_FROM_LAB_DIVE: case VB_GIVE_ITEM_FROM_SKULL_KID_SARIAS_SONG: case VB_GIVE_ITEM_FROM_MAN_ON_ROOF: - case VB_GIVE_ITEM_SKULL_TOKEN: case VB_GIVE_ITEM_FROM_BLUE_WARP: case VB_GIVE_ITEM_FAIRY_OCARINA: case VB_GIVE_ITEM_WEIRD_EGG: @@ -1626,6 +1626,9 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l case VB_GIVE_ITEM_SHADOW_MEDALLION: *should = false; break; + case VB_GIVE_ITEM_SKULL_TOKEN: + *should = (Rando::Context::GetInstance()->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_OFF)); + break; default: break; } diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 5cdf06d9e..792bf0639 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2379,7 +2379,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { if (CVarGetInteger(CVAR_ENHANCEMENT("InjectItemCounts.GoldSkulltula"), 0) != 0) { // The freeze text cannot be manually dismissed and must be auto-dismissed. // This is fine and even wanted when skull tokens are not shuffled, but when - // when they are shuffled we don't want to be able to manually dismiss the box. + // when they are shuffled we want to be able to manually dismiss the box. // Otherwise if we get a token from a chest or an NPC we get stuck in the ItemGet // animation until the text box auto-dismisses. // RANDOTODO: Implement a way to determine if an item came from a skulltula and @@ -2395,7 +2395,11 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { s16 gsCount = gSaveContext.inventory.gsTokens + (IS_RANDO ? 1 : 0); messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId, MF_FORMATTED); messageEntry.Replace("[[gsCount]]", std::to_string(gsCount)); - } + } else if (CVarGetInteger(CVAR_ENHANCEMENT("SkulltulaFreeze"), 0) != 0 && (!IS_RANDO || Randomizer_GetSettingValue(RSK_SHUFFLE_TOKENS) == RO_TOKENSANITY_OFF)) { + messageEntry = CustomMessage::LoadVanillaMessageTableEntry(TEXT_GS_FREEZE); + messageEntry.Replace(CustomMessage::MESSAGE_END(), "\x0E\x3C"); + messageEntry += CustomMessage::MESSAGE_END(); + } } else if ((IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("BetterBombchuShopping"), 0)) && (textId == TEXT_BUY_BOMBCHUS_10_DESC || textId == TEXT_BUY_BOMBCHUS_10_PROMPT)) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId, MF_FORMATTED);