diff --git a/soh/soh/GameMenuBar.cpp b/soh/soh/GameMenuBar.cpp index b97bed5ea..95f269860 100644 --- a/soh/soh/GameMenuBar.cpp +++ b/soh/soh/GameMenuBar.cpp @@ -182,6 +182,8 @@ namespace GameMenuBar { CVar_SetS32("gInstantPutaway", 0); // Instant Boomerang Recall CVar_SetS32("gFastBoomerang", 0); + // Ask to Equip New Items + CVar_SetS32("gAskToEquip", 0); // Mask Select in Inventory CVar_SetS32("gMaskSelect", 0); // Remember Save Location @@ -441,6 +443,8 @@ namespace GameMenuBar { CVar_SetS32("gInstantPutaway", 1); // Instant Boomerang Recall CVar_SetS32("gFastBoomerang", 1); + // Ask to Equip New Items + CVar_SetS32("gAskToEquip", 1); // Mask Select in Inventory CVar_SetS32("gMaskSelect", 1); // Always Win Goron Pot @@ -809,6 +813,8 @@ namespace GameMenuBar { ); UIWidgets::PaddedEnhancementCheckbox("Skip Pickup Messages", "gFastDrops", true, false); UIWidgets::Tooltip("Skip pickup messages for new consumable items and bottle swipes"); + UIWidgets::PaddedEnhancementCheckbox("Ask to Equip New Items", "gAskToEquip", true, false); + UIWidgets::Tooltip("Adds a prompt to equip newly-obtained swords, shields and tunics"); UIWidgets::PaddedEnhancementCheckbox("Better Owl", "gBetterOwl", true, false); UIWidgets::Tooltip("The default response to Kaepora Gaebora is always that you understood what he said"); UIWidgets::PaddedEnhancementCheckbox("Fast Ocarina Playback", "gFastOcarinaPlayback", true, false); diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index b03421f33..85f971d5e 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1768,6 +1768,41 @@ extern "C" void* getN64WeirdFrame(s32 i) { return &weirdFrameBytes[i + sizeof(n64WeirdFrames)]; } +extern "C" int GetEquipNowMessage(char* buffer, char* src, const int maxBufferSize) { + std::string postfix; + + if (gSaveContext.language == LANGUAGE_FRA) { + postfix = "\x04\x1A\x08" "Désirez-vous l'équiper maintenant?" "\x09&&" + "\x1B%g" "Oui" "&" + "Non" "%w\x02"; + } else if (gSaveContext.language == LANGUAGE_GER) { + postfix = "\x04\x1A\x08" "Möchtest Du es jetzt ausrüsten?" "\x09&&" + "\x1B%g" "Ja!" "&" + "Nein!" "%w\x02"; + } else { + postfix = "\x04\x1A\x08" "Would you like to equip it now?" "\x09&&" + "\x1B%g" "Yes" "&" + "No" "%w\x02"; + } + CustomMessageManager::Instance->FormatCustomMessage(postfix); + std::string str; + std::string FixedBaseStr(src); + int RemoveControlChar = FixedBaseStr.find_first_of("\x02"); + + if (RemoveControlChar != std::string::npos) { + FixedBaseStr = FixedBaseStr.substr(0, RemoveControlChar); + } + str = FixedBaseStr + postfix; + + if (!str.empty()) { + memset(buffer, 0, maxBufferSize); + const int copiedCharLen = std::min(maxBufferSize - 1, str.length()); + memcpy(buffer, str.c_str(), copiedCharLen); + return copiedCharLen; + } + return 0; +} + extern "C" void Randomizer_LoadSettings(const char* spoilerFileName) { OTRGlobals::Instance->gRandomizer->LoadRandomizerSettings(spoilerFileName); } diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 7155dfbf0..0dc49b6e2 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -106,6 +106,7 @@ void Controller_BlockGameInput(); void Controller_UnblockGameInput(); void Hooks_ExecuteAudioInit(); void* getN64WeirdFrame(s32 i); +int GetEquipNowMessage(char* buffer, char* src, const int maxBufferSize); u32 SpoilerFileExists(const char* spoilerFileName); Sprite* GetSeedTexture(uint8_t index); void Randomizer_LoadSettings(const char* spoilerFileName); diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index ad6e3fd12..e756f9ed4 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -1748,6 +1748,19 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) { // OTRTODO //DmaMgr_SendRequest1(font->msgBuf, (uintptr_t)(_staff_message_data_staticSegmentRomStart + 4 + font->msgOffset), //font->msgLength, __FILE__, __LINE__); + + } else if (CVar_GetS32("gAskToEquip", 0) && + (((LINK_IS_ADULT || CVar_GetS32("gNoRestrictAge", 0)) && + // 0C = Biggoron, 4B = Giant's, 4E = Mirror Shield, 50-51 = Tunics + (textId == 0x0C || textId == 0x4B || textId == 0x4E || + textId == 0x50 || textId == 0x51)) || + ((!LINK_IS_ADULT || CVar_GetS32("gNoRestrictAge", 0)) && + // 4C = Deku Shield, A4 = Kokiri Sword + (textId == 0x4C || textId == 0xA4)) || + // 4D == Hylian Shield + textId == 0x4D)) { + Message_FindMessage(globalCtx, textId); + msgCtx->msgLength = font->msgLength = GetEquipNowMessage(font->msgBuf, font->msgOffset, sizeof(font->msgBuf)); } else { Message_FindMessage(globalCtx, textId); msgCtx->msgLength = font->msgLength; diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index c9b1bd79d..26f43dfce 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -12570,6 +12570,8 @@ s32 func_8084DFF4(GlobalContext* globalCtx, Player* this) { GetItemEntry giEntry; s32 temp1; s32 temp2; + static s32 equipItem; + static bool equipNow; if (this->getItemId == GI_NONE && this->getItemEntry.objectId == OBJECT_INVALID) { return 1; @@ -12582,6 +12584,10 @@ s32 func_8084DFF4(GlobalContext* globalCtx, Player* this) { giEntry = this->getItemEntry; } this->unk_84F = 1; + equipItem = giEntry.itemId; + equipNow = CVar_GetS32("gAskToEquip", 0) && equipItem >= ITEM_SWORD_KOKIRI && equipItem <= ITEM_TUNIC_ZORA && + ((gItemAgeReqs[equipItem] == 9 || gItemAgeReqs[equipItem] == gSaveContext.linkAge) || + CVar_GetS32("gNoRestrictAge", 0)); Message_StartTextbox(globalCtx, giEntry.textId, &this->actor); // RANDOTODO: Macro this boolean check. @@ -12632,6 +12638,30 @@ s32 func_8084DFF4(GlobalContext* globalCtx, Player* this) { // Just in case something weird happens with modIndex. Audio_PlayFanfare(NA_BGM_ITEM_GET | 0x900); } + } + else if (equipNow && Message_ShouldAdvanceSilent(globalCtx) && + Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_CHOICE) { + if (globalCtx->msgCtx.choiceIndex == 0) { // Equip now? Yes + + if (equipItem >= ITEM_SWORD_KOKIRI && equipItem <= ITEM_SWORD_BGS) { + gSaveContext.equips.buttonItems[0] = equipItem; + Inventory_ChangeEquipment(EQUIP_SWORD, equipItem - ITEM_SWORD_KOKIRI + 1); + func_808328EC(this, NA_SE_IT_SWORD_PUTAWAY); + + } else if (equipItem >= ITEM_SHIELD_DEKU && equipItem <= ITEM_SHIELD_MIRROR) { + Inventory_ChangeEquipment(EQUIP_SHIELD, equipItem - ITEM_SHIELD_DEKU + 1); + func_808328EC(&this->actor, NA_SE_IT_SHIELD_REMOVE); + Player_SetEquipmentData(globalCtx, this); + + } else if (equipItem == ITEM_TUNIC_GORON || equipItem == ITEM_TUNIC_ZORA) { + Inventory_ChangeEquipment(EQUIP_TUNIC, equipItem - ITEM_TUNIC_KOKIRI + 1); + func_808328EC(this, NA_SE_PL_CHANGE_ARMS); + Player_SetEquipmentData(globalCtx, this); + } + } + equipNow = false; + Message_CloseTextbox(globalCtx); + globalCtx->msgCtx.msgMode = MSGMODE_TEXT_DONE; } else { if (Message_GetState(&globalCtx->msgCtx) == TEXT_STATE_CLOSING) { if (this->getItemId == GI_GAUNTLETS_SILVER && !gSaveContext.n64ddFlag) {