From 2d34d1745704a780e7703409e6e665730d5f78ef Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sun, 5 Jan 2025 20:56:15 -0600 Subject: [PATCH] Minigame options for Archery & H&D --- mm/2s2h/BenGui/SearchableMenuItems.h | 117 +++++++++++------- mm/2s2h/Enhancements/Minigames/Archery.cpp | 54 ++++++++ .../Minigames/HoneyAndDarling.cpp | 26 ++++ mm/2s2h/GameInteractor/GameInteractor.h | 2 + mm/src/overlays/actors/ovl_En_Fu/z_en_fu.c | 10 +- .../ovl_En_Syateki_Man/z_en_syateki_man.c | 3 +- 6 files changed, 165 insertions(+), 47 deletions(-) create mode 100644 mm/2s2h/Enhancements/Minigames/Archery.cpp create mode 100644 mm/2s2h/Enhancements/Minigames/HoneyAndDarling.cpp diff --git a/mm/2s2h/BenGui/SearchableMenuItems.h b/mm/2s2h/BenGui/SearchableMenuItems.h index db18afdf9d..fda1287b13 100644 --- a/mm/2s2h/BenGui/SearchableMenuItems.h +++ b/mm/2s2h/BenGui/SearchableMenuItems.h @@ -1058,29 +1058,6 @@ void AddEnhancements() { { 1, 5, 1 } }, { "Dpad Equips", "gEnhancements.Dpad.DpadEquips", "Allows you to equip items to your d-pad", WIDGET_CVAR_CHECKBOX }, - { "Always Win Doggy Race", - "gEnhancements.Minigames.AlwaysWinDoggyRace", - "Makes the Doggy Race easier to win.", - WIDGET_CVAR_COMBOBOX, - { .comboBoxOptions = alwaysWinDoggyraceOptions } }, - { "Milk Run Reward Options", - "gEnhancements.Minigames.CremiaHugs", - "Choose what reward you get for winning the Milk Run minigame after the first time. \n" - "-Vanilla: Reward is Random\n" - "-Hug: Get the hugging cutscene\n" - "-Rupee: Get the rupee reward", - WIDGET_CVAR_COMBOBOX, - { .comboBoxOptions = cremiaRewardOptions } }, - { "Cucco Shack Cucco Count", - "gEnhancements.Minigames.CuccoShackCuccoCount", - "Choose how many cuccos you need to raise to make Grog happy.", - WIDGET_CVAR_SLIDER_INT, - { 1, 10, 10 } }, - { "Swordsman School Winning Score", - "gEnhancements.Minigames.SwordsmanSchoolScore", - "Sets the score required to win the Swordsman School.", - WIDGET_CVAR_SLIDER_INT, - { 1, 30, 30 } }, { "Fast Magic Arrow Equip Animation", "gEnhancements.Equipment.MagicArrowEquipSpeed", "Removes the animation for equipping Magic Arrows.", WIDGET_CVAR_CHECKBOX }, { "Instant Fin Boomerangs Recall", "gEnhancements.PlayerActions.InstantRecall", @@ -1089,26 +1066,80 @@ void AddEnhancements() { { "Two-Handed Sword Spin Attack", "gEnhancements.Equipment.TwoHandedSwordSpinAttack", "Enables magic spin attacks for the Fierce Deity Sword and Great Fairy's Sword.", WIDGET_CVAR_CHECKBOX } }, - { { .widgetName = "Modes", .widgetType = WIDGET_SEPARATOR_TEXT }, - { "Play as Kafei", "gModes.PlayAsKafei", "Requires scene reload to take effect.", WIDGET_CVAR_CHECKBOX }, - { "Hyrule Warriors Styled Link", "gModes.HyruleWarriorsStyledLink", - "When acquired, places the Keaton and Fierce Deity masks on Link similarly to how he wears them in " - "Hyrule Warriors", - WIDGET_CVAR_CHECKBOX }, - { "Time Moves when you Move", "gModes.TimeMovesWhenYouMove", - "Time only moves when Link is not standing still.", WIDGET_CVAR_CHECKBOX }, - { "Mirrored World", - "gModes.MirroredWorld.Mode", - "Mirrors the world horizontally.", - WIDGET_CVAR_CHECKBOX, - {}, - ([](widgetInfo& info) { - if (CVarGetInteger("gModes.MirroredWorld.Mode", 0)) { - CVarSetInteger("gModes.MirroredWorld.State", 1); - } else { - CVarClear("gModes.MirroredWorld.State"); - } - }) } }, + { + { .widgetName = "Modes", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Play as Kafei", "gModes.PlayAsKafei", "Requires scene reload to take effect.", + WIDGET_CVAR_CHECKBOX }, + { "Hyrule Warriors Styled Link", "gModes.HyruleWarriorsStyledLink", + "When acquired, places the Keaton and Fierce Deity masks on Link similarly to how he wears them in " + "Hyrule Warriors", + WIDGET_CVAR_CHECKBOX }, + { "Time Moves when you Move", "gModes.TimeMovesWhenYouMove", + "Time only moves when Link is not standing still.", WIDGET_CVAR_CHECKBOX }, + { "Mirrored World", + "gModes.MirroredWorld.Mode", + "Mirrors the world horizontally.", + WIDGET_CVAR_CHECKBOX, + {}, + ([](widgetInfo& info) { + if (CVarGetInteger("gModes.MirroredWorld.Mode", 0)) { + CVarSetInteger("gModes.MirroredWorld.State", 1); + } else { + CVarClear("gModes.MirroredWorld.State"); + } + }) }, + { .widgetName = "Minigames", .widgetType = WIDGET_SEPARATOR_TEXT }, + { "Always Win Doggy Race", + "gEnhancements.Minigames.AlwaysWinDoggyRace", + "Makes the Doggy Race easier to win.", + WIDGET_CVAR_COMBOBOX, + { .comboBoxOptions = alwaysWinDoggyraceOptions } }, + { "Milk Run Reward Options", + "gEnhancements.Minigames.CremiaHugs", + "Choose what reward you get for winning the Milk Run minigame after the first time. \n" + "-Vanilla: Reward is Random\n" + "-Hug: Get the hugging cutscene\n" + "-Rupee: Get the rupee reward", + WIDGET_CVAR_COMBOBOX, + { .comboBoxOptions = cremiaRewardOptions } }, + { "Cucco Shack Cucco Count", + "gEnhancements.Minigames.CuccoShackCuccoCount", + "Choose how many cuccos you need to raise to make Grog happy.", + WIDGET_CVAR_SLIDER_INT, + { 1, 10, 10 } }, + { "Swordsman School Winning Score", + "gEnhancements.Minigames.SwordsmanSchoolScore", + "Sets the score required to win the Swordsman School.", + WIDGET_CVAR_SLIDER_INT, + { 1, 30, 30 } }, + { "Swamp Archery Perfect Score", + "gEnhancements.Minigames.SwampArcheryScore", + "Sets the score required to win the Swamp Archery minigame, if this is changed it also speeds up the " + "final score counting.", + WIDGET_CVAR_SLIDER_INT, + { 1000, 2180, 2180 } }, + { "Town Archery Perfect Score", + "gEnhancements.Minigames.TownArcheryScore", + "Sets the score required to win the Town Archery minigame. Reaching this score will end the " + "minigame.", + WIDGET_CVAR_SLIDER_INT, + { 1, 50, 50 } }, + { "Honey & Darling Day 1 (Bombchus)", + "gEnhancements.Minigames.HoneyAndDarlingDay1", + "Sets the score required to win the Honey & Darling minigame on Day 1.", + WIDGET_CVAR_SLIDER_INT, + { 1, 8, 8 } }, + { "Honey & Darling Day 2 (Bombs)", + "gEnhancements.Minigames.HoneyAndDarlingDay2", + "Sets the score required to win the Honey & Darling minigame on Day 2.", + WIDGET_CVAR_SLIDER_INT, + { 1, 8, 8 } }, + { "Honey & Darling Day 3 (Bow)", + "gEnhancements.Minigames.HoneyAndDarlingDay3", + "Sets the score required to win the Honey & Darling minigame on Day 3.", + WIDGET_CVAR_SLIDER_INT, + { 1, 16, 16 } }, + }, { { .widgetName = "Saving", .widgetType = WIDGET_SEPARATOR_TEXT }, { "Persistent Owl Saves", "gEnhancements.Saving.PersistentOwlSaves", "Continuing a save will not remove the owl save. Playing Song of " diff --git a/mm/2s2h/Enhancements/Minigames/Archery.cpp b/mm/2s2h/Enhancements/Minigames/Archery.cpp new file mode 100644 index 0000000000..067e8d298b --- /dev/null +++ b/mm/2s2h/Enhancements/Minigames/Archery.cpp @@ -0,0 +1,54 @@ +#include +#include "2s2h/GameInteractor/GameInteractor.h" +#include "2s2h/ShipInit.hpp" + +extern "C" { +#include "overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.h" + +void EnSyatekiMan_Swamp_RunGame(EnSyatekiMan* enSyatekiMan, PlayState* play); +void EnSyatekiMan_Town_RunGame(EnSyatekiMan* enSyatekiMan, PlayState* play); +} + +#define SWAMP_CVAR_NAME "gEnhancements.Minigames.SwampArcheryScore" +#define SWAMP_CVAR CVarGetInteger(SWAMP_CVAR_NAME, 2180) +#define TOWN_CVAR_NAME "gEnhancements.Minigames.TownArcheryScore" +#define TOWN_CVAR CVarGetInteger(TOWN_CVAR_NAME, 50) + +void RegisterArchery() { + COND_ID_HOOK(ShouldActorUpdate, ACTOR_EN_SYATEKI_MAN, SWAMP_CVAR != 2180, [](Actor* actor, bool* should) { + EnSyatekiMan* enSyatekiMan = (EnSyatekiMan*)actor; + + if (enSyatekiMan->actionFunc == EnSyatekiMan_Swamp_RunGame) { + // This checks if their current score plus the amount of bonus points they would get from the timer is + // greater than or equal to the score required to win + if (enSyatekiMan->score != 0 && + (enSyatekiMan->score + (gSaveContext.timerCurTimes[TIMER_ID_MINIGAME_1] / 10)) >= SWAMP_CVAR) { + enSyatekiMan->score = 2120; + enSyatekiMan->currentWave = 4; + enSyatekiMan->wolfosFlags = 0; + enSyatekiMan->bonusDekuScrubHitCounter = 2; + } + } + }); + + COND_VB_SHOULD(VB_ARCHERY_ADD_BONUS_POINTS, SWAMP_CVAR != 2180, { + Actor* actor = va_arg(args, Actor*); + s32* sBonusTimer = va_arg(args, s32*); + + *sBonusTimer = 11; + *should = true; + }); + + COND_ID_HOOK(ShouldActorUpdate, ACTOR_EN_SYATEKI_MAN, TOWN_CVAR != 50, [](Actor* actor, bool* should) { + EnSyatekiMan* enSyatekiMan = (EnSyatekiMan*)actor; + + if (enSyatekiMan->actionFunc == EnSyatekiMan_Town_RunGame) { + if (enSyatekiMan->score >= TOWN_CVAR) { + enSyatekiMan->score = 50; + gSaveContext.timerCurTimes[TIMER_ID_MINIGAME_1] = 0; + } + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterArchery, { SWAMP_CVAR_NAME, TOWN_CVAR_NAME }); diff --git a/mm/2s2h/Enhancements/Minigames/HoneyAndDarling.cpp b/mm/2s2h/Enhancements/Minigames/HoneyAndDarling.cpp new file mode 100644 index 0000000000..d90ca1dc42 --- /dev/null +++ b/mm/2s2h/Enhancements/Minigames/HoneyAndDarling.cpp @@ -0,0 +1,26 @@ +#include +#include "2s2h/GameInteractor/GameInteractor.h" +#include "2s2h/ShipInit.hpp" + +extern "C" { +#include "overlays/actors/ovl_En_Fu/z_en_fu.h" +} + +#define DAY1_CVAR_NAME "gEnhancements.Minigames.HoneyAndDarlingDay1" +#define DAY1_CVAR CVarGetInteger(DAY1_CVAR_NAME, 8) +#define DAY2_CVAR_NAME "gEnhancements.Minigames.HoneyAndDarlingDay2" +#define DAY2_CVAR CVarGetInteger(DAY2_CVAR_NAME, 8) +#define DAY3_CVAR_NAME "gEnhancements.Minigames.HoneyAndDarlingDay3" +#define DAY3_CVAR CVarGetInteger(DAY3_CVAR_NAME, 16) + +void RegisterHoneyAndDarling() { + COND_VB_SHOULD(VB_HONEY_AND_DARLING_MINIGAME_FINISH, (DAY1_CVAR != 8 || DAY2_CVAR != 8 || DAY3_CVAR != 16), { + EnFu* enFu = va_arg(args, EnFu*); + if ((CURRENT_DAY == 1 && enFu->unk_548 >= DAY1_CVAR) || (CURRENT_DAY == 2 && enFu->unk_548 >= DAY2_CVAR) || + (CURRENT_DAY == 3 && enFu->unk_548 >= DAY3_CVAR)) { + enFu->unk_548 = enFu->unk_54C; + } + }); +} + +static RegisterShipInitFunc initFunc(RegisterHoneyAndDarling, { DAY1_CVAR_NAME, DAY2_CVAR_NAME, DAY3_CVAR_NAME }); diff --git a/mm/2s2h/GameInteractor/GameInteractor.h b/mm/2s2h/GameInteractor/GameInteractor.h index 0404f0a2bb..27a294cd2d 100644 --- a/mm/2s2h/GameInteractor/GameInteractor.h +++ b/mm/2s2h/GameInteractor/GameInteractor.h @@ -83,6 +83,8 @@ typedef enum { VB_DISPLAY_SONG_OF_DOUBLE_TIME_PROMPT, VB_ALLOW_SONG_DOUBLE_TIME_ON_FINAL_NIGHT, VB_OWL_TELL_ABOUT_SHRINE, + VB_ARCHERY_ADD_BONUS_POINTS, + VB_HONEY_AND_DARLING_MINIGAME_FINISH, } GIVanillaBehavior; typedef enum { diff --git a/mm/src/overlays/actors/ovl_En_Fu/z_en_fu.c b/mm/src/overlays/actors/ovl_En_Fu/z_en_fu.c index 2f5c5495d7..d588adea07 100644 --- a/mm/src/overlays/actors/ovl_En_Fu/z_en_fu.c +++ b/mm/src/overlays/actors/ovl_En_Fu/z_en_fu.c @@ -12,6 +12,7 @@ #include "objects/gameplay_keep/gameplay_keep.h" #include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS \ (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10 | ACTOR_FLAG_2000000 | ACTOR_FLAG_CANT_LOCK_ON) @@ -802,9 +803,12 @@ void func_80962F4C(EnFu* this, PlayState* play) { Message_StartTextbox(play, 0x288B, &this->actor); } - if ((!DynaPolyActor_IsPlayerAbove((DynaPolyActor*)this->actor.child) && - (player->actor.bgCheckFlags & BGCHECKFLAG_GROUND)) || - (gSaveContext.timerCurTimes[TIMER_ID_MINIGAME_2] <= SECONDS_TO_TIMER(0)) || (this->unk_548 == this->unk_54C)) { + if (GameInteractor_Should(VB_HONEY_AND_DARLING_MINIGAME_FINISH, + (!DynaPolyActor_IsPlayerAbove((DynaPolyActor*)this->actor.child) && + (player->actor.bgCheckFlags & BGCHECKFLAG_GROUND)) || + (gSaveContext.timerCurTimes[TIMER_ID_MINIGAME_2] <= SECONDS_TO_TIMER(0)) || + (this->unk_548 == this->unk_54C), + this)) { player->stateFlags3 &= ~PLAYER_STATE3_400000; func_80961E88(play); player->stateFlags1 |= PLAYER_STATE1_20; diff --git a/mm/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c b/mm/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c index 57dba44ff9..8c8d1c0270 100644 --- a/mm/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c +++ b/mm/src/overlays/actors/ovl_En_Syateki_Man/z_en_syateki_man.c @@ -12,6 +12,7 @@ #include "overlays/actors/ovl_En_Syateki_Dekunuts/z_en_syateki_dekunuts.h" #include "overlays/actors/ovl_En_Syateki_Okuta/z_en_syateki_okuta.h" #include "overlays/actors/ovl_En_Syateki_Wf/z_en_syateki_wf.h" +#include "2s2h/GameInteractor/GameInteractor.h" #define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_FRIENDLY | ACTOR_FLAG_10 | ACTOR_FLAG_CANT_LOCK_ON) @@ -1192,7 +1193,7 @@ void EnSyatekiMan_Swamp_AddBonusPoints(EnSyatekiMan* this, PlayState* play) { Player* player = GET_PLAYER(play); player->stateFlags1 |= PLAYER_STATE1_20; - if (!play->interfaceCtx.perfectLettersOn) { + if (GameInteractor_Should(VB_ARCHERY_ADD_BONUS_POINTS, !play->interfaceCtx.perfectLettersOn, this, &sBonusTimer)) { if (gSaveContext.timerCurTimes[TIMER_ID_MINIGAME_1] == SECONDS_TO_TIMER(0)) { gSaveContext.timerCurTimes[TIMER_ID_MINIGAME_1] = SECONDS_TO_TIMER(0); gSaveContext.timerStates[TIMER_ID_MINIGAME_1] = TIMER_STATE_STOP;