From 6b6805d9cfa51d462699d692af692a16cc03fb3c Mon Sep 17 00:00:00 2001 From: lilDavid <1337lilDavid@gmail.com> Date: Sat, 26 Nov 2022 11:39:04 -0600 Subject: [PATCH] Overhaul item menu layout --- soh/include/variables.h | 2 +- soh/include/z64.h | 2 + soh/include/z64item.h | 60 +-- soh/include/z64save.h | 5 +- .../controls/GameControlEditor.cpp | 2 + .../cosmetics/CosmeticsEditor.cpp | 2 +- .../custom-message/CustomMessageTypes.h | 3 + .../Enhancements/debugger/debugSaveEditor.cpp | 12 +- soh/soh/Enhancements/presets.h | 7 - soh/soh/OTRGlobals.cpp | 29 +- soh/soh/SaveManager.cpp | 19 +- soh/soh/SohMenuBar.cpp | 2 - soh/soh/z_message_OTR.cpp | 37 +- soh/src/code/code_80097A00.c | 4 +- soh/src/code/z_en_item00.c | 10 +- soh/src/code/z_map_exp.c | 22 +- soh/src/code/z_parameter.c | 231 +++++----- .../actors/ovl_Arms_Hook/z_arms_hook.c | 4 +- .../actors/ovl_Obj_Tsubo/z_obj_tsubo.c | 7 + .../actors/ovl_player_actor/z_player.c | 70 +-- .../ovl_kaleido_scope/z_kaleido_equipment.c | 28 +- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 400 ++++++++++++++---- .../misc/ovl_kaleido_scope/z_kaleido_scope.h | 9 + .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 82 ++-- 24 files changed, 724 insertions(+), 325 deletions(-) diff --git a/soh/include/variables.h b/soh/include/variables.h index 2bad8335c99..ce1a9dbec95 100644 --- a/soh/include/variables.h +++ b/soh/include/variables.h @@ -102,7 +102,7 @@ extern "C" extern void* gItemIcons[0x82]; extern u8 gItemAgeReqs[]; extern u8 gSlotAgeReqs[]; - extern u8 gItemSlots[56]; + extern u8 gItemSlots[71]; extern void (*gSceneCmdHandlers[SCENE_CMD_ID_MAX])(PlayState*, SceneCmd*); extern s16 gLinkObjectIds[2]; extern u32 gObjectTableSize; diff --git a/soh/include/z64.h b/soh/include/z64.h index 23ffcfb1717..5cc757fd535 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -914,6 +914,8 @@ typedef struct { /* 0x0266 */ u8 worldMapPoints[20]; // 0 = hidden; 1 = displayed; 2 = highlighted /* 0x027A */ u8 tradeQuestLocation; /* 0x027C */ SkelAnime playerSkelAnime; + Vtx* arrowSelectVtx; + s16 arrowMenuAnimPos; } PauseContext; // size = 0x2C0 typedef enum { diff --git a/soh/include/z64item.h b/soh/include/z64item.h index 1fc919a45f6..9e58b460ea1 100644 --- a/soh/include/z64item.h +++ b/soh/include/z64item.h @@ -116,36 +116,38 @@ typedef enum { } DungeonItem; typedef enum { - /* 0x00 */ SLOT_STICK, - /* 0x01 */ SLOT_NUT, - /* 0x02 */ SLOT_BOMB, - /* 0x03 */ SLOT_BOW, - /* 0x04 */ SLOT_ARROW_FIRE, - /* 0x05 */ SLOT_DINS_FIRE, - /* 0x06 */ SLOT_SLINGSHOT, - /* 0x07 */ SLOT_OCARINA, - /* 0x08 */ SLOT_BOMBCHU, - /* 0x09 */ SLOT_HOOKSHOT, - /* 0x0A */ SLOT_ARROW_ICE, - /* 0x0B */ SLOT_FARORES_WIND, - /* 0x0C */ SLOT_BOOMERANG, - /* 0x0D */ SLOT_LENS, - /* 0x0E */ SLOT_BEAN, + /* 0x00 */ SLOT_DINS_FIRE, + /* 0x01 */ SLOT_BOMB, + /* 0x02 */ SLOT_BOMBCHU, + /* 0x03 */ SLOT_NUT, + /* 0x04 */ SLOT_LENS, + /* 0x05 */ SLOT_BEAN, + /* 0x06 */ SLOT_FARORES_WIND, + /* 0x07 */ SLOT_SLINGSHOT, + /* 0x08 */ SLOT_BOOMERANG, + /* 0x09 */ SLOT_STICK, + /* 0x0A */ SLOT_BOOTS_HOVER, + /* 0x0B */ SLOT_TRADE_CHILD, + /* 0x0C */ SLOT_NAYRUS_LOVE, + /* 0x0D */ SLOT_BOW, + /* 0x0E */ SLOT_HOOKSHOT, /* 0x0F */ SLOT_HAMMER, - /* 0x10 */ SLOT_ARROW_LIGHT, - /* 0x11 */ SLOT_NAYRUS_LOVE, - /* 0x12 */ SLOT_BOTTLE_1, - /* 0x13 */ SLOT_BOTTLE_2, - /* 0x14 */ SLOT_BOTTLE_3, - /* 0x15 */ SLOT_BOTTLE_4, - /* 0x16 */ SLOT_TRADE_ADULT, - /* 0x17 */ SLOT_TRADE_CHILD, - /* 0x18 */ SLOT_TUNIC_KOKIRI, - /* 0x19 */ SLOT_TUNIC_GORON, - /* 0x1A */ SLOT_TUNIC_ZORA, - /* 0x1B */ SLOT_BOOTS_KOKIRI, - /* 0x1C */ SLOT_BOOTS_IRON, - /* 0x1D */ SLOT_BOOTS_HOVER, + /* 0x10 */ SLOT_BOOTS_IRON, + /* 0x11 */ SLOT_TRADE_ADULT, + /* 0x12 */ SLOT_EMPTY_LEFT, + /* 0x13 */ SLOT_BOTTLE_1, + /* 0x14 */ SLOT_BOTTLE_2, + /* 0x15 */ SLOT_BOTTLE_3, + /* 0x16 */ SLOT_BOTTLE_4, + /* 0x17 */ SLOT_EMPTY_RIGHT, + /* 0x18 */ SLOT_OCARINA, + /* 0x19 */ SLOT_ARROW_FIRE, + /* 0x1A */ SLOT_ARROW_ICE, + /* 0x1B */ SLOT_ARROW_LIGHT, + /* 0x1C */ SLOT_TUNIC_KOKIRI, + /* 0x1D */ SLOT_TUNIC_GORON, + /* 0x1E */ SLOT_TUNIC_ZORA, + /* 0x1F */ SLOT_BOOTS_KOKIRI, /* 0xFF */ SLOT_NONE = 0xFF } InventorySlot; diff --git a/soh/include/z64save.h b/soh/include/z64save.h index c7bee045fc1..b3ff798ef81 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -43,7 +43,7 @@ typedef struct { } ItemEquips; // size = 0x0A typedef struct { - /* 0x00 */ u8 items[24]; + /* 0x00 */ u8 items[28]; /* 0x18 */ s8 ammo[16]; /* 0x28 */ u16 equipment; // a mask where each nibble corresponds to a type of equipment `EquipmentType`, and each bit to an owned piece `EquipInv*` /* 0x2C */ u32 upgrades; @@ -389,7 +389,8 @@ typedef enum { typedef enum { /* 0 */ LINK_AGE_ADULT, - /* 1 */ LINK_AGE_CHILD + /* 1 */ LINK_AGE_CHILD, + /* 9 */ LINK_AGE_EITHER = 9 } LinkAge; diff --git a/soh/soh/Enhancements/controls/GameControlEditor.cpp b/soh/soh/Enhancements/controls/GameControlEditor.cpp index 935935c4801..1e30d365b11 100644 --- a/soh/soh/Enhancements/controls/GameControlEditor.cpp +++ b/soh/soh/Enhancements/controls/GameControlEditor.cpp @@ -295,6 +295,8 @@ namespace GameControlEditor { "To make the cursor only move a single space during name entry no matter how long a direction is held, manually set gDpadHoldChange to 0"); UIWidgets::PaddedEnhancementCheckbox("D-pad as Equip Items", "gDpadEquips"); DrawHelpIcon("Equip items and equipment on the D-pad\nIf used with D-pad on Pause Screen, you must hold C-Up to equip instead of navigate"); + UIWidgets::PaddedEnhancementCheckbox("Toggle minimap with D-pad down", "gMapOnDDown"); + DrawHelpIcon("Toggle the minimap by pressing down on the D-pad\nIf \"D-pad as Equip Items\" is enabled, equipping an item on D-pad down will prevent you from toggling the map"); window->EndGroupPanelPublic(0); } diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index 9c56ac32ba1..487af7f03d2 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -1328,7 +1328,7 @@ void Draw_Placements(){ ImGui::EndTable(); } } - if (CVarGetInteger("gDpadEquips",0) && ImGui::CollapsingHeader("DPad items position")) { + if (ImGui::CollapsingHeader("DPad items position")) { if (ImGui::BeginTable("tabledpaditems", 1, FlagsTable)) { ImGui::TableSetupColumn("DPad items settings", FlagsCell, TablesCellsWidth); Table_InitHeader(false); diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index 916e1a7f822..d714da45567 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -53,6 +53,9 @@ typedef enum { TEXT_WARP_RANDOM_REPLACED_TEXT = 0x9200, TEXT_LAKE_HYLIA_WATER_SWITCH_SIGN = 0x346, // 0x3yy for cuttable sign range TEXT_LAKE_HYLIA_WATER_SWITCH_NAVI = 0x1B3, // 0x1yy for Navi msg range + TEXT_FIRE_ARROW = 0x0070, + TEXT_ICE_ARROW = 0x0071, + TEXT_LIGHT_ARROW = 0x0072, } TextIDs; #ifdef __cplusplus diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 9af4eadb7e9..66c8944c0f1 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -639,12 +639,16 @@ void DrawInventoryTab() { ImGui::Checkbox("Restrict to valid items", &restrictToValid); UIWidgets::InsertHelpHoverText("Restricts items and ammo to only what is possible to legally acquire in-game"); - for (int32_t y = 0; y < 4; y++) { + for (int32_t y = 0; y < 5; y++) { for (int32_t x = 0; x < 6; x++) { int32_t index = x + y * 6; static int32_t selectedIndex = -1; static const char* itemPopupPicker = "itemPopupPicker"; + if (index >= ARRAY_COUNT(gSaveContext.inventory.items)) { + break; + } + ImGui::PushID(index); if (x != 0) { @@ -1705,10 +1709,10 @@ void DrawPlayerTab() { ImGui::SameLine(); ImGui::InputScalar("C Right", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[3], &one, NULL); + ImGui::NewLine(); + ImGui::Text("Current D-pad Equips"); + ImGui::InputScalar("D-pad Up ", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[4], &one, NULL); // Two spaces at the end for aligning, not elegant but it's working if (CVarGetInteger("gDpadEquips", 0)) { - ImGui::NewLine(); - ImGui::Text("Current D-pad Equips"); - ImGui::InputScalar("D-pad Up ", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[4], &one, NULL); // Two spaces at the end for aligning, not elegant but it's working ImGui::SameLine(); ImGui::InputScalar("D-pad Down", ImGuiDataType_U8, &gSaveContext.equips.buttonItems[5], &one, NULL); // Intentionnal to not put everything on the same line, else it's taking too much for lower resolution. diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index f0f586e0031..53333767710 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -173,7 +173,6 @@ const std::vector enhancementsCvars = { "gDisableCritWiggle", "gChestSizeDependsStoneOfAgony", "gSkipArrowAnimation", - "gSeparateArrows", "gCustomizeShootingGallery", "gInstantShootingGalleryWin", "gConstantAdultGallery", @@ -576,9 +575,6 @@ const std::vector enhancedPresetEntries = { // Skip Magic Arrow Equip Animation PRESET_ENTRY_S32("gSkipArrowAnimation", 1), - // Equip arrows on multiple slots - PRESET_ENTRY_S32("gSeparateArrows", 1), - // Disable Navi Call Audio PRESET_ENTRY_S32("gDisableNaviCallAudio", 1), @@ -700,9 +696,6 @@ const std::vector randomizerPresetEntries = { // Exit Market at Night PRESET_ENTRY_S32("gMarketSneak", 1), - // Equip arrows on multiple slots - PRESET_ENTRY_S32("gSeparateArrows", 1), - // Disable Navi Call Audio PRESET_ENTRY_S32("gDisableNaviCallAudio", 1), diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index ad57d1ca5d2..1a2acdc7a69 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -241,9 +241,9 @@ const char* constCameraStrings[] = { OTRGlobals::OTRGlobals() { std::vector OTRFiles; std::string mqPath = LUS::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName); - if (std::filesystem::exists(mqPath)) { + if (std::filesystem::exists(mqPath)) { OTRFiles.push_back(mqPath); - } + } std::string ootPath = LUS::Context::LocateFileAcrossAppDirs("oot.otr", appShortName); if (std::filesystem::exists(ootPath)) { OTRFiles.push_back(ootPath); @@ -262,7 +262,7 @@ OTRGlobals::OTRGlobals() { } } } - std::unordered_set ValidHashes = { + std::unordered_set ValidHashes = { OOT_PAL_MQ, OOT_NTSC_JP_MQ, OOT_NTSC_US_MQ, @@ -849,7 +849,7 @@ void CheckSoHOTRVersion(std::string otrPath) { } // Checks the program version stored in the otr and compares the major value to soh -// For Windows/Mac/Linux if the version doesn't match, offer to +// For Windows/Mac/Linux if the version doesn't match, offer to void DetectOTRVersion(std::string fileName, bool isMQ) { bool isOtrOld = false; std::string otrPath = LUS::Context::LocateFileAcrossAppDirs(fileName, appShortName); @@ -1033,7 +1033,7 @@ extern "C" void InitOTR() { SpeechSynthesizer::Instance = new SAPISpeechSynthesizer(); SpeechSynthesizer::Instance->Init(); #endif - + clearMtx = (uintptr_t)&gMtxClear; OTRMessage_Init(); OTRAudio_Init(); @@ -1063,7 +1063,7 @@ extern "C" void InitOTR() { } #endif - std::shared_ptr conf = OTRGlobals::Instance->context->GetConfig(); + std::shared_ptr conf = OTRGlobals::Instance->context->GetConfig(); conf->RegisterConfigVersionUpdater(std::make_shared()); conf->RegisterConfigVersionUpdater(std::make_shared()); conf->RunVersionUpdates(); @@ -1458,11 +1458,11 @@ std::shared_ptr GetResourceByNameHandlingMQ(const char* path) { extern "C" char* GetResourceDataByNameHandlingMQ(const char* path) { auto res = GetResourceByNameHandlingMQ(path); - + if (res == nullptr) { return nullptr; } - + return (char*)res->GetRawPointer(); } @@ -1544,7 +1544,7 @@ extern "C" char* ResourceMgr_LoadIfDListByName(const char* filePath) { if (res->GetInitData()->Type == LUS::ResourceType::DisplayList) return (char*)&((std::static_pointer_cast(res))->Instructions[0]); - + return nullptr; } @@ -2113,10 +2113,10 @@ extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) { extern "C" int Controller_ShouldRumble(size_t slot) { auto controlDeck = LUS::Context::GetInstance()->GetControlDeck(); - + if (slot < controlDeck->GetNumConnectedPorts()) { auto physicalDevice = controlDeck->GetDeviceFromPortIndex(slot); - + if (physicalDevice->GetProfile(slot)->UseRumble && physicalDevice->CanRumble()) { return 1; } @@ -2338,7 +2338,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { Player_GetMask(play) == PLAYER_MASK_TRUTH) || (Randomizer_GetSettingValue(RSK_GOSSIP_STONE_HINTS) == RO_GOSSIP_STONES_NEED_STONE && CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY)))) { - Actor* stone = GET_PLAYER(play)->targetActor; + Actor* stone = GET_PLAYER(play)->targetActor; actorParams = stone->params; // if we're in a generic grotto @@ -2374,7 +2374,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::hintMessageTableID, TEXT_GANONDORF); } } else if (textId == TEXT_SHEIK_NEED_HOOK || textId == TEXT_SHEIK_HAVE_HOOK) { - messageEntry = OTRGlobals::Instance->gRandomizer->GetSheikMessage(gPlayState->sceneNum, textId); + messageEntry = OTRGlobals::Instance->gRandomizer->GetSheikMessage(gPlayState->sceneNum, textId); // textId: TEXT_SCRUB_RANDOM + (randomizerInf - RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT) } else if (textId >= TEXT_SCRUB_RANDOM && textId <= TEXT_SCRUB_RANDOM + NUM_SCRUBS) { RandomizerInf randoInf = (RandomizerInf)((textId - TEXT_SCRUB_RANDOM) + RAND_INF_SCRUBS_PURCHASED_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT); @@ -2478,6 +2478,9 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { if (textId == TEXT_MARKET_GUARD_NIGHT && CVarGetInteger("gMarketSneak", 0) && play->sceneNum == SCENE_MARKET_ENTRANCE_NIGHT) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_MARKET_GUARD_NIGHT); } + if (textId >= TEXT_FIRE_ARROW && textId <= TEXT_LIGHT_ARROW) { + messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId); + } font->charTexBuf[0] = (messageEntry.GetTextBoxType() << 4) | messageEntry.GetTextBoxPosition(); switch (gSaveContext.language) { case LANGUAGE_FRA: diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index e61cf922354..d75b0b9898f 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -662,6 +662,8 @@ void SaveManager::InitFileDebug() { for (int button = 0; button < ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots); button++) { gSaveContext.childEquips.cButtonSlots[button] = SLOT_NONE; } + gSaveContext.childEquips.buttonItems[4] = ITEM_OCARINA_FAIRY; + gSaveContext.childEquips.cButtonSlots[3] = SLOT_OCARINA; gSaveContext.childEquips.equipment = 0; for (int button = 0; button < ARRAY_COUNT(gSaveContext.adultEquips.buttonItems); button++) { gSaveContext.adultEquips.buttonItems[button] = ITEM_NONE; @@ -669,6 +671,8 @@ void SaveManager::InitFileDebug() { for (int button = 0; button < ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots); button++) { gSaveContext.adultEquips.cButtonSlots[button] = SLOT_NONE; } + gSaveContext.adultEquips.buttonItems[4] = ITEM_OCARINA_FAIRY; + gSaveContext.adultEquips.cButtonSlots[3] = SLOT_OCARINA; gSaveContext.adultEquips.equipment = 0; gSaveContext.unk_54 = 0; gSaveContext.savedSceneNum = 0x51; @@ -682,19 +686,22 @@ void SaveManager::InitFileDebug() { for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); button++) { gSaveContext.equips.cButtonSlots[button] = sCButtonSlots[button]; } + gSaveContext.equips.buttonItems[4] = ITEM_OCARINA_FAIRY; + gSaveContext.equips.cButtonSlots[3] = SLOT_OCARINA; gSaveContext.equips.equipment = 0x1122; // Inventory - static std::array sItems = { - ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_ARROW_FIRE, ITEM_DINS_FIRE, - ITEM_SLINGSHOT, ITEM_OCARINA_FAIRY, ITEM_BOMBCHU, ITEM_HOOKSHOT, ITEM_ARROW_ICE, ITEM_FARORES_WIND, - ITEM_BOOMERANG, ITEM_LENS, ITEM_BEAN, ITEM_HAMMER, ITEM_ARROW_LIGHT, ITEM_NAYRUS_LOVE, - ITEM_BOTTLE, ITEM_POTION_RED, ITEM_POTION_GREEN, ITEM_POTION_BLUE, ITEM_POCKET_EGG, ITEM_WEIRD_EGG, + static std::array sItems = { + ITEM_DINS_FIRE, ITEM_BOMB, ITEM_BOMBCHU, ITEM_NUT, ITEM_LENS, ITEM_BEAN, + ITEM_FARORES_WIND, ITEM_SLINGSHOT, ITEM_BOOMERANG, ITEM_STICK, ITEM_BOOTS_HOVER, ITEM_WEIRD_EGG, + ITEM_NAYRUS_LOVE, ITEM_BOW, ITEM_HOOKSHOT, ITEM_HAMMER, ITEM_BOOTS_IRON, ITEM_CLAIM_CHECK, + ITEM_NONE, ITEM_BOTTLE, ITEM_POTION_RED, ITEM_POTION_GREEN, ITEM_POTION_BLUE, ITEM_NONE, + ITEM_OCARINA_FAIRY, ITEM_ARROW_FIRE, ITEM_ARROW_ICE, ITEM_ARROW_LIGHT }; for (int item = 0; item < ARRAY_COUNT(gSaveContext.inventory.items); item++) { gSaveContext.inventory.items[item] = sItems[item]; } - static std::array sAmmo = { 50, 50, 10, 30, 1, 1, 30, 1, 50, 1, 1, 1, 1, 1, 1, 1 }; + static std::array sAmmo = { 1, 20, 50, 20, 1, 10, 1, 30, 1, 10, 1, 1, 1, 30, 1, 1 }; for (int ammo = 0; ammo < ARRAY_COUNT(gSaveContext.inventory.ammo); ammo++) { gSaveContext.inventory.ammo[ammo] = sAmmo[ammo]; } diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 8db6c77036b..37d9a6a9fa7 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -604,8 +604,6 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("After completing the mask trading sub-quest, press A and any direction on the mask slot to change masks"); UIWidgets::PaddedEnhancementCheckbox("Nuts explode bombs", "gNutsExplodeBombs", true, false); UIWidgets::Tooltip("Makes nuts explode bombs, similar to how they interact with bombchus. This does not affect bombflowers."); - UIWidgets::PaddedEnhancementCheckbox("Equip Multiple Arrows at Once", "gSeparateArrows", true, false); - UIWidgets::Tooltip("Allow the bow and magic arrows to be equipped at the same time on different slots"); UIWidgets::PaddedEnhancementCheckbox("Bow as Child/Slingshot as Adult", "gBowSlingShotAmmoFix", true, false); UIWidgets::Tooltip("Allows child to use bow with arrows.\nAllows adult to use slingshot with seeds.\n\nRequires glitches or 'Timeless Equipment' cheat to equip."); UIWidgets::PaddedEnhancementCheckbox("Better Farore's Wind", "gBetterFW", true, false); diff --git a/soh/soh/z_message_OTR.cpp b/soh/soh/z_message_OTR.cpp index f90e8bb9370..097e23366e5 100644 --- a/soh/soh/z_message_OTR.cpp +++ b/soh/soh/z_message_OTR.cpp @@ -13,14 +13,14 @@ extern "C" MessageTableEntry* sNesMessageEntryTablePtr; extern "C" MessageTableEntry* sGerMessageEntryTablePtr; extern "C" MessageTableEntry* sFraMessageEntryTablePtr; extern "C" MessageTableEntry* sStaffMessageEntryTablePtr; -//extern "C" MessageTableEntry* _message_0xFFFC_nes; +//extern "C" MessageTableEntry* _message_0xFFFC_nes; MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) { auto file = std::static_pointer_cast(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(filePath)); if (file == nullptr) return nullptr; - + // Allocate room for an additional message // OTRTODO: Should not be malloc'ing here. It's fine for now since we check elsewhere that the message table is // already null. @@ -154,4 +154,37 @@ extern "C" void OTRMessage_Init() CustomMessage("You look bored. Wanna go out for a&walk?\x1B&%gYes&No%w", "Du siehst gelangweilt aus.&Willst du einen Spaziergang machen?\x1B&%gJa&Nein%w", "Tu as l'air de t'ennuyer. Tu veux&aller faire un tour?\x1B&%gOui&Non%w")); + CustomMessageManager::Instance->CreateGetItemMessage( + customMessageTableID, (GetItemID)TEXT_FIRE_ARROW, ITEM_ARROW_FIRE, + CustomMessage( + "You got the %rFire Arrow%w!&Any target it strikes will&catch fire.^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %rFire Arrow%w!&Any target it strikes will&catch fire.^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %rFire Arrow%w!&Any target it strikes will&catch fire.^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + TEXTBOX_TYPE_BLUE)); + CustomMessageManager::Instance->CreateGetItemMessage( + customMessageTableID, (GetItemID)TEXT_ICE_ARROW, ITEM_ARROW_ICE, + CustomMessage( + "You got the %bIce Arrow%w!&Any target it strikes&will freeze.^" + "This arrow magic is granted&only to those who complete the&difficult training of the Gerudo,&so use it with pride!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %bIce Arrow%w!&Any target it strikes&will freeze.^" + "This arrow magic is granted&only to those who complete the&difficult training of the Gerudo,&so use it with pride!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %bIce Arrow%w!&Any target it strikes&will freeze.^" + "This arrow magic is granted&only to those who complete the&difficult training of the Gerudo,&so use it with pride!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + TEXTBOX_TYPE_BLUE)); + CustomMessageManager::Instance->CreateGetItemMessage( + customMessageTableID, (GetItemID)TEXT_LIGHT_ARROW, ITEM_ARROW_LIGHT, + CustomMessage( + "You got the %cLight Arrow%w!&The light of justice will&smite evil!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %cLight Arrow%w!&The light of justice will&smite evil!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + "You got the %cLight Arrow%w!&The light of justice will&smite evil!^" + "Select your bow with %b\x9f%w to&open the arrow submenu.&Tilt %c\xaa%w to equip your bow&with powered-up arrows!", + TEXTBOX_TYPE_BLUE)); } diff --git a/soh/src/code/code_80097A00.c b/soh/src/code/code_80097A00.c index eb83738e360..4068117e7c8 100644 --- a/soh/src/code/code_80097A00.c +++ b/soh/src/code/code_80097A00.c @@ -180,7 +180,9 @@ u8 gItemSlots[] = { SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_CHILD, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, - SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, + SLOT_TRADE_ADULT, SLOT_TRADE_ADULT, SLOT_BOW, SLOT_BOW, SLOT_BOW, SLOT_NONE, + SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE, + SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_BOOTS_IRON, SLOT_BOOTS_HOVER, }; void Inventory_ChangeEquipment(s16 equipment, u16 value) { diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index 42ea78f90ba..87c43f98af0 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -333,7 +333,9 @@ void EnItem00_SetupAction(EnItem00* this, EnItem00ActionFunc actionFunc) { void EnItem00_SetObjectDependency(EnItem00* this, PlayState* play, s16 objectIndex) { // Remove object dependency for Enemy Randomizer and Crowd Control to allow Like-likes to // drop equipment correctly in rooms where Like-likes normally don't spawn. - if (CVarGetInteger("gRandomizedEnemies", 0) || CVarGetInteger("gCrowdControl", 0)) { + // Also remove object dependency for Master Quest Fire Temple to fix the Like-like there + if (CVarGetInteger("gRandomizedEnemies", 0) || CVarGetInteger("gCrowdControl", 0) || + (ResourceMgr_IsSceneMasterQuest(SCENE_FIRE_TEMPLE) && play->sceneNum == SCENE_FIRE_TEMPLE)) { this->actor.objBankIndex = 0; } else { this->actor.objBankIndex = Object_GetIndex(&play->objectCtx, objectIndex); @@ -1371,7 +1373,7 @@ void EnItem00_DrawCollectible(EnItem00* this, PlayState* play) { Randomizer_GetItemFromKnownCheck(randoCheck, GI_NONE); this->randoGiEntry.getItemFrom = ITEM_FROM_FREESTANDING; } - + f32 mtxScale = 10.67f; Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); EnItem00_CustomItemsParticles(&this->actor, play, this->randoGiEntry); @@ -1532,7 +1534,7 @@ s16 func_8001F404(s16 dropId) { } } - if ((CVarGetInteger("gBombchuDrops", 0) || + if ((CVarGetInteger("gBombchuDrops", 0) || (IS_RANDO && Randomizer_GetSettingValue(RSK_ENABLE_BOMBCHU_DROPS) == 1)) && (dropId == ITEM00_BOMBS_A || dropId == ITEM00_BOMBS_B || dropId == ITEM00_BOMBS_SPECIAL)) { dropId = EnItem00_ConvertBombDropToBombchu(dropId); @@ -1612,7 +1614,7 @@ EnItem00* Item_DropCollectible2(PlayState* play, Vec3f* spawnPos, s16 params) { params &= 0x3FFF; if ((params & 0x00FF) == ITEM00_HEART && CVarGetInteger("gNoHeartDrops", 0)) { return NULL; } - + if (((params & 0x00FF) == ITEM00_FLEXIBLE) && !param4000) { // TODO: Prevent the cast to EnItem00 here since this is a different actor (En_Elf) spawnedActor = (EnItem00*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ELF, spawnPos->x, diff --git a/soh/src/code/z_map_exp.c b/soh/src/code/z_map_exp.c index c4db0098b23..99a19316c7d 100644 --- a/soh/src/code/z_map_exp.c +++ b/soh/src/code/z_map_exp.c @@ -734,10 +734,20 @@ void Minimap_Draw(PlayState* play) { OPEN_DISPS(play->state.gfxCtx); - // If any of these CVars are enabled, disable toggling the minimap with L, unless gEnableMapToggle is set - bool enableMapToggle = - !(CVarGetInteger("gDebugEnabled", 0) || CVarGetInteger("gMoonJumpOnL", 0) || CVarGetInteger("gTurboOnL", 0)) || - CVarGetInteger("gEnableMapToggle", 0); + u16 minimapToggleBtn; + bool enableMapToggle; + if (CVarGetInteger("gMapOnDDown", 0)) { + minimapToggleBtn = BTN_DDOWN; + // If you can use an item with D down, disable toggling the minimap with it + enableMapToggle = !(CVarGetInteger("gDpadEquips", 0) && gSaveContext.equips.buttonItems[5] < 0xF0); + } else { + minimapToggleBtn = BTN_L; + // If any of these CVars are enabled, disable toggling the minimap with L + enableMapToggle = + !(CVarGetInteger("gDebugEnabled", 0) || CVarGetInteger("gMoonJumpOnL", 0) || CVarGetInteger("gTurboOnL", 0)); + } + // If this CVar is set, allow toggling the map despite conflicts + enableMapToggle = enableMapToggle || CVarGetInteger("gEnableMapToggle", 0); if (play->pauseCtx.state < 4) { //Minimap margins @@ -808,7 +818,7 @@ void Minimap_Draw(PlayState* play) { } } - if (CHECK_BTN_ALL(play->state.input[0].press.button, BTN_L) && !Play_InCsMode(play) && enableMapToggle) { + if (CHECK_BTN_ALL(play->state.input[0].press.button, minimapToggleBtn) && !Play_InCsMode(play) && enableMapToggle) { osSyncPrintf("Game_play_demo_mode_check=%d\n", Play_InCsMode(play)); // clang-format off if (!R_MINIMAP_DISABLED) { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_UP, &D_801333D4, 4, @@ -964,7 +974,7 @@ void Minimap_Draw(PlayState* play) { Minimap_DrawCompassIcons(play); // Draw icons for the player spawn and current position } - if (CHECK_BTN_ALL(play->state.input[0].press.button, BTN_L) && !Play_InCsMode(play) && enableMapToggle) { + if (CHECK_BTN_ALL(play->state.input[0].press.button, minimapToggleBtn) && !Play_InCsMode(play) && enableMapToggle) { // clang-format off if (!R_MINIMAP_DISABLED) { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_UP, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); } diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index bbaa8d90bd5..3b6a86538de 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1441,7 +1441,7 @@ void Inventory_SwapAgeEquipment(void) { u16 shieldEquipValue; if (LINK_AGE_IN_YEARS == YEARS_CHILD) { - + for (i = 0; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if (i != 0) { @@ -1472,6 +1472,7 @@ void Inventory_SwapAgeEquipment(void) { Flags_SetInfTable(INFTABLE_SWORDLESS); } + // Nuts on C-left (if present) if (gSaveContext.inventory.items[SLOT_NUT] != ITEM_NONE) { gSaveContext.equips.buttonItems[1] = ITEM_NUT; gSaveContext.equips.cButtonSlots[0] = SLOT_NUT; @@ -1479,27 +1480,32 @@ void Inventory_SwapAgeEquipment(void) { gSaveContext.equips.buttonItems[1] = gSaveContext.equips.cButtonSlots[0] = ITEM_NONE; } + // Bombs on C-down gSaveContext.equips.buttonItems[2] = ITEM_BOMB; - gSaveContext.equips.buttonItems[3] = gSaveContext.inventory.items[SLOT_OCARINA]; gSaveContext.equips.cButtonSlots[1] = SLOT_BOMB; - gSaveContext.equips.cButtonSlots[2] = SLOT_OCARINA; - + + // Nothing on C-right + gSaveContext.equips.buttonItems[3] = ITEM_NONE; + gSaveContext.equips.cButtonSlots[2] = ITEM_NONE; + gSaveContext.equips.equipment = (EQUIP_VALUE_SWORD_MASTER << (EQUIP_TYPE_SWORD * 4)) | (EQUIP_VALUE_SHIELD_HYLIAN << (EQUIP_TYPE_SHIELD * 4)) | (EQUIP_VALUE_TUNIC_KOKIRI << (EQUIP_TYPE_TUNIC * 4)) | (EQUIP_VALUE_BOOTS_KOKIRI << (EQUIP_TYPE_BOOTS * 4)); - if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && + if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && gSaveContext.equips.buttonItems[0] == ITEM_NONE) { gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); } - // Set the dpad to nothing - gSaveContext.equips.buttonItems[4] = ITEM_NONE; + // Ocarina on D-up + gSaveContext.equips.buttonItems[4] = gSaveContext.inventory.items[SLOT_OCARINA]; + gSaveContext.equips.cButtonSlots[3] = SLOT_OCARINA; + + // Set the rest of the d-pad to nothing gSaveContext.equips.buttonItems[5] = ITEM_NONE; gSaveContext.equips.buttonItems[6] = ITEM_NONE; gSaveContext.equips.buttonItems[7] = ITEM_NONE; - gSaveContext.equips.cButtonSlots[3] = SLOT_NONE; gSaveContext.equips.cButtonSlots[4] = SLOT_NONE; gSaveContext.equips.cButtonSlots[5] = SLOT_NONE; gSaveContext.equips.cButtonSlots[6] = SLOT_NONE; @@ -1814,14 +1820,14 @@ u8 Return_Item(u8 itemID, ModIndex modId, ItemID returnItem) { /** * @brief Adds the given item to Link's inventory. - * + * * NOTE: This function has been edited to be safe to use with a NULL play. * If you need to add to this function, be sure you check if the play is not * NULL before doing any operations requiring it. - * - * @param play - * @param item - * @return u8 + * + * @param play + * @param item + * @return u8 */ u8 Item_Give(PlayState* play, u8 item) { lusprintf(__FILE__, __LINE__, 2, "Item Give - item: %#x", item); @@ -1902,10 +1908,10 @@ u8 Item_Give(PlayState* play, u8 item) { // In rando, when buying Giant's Knife, also check // without the Koriri Sword in case we don't have it - if (ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == + if (ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == ((1 << EQUIP_INV_SWORD_KOKIRI) | (1 << EQUIP_INV_SWORD_MASTER) | (1 << EQUIP_INV_SWORD_BIGGORON) | - (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)) || - (IS_RANDO && ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == + (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)) || + (IS_RANDO && ALL_EQUIP_VALUE(EQUIP_TYPE_SWORD) == ((1 << EQUIP_INV_SWORD_MASTER) | (1 << EQUIP_INV_SWORD_BIGGORON) | (1 << EQUIP_INV_SWORD_BROKENGIANTKNIFE)))) { gSaveContext.inventory.equipment ^= OWNED_EQUIP_FLAG_ALT(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_BROKENGIANTKNIFE); @@ -1917,7 +1923,7 @@ u8 Item_Give(PlayState* play, u8 item) { } } } - + } else if (item == ITEM_SWORD_MASTER) { gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4)); @@ -1936,6 +1942,9 @@ u8 Item_Give(PlayState* play, u8 item) { return Return_Item(item, MOD_NONE, ITEM_NONE); } else if ((item >= ITEM_BOOTS_KOKIRI) && (item <= ITEM_BOOTS_HOVER)) { gSaveContext.inventory.equipment |= OWNED_EQUIP_FLAG(EQUIP_TYPE_BOOTS, item - ITEM_BOOTS_KOKIRI); + if (item != ITEM_BOOTS_KOKIRI) { + INV_CONTENT(item) = item; + } return Return_Item(item, MOD_NONE, ITEM_NONE); } else if ((item == ITEM_KEY_BOSS) || (item == ITEM_COMPASS) || (item == ITEM_DUNGEON_MAP)) { gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS]; @@ -2206,6 +2215,14 @@ u8 Item_Give(PlayState* play, u8 item) { return Return_Item(item, MOD_NONE, ITEM_SEEDS); } else if (item == ITEM_OCARINA_FAIRY) { INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY; + + gSaveContext.equips.buttonItems[4] = item; + gSaveContext.equips.cButtonSlots[3] = SLOT_OCARINA; + gSaveContext.childEquips.buttonItems[4] = item; + gSaveContext.childEquips.cButtonSlots[3] = SLOT_OCARINA; + gSaveContext.adultEquips.buttonItems[4] = item; + gSaveContext.adultEquips.cButtonSlots[3] = SLOT_OCARINA; + return Return_Item(item, MOD_NONE, ITEM_NONE); } else if (item == ITEM_OCARINA_TIME) { INV_CONTENT(ITEM_OCARINA_TIME) = ITEM_OCARINA_TIME; @@ -2657,7 +2674,7 @@ u8 Item_CheckObtainability(u8 item) { return ITEM_NONE; } } - + if ((item >= ITEM_SONG_MINUET) && (item <= ITEM_SONG_STORMS)) { return ITEM_NONE; } else if ((item >= ITEM_MEDALLION_FOREST) && (item <= ITEM_MEDALLION_LIGHT)) { @@ -2921,7 +2938,7 @@ bool Inventory_HatchPocketCucco(PlayState* play) { return Inventory_ReplaceItem(play, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); } - if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { + if (!PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(ITEM_POCKET_EGG)) { return 0; } @@ -2960,7 +2977,7 @@ void Interface_LoadActionLabel(InterfaceContext* interfaceCtx, u16 action, s16 l } doAction = newName[loadOffset]; } - + char* segment = interfaceCtx->doActionSegment[loadOffset]; interfaceCtx->doActionSegment[loadOffset] = action != DO_ACTION_NONE ? doAction : gEmptyTexture; gSegments[7] = interfaceCtx->doActionSegment[loadOffset]; @@ -3027,7 +3044,7 @@ void Interface_LoadActionLabelB(PlayState* play, u16 action) { } interfaceCtx->unk_1FC = action; - + char* segment = interfaceCtx->doActionSegment[1]; interfaceCtx->doActionSegment[1] = action != DO_ACTION_NONE ? doAction : gEmptyTexture; osRecvMesg(&interfaceCtx->loadQueue, NULL, OS_MESG_BLOCK); @@ -3052,7 +3069,7 @@ s32 Health_ChangeBy(PlayState* play, s16 healthChange) { if (healthChange < 0) { gSaveContext.health = 0; } - + return 0; } @@ -3121,7 +3138,7 @@ void Rupees_ChangeBy(s16 rupeeChange) { void GameplayStats_UpdateAmmoUsed(s16 item, s16 ammoUsed) { - switch (item) { + switch (item) { case ITEM_STICK: gSaveContext.sohStats.count[COUNT_AMMO_USED_STICK] += ammoUsed; break; @@ -3465,7 +3482,7 @@ void Interface_UpdateMagicBar(PlayState* play) { (msgCtx->msgMode == MSGMODE_NONE) && (play->gameOverCtx.state == GAMEOVER_INACTIVE) && (play->sceneLoadFlag == 0) && (play->transitionMode == 0) && !Play_InCsMode(play)) { bool hasLens = false; - for (int buttonIndex = 1; buttonIndex < (CVarGetInteger("gDpadEquips", 0) != 0) ? ARRAY_COUNT(gSaveContext.equips.buttonItems) : 4; buttonIndex++) { + for (int buttonIndex = 1; buttonIndex < (CVarGetInteger("gDpadEquips", 0)) ? ARRAY_COUNT(gSaveContext.equips.buttonItems) : 5; buttonIndex++) { if (gSaveContext.equips.buttonItems[buttonIndex] == ITEM_LENS) { hasLens = true; break; @@ -4307,7 +4324,7 @@ void Interface_DrawItemButtons(PlayState* play) { G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, C_Up_BTN_Pos[0]-LabelX_Navi << 2, C_Up_BTN_Pos[1]+LabelY_Navi << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, C_Up_BTN_Pos[0]-LabelX_Navi << 2, C_Up_BTN_Pos[1]+LabelY_Navi << 2, (C_Up_BTN_Pos[0]-LabelX_Navi + 32) << 2, (C_Up_BTN_Pos[1]+LabelY_Navi + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } @@ -4425,7 +4442,7 @@ void Interface_DrawItemButtons(PlayState* play) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, cRightButtonColor.r, cRightButtonColor.g, cRightButtonColor.b, interfaceCtx->cRightAlpha); } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, ((u8*)gButtonBackgroundTex), 32, 32, ItemIconPos[temp-1][0], ItemIconPos[temp-1][1], ItemIconWidthFactor[temp-1][0], ItemIconWidthFactor[temp-1][0], ItemIconWidthFactor[temp-1][1], ItemIconWidthFactor[temp-1][1]); @@ -4500,8 +4517,8 @@ void Interface_DrawItemIconTexture(PlayState* play, void* texture, s16 button) { { C_DOWN_BUTTON_X+X_Margins_CD, C_DOWN_BUTTON_Y+Y_Margins_CD }, { C_RIGHT_BUTTON_X+X_Margins_CR, C_RIGHT_BUTTON_Y+Y_Margins_CR }, { DPAD_UP_X+X_Margins_DPad_Items, DPAD_UP_Y+Y_Margins_DPad_Items }, - { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, - { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, + { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, + { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, { DPAD_RIGHT_X+X_Margins_DPad_Items, DPAD_RIGHT_Y+Y_Margins_DPad_Items } }; u16 ItemsSlotsAlpha[8] = { @@ -4633,10 +4650,17 @@ void Interface_DrawItemIconTexture(PlayState* play, void* texture, s16 button) { ItemIconPos[3][1] = ItemIconPos_ori[3][1]; } - gDPLoadTextureBlock(OVERLAY_DISP++, texture, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, + // Exception specifically for dungeon map texture since only that appears on a button + bool smallTex = texture == gItemIcons[ITEM_DUNGEON_MAP]; + int texSize = smallTex ? 24 : 32; + int offset = smallTex ? 4 : 0; + + gDPLoadTextureBlock(OVERLAY_DISP++, texture, G_IM_FMT_RGBA, G_IM_SIZ_32b, texSize, texSize, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, ItemIconPos[button][0] << 2, ItemIconPos[button][1] << 2, + gSPWideTextureRectangle(OVERLAY_DISP++, + (ItemIconPos[button][0] + offset << 2), + (ItemIconPos[button][1] + offset << 2), (ItemIconPos[button][0] + gItemIconWidth[button]) << 2, (ItemIconPos[button][1] + gItemIconWidth[button]) << 2, G_TX_RENDERTILE, 0, 0, gItemIconDD[button] << 1, gItemIconDD[button] << 1); @@ -4877,11 +4901,11 @@ void Interface_DrawAmmoCount(PlayState* play, s16 button, s16 alpha) { } if (i != 0) { - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[i], 8, 8, ItemIconPos[button][0], ItemIconPos[button][1], 8, 8, 1 << 10, 1 << 10); } - OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[ammo], 8, 8, + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, (u8*)_gAmmoDigit0Tex[ammo], 8, 8, ItemIconPos[button][0] + 6, ItemIconPos[button][1], 8, 8, 1 << 10, 1 << 10); } @@ -5386,7 +5410,7 @@ void Interface_Draw(PlayState* play) { PosY_adjust = 6; PosX_adjust = -10; } - + s16 BbtnPosX; s16 BbtnPosY; s16 X_Margins_BtnB_label; @@ -5470,76 +5494,87 @@ void Interface_Draw(PlayState* play) { Interface_DrawAmmoCount(play, 3, interfaceCtx->cRightAlpha); } - if (CVarGetInteger("gDpadEquips", 0) != 0) { - // DPad is only greyed-out when all 4 DPad directions are too - uint16_t dpadAlpha = - MAX(MAX(MAX(interfaceCtx->dpadUpAlpha, interfaceCtx->dpadDownAlpha), interfaceCtx->dpadLeftAlpha), - interfaceCtx->dpadRightAlpha); - - // Draw DPad - s16 DpadPosX; - s16 DpadPosY; - s16 X_Margins_Dpad; - s16 Y_Margins_Dpad; - if (CVarGetInteger("gDPadUseMargins", 0) != 0) { - if (CVarGetInteger("gDPadPosType", 0) == 0) {X_Margins_Dpad = Right_HUD_Margin;}; - Y_Margins_Dpad = (Top_HUD_Margin*-1); - } else { - Y_Margins_Dpad = 0; - X_Margins_Dpad = 0; - } - if (CVarGetInteger("gDPadPosType", 0) != 0) { - DpadPosY = CVarGetInteger("gDPadPosY", 0)+Y_Margins_Dpad; - if (CVarGetInteger("gDPadPosType", 0) == 1) {//Anchor Left - if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Left_HUD_Margin;}; - DpadPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); - } else if (CVarGetInteger("gDPadPosType", 0) == 2) {//Anchor Right - if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Right_HUD_Margin;}; - DpadPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); - } else if (CVarGetInteger("gDPadPosType", 0) == 3) {//Anchor None - DpadPosX = CVarGetInteger("gDPadPosX", 0); - } else if (CVarGetInteger("gDPadPosType", 0) == 4) {//Hidden - DpadPosX = -9999; - } - } else { - DpadPosX = OTRGetRectDimensionFromRightEdge(DPAD_X+X_Margins_Dpad); - DpadPosY = DPAD_Y+Y_Margins_Dpad; + // DPad is only greyed-out when all 4 DPad directions are too + uint16_t dpadAlpha = + MAX(MAX(MAX(interfaceCtx->dpadUpAlpha, interfaceCtx->dpadDownAlpha), interfaceCtx->dpadLeftAlpha), + interfaceCtx->dpadRightAlpha); + + // Draw DPad + s16 DpadPosX; + s16 DpadPosY; + s16 X_Margins_Dpad; + s16 Y_Margins_Dpad; + if (CVarGetInteger("gDPadUseMargins", 0) != 0) { + if (CVarGetInteger("gDPadPosType", 0) == 0) {X_Margins_Dpad = Right_HUD_Margin;}; + Y_Margins_Dpad = (Top_HUD_Margin*-1); + } else { + Y_Margins_Dpad = 0; + X_Margins_Dpad = 0; + } + if (CVarGetInteger("gDPadPosType", 0) != 0) { + DpadPosY = CVarGetInteger("gDPadPosY", 0)+Y_Margins_Dpad; + if (CVarGetInteger("gDPadPosType", 0) == 1) {//Anchor Left + if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Left_HUD_Margin;}; + DpadPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); + } else if (CVarGetInteger("gDPadPosType", 0) == 2) {//Anchor Right + if (CVarGetInteger("gDPadUseMargins", 0) != 0) {X_Margins_Dpad = Right_HUD_Margin;}; + DpadPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gDPadPosX", 0)+X_Margins_Dpad); + } else if (CVarGetInteger("gDPadPosType", 0) == 3) {//Anchor None + DpadPosX = CVarGetInteger("gDPadPosX", 0); + } else if (CVarGetInteger("gDPadPosType", 0) == 4) {//Hidden + DpadPosX = -9999; } + } else { + DpadPosX = OTRGetRectDimensionFromRightEdge(DPAD_X+X_Margins_Dpad); + DpadPosY = DPAD_Y+Y_Margins_Dpad; + } - gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, dPadColor.r, dPadColor.g, dPadColor.b, dpadAlpha); - if (fullUi) { - gDPLoadTextureBlock(OVERLAY_DISP++, gDPadTex, - G_IM_FMT_IA, G_IM_SIZ_16b, 32, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, DpadPosX << 2, DpadPosY << 2, - (DpadPosX + 32) << 2, (DpadPosY + 32) << 2, - G_TX_RENDERTILE, 0, 0, (1 << 10), (1 << 10)); - } + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, dPadColor.r, dPadColor.g, dPadColor.b, dpadAlpha); + if (fullUi) { + gDPLoadTextureBlock(OVERLAY_DISP++, gDPadTex, + G_IM_FMT_IA, G_IM_SIZ_16b, 32, 32, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSPWideTextureRectangle(OVERLAY_DISP++, DpadPosX << 2, DpadPosY << 2, + (DpadPosX + 32) << 2, (DpadPosY + 32) << 2, + G_TX_RENDERTILE, 0, 0, (1 << 10), (1 << 10)); + } - // DPad-Up Button Icon & Ammo Count - if (gSaveContext.equips.buttonItems[4] < 0xF0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadUpAlpha); - gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); - Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[4]], 4); - gDPPipeSync(OVERLAY_DISP++); - gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, - PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); - Interface_DrawAmmoCount(play, 4, interfaceCtx->dpadUpAlpha); - } + bool dpadEquips = CVarGetInteger("gDpadEquips", 0); - // DPad-Down Button Icon & Ammo Count - if (gSaveContext.equips.buttonItems[5] < 0xF0) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadDownAlpha); - gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); - Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[5]], 5); - gDPPipeSync(OVERLAY_DISP++); - gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, - PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + // DPad-Up Button Icon & Ammo Count + // Ocarina is perma-mapped to D-up, so that part has to be drawn + if (gSaveContext.equips.buttonItems[4] < 0xF0) { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadUpAlpha); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); + Interface_DrawItemIconTexture(play, gItemIcons[gSaveContext.equips.buttonItems[4]], 4); + gDPPipeSync(OVERLAY_DISP++); + gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + Interface_DrawAmmoCount(play, 4, interfaceCtx->dpadUpAlpha); + } + + // DPad-Down Button Icon & Ammo Count + bool itemOnDpad = dpadEquips && gSaveContext.equips.buttonItems[5] < 0xF0; + bool dpadMap = fullUi && CVarGetInteger("gMapOnDDown", 0) && + play->pauseCtx.state < 4 && + ((play->sceneNum >= SCENE_DEKU_TREE && play->sceneNum <= SCENE_ICE_CAVERN) || + (play->sceneNum >= SCENE_HYRULE_FIELD && play->sceneNum <= SCENE_OUTSIDE_GANONS_CASTLE)); + if (itemOnDpad || dpadMap) { + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadDownAlpha); + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); + void* texture = gItemIcons[itemOnDpad ? gSaveContext.equips.buttonItems[5] : ITEM_DUNGEON_MAP]; + Interface_DrawItemIconTexture(play, texture, 5); + gDPPipeSync(OVERLAY_DISP++); + gDPSetCombineLERP(OVERLAY_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, + PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + if (itemOnDpad) { Interface_DrawAmmoCount(play, 5, interfaceCtx->dpadDownAlpha); } + } + if (dpadEquips) { // DPad-Left Button Icon & Ammo Count if (gSaveContext.equips.buttonItems[6] < 0xF0) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->dpadLeftAlpha); @@ -5704,7 +5739,7 @@ void Interface_Draw(PlayState* play) { CarrotsPosY = CVarGetInteger("gCarrotsPosY", 0); if (CVarGetInteger("gCarrotsPosType", 0) == 1) {//Anchor Left if (CVarGetInteger("gCarrotsUseMargins", 0) != 0) {CarrotsMargins_X = Left_HUD_Margin;}; - CarrotsPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); + CarrotsPosX = OTRGetDimensionFromLeftEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); } else if (CVarGetInteger("gCarrotsPosType", 0) == 2) {//Anchor Right if (CVarGetInteger("gCarrotsUseMargins", 0) != 0) {CarrotsMargins_X = Right_HUD_Margin;}; CarrotsPosX = OTRGetDimensionFromRightEdge(CVarGetInteger("gCarrotsPosX", 0)+CarrotsMargins_X); @@ -6214,7 +6249,7 @@ void Interface_Draw(PlayState* play) { for (svar1 = 0; svar1 < 5; svar1++) { // clang-format off //svar5 = svar5 + 8; - //svar5 = OTRGetRectDimensionFromLeftEdge(gSaveContext.timerX[svar6]); + //svar5 = OTRGetRectDimensionFromLeftEdge(gSaveContext.timerX[svar6]); OVERLAY_DISP = Gfx_TextureI8(OVERLAY_DISP, digitTextures[timerDigits[svar1]], 8, 16, svar5 + timerDigitLeftPos[svar1], svar2, digitWidth[svar1], VREG(42), VREG(43) << 1, @@ -6358,7 +6393,7 @@ void Interface_Update(PlayState* play) { Left_HUD_Margin = CVarGetInteger("gHUDMargin_L", 0); Right_HUD_Margin = CVarGetInteger("gHUDMargin_R", 0); Bottom_HUD_Margin = CVarGetInteger("gHUDMargin_B", 0); - + GameInteractor_ExecuteOnInterfaceUpdate(); if (CHECK_BTN_ALL(debugInput->press.button, BTN_DLEFT)) { diff --git a/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c b/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c index 93ff272f4d9..cf011c07064 100644 --- a/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c +++ b/soh/src/overlays/actors/ovl_Arms_Hook/z_arms_hook.c @@ -257,9 +257,9 @@ void ArmsHook_Shoot(ArmsHook* this, PlayState* play) { sp60.x = this->unk_1F4.x - (this->unk_1E8.x - this->unk_1F4.x); sp60.y = this->unk_1F4.y - (this->unk_1E8.y - this->unk_1F4.y); sp60.z = this->unk_1F4.z - (this->unk_1E8.z - this->unk_1F4.z); - u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if (BgCheck_EntityLineTest1(&play->colCtx, &sp60, &this->unk_1E8, &sp78, &poly, true, true, true, true, &bgId) && diff --git a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c index 2346b34ffeb..b6a7a85911c 100644 --- a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c +++ b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c @@ -86,6 +86,13 @@ static InitChainEntry sInitChain[] = { void ObjTsubo_SpawnCollectible(ObjTsubo* this, PlayState* play) { s16 dropParams = this->actor.params & 0x1F; + // Avoid spawning a Deku Shield if the item isn't loaded. + // Targeted fix for a crash due to a broken drop from the pot in Spirit + // Temple surrounded by a circling spike trap. + if (dropParams == ITEM00_SHIELD_DEKU && Object_GetIndex(&play->objectCtx, OBJECT_GI_SHIELD_1) == -1) { + return; + } + if ((dropParams >= ITEM00_RUPEE_GREEN) && (dropParams <= ITEM00_BOMBS_SPECIAL)) { Item_DropCollectible(play, &this->actor.world.pos, (dropParams | (((this->actor.params >> 9) & 0x3F) << 8))); 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 497935a6958..afecdedc744 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -2029,7 +2029,7 @@ s32 func_80833C98(s32 item1, s32 actionParam) { } s32 func_80833CDC(PlayState* play, s32 index) { - if (index >= ((CVarGetInteger("gDpadEquips", 0) != 0) ? 8 : 4)) { + if (index >= ((CVarGetInteger("gDpadEquips", 0) != 0) ? 8 : 5)) { return ITEM_NONE; } else if (play->bombchuBowlingStatus != 0) { return (play->bombchuBowlingStatus > 0) ? ITEM_BOMBCHU : ITEM_NONE; @@ -2062,7 +2062,7 @@ void func_80833DF8(Player* this, PlayState* play) { s32 maskItem = this->currentMask - PLAYER_MASK_KEATON + ITEM_MASK_KEATON; bool hasOnDpad = false; if (CVarGetInteger("gDpadEquips", 0) != 0) { - for (int buttonIndex = 4; buttonIndex < 8; buttonIndex++) { + for (int buttonIndex = 5; buttonIndex < 8; buttonIndex++) { hasOnDpad |= gSaveContext.equips.buttonItems[buttonIndex] == maskItem; } } @@ -2077,7 +2077,7 @@ void func_80833DF8(Player* this, PlayState* play) { maskActionParam = this->currentMask - 1 + PLAYER_IA_MASK_KEATON; bool hasOnDpad = false; if (CVarGetInteger("gDpadEquips", 0) != 0) { - for (int buttonIndex = 0; buttonIndex < 4; buttonIndex++) { + for (int buttonIndex = 0; buttonIndex < 5; buttonIndex++) { hasOnDpad |= func_80833C98(DPAD_ITEM(buttonIndex), maskActionParam); } } @@ -2088,6 +2088,28 @@ void func_80833DF8(Player* this, PlayState* play) { } } + // Since boots are items now, take them off if not equipped on a button + if (this->currentBoots != PLAYER_BOOTS_KOKIRI) { + s32 bootsItemAction = this->currentBoots + PLAYER_IA_BOOTS_KOKIRI; + + bool hasOnCBtn = false; + bool hasOnDpad = false; + for (int buttonIndex = 0; buttonIndex < 3; buttonIndex++) { + hasOnCBtn |= func_80833C98(C_BTN_ITEM(buttonIndex), bootsItemAction); + } + if (CVarGetInteger("gDpadEquips", 0)) { + for (int buttonIndex = 1; buttonIndex < 4; buttonIndex++) { + hasOnDpad |= func_80833C98(DPAD_ITEM(buttonIndex), bootsItemAction); + } + } + + if (!hasOnCBtn && !hasOnDpad) { + Inventory_ChangeEquipment(EQUIP_TYPE_BOOTS, PLAYER_BOOTS_KOKIRI + 1); + Player_SetEquipmentData(play, this); + func_808328EC(this, NA_SE_PL_CHANGE_ARMS); + } + } + if (!(this->stateFlags1 & (PLAYER_STATE1_ITEM_OVER_HEAD | PLAYER_STATE1_IN_CUTSCENE)) && !func_8008F128(this)) { if (this->itemAction >= PLAYER_IA_FISHING_POLE) { bool hasOnDpad = false; @@ -2472,9 +2494,9 @@ s32 func_80834E44(PlayState* play) { } s32 func_80834E7C(PlayState* play) { - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } return (play->shootingGalleryStatus != 0) && ((play->shootingGalleryStatus < 0) || CHECK_BTN_ANY(sControlInput->cur.button, buttonsToCheck)); @@ -4934,7 +4956,7 @@ s32 func_8083AD4C(PlayState* play, Player* this) { if(CVarGetInteger("gBowSlingShotAmmoFix", 0)){ shouldUseBowCamera = this->heldItemAction != PLAYER_IA_SLINGSHOT; } - + cameraMode = shouldUseBowCamera ? CAM_MODE_BOWARROW : CAM_MODE_SLINGSHOT; } else { cameraMode = CAM_MODE_BOOMERANG; @@ -5378,7 +5400,7 @@ s32 func_8083BDBC(Player* this, PlayState* play) { if (sp2C == 2) { gSaveContext.sohStats.count[COUNT_BACKFLIPS]++; } - + return 1; } } @@ -6106,8 +6128,8 @@ void func_8083DFE0(Player* this, f32* arg1, s16* arg2) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) == BUNNY_HOOD_FAST_AND_JUMP && this->currentMask == PLAYER_MASK_BUNNY) { maxSpeed *= 1.5f; - } - + } + if (CVarGetInteger("gEnableWalkModify", 0) && !CVarGetInteger("gWalkModifierDoesntChangeJump", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -6350,8 +6372,8 @@ s32 func_8083E5A8(Player* this, PlayState* play) { uint8_t showItemCutscene = play->sceneNum == SCENE_BOMBCHU_BOWLING_ALLEY || Item_CheckObtainability(giEntry.itemId) == ITEM_NONE || IS_RANDO; // Only skip cutscenes for drops when they're items/consumables from bushes/rocks/enemies. - uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || - interactedActor->id == ACTOR_EN_KAREBABA || + uint8_t isDropToSkip = (interactedActor->id == ACTOR_EN_ITEM00 && interactedActor->params != 6 && interactedActor->params != 17) || + interactedActor->id == ACTOR_EN_KAREBABA || interactedActor->id == ACTOR_EN_DEKUBABA; // Skip cutscenes from picking up consumables with "Fast Pickup Text" enabled, even when the player never picked it up before. @@ -6482,9 +6504,9 @@ s32 func_8083EAF0(Player* this, Actor* actor) { } s32 func_8083EB44(Player* this, PlayState* play) { - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if ((this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) && (this->heldActor != NULL) && CHECK_BTN_ANY(sControlInput->press.button, buttonsToCheck)) { @@ -7759,7 +7781,7 @@ void func_80842180(Player* this, PlayState* play) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && this->currentMask == PLAYER_MASK_BUNNY) { sp2C *= 1.5f; } - + if (CVarGetInteger("gEnableWalkModify", 0)) { if (CVarGetInteger("gWalkSpeedToggle", 0)) { if (gWalkSpeedToggle1) { @@ -8546,9 +8568,9 @@ void func_8084411C(Player* this, PlayState* play) { if (this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) { Actor* heldActor = this->heldActor; - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if (!func_80835644(play, this, heldActor) && (heldActor->id == ACTOR_EN_NIW) && CHECK_BTN_ANY(sControlInput->press.button, buttonsToCheck)) { @@ -9328,7 +9350,7 @@ void func_80846260(Player* this, PlayState* play) { return; } - u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } @@ -11186,7 +11208,7 @@ void Player_Update(Actor* thisx, PlayState* play) { // Play fan sound (too annoying) //func_8002F974(&player->actor, NA_SE_EV_WIND_TRAP - SFX_FLAG); } - + GameInteractor_ExecuteOnPlayerUpdate(); } @@ -11237,7 +11259,7 @@ void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList, MATRIX_TOMTX(sp70); } - + if (this->currentMask != PLAYER_MASK_BUNNY || !CVarGetInteger("gHideBunnyHood", 0)) { gSPDisplayList(POLY_OPA_DISP++, sMaskDlists[this->currentMask - 1]); } @@ -11589,9 +11611,9 @@ void func_8084B1D8(Player* this, PlayState* play) { func_80836670(this, play); } - u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN; + u16 buttonsToCheck = BTN_A | BTN_B | BTN_R | BTN_CUP | BTN_CLEFT | BTN_CRIGHT | BTN_CDOWN | BTN_DUP; if (CVarGetInteger("gDpadEquips", 0) != 0) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if ((this->csMode != 0) || (this->unk_6AD == 0) || (this->unk_6AD >= 4) || func_80833B54(this) || (this->unk_664 != NULL) || !func_8083AD4C(play, this) || @@ -13568,7 +13590,7 @@ void func_8084F88C(Player* this, PlayState* play) { play->nextEntranceIndex = 0x0088; } else if (this->unk_84F < 0) { Play_TriggerRespawn(play); - // In ER, handle DMT and other special void outs to respawn from last entrance from grotto + // In ER, handle DMT and other special void outs to respawn from last entrance from grotto if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) { Grotto_ForceRegularVoidOut(); } @@ -14995,7 +15017,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { this->heldItemId = ITEM_NONE; this->modelGroup = this->nextModelGroup = Player_ActionToModelGroup(this, PLAYER_IA_NONE); this->leftHandDLists = gPlayerLeftHandOpenDLs; - + // If MS sword is shuffled and not in the players inventory, then we need to unequip the current sword // and set swordless flag to mimic Link having his weapon knocked out of his hand in the Ganon fight if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && !CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_MASTER)) { @@ -15004,7 +15026,7 @@ void func_80852648(PlayState* play, Player* this, CsCmdActorAction* arg2) { Flags_SetInfTable(INFTABLE_SWORDLESS); return; } - + Inventory_ChangeEquipment(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_MASTER); gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; Inventory_DeleteEquipment(play, EQUIP_TYPE_SWORD); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c index d255f40d248..3a460d94e82 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_equipment.c @@ -188,7 +188,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, ZREG(39), ZREG(40), ZREG(41), pauseCtx->alpha); gDPSetEnvColor(POLY_KAL_DISP++, ZREG(43), ZREG(44), ZREG(45), 0); - for (i = 0, j = 64; i < 4; i++, j += 4) { + for (i = 0, j = 64; i < 3; i++, j += 4) { if (CUR_EQUIP_VALUE(i) != 0) { gDPPipeSync(POLY_KAL_DISP++); gSPVertex(POLY_KAL_DISP++, &pauseCtx->equipVtx[j], 4, 0); @@ -220,6 +220,12 @@ void KaleidoScope_DrawEquipment(PlayState* play) { pauseCtx->cursorX[PAUSE_EQUIP] -= 1; pauseCtx->cursorPoint[PAUSE_EQUIP] -= 1; + // Kokiri tunic -> scale + if (pauseCtx->cursorY[PAUSE_EQUIP] == 2 && pauseCtx->cursorX[PAUSE_EQUIP] == 0) { + pauseCtx->cursorY[PAUSE_EQUIP] += 1; + pauseCtx->cursorPoint[PAUSE_EQUIP] += 4; + } + if (pauseCtx->cursorX[PAUSE_EQUIP] == 0) { if (pauseCtx->cursorY[PAUSE_EQUIP] == 0) { if (CUR_UPG_VALUE(UPG_BULLET_BAG) != 0) { @@ -260,6 +266,13 @@ void KaleidoScope_DrawEquipment(PlayState* play) { pauseCtx->cursorX[PAUSE_EQUIP] += 1; pauseCtx->cursorPoint[PAUSE_EQUIP] += 1; + // Strength -> Deku shield + // Scale -> Kokiri tunic + if (pauseCtx->cursorX[PAUSE_EQUIP] == 1 && pauseCtx->cursorY[PAUSE_EQUIP] >= 2) { + pauseCtx->cursorY[PAUSE_EQUIP] -= 1; + pauseCtx->cursorPoint[PAUSE_EQUIP] -= 4; + } + if (pauseCtx->cursorX[PAUSE_EQUIP] == 0) { if (CUR_UPG_VALUE(pauseCtx->cursorY[PAUSE_EQUIP]) != 0) { cursorMoveResult = 1; @@ -328,6 +341,12 @@ void KaleidoScope_DrawEquipment(PlayState* play) { pauseCtx->cursorY[PAUSE_EQUIP] += 1; pauseCtx->cursorPoint[PAUSE_EQUIP] += 4; + // Tunics -> scale + if (pauseCtx->cursorY[PAUSE_EQUIP] == 3 && pauseCtx->cursorX[PAUSE_EQUIP] > 0) { + pauseCtx->cursorPoint[PAUSE_EQUIP] -= pauseCtx->cursorX[PAUSE_EQUIP]; + pauseCtx->cursorX[PAUSE_EQUIP] = 0; + } + if (pauseCtx->cursorX[PAUSE_EQUIP] == 0) { if (CUR_UPG_VALUE(pauseCtx->cursorY[PAUSE_EQUIP]) != 0) { cursorMoveResult = 1; @@ -506,7 +525,7 @@ void KaleidoScope_DrawEquipment(PlayState* play) { u16 buttonsToCheck = BTN_A | BTN_CLEFT | BTN_CDOWN | BTN_CRIGHT; if (CVarGetInteger("gDpadEquips", 0) && (!CVarGetInteger("gDpadPause", 0) || CHECK_BTN_ALL(input->cur.button, BTN_CUP))) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if ((pauseCtx->cursorSpecialPos == 0) && (cursorItem != PAUSE_ITEM_NONE) && (pauseCtx->state == 6) && @@ -700,6 +719,11 @@ void KaleidoScope_DrawEquipment(PlayState* play) { gSPGrayscale(POLY_KAL_DISP++, false); } } + + if (i == 3) { + continue; + } + // Draw inventory screen icons for (k = 0, bit = rowStart, point = 4; k < 3; k++, point += 4, temp++, bit++) { diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c index 74460691056..1fdc9afadaa 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_item.c @@ -7,8 +7,9 @@ #include "soh/Enhancements/cosmetics/cosmeticsTypes.h" u8 gAmmoItems[] = { - ITEM_STICK, ITEM_NUT, ITEM_BOMB, ITEM_BOW, ITEM_NONE, ITEM_NONE, ITEM_SLINGSHOT, ITEM_NONE, - ITEM_BOMBCHU, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_BEAN, ITEM_NONE, + ITEM_NONE, ITEM_BOMB, ITEM_BOMBCHU, ITEM_NUT, ITEM_NONE, ITEM_BEAN, + ITEM_NONE, ITEM_SLINGSHOT, ITEM_NONE, ITEM_STICK, ITEM_NONE, ITEM_NONE, + ITEM_NONE, ITEM_BOW, ITEM_NONE, ITEM_NONE, }; static s16 sEquipState = 0; @@ -17,10 +18,23 @@ static s16 sEquipMoveTimer = 10; bool gSelectingMask; bool gSelectingAdultTrade; +ArrowMenuState gArrowMenuState; +static s16 sArrowMenuTimer = 0; + +/* Maps an inventory slot to double the position of its ammo count in sAmmoVtxTableIdx */ static s16 sAmmoVtxOffset[] = { - 0, 2, 4, 6, 99, 99, 8, 99, 10, 99, 99, 99, 99, 99, 12, + 99, 0, 2, 4, 99, 6, + 99, 8, 99, 10, 99, 99, + 99, 12, 99 }; +typedef enum { + ES_MAGIC_ARROW_GLOWING = 0, + ES_MAGIC_ARROW_APPLYING = 1, + ES_MAGIC_ARROW_EQUIPPING = 2, // Unused in item screen mod + ES_DEFAULT = 3, +} EquipState; + extern const char* _gAmmoDigit0Tex[]; void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, s16 item, int slot) { @@ -41,7 +55,8 @@ void KaleidoScope_DrawAmmoCount(PauseContext* pauseCtx, GraphicsContext* gfxCtx, if (ammo == 0) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 130, 130, 130, pauseCtx->alpha); } else if ((item == ITEM_BOMB && AMMO(item) == CUR_CAPACITY(UPG_BOMB_BAG)) || - (item == ITEM_BOW && AMMO(item) == CUR_CAPACITY(UPG_QUIVER)) || + ((item == ITEM_BOW || item == ITEM_BOW_ARROW_FIRE || item == ITEM_BOW_ARROW_ICE || item == ITEM_BOW_ARROW_LIGHT) + && AMMO(item) == CUR_CAPACITY(UPG_QUIVER)) || (item == ITEM_SLINGSHOT && AMMO(item) == CUR_CAPACITY(UPG_BULLET_BAG)) || (item == ITEM_STICK && AMMO(item) == CUR_CAPACITY(UPG_STICKS)) || (item == ITEM_NUT && AMMO(item) == CUR_CAPACITY(UPG_NUTS)) || (item == ITEM_BOMBCHU && ammo == 50) || @@ -220,6 +235,217 @@ void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8 CLOSE_DISPS(play->state.gfxCtx); } +void KaleidoScope_SetArrowSelectActive(PauseContext* pauseCtx, bool active) { + if (ARROW_SELECT_OPEN == active) + return; + + gArrowMenuState = AMS_CLOSING + active; + pauseCtx->arrowMenuAnimPos = 12; + sArrowMenuTimer = 2; +} + +void KaleidoScope_ArrowSelect(PlayState* play, u16 cursorSlot) { + PauseContext* pauseCtx = &play->pauseCtx; + if (cursorSlot != SLOT_BOW || !CHECK_AGE_REQ_SLOT(SLOT_BOW)) { + gArrowMenuState = AMS_DISABLED; + pauseCtx->arrowMenuAnimPos = 0; + sArrowMenuTimer = 0; + return; + } + + Input* input = &play->state.input[0]; + + // Allow changing arrows if: + // - Selecting bow slot and pressing A + // - You have an item in the bow slot and any magic arrow + if (CHECK_BTN_ALL(input->press.button, BTN_A) && + INV_CONTENT(ITEM_BOW) != ITEM_NONE && + (INV_CONTENT(ITEM_ARROW_FIRE) != ITEM_NONE || + INV_CONTENT(ITEM_ARROW_ICE) != ITEM_NONE || + INV_CONTENT(ITEM_ARROW_LIGHT) != ITEM_NONE)) { + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + KaleidoScope_SetArrowSelectActive(pauseCtx, !ARROW_SELECT_OPEN); + } + + if (!ARROW_SELECT_OPEN) { + return; + } + + pauseCtx->cursorColorSet = 8; + bool dpad = CVarGetInteger("gDpadPause", 0); + + // Select arrow with stick/d-pad + // Up = Fire + // Left = Ice + // Right = Light + // Down = Normal + u8 newBow = ITEM_NONE; + u16 arrowCursorSlot; + if (pauseCtx->stickRelY < -30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DDOWN))) { + newBow = ITEM_BOW; + arrowCursorSlot = cursorSlot + 6; + } else if (pauseCtx->stickRelY > 30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DUP))) { + newBow = (INV_CONTENT(ITEM_ARROW_FIRE) != ITEM_NONE) ? ITEM_BOW_ARROW_FIRE : ITEM_NONE; + arrowCursorSlot = cursorSlot - 6; + } else if (pauseCtx->stickRelX < -30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DLEFT))) { + newBow = (INV_CONTENT(ITEM_ARROW_ICE) != ITEM_NONE) ? ITEM_BOW_ARROW_ICE : ITEM_NONE; + arrowCursorSlot = cursorSlot - 1; + } else if (pauseCtx->stickRelX > 30 || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT))) { + newBow = (INV_CONTENT(ITEM_ARROW_LIGHT) != ITEM_NONE) ? ITEM_BOW_ARROW_LIGHT : ITEM_NONE; + arrowCursorSlot = cursorSlot + 1; + } + + if (newBow == ITEM_NONE) { + return; + } + + // If you double select an arrow, reset to normal + if (newBow == INV_CONTENT(ITEM_BOW)) { + newBow = ITEM_BOW; + + // If double selecting regular arrows, cancel + if (INV_CONTENT(ITEM_BOW) == ITEM_BOW) { + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + KaleidoScope_SetArrowSelectActive(pauseCtx, false); + return; + } + } + + u16 sfxId; + if (newBow == ITEM_BOW || CVarGetInteger("gSkipArrowAnimation", 0)) { + sfxId = NA_SE_SY_DECIDE; + pauseCtx->equipTargetItem = newBow; + pauseCtx->equipAnimAlpha = 255; + sEquipState = ES_MAGIC_ARROW_APPLYING; + } else { + sfxId = NA_SE_SY_SET_FIRE_ARROW + (newBow - ITEM_BOW_ARROW_FIRE); + pauseCtx->equipTargetItem = 0xBF - ITEM_BOW_ARROW_FIRE + newBow; + pauseCtx->equipAnimAlpha = 0; + sEquipState = ES_MAGIC_ARROW_GLOWING; + } + + Audio_PlaySoundGeneral(sfxId, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + pauseCtx->equipAnimX = pauseCtx->itemVtx[arrowCursorSlot * 4].v.ob[0] * 10; + pauseCtx->equipAnimY = pauseCtx->itemVtx[arrowCursorSlot * 4].v.ob[1] * 10; + sEquipMoveTimer = 6; + sEquipAnimTimer = 0; + pauseCtx->unk_1E4 = 3; +} + +void KaleidoScope_BowMenuSetRect(PauseContext* pauseCtx, s16 xOffset, s16 yOffset, s16 size, u8 vtx) { + s16 bowCenterX = -64 + 16; + s16 bowCenterY = -6 - 16 + pauseCtx->offsetY; + s16 arrowCenterX = bowCenterX + xOffset; + s16 arrowCenterY = bowCenterY + yOffset; + s16 arrowX = arrowCenterX - size / 2; + s16 arrowY = arrowCenterY + size / 2; + + pauseCtx->arrowSelectVtx[vtx].v.ob[0] = pauseCtx->arrowSelectVtx[vtx + 2].v.ob[0] = arrowX; + pauseCtx->arrowSelectVtx[vtx + 1].v.ob[0] = pauseCtx->arrowSelectVtx[vtx + 3].v.ob[0] = arrowX + size; + pauseCtx->arrowSelectVtx[vtx].v.ob[1] = pauseCtx->arrowSelectVtx[vtx + 1].v.ob[1] = arrowY; + pauseCtx->arrowSelectVtx[vtx + 2].v.ob[1] = pauseCtx->arrowSelectVtx[vtx + 3].v.ob[1] = arrowY - size; +} + +void KaleidoScope_DrawBowMenuTexture(PlayState* play, s16 xOffset, s16 yOffset, s16 drawSize, u8 vtx, void* tex, u16 texSize) { + PauseContext* pauseCtx = &play->pauseCtx; + + KaleidoScope_BowMenuSetRect(pauseCtx, xOffset, yOffset, drawSize, vtx); + pauseCtx->arrowSelectVtx[vtx + 1].v.tc[0] = pauseCtx->arrowSelectVtx[vtx + 2].v.tc[1] = + pauseCtx->arrowSelectVtx[vtx + 3].v.tc[0] = pauseCtx->arrowSelectVtx[vtx + 3].v.tc[1] = texSize << 5; + + OPEN_DISPS(play->state.gfxCtx); + + gSPVertex(POLY_KAL_DISP++, &pauseCtx->arrowSelectVtx[vtx], 4, 0); + KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, tex, texSize, texSize, 0); + + CLOSE_DISPS(play->state.gfxCtx); +} + +void KaleidoScope_DrawMagicArrowIcon(PlayState* play, s16 offset, u8 itemId) { + if (INV_CONTENT(itemId) == ITEM_NONE || !CHECK_AGE_REQ_SLOT(SLOT_BOW)) { + return; + } + + s16 xOffset, yOffset, vtx; + char* source; + switch (itemId) { + case ITEM_ARROW_FIRE: + xOffset = 0; + yOffset = offset; + vtx = 0; + source = "__OTR__textures/icon_item_static/gFireArrowPower"; + break; + case ITEM_ARROW_ICE: + xOffset = -offset; + yOffset = 0; + vtx = 4; + source = "__OTR__textures/icon_item_static/gIceArrowPower"; + break; + case ITEM_ARROW_LIGHT: + xOffset = offset; + yOffset = 0; + vtx = 8; + source = "__OTR__textures/icon_item_static/gLightArrowPower"; + break; + default: + return; + } + + KaleidoScope_DrawBowMenuTexture(play, xOffset, yOffset, 12, vtx, source, 16); +} + +void KaleidoScope_DrawSelectableArrow(PlayState* play, s16 offset, u8 itemId) { + if (INV_CONTENT(itemId) == ITEM_NONE || !CHECK_AGE_REQ_SLOT(SLOT_BOW)) { + return; + } + + s16 xOffset, yOffset, vtx; + char* tex = gItemIcons[itemId]; + switch (itemId) { + case ITEM_ARROW_FIRE: + xOffset = 0; + yOffset = offset; + vtx = 0; + break; + case ITEM_ARROW_ICE: + xOffset = -offset; + yOffset = 0; + vtx = 4; + break; + case ITEM_ARROW_LIGHT: + xOffset = offset; + yOffset = 0; + vtx = 8; + break; + case ITEM_BOW: + xOffset = 0; + yOffset = -offset; + vtx = 12; + tex = "__OTR__textures/icon_item_static/gArrowIconTex"; + break; + default: + return; + } + + if (gArrowMenuState == AMS_ENABLED) { + PauseContext* pauseCtx = &play->pauseCtx; + OPEN_DISPS(play->state.gfxCtx); + gDPPipeSync(POLY_KAL_DISP++); + vtx += 16; + + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); + gDPSetEnvColor(POLY_KAL_DISP++, 0, 0, 0, 0); + KaleidoScope_BowMenuSetRect(pauseCtx, xOffset, yOffset, 32, vtx); + gSPVertex(POLY_KAL_DISP++, &pauseCtx->arrowSelectVtx[vtx], 4, 0); + POLY_KAL_DISP = KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, gEquippedItemOutlineTex, 32, 32, 0); + + vtx -= 16; + CLOSE_DISPS(play->state.gfxCtx); + } + + KaleidoScope_DrawBowMenuTexture(play, xOffset, yOffset, 28, vtx, tex, 32); +} + void KaleidoScope_DrawItemSelect(PlayState* play) { static s16 magicArrowEffectsR[] = { 255, 100, 255 }; static s16 magicArrowEffectsG[] = { 0, 100, 255 }; @@ -260,7 +486,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { pauseCtx->nameColorSet = 0; if ((pauseCtx->state == 6) && (pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM)) { - moveCursorResult = 0 || gSelectingMask || gSelectingAdultTrade; + moveCursorResult = 0 || ARROW_SELECT_OPEN || gSelectingMask || gSelectingAdultTrade; oldCursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM]; cursorItem = pauseCtx->cursorItem[PAUSE_ITEM]; @@ -434,7 +660,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { if (pauseCtx->cursorSpecialPos == 0) { if (cursorItem != PAUSE_ITEM_NONE) { if ((ABS(pauseCtx->stickRelY) > 30) || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DDOWN | BTN_DUP))) { - moveCursorResult = 0 || gSelectingMask || gSelectingAdultTrade; + moveCursorResult = 0 || ARROW_SELECT_OPEN || gSelectingMask || gSelectingAdultTrade; cursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM]; cursorY = pauseCtx->cursorY[PAUSE_ITEM]; @@ -561,9 +787,12 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { } gSelectingAdultTrade = cursorSlot == SLOT_TRADE_ADULT; } + + KaleidoScope_ArrowSelect(play, cursorSlot); + u16 buttonsToCheck = BTN_CLEFT | BTN_CDOWN | BTN_CRIGHT; if (CVarGetInteger("gDpadEquips", 0) && (!CVarGetInteger("gDpadPause", 0) || CHECK_BTN_ALL(input->cur.button, BTN_CUP))) { - buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; + buttonsToCheck |= BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT; } if (CHECK_BTN_ANY(input->press.button, buttonsToCheck)) { if (CHECK_AGE_REQ_SLOT(cursorSlot) && @@ -602,9 +831,11 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { gDPSetEnvColor(POLY_KAL_DISP++, 0, 0, 0, 0); for (i = 0, j = 24 * 4; i < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); i++, j += 4) { - if ((gSaveContext.equips.buttonItems[i + 1] != ITEM_NONE) && - !((gSaveContext.equips.buttonItems[i + 1] >= ITEM_SHIELD_DEKU) && - (gSaveContext.equips.buttonItems[i + 1] <= ITEM_BOOTS_HOVER))) { + u8 buttonItem = gSaveContext.equips.buttonItems[i + 1]; + if ((buttonItem != ITEM_NONE) && // equipped + (buttonItem < ARRAY_COUNT(gItemSlots)) && // has an assigned slot + (gItemSlots[buttonItem] < 24) && // assigned slot is on the menu + !((buttonItem >= ITEM_SHIELD_DEKU) && (buttonItem <= ITEM_BOOTS_KOKIRI))) { // not equipment (except boots) gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[j], 4, 0); POLY_KAL_DISP = KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, gEquippedItemOutlineTex, 32, 32, 0); } @@ -616,39 +847,20 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { for (i = j = 0; i < 24; i++, j += 4) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); - if (gSaveContext.inventory.items[i] != ITEM_NONE) { - if ((pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM) && (pauseCtx->cursorSpecialPos == 0)) { - if (CHECK_AGE_REQ_SLOT(i)) { - if ((sEquipState == 2) && (i == 3)) { - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, magicArrowEffectsR[pauseCtx->equipTargetItem - 0xBF], - magicArrowEffectsG[pauseCtx->equipTargetItem - 0xBF], - magicArrowEffectsB[pauseCtx->equipTargetItem - 0xBF], pauseCtx->alpha); - - pauseCtx->itemVtx[j + 0].v.ob[0] = pauseCtx->itemVtx[j + 2].v.ob[0] = - pauseCtx->itemVtx[j + 0].v.ob[0] - 2; - - pauseCtx->itemVtx[j + 1].v.ob[0] = pauseCtx->itemVtx[j + 3].v.ob[0] = - pauseCtx->itemVtx[j + 0].v.ob[0] + 32; - - pauseCtx->itemVtx[j + 0].v.ob[1] = pauseCtx->itemVtx[j + 1].v.ob[1] = - pauseCtx->itemVtx[j + 0].v.ob[1] + 2; + if ((gSaveContext.inventory.items[i] != ITEM_NONE)) { + if ((pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM) && + (pauseCtx->cursorSpecialPos == 0) && CHECK_AGE_REQ_SLOT(i) && (i == cursorSlot)) { + pauseCtx->itemVtx[j + 0].v.ob[0] = pauseCtx->itemVtx[j + 2].v.ob[0] = + pauseCtx->itemVtx[j + 0].v.ob[0] - 2; - pauseCtx->itemVtx[j + 2].v.ob[1] = pauseCtx->itemVtx[j + 3].v.ob[1] = - pauseCtx->itemVtx[j + 0].v.ob[1] - 32; - } else if (i == cursorSlot) { - pauseCtx->itemVtx[j + 0].v.ob[0] = pauseCtx->itemVtx[j + 2].v.ob[0] = - pauseCtx->itemVtx[j + 0].v.ob[0] - 2; + pauseCtx->itemVtx[j + 1].v.ob[0] = pauseCtx->itemVtx[j + 3].v.ob[0] = + pauseCtx->itemVtx[j + 0].v.ob[0] + 32; - pauseCtx->itemVtx[j + 1].v.ob[0] = pauseCtx->itemVtx[j + 3].v.ob[0] = - pauseCtx->itemVtx[j + 0].v.ob[0] + 32; + pauseCtx->itemVtx[j + 0].v.ob[1] = pauseCtx->itemVtx[j + 1].v.ob[1] = + pauseCtx->itemVtx[j + 0].v.ob[1] + 2; - pauseCtx->itemVtx[j + 0].v.ob[1] = pauseCtx->itemVtx[j + 1].v.ob[1] = - pauseCtx->itemVtx[j + 0].v.ob[1] + 2; - - pauseCtx->itemVtx[j + 2].v.ob[1] = pauseCtx->itemVtx[j + 3].v.ob[1] = - pauseCtx->itemVtx[j + 0].v.ob[1] - 32; - } - } + pauseCtx->itemVtx[j + 2].v.ob[1] = pauseCtx->itemVtx[j + 3].v.ob[1] = + pauseCtx->itemVtx[j + 0].v.ob[1] - 32; } gSPVertex(POLY_KAL_DISP++, &pauseCtx->itemVtx[j + 0], 4, 0); @@ -688,6 +900,38 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { childTradeItem <= ITEM_MASK_KEATON ? ITEM_MASK_TRUTH : childTradeItem - 1, childTradeItem >= ITEM_MASK_TRUTH ? ITEM_MASK_KEATON : childTradeItem + 1); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, pauseCtx->alpha); + if (gArrowMenuState == AMS_DISABLED) { + s16 offset = 14; + KaleidoScope_DrawMagicArrowIcon(play, offset, ITEM_ARROW_FIRE); + KaleidoScope_DrawMagicArrowIcon(play, offset, ITEM_ARROW_ICE); + KaleidoScope_DrawMagicArrowIcon(play, offset, ITEM_ARROW_LIGHT); + } else { + s16 offset; + if (gArrowMenuState == AMS_ENABLED) { + offset = 32; + } else { + offset = pauseCtx->arrowMenuAnimPos / sArrowMenuTimer; + pauseCtx->arrowMenuAnimPos -= offset; + if (gArrowMenuState == AMS_OPENING) { + offset = 32 - pauseCtx->arrowMenuAnimPos; + } else { + offset = 20 + pauseCtx->arrowMenuAnimPos; + } + } + + KaleidoScope_DrawSelectableArrow(play, offset, ITEM_ARROW_FIRE); + KaleidoScope_DrawSelectableArrow(play, offset, ITEM_ARROW_ICE); + KaleidoScope_DrawSelectableArrow(play, offset, ITEM_ARROW_LIGHT); + KaleidoScope_DrawSelectableArrow(play, offset, ITEM_BOW); + + sArrowMenuTimer--; + + if (sArrowMenuTimer == 0) { + gArrowMenuState &= 1; + } + } + CLOSE_DISPS(play->state.gfxCtx); } @@ -696,6 +940,7 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, PauseContext* pauseCtx = &play->pauseCtx; gSelectingMask = false; gSelectingAdultTrade = false; + KaleidoScope_SetArrowSelectActive(pauseCtx, false); if (CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) { pauseCtx->equipTargetCBtn = 0; @@ -704,9 +949,10 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, } else if (CHECK_BTN_ALL(input->press.button, BTN_CRIGHT)) { pauseCtx->equipTargetCBtn = 2; } else if (CVarGetInteger("gDpadEquips", 0)) { - if (CHECK_BTN_ALL(input->press.button, BTN_DUP)) { + // D up is permanently mapped to ocarina + /*if (CHECK_BTN_ALL(input->press.button, BTN_DUP)) { pauseCtx->equipTargetCBtn = 3; - } else if (CHECK_BTN_ALL(input->press.button, BTN_DDOWN)) { + } else */if (CHECK_BTN_ALL(input->press.button, BTN_DDOWN)) { pauseCtx->equipTargetCBtn = 4; } else if (CHECK_BTN_ALL(input->press.button, BTN_DLEFT)) { pauseCtx->equipTargetCBtn = 5; @@ -722,7 +968,7 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, pauseCtx->equipAnimY = animY; pauseCtx->equipAnimAlpha = 255; sEquipAnimTimer = 0; - sEquipState = 3; + sEquipState = ES_DEFAULT; sEquipMoveTimer = 10; if ((pauseCtx->equipTargetItem == ITEM_ARROW_FIRE) || (pauseCtx->equipTargetItem == ITEM_ARROW_ICE) || (pauseCtx->equipTargetItem == ITEM_ARROW_LIGHT)) { @@ -738,7 +984,7 @@ void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, } Audio_PlaySoundGeneral(NA_SE_SY_SET_FIRE_ARROW + index, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); pauseCtx->equipTargetItem = 0xBF + index; - sEquipState = 0; + sEquipState = ES_MAGIC_ARROW_GLOWING; pauseCtx->equipAnimAlpha = 0; sEquipMoveTimer = 6; } @@ -813,8 +1059,8 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { { C_DOWN_BUTTON_X+X_Margins_CD, C_DOWN_BUTTON_Y+Y_Margins_CD }, { C_RIGHT_BUTTON_X+X_Margins_CR, C_RIGHT_BUTTON_Y+Y_Margins_CR }, { DPAD_UP_X+X_Margins_DPad_Items, DPAD_UP_Y+Y_Margins_DPad_Items }, - { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, - { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, + { DPAD_DOWN_X+X_Margins_DPad_Items, DPAD_DOWN_Y+Y_Margins_DPad_Items }, + { DPAD_LEFT_X+X_Margins_DPad_Items, DPAD_LEFT_Y+Y_Margins_DPad_Items }, { DPAD_RIGHT_X+X_Margins_DPad_Items, DPAD_RIGHT_Y+Y_Margins_DPad_Items } }; s16 DPad_ItemsOffset[4][2] = { @@ -922,35 +1168,18 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { sCButtonPosX[6] = sCButtonPosX[6] - 160; sCButtonPosY[6] = 120 - sCButtonPosY[6]; - if (sEquipState == 0) { + if (sEquipState == ES_MAGIC_ARROW_GLOWING) { pauseCtx->equipAnimAlpha += 14; if (pauseCtx->equipAnimAlpha > 255) { pauseCtx->equipAnimAlpha = 254; - sEquipState++; + sEquipState = ES_MAGIC_ARROW_APPLYING; } sEquipAnimTimer = 5; return; } - if (sEquipState == 2) { - D_8082A488--; - - if (D_8082A488 == 0) { - pauseCtx->equipTargetItem -= 0xBF - ITEM_BOW_ARROW_FIRE; - if (!CVarGetInteger("gSeparateArrows", 0)) { - pauseCtx->equipTargetSlot = SLOT_BOW; - } - sEquipMoveTimer = 6; - WREG(90) = 320; - WREG(87) = WREG(91); - sEquipState++; - Audio_PlaySoundGeneral(NA_SE_SY_SYNTH_MAGIC_ARROW, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - } - return; - } - - if (sEquipState == 1) { - bowItemVtx = &pauseCtx->itemVtx[12]; + if (sEquipState == ES_MAGIC_ARROW_APPLYING) { + bowItemVtx = &pauseCtx->itemVtx[52]; offsetX = ABS(pauseCtx->equipAnimX - bowItemVtx->v.ob[0] * 10) / sEquipMoveTimer; offsetY = ABS(pauseCtx->equipAnimY - bowItemVtx->v.ob[1] * 10) / sEquipMoveTimer; } else { @@ -971,14 +1200,14 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { WREG(90) -= WREG(87) / sEquipMoveTimer; WREG(87) -= WREG(87) / sEquipMoveTimer; - if (sEquipState == 1) { - if (pauseCtx->equipAnimX >= (pauseCtx->itemVtx[12].v.ob[0] * 10)) { + if (sEquipState == ES_MAGIC_ARROW_APPLYING) { + if (pauseCtx->equipAnimX >= (pauseCtx->itemVtx[52].v.ob[0] * 10)) { pauseCtx->equipAnimX -= offsetX; } else { pauseCtx->equipAnimX += offsetX; } - if (pauseCtx->equipAnimY >= (pauseCtx->itemVtx[12].v.ob[1] * 10)) { + if (pauseCtx->equipAnimY >= (pauseCtx->itemVtx[52].v.ob[1] * 10)) { pauseCtx->equipAnimY -= offsetY; } else { pauseCtx->equipAnimY += offsetY; @@ -1000,34 +1229,19 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { sEquipMoveTimer--; if (sEquipMoveTimer == 0) { - if (sEquipState == 1) { - sEquipState++; - D_8082A488 = 4; + if (sEquipState == ES_MAGIC_ARROW_APPLYING) { + pauseCtx->unk_1E4 = 0; + s16 magicArrowType = pauseCtx->equipTargetItem - 0xBF; + if (magicArrowType >= 0 && magicArrowType <= 2) { + pauseCtx->equipTargetItem = ITEM_BOW_ARROW_FIRE + magicArrowType; + } + Inventory_ReplaceItem(play, INV_CONTENT(ITEM_BOW), pauseCtx->equipTargetItem); + KaleidoScope_SetArrowSelectActive(pauseCtx, false); return; } osSyncPrintf("\n================================\n"); - // Skipping the arrow animation: need to change the item's type and - // slot when it hits the button since it didn't get set earlier - if (pauseCtx->equipTargetItem == ITEM_ARROW_FIRE || pauseCtx->equipTargetItem == ITEM_ARROW_ICE || - pauseCtx->equipTargetItem == ITEM_ARROW_LIGHT) { - switch (pauseCtx->equipTargetItem) { - case ITEM_ARROW_FIRE: - pauseCtx->equipTargetItem = ITEM_BOW_ARROW_FIRE; - break; - case ITEM_ARROW_ICE: - pauseCtx->equipTargetItem = ITEM_BOW_ARROW_ICE; - break; - case ITEM_ARROW_LIGHT: - pauseCtx->equipTargetItem = ITEM_BOW_ARROW_LIGHT; - break; - } - if (!CVarGetInteger("gSeparateArrows", 0)) { - pauseCtx->equipTargetSlot = SLOT_BOW; - } - } - // If the item is on another button already, swap the two uint16_t targetButtonIndex = pauseCtx->equipTargetCBtn + 1; for (uint16_t otherSlotIndex = 0; otherSlotIndex < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h index 6f4ed7ad257..7cc3ec40e20 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope.h @@ -12,6 +12,14 @@ extern u8 gSlotAgeReqs[]; extern u8 gItemAgeReqs[]; extern u8 gAreaGsFlags[]; extern bool gSelectingMask; +typedef enum { + AMS_DISABLED, + AMS_ENABLED, + AMS_CLOSING, + AMS_OPENING +} ArrowMenuState; +extern ArrowMenuState gArrowMenuState; +#define ARROW_SELECT_OPEN (gArrowMenuState & 1) #define AGE_REQ_ADULT LINK_AGE_ADULT #define AGE_REQ_CHILD LINK_AGE_CHILD @@ -41,6 +49,7 @@ void KaleidoScope_ProcessPlayerPreRender(); void KaleidoScope_SetupPlayerPreRender(PlayState* play); void KaleidoScope_DrawCursor(PlayState* play, u16 pageIndex); void KaleidoScope_UpdateDungeonMap(PlayState* play); +void KaleidoScope_SetArrowSelectActive(PauseContext* pauseCtx, bool active); void PauseMapMark_Draw(PlayState* play); diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 35490f0798d..cd89a9cb414 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -734,30 +734,10 @@ static u16 D_8082ABEC[] = { }; u8 gSlotAgeReqs[] = { - AGE_REQ_CHILD, // SLOT_DEKU_STICK - AGE_REQ_NONE, // SLOT_DEKU_NUT - AGE_REQ_NONE, // SLOT_BOMB - AGE_REQ_ADULT, // SLOT_BOW - AGE_REQ_ADULT, // SLOT_ARROW_FIRE - AGE_REQ_NONE, // SLOT_DINS_FIRE - AGE_REQ_CHILD, // SLOT_SLINGSHOT - AGE_REQ_NONE, // SLOT_OCARINA - AGE_REQ_NONE, // SLOT_BOMBCHU - AGE_REQ_ADULT, // SLOT_HOOKSHOT - AGE_REQ_ADULT, // SLOT_ARROW_ICE - AGE_REQ_NONE, // SLOT_FARORES_WIND - AGE_REQ_CHILD, // SLOT_BOOMERANG - AGE_REQ_NONE, // SLOT_LENS_OF_TRUTH - AGE_REQ_CHILD, // SLOT_MAGIC_BEAN - AGE_REQ_ADULT, // SLOT_HAMMER - AGE_REQ_ADULT, // SLOT_ARROW_LIGHT - AGE_REQ_NONE, // SLOT_NAYRUS_LOVE - AGE_REQ_NONE, // SLOT_BOTTLE_1 - AGE_REQ_NONE, // SLOT_BOTTLE_2 - AGE_REQ_NONE, // SLOT_BOTTLE_3 - AGE_REQ_NONE, // SLOT_BOTTLE_4 - AGE_REQ_ADULT, // SLOT_TRADE_ADULT - AGE_REQ_CHILD, // SLOT_TRADE_CHILD + LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_CHILD, + LINK_AGE_EITHER, LINK_AGE_CHILD, LINK_AGE_CHILD, LINK_AGE_CHILD, LINK_AGE_ADULT, LINK_AGE_CHILD, + LINK_AGE_EITHER, LINK_AGE_ADULT, LINK_AGE_ADULT, LINK_AGE_ADULT, LINK_AGE_ADULT, LINK_AGE_ADULT, + LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, LINK_AGE_EITHER, }; u8 gEquipAgeReqs[][4] = { @@ -1009,6 +989,7 @@ void KaleidoScope_SetDefaultCursor(PlayState* play) { s16 s; s16 i; gSelectingMask = false; + KaleidoScope_SetArrowSelectActive(pauseCtx, false); switch (pauseCtx->pageIndex) { case PAUSE_ITEM: @@ -1043,6 +1024,7 @@ void KaleidoScope_SwitchPage(PauseContext* pauseCtx, u8 pt) { pauseCtx->unk_1E4 = 1; pauseCtx->unk_1EA = 0; gSelectingMask = false; + KaleidoScope_SetArrowSelectActive(pauseCtx, false); if (!pt) { pauseCtx->mode = pauseCtx->pageIndex * 2 + 1; @@ -2224,6 +2206,18 @@ void KaleidoScope_UpdateNamePanel(PlayState* play) { } else { osSyncPrintf("zoom_name=%d\n", pauseCtx->namedItem); + switch (sp2A) { + case ITEM_BOW_ARROW_FIRE: + sp2A = ITEM_ARROW_FIRE; + break; + case ITEM_BOW_ARROW_ICE: + sp2A = ITEM_ARROW_ICE; + break; + case ITEM_BOW_ARROW_LIGHT: + sp2A = ITEM_ARROW_LIGHT; + break; + } + if (gSaveContext.language) { sp2A += 123; } @@ -2613,7 +2607,8 @@ s16 func_80823A0C(PlayState* play, Vtx* vtx, s16 arg2, s16 arg3) { return phi_t1; } -static s16 D_8082B11C[] = { 0, 4, 8, 12, 24, 32, 56 }; +/* Maps an ammo item to an inventory slot by 4x its slot number */ +static s16 sAmmoVtxTableIdx[] = { 4, 8, 12, 20, 28, 36, 52 }; static s16 D_8082B12C[] = { -114, 12, 44, 76 }; @@ -2778,7 +2773,7 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { for (phi_t3 = 1; phi_t3 < ARRAY_COUNT(gSaveContext.equips.buttonItems); phi_t3++, phi_t2 += 4) { if (gSaveContext.equips.cButtonSlots[phi_t3 - 1] != ITEM_NONE && - ((phi_t3 < 4) || CVarGetInteger("gDpadEquips", 0))) { + ((phi_t3 < 5) || CVarGetInteger("gDpadEquips", 0))) { phi_t4 = gSaveContext.equips.cButtonSlots[phi_t3 - 1] * 4; pauseCtx->itemVtx[phi_t2 + 0].v.ob[0] = pauseCtx->itemVtx[phi_t2 + 2].v.ob[0] = @@ -2828,7 +2823,7 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { } for (phi_t3 = 0; phi_t3 < 7; phi_t3++) { - phi_t4 = D_8082B11C[phi_t3]; + phi_t4 = sAmmoVtxTableIdx[phi_t3]; pauseCtx->itemVtx[phi_t2 + 0].v.ob[0] = pauseCtx->itemVtx[phi_t2 + 2].v.ob[0] = pauseCtx->itemVtx[phi_t4].v.ob[0]; @@ -2889,7 +2884,7 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { pauseCtx->equipVtx[phi_t4 + 0].v.ob[0] + 28; pauseCtx->equipVtx[phi_t4 + 0].v.ob[1] = pauseCtx->equipVtx[phi_t4 + 1].v.ob[1] = - phi_t5 + pauseCtx->offsetY - 2; + phi_t5 + pauseCtx->offsetY - 2 - (phi_t3 > 0 ? 16 : 0); pauseCtx->equipVtx[phi_t4 + 2].v.ob[1] = pauseCtx->equipVtx[phi_t4 + 3].v.ob[1] = pauseCtx->equipVtx[phi_t4 + 0].v.ob[1] - 28; @@ -3080,6 +3075,34 @@ void KaleidoScope_InitVertices(PlayState* play, GraphicsContext* gfxCtx) { pauseCtx->saveVtx = Graph_Alloc(gfxCtx, 80 * sizeof(Vtx)); func_80823A0C(play, pauseCtx->saveVtx, 5, 5); + + pauseCtx->arrowSelectVtx = Graph_Alloc(gfxCtx, 32 * sizeof(Vtx)); + + // All arrow select vertices + for (phi_t2 = 0; phi_t2 < 32; phi_t2++) { + pauseCtx->arrowSelectVtx[phi_t2].v.flag = 0; + + // Z position + pauseCtx->arrowSelectVtx[phi_t2].v.ob[2] = 0; + + // Color + pauseCtx->arrowSelectVtx[phi_t2].v.cn[0] = pauseCtx->arrowSelectVtx[phi_t2].v.cn[1] = + pauseCtx->arrowSelectVtx[phi_t2].v.cn[2] = pauseCtx->arrowSelectVtx[phi_t2].v.cn[3] = 255; + } + + // All arrow select quads + for (phi_t2 = 0; phi_t2 < 32; phi_t2 += 4) { + // Top left UV at (0, 0); + pauseCtx->arrowSelectVtx[phi_t2 + 0].v.tc[0] = pauseCtx->arrowSelectVtx[phi_t2 + 0].v.tc[1] = + pauseCtx->arrowSelectVtx[phi_t2 + 1].v.tc[1] = pauseCtx->arrowSelectVtx[phi_t2 + 2].v.tc[0] = 0; + } + + // Background quads + for (phi_t2 = 16; phi_t2 < 32; phi_t2 += 4) { + // Bottom left UV at (32, 32) + pauseCtx->arrowSelectVtx[phi_t2 + 1].v.tc[0] = pauseCtx->arrowSelectVtx[phi_t2 + 2].v.tc[1] = + pauseCtx->arrowSelectVtx[phi_t2 + 3].v.tc[0] = pauseCtx->arrowSelectVtx[phi_t2 + 3].v.tc[1] = 0x400; + } } void KaleidoScope_DrawGameOver(PlayState* play) { @@ -4317,6 +4340,9 @@ void KaleidoScope_Update(PlayState* play) break; case 0x12: + // OTRTODO: move this somewhere it won't be called repeatedly for several frames + KaleidoScope_SetArrowSelectActive(pauseCtx, false); + if (pauseCtx->unk_1F4 != 160.0f) { pauseCtx->unk_1F4 = pauseCtx->unk_1F8 = pauseCtx->unk_1FC = pauseCtx->unk_200 += 160.0f / WREG(6); pauseCtx->infoPanelOffsetY -= 40 / WREG(6);