diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 859064a49ca..9f16bb58467 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -73,6 +73,7 @@ const std::vector enhancementsCvars = { "gFasterHeavyBlockLift", "gNoForcedNavi", "gSkulltulaFreeze", + "gMMPoeBottling", "gMMBunnyHood", "gAdultBunnyHood", "gFastChests", @@ -170,6 +171,7 @@ const std::vector enhancementsCvars = { "gRestoreRBAValues", "gSkipSaveConfirmation", "gAutosave", + "gSaveAndQuit", "gDisableCritWiggle", "gChestSizeDependsStoneOfAgony", "gSkipArrowAnimation", @@ -212,6 +214,9 @@ const std::vector enhancementsCvars = { "gFPSGauntlets", "gSceneSpecificDirtPathFix", "gZFightingMode", + "gVisualKeys", + "gSmallKeySpacing", + "gRightAlignKeys", "gAuthenticLogo", "gPauseLiveLinkRotationSpeed", "gBowReticle", diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index ecbebb50b3f..261c6781acc 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -391,7 +391,7 @@ void DrawSettingsMenu() { UIWidgets::Tooltip("Changes the scaling of the ImGui menu elements."); UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f); - + static std::unordered_map windowBackendNames = { { LUS::WindowBackend::DX11, "DirectX" }, { LUS::WindowBackend::SDL_OPENGL, "OpenGL"}, @@ -468,9 +468,9 @@ void DrawSettingsMenu() { } ImGui::EndMenu(); } - + UIWidgets::Spacer(0); - + if (ImGui::BeginMenu("Accessibility")) { #if defined(_WIN32) || defined(__APPLE__) UIWidgets::PaddedEnhancementCheckbox("Text to Speech", "gA11yTTS"); @@ -478,7 +478,7 @@ void DrawSettingsMenu() { #endif UIWidgets::PaddedEnhancementCheckbox("Disable Idle Camera Re-Centering", "gA11yDisableIdleCam"); UIWidgets::Tooltip("Disables the automatic re-centering of the camera when idle."); - + ImGui::EndMenu(); } ImGui::EndMenu(); @@ -602,6 +602,8 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Allows the bunny hood to be equipped normally from the pause menu as adult."); UIWidgets::PaddedEnhancementCheckbox("Mask Select in Inventory", "gMaskSelect", true, false); UIWidgets::Tooltip("After completing the mask trading sub-quest, press A and any direction on the mask slot to change masks"); + UIWidgets::PaddedEnhancementCheckbox("Catch Poes with a bottle", "gMMPoeBottling", true, false); + UIWidgets::Tooltip("Catch Poes by swinging an empty bottle at them instead of from a text box like you can in Majora's Mask."); 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); @@ -861,6 +863,8 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Allows equipping the tunic and boots to c-buttons"); UIWidgets::PaddedEnhancementCheckbox("Equipment Toggle", "gEquipmentCanBeRemoved", true, false); UIWidgets::Tooltip("Allows equipment to be removed by toggling it off on\nthe equipment subscreen."); + UIWidgets::PaddedEnhancementCheckbox("Extra Underwater Actions", "gEnhancedIronBoots", true, false); + UIWidgets::Tooltip("Allows opening chests and using your sword and Bombchus when underwater with Iron Boots"); UIWidgets::PaddedEnhancementCheckbox("Link's Cow in Both Time Periods", "gCowOfTime", true, false); UIWidgets::Tooltip("Allows the Lon Lon Ranch obstacle course reward to be shared across time periods"); UIWidgets::PaddedEnhancementCheckbox("Enable visible guard vision", "gGuardVision", true, false); @@ -879,7 +883,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BLUE_FIRE_ARROWS); static const char* forceEnableBlueFireArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Blue Fire Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false, forceEnableBlueFireArrows, forceEnableBlueFireArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Ice Arrows to melt red ice.\nMay require a room reload if toggled during gameplay."); @@ -888,7 +892,7 @@ void DrawEnhancementsMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SUNLIGHT_ARROWS); static const char* forceEnableSunLightArrowsText = "This setting is forcefully enabled because a savefile\nwith \"Sunlight Arrows\" is loaded."; - UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, + UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false, forceEnableSunLightArrows, forceEnableSunLightArrowsText, UIWidgets::CheckboxGraphics::Checkmark); UIWidgets::Tooltip("Allows Light Arrows to activate sun switches.\nMay require a room reload if toggled during gameplay."); @@ -900,6 +904,11 @@ void DrawEnhancementsMenu() { UIWidgets::PaddedEnhancementCheckbox("Targetable Hookshot Reticle", "gHookshotableReticle", true, false); UIWidgets::Tooltip("Use a different color when aiming at hookshotable collision"); + UIWidgets::PaddedEnhancementCheckbox("Ask to continue playing after saving", "gSaveAndQuit", true, false); + UIWidgets::Tooltip( + "The save dialog from the pause menu will ask you to continue playing after you select Yes or No.\n" + "Pressing B or Start on the save prompt will close the pause menu without displaying the extra screen."); + ImGui::EndMenu(); } @@ -999,6 +1008,11 @@ void DrawEnhancementsMenu() { "Consistent: Certain paths vanish the same way in all resolutions\n" "No Vanish: Paths do not vanish, Link seems to sink in to some paths\n" "This might affect other decal effects\n"); + UIWidgets::PaddedEnhancementCheckbox("Visual Small Key display", "gVisualKeys", true, false); + UIWidgets::Tooltip("Displays Small Key count using multiple icons rather than a numeric counter"); + const bool disableKeySpacing = !CVarGetInteger("gVisualKeys", 0); + static const char* disableKeySpacingTooltip = "This option is disabled because \"Visual Small Key display\" is turned off"; + UIWidgets::EnhancementSliderInt("Small Key icon spacing: %d", "##SmallKeySpacing", "gSmallKeySpacing", 1, 16, "", 8, true, disableKeySpacing, disableKeySpacingTooltip); UIWidgets::PaddedEnhancementSliderInt("Text Spacing: %d", "##TEXTSPACING", "gTextSpacing", 4, 6, "", 6, true, true, true); UIWidgets::Tooltip("Space between text characters (useful for HD font textures)"); UIWidgets::PaddedEnhancementCheckbox("More info in file select", "gFileSelectMoreInfo", true, false); @@ -1062,8 +1076,8 @@ void DrawEnhancementsMenu() { "Fixes an incorrect calculation that acted like water underneath ground was above it."); UIWidgets::PaddedEnhancementCheckbox("Fix Bush Item Drops", "gBushDropFix", true, false); UIWidgets::Tooltip("Fixes the bushes to drop items correctly rather than spawning undefined items."); - UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); - UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); + UIWidgets::PaddedEnhancementCheckbox("Fix falling from vine edges", "gFixVineFall", true, false); + UIWidgets::Tooltip("Prevents immediately falling off climbable surfaces if climbing on the edges."); UIWidgets::PaddedEnhancementCheckbox("Fix Link's eyes open while sleeping", "gFixEyesOpenWhileSleeping", true, false); UIWidgets::Tooltip("Fixes Link's eyes being open in the opening cutscene when he is supposed to be sleeping."); @@ -1389,12 +1403,12 @@ void DrawCheatsMenu() { if (ImGui::Button("Change Age")) { CVarSetInteger("gSwitchAge", 1); } - UIWidgets::Tooltip("Switches Link's age and reloads the area."); + UIWidgets::Tooltip("Switches Link's age and reloads the area."); if (ImGui::Button("Clear Cutscene Pointer")) { GameInteractor::RawAction::ClearCutscenePointer(); } - UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); + UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); ImGui::EndMenu(); } @@ -1568,12 +1582,12 @@ void DrawRandomizerMenu() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BOSS_KEYSANITY) == RO_DUNGEON_ITEM_LOC_ANYWHERE || (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_VANILLA && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_OWN_DUNGEON && - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_STARTWITH) || !IS_RANDO) { disableKeyColors = false; } - static const char* disableKeyColorsText = + static const char* disableKeyColorsText = "This setting is disabled because a savefile is loaded without any key\n" "shuffle settings set to \"Any Dungeon\", \"Overworld\" or \"Anywhere\""; @@ -1629,4 +1643,4 @@ void SohMenuBar::DrawElement() { ImGui::EndMenuBar(); } } -} // namespace SohGui \ No newline at end of file +} // namespace SohGui \ No newline at end of file diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index bbaa8d90bd5..c287d182075 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -964,11 +964,19 @@ void func_80083108(PlayState* play) { gSaveContext.buttonStatus[3] = gSaveContext.buttonStatus[5] = gSaveContext.buttonStatus[6] = gSaveContext.buttonStatus[7] = gSaveContext.buttonStatus[8] = BTN_DISABLED; } else if ((Player_GetEnvironmentalHazard(play) >= 2) && (Player_GetEnvironmentalHazard(play) < 5)) { - if (gSaveContext.buttonStatus[0] != BTN_DISABLED) { - sp28 = 1; - } + if (CVarGetInteger("gEnhancedIronBoots", 0) && Player_GetEnvironmentalHazard(play) == 2) { + if (gSaveContext.buttonStatus[0] == BTN_DISABLED) { + sp28 = 1; + } + + gSaveContext.buttonStatus[0] = BTN_ENABLED; + } else { + if (gSaveContext.buttonStatus[0] != BTN_DISABLED) { + sp28 = 1; + } - gSaveContext.buttonStatus[0] = BTN_DISABLED; + gSaveContext.buttonStatus[0] = BTN_DISABLED; + } for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] >= ITEM_SHIELD_DEKU) && @@ -981,7 +989,9 @@ void func_80083108(PlayState* play) { gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] = BTN_ENABLED; } else if (Player_GetEnvironmentalHazard(play) == 2) { if ((gSaveContext.equips.buttonItems[i] != ITEM_HOOKSHOT) && - (gSaveContext.equips.buttonItems[i] != ITEM_LONGSHOT)) { + (gSaveContext.equips.buttonItems[i] != ITEM_LONGSHOT) && + (CVarGetInteger("gEnhancedIronBoots", 0) + && gSaveContext.equips.buttonItems[i] != ITEM_BOMBCHU)) { if (gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] == BTN_ENABLED) { sp28 = 1; } @@ -1441,7 +1451,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) { @@ -1483,13 +1493,13 @@ void Inventory_SwapAgeEquipment(void) { gSaveContext.equips.buttonItems[3] = gSaveContext.inventory.items[SLOT_OCARINA]; gSaveContext.equips.cButtonSlots[1] = SLOT_BOMB; gSaveContext.equips.cButtonSlots[2] = SLOT_OCARINA; - + 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)); } @@ -1814,14 +1824,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 +1912,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 +1927,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)); @@ -2657,7 +2667,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 +2931,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 +2970,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 +3037,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 +3062,7 @@ s32 Health_ChangeBy(PlayState* play, s16 healthChange) { if (healthChange < 0) { gSaveContext.health = 0; } - + return 0; } @@ -3121,7 +3131,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; @@ -4307,7 +4317,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 +4435,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 +4510,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] = { @@ -4877,11 +4887,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); } @@ -5240,6 +5250,21 @@ void Interface_Draw(PlayState* play) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, keyCountColor.r,keyCountColor.g,keyCountColor.b, interfaceCtx->magicAlpha); gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 20, 255); //We reset this here so it match user color :) + + if (CVarGetInteger("gVisualKeys", 0)) { + s8 keyCount = gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]; + s16 rectLeft = PosX_SKC; + s16 keyOffset = CVarGetInteger("gSmallKeySpacing", 8); + if (CVarGetInteger("gRightAlignKeys", 0)) { + keyOffset = -keyOffset; + } + for (int i = 0; i < keyCount; i++, rectLeft += keyOffset) { + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, gSmallKeyCounterIconTex, 16, 16, rectLeft, PosY_SKC, 16, 16, + 1 << 10, 1 << 10); + } + break; + } + OVERLAY_DISP = Gfx_TextureIA8(OVERLAY_DISP, gSmallKeyCounterIconTex, 16, 16, PosX_SKC, PosY_SKC, 16, 16, 1 << 10, 1 << 10); @@ -5386,7 +5411,7 @@ void Interface_Draw(PlayState* play) { PosY_adjust = 6; PosX_adjust = -10; } - + s16 BbtnPosX; s16 BbtnPosY; s16 X_Margins_BtnB_label; @@ -5704,7 +5729,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 +6239,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 +6383,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_En_Po_Field/z_en_po_field.c b/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c index c11feb327d9..b7f2f5bb4ec 100644 --- a/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c +++ b/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c @@ -658,7 +658,7 @@ void func_80AD58D4(EnPoField* this, PlayState* play) { if (this->actionTimer != 0) { this->actionTimer--; } - if (Actor_ProcessTalkRequest(&this->actor, play)) { + if (!CVarGetInteger("gMMPoeBottling", 0) && Actor_ProcessTalkRequest(&this->actor, play)) { EnPoField_SetupInteractWithSoul(this); return; } @@ -668,7 +668,15 @@ void func_80AD58D4(EnPoField* this, PlayState* play) { EnPoField_SetupSoulDisappear(this); return; } - if (this->collider.base.ocFlags1 & OC1_HIT) { + if (CVarGetInteger("gMMPoeBottling", 0)) { + // do not collide + if (Actor_HasParent(&this->actor, play)) { + Actor_Kill(&this->actor); + } + + // GI_MAX in this case allows the player to catch the actor in a bottle + func_8002F434(&this->actor, play, GI_MAX, 35.0f, 60.0f); + } else if (this->collider.base.ocFlags1 & OC1_HIT) { this->actor.flags |= ACTOR_FLAG_WILL_TALK; func_8002F2F4(&this->actor, play); } else { diff --git a/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c b/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c index 809150fe630..fb682b7037e 100644 --- a/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c +++ b/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c @@ -770,7 +770,8 @@ void func_80ADFE80(EnPoh* this, PlayState* play) { if (this->unk_198 != 0) { this->unk_198--; } - if (Actor_ProcessTalkRequest(&this->actor, play)) { + if (!(CVarGetInteger("gMMPoeBottling", 0) && this->actor.params < EN_POH_SHARP) && + Actor_ProcessTalkRequest(&this->actor, play)) { if (this->actor.params >= EN_POH_SHARP) { func_80ADE9BC(this); } else { @@ -783,7 +784,15 @@ void func_80ADFE80(EnPoh* this, PlayState* play) { this->actor.flags &= ~ACTOR_FLAG_WILL_TALK; return; } - if (this->colliderCyl.base.ocFlags1 & OC1_HIT) { + if (CVarGetInteger("gMMPoeBottling", 0) && this->actor.params < EN_POH_SHARP) { + if (Actor_HasParent(&this->actor, play)) { + Actor_Kill(&this->actor); + return; + } + + // GI_MAX in this case allows the player to catch the actor in a bottle + func_8002F434(&this->actor, play, GI_MAX, 35.0f, 60.0f); + } else if (this->colliderCyl.base.ocFlags1 & OC1_HIT) { this->actor.flags |= ACTOR_FLAG_WILL_TALK; func_8002F2F4(&this->actor, play); } else { 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 2746bb3aa33..5f5e976fb01 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -3074,7 +3074,9 @@ void func_80835F44(PlayState* play, Player* this, s32 item) { if ((actionParam == PLAYER_IA_NONE) || !(this->stateFlags1 & PLAYER_STATE1_IN_WATER) || ((this->actor.bgCheckFlags & 1) && - ((actionParam == PLAYER_IA_HOOKSHOT) || (actionParam == PLAYER_IA_LONGSHOT))) || + ((actionParam == PLAYER_IA_HOOKSHOT) || (actionParam == PLAYER_IA_LONGSHOT) || + (CVarGetInteger("gEnhancedIronBoots", 0) && + ((Player_ActionToMeleeWeapon(actionParam) != 0) || (actionParam == PLAYER_IA_BOMBCHU))))) || ((actionParam >= PLAYER_IA_SHIELD_DEKU) && (actionParam <= PLAYER_IA_BOOTS_HOVER))) { if ((play->bombchuBowlingStatus == 0) && @@ -6504,7 +6506,7 @@ s32 func_8083E5A8(Player* this, PlayState* play) { this->getItemEntry = (GetItemEntry)GET_ITEM_NONE; } } else if (CHECK_BTN_ALL(sControlInput->press.button, BTN_A) && !(this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) && - !(this->stateFlags2 & PLAYER_STATE2_UNDERWATER)) { + (CVarGetInteger("gEnhancedIronBoots", 0) || !(this->stateFlags2 & PLAYER_STATE2_UNDERWATER))) { if (this->getItemId != GI_NONE) { GetItemEntry giEntry; if (this->getItemEntry.objectId == OBJECT_INVALID) { @@ -9959,7 +9961,8 @@ void func_808473D4(PlayState* play, Player* this) { } else if ((!(this->stateFlags1 & PLAYER_STATE1_ITEM_OVER_HEAD) || (heldActor == NULL)) && (interactRangeActor != NULL) && ((!sp1C && (this->getItemId == GI_NONE)) || - (this->getItemId < 0 && !(this->stateFlags1 & PLAYER_STATE1_IN_WATER)))) { + (this->getItemId < 0 && !(this->stateFlags1 & PLAYER_STATE1_IN_WATER)) || + CVarGetInteger("gEnhancedIronBoots", 0) && this->stateFlags2 & PLAYER_STATE2_UNDERWATER)) { if (this->getItemId < 0) { doAction = DO_ACTION_OPEN; } else if ((interactRangeActor->id == ACTOR_BG_TOKI_SWD) && LINK_IS_ADULT) { @@ -13362,6 +13365,8 @@ static BottleCatchInfo D_80854A04[] = { { ACTOR_EN_FISH, ITEM_FISH, 0x1F, 0x47 }, { ACTOR_EN_ICE_HONO, ITEM_BLUE_FIRE, 0x20, 0x5D }, { ACTOR_EN_INSECT, ITEM_BUG, 0x21, 0x7A }, + { ACTOR_EN_POH, ITEM_POE, PLAYER_IA_BOTTLE_POE, 0x97 }, + { ACTOR_EN_PO_FIELD, ITEM_BIG_POE, PLAYER_IA_BOTTLE_BIG_POE, 0xF9 }, }; void func_8084ECA4(Player* this, PlayState* play) { @@ -13404,13 +13409,29 @@ void func_8084ECA4(Player* this, PlayState* play) { if (this->interactRangeActor != NULL) { catchInfo = &D_80854A04[0]; - for (i = 0; i < 4; i++, catchInfo++) { + for (i = 0; i < ARRAY_COUNT(D_80854A04); i++, catchInfo++) { if (this->interactRangeActor->id == catchInfo->actorId) { break; } } - if (i < 4) { + if (catchInfo->actorId == ACTOR_EN_POH || catchInfo->actorId == ACTOR_EN_PO_FIELD) { + // Don't catch Sharp or Flat + // I think they talk to you before you can get in catching range, but might as well prevent it outright + if (catchInfo->actorId == ACTOR_EN_POH && this->interactRangeActor->params >= 2) { + i = ARRAY_COUNT(D_80854A04); + } + // If the catch is a small field Poe (as opposed to a Big Poe), catch a graveyard Poe instead + if (catchInfo->actorId == ACTOR_EN_PO_FIELD && this->interactRangeActor->params == 0) { + i--; + catchInfo--; + } + if (!CVarGetInteger("gMMPoeBottling", 0)) { + i = ARRAY_COUNT(D_80854A04); + } + } + + if (i < ARRAY_COUNT(D_80854A04)) { this->unk_84F = i + 1; this->unk_850 = 0; this->interactRangeActor->parent = &this->actor; diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_prompt.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_prompt.c index 0807b8356a8..53e30257fe7 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_prompt.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_prompt.c @@ -9,7 +9,7 @@ void KaleidoScope_UpdatePrompt(PlayState* play) { s16 step; bool dpad = CVarGetInteger("gDpadPause", 0); - if (((pauseCtx->state == 7) && (pauseCtx->unk_1EC == 1)) || (pauseCtx->state == 0xE) || (pauseCtx->state == 0x10)) { + if (((pauseCtx->state == 7) && (pauseCtx->unk_1EC == 1 || pauseCtx->unk_1EC == 7)) || (pauseCtx->state == 0xE) || (pauseCtx->state == 0x10)) { if ((pauseCtx->promptChoice == 0) && ((relStickX >= 30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DRIGHT)))) { Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); pauseCtx->promptChoice = 4; 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..8db7779a381 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 @@ -1595,9 +1595,17 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) { gSPVertex(POLY_KAL_DISP++, &pauseCtx->saveVtx[60], 32, 0); - if (((pauseCtx->state == 7) && (pauseCtx->unk_1EC < 4)) || (pauseCtx->state == 0xE)) { - POLY_KAL_DISP = - KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, sSavePromptTexs[gSaveContext.language], 152, 16, 0); + if (((pauseCtx->state == 7) && + (pauseCtx->unk_1EC < 4 || pauseCtx->unk_1EC == 7 || + (CVarGetInteger("gSaveAndQuit", 0) && pauseCtx->unk_1EC == 5))) || + (pauseCtx->state == 0xE)) { + if (pauseCtx->unk_1EC == 7 || pauseCtx->unk_1EC == 5) { + POLY_KAL_DISP = + KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, sContinuePromptTexs[gSaveContext.language], 152, 16, 0); + } else { + POLY_KAL_DISP = + KaleidoScope_QuadTextureIA8(POLY_KAL_DISP, sSavePromptTexs[gSaveContext.language], 152, 16, 0); + } gDPSetCombineLERP(POLY_KAL_DISP++, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0); @@ -3926,6 +3934,12 @@ void KaleidoScope_Update(PlayState* play) case 1: if (CHECK_BTN_ALL(input->press.button, BTN_A)) { if (pauseCtx->promptChoice != 0) { + if (CVarGetInteger("gSaveAndQuit", 0)) { + pauseCtx->promptChoice = 0; + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + pauseCtx->unk_1EC = 7; + break; + } Interface_SetDoAction(play, DO_ACTION_NONE); gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] = gSaveContext.buttonStatus[3] = BTN_ENABLED; @@ -3941,7 +3955,7 @@ void KaleidoScope_Update(PlayState* play) Audio_PlaySoundGeneral(NA_SE_SY_PIECE_OF_HEART, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); Play_PerformSave(play); - pauseCtx->unk_1EC = 4; + pauseCtx->unk_1EC = CVarGetInteger("gSaveAndQuit", 0) ? 7 : 4; D_8082B25C = CVarGetInteger("gSkipSaveConfirmation", 0) ? 3 /* 0.1 sec */ : 90 /* 3 secs */; } } else if (CHECK_BTN_ALL(input->press.button, BTN_START) || @@ -3963,6 +3977,10 @@ void KaleidoScope_Update(PlayState* play) case 4: if (CHECK_BTN_ALL(input->press.button, BTN_B) || CHECK_BTN_ALL(input->press.button, BTN_A) || CHECK_BTN_ALL(input->press.button, BTN_START) || (--D_8082B25C == 0)) { + if (CVarGetInteger("gSaveAndQuit", 0)) { + pauseCtx->unk_1EC = 7; + break; + } Interface_SetDoAction(play, DO_ACTION_NONE); gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] = gSaveContext.buttonStatus[3] = BTN_ENABLED; @@ -4013,6 +4031,46 @@ void KaleidoScope_Update(PlayState* play) pauseCtx->unk_204 = -434.0f; } break; + + // 7 and 8 are used by "Prompt to quit after saving" enhancement + case 7: + if (CHECK_BTN_ALL(input->press.button, BTN_A) || CHECK_BTN_ALL(input->press.button, BTN_B) || + CHECK_BTN_ALL(input->press.button, BTN_START)) { + if (pauseCtx->promptChoice == 0 || CHECK_BTN_ALL(input->press.button, BTN_B)) { + Interface_SetDoAction(play, DO_ACTION_NONE); + gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] = + gSaveContext.buttonStatus[3] = BTN_ENABLED; + gSaveContext.buttonStatus[5] = gSaveContext.buttonStatus[6] = gSaveContext.buttonStatus[7] = + gSaveContext.buttonStatus[8] = BTN_ENABLED; + gSaveContext.unk_13EA = 0; + Interface_ChangeAlpha(50); + pauseCtx->unk_1EC = 5; + WREG(2) = -6240; + YREG(8) = pauseCtx->unk_204; + func_800F64E0(0); + } else { + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, + &D_801333E8); + pauseCtx->unk_1EC = 8; + } + } + break; + + case 8: + if (interfaceCtx->unk_244 != 255) { + interfaceCtx->unk_244 += 10; + if (interfaceCtx->unk_244 >= 255) { + interfaceCtx->unk_244 = 255; + pauseCtx->state = 0; + R_UPDATE_RATE = 3; + R_PAUSE_MENU_MODE = 0; + func_800981B8(&play->objectCtx); + func_800418D0(&play->colCtx, play); + play->state.running = 0; + SET_NEXT_GAMESTATE(&play->state, Opening_Init, OpeningContext); + } + } + break; } break;