diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 22c9dd7db3d..2fa06642fc3 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", diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 2f654c04f91..2303c32f82c 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(); @@ -604,6 +604,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); @@ -878,7 +880,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."); @@ -887,7 +889,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."); @@ -1064,8 +1066,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."); UIWidgets::PaddedEnhancementCheckbox("Fix Darunia dancing too fast", "gEnhancements.FixDaruniaDanceSpeed", @@ -1398,12 +1400,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::EndDisabled(); @@ -1583,12 +1585,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\""; @@ -1644,4 +1646,4 @@ void SohMenuBar::DrawElement() { ImGui::EndMenuBar(); } } -} // namespace SohGui +} // namespace SohGui 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 ca7333497a0..bb8fcddaf1f 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -13247,6 +13247,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) { @@ -13289,13 +13291,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;