diff options
| author | Jordan Longstaff <JordanLongstaff@users.noreply.github.com> | 2026-07-24 12:28:36 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-24 16:28:36 +0000 |
| commit | 9d1e5d281100c2d3ab40541759041e2c912ae154 (patch) | |
| tree | ca617a5dcd4767e6d9548bb00930fbbdf5f4324a | |
| parent | 44909ab230d80a35067e1acf86ae60f2482edd44 (diff) | |
Hookify Lost Woods Ocarina game (#6976)
| -rw-r--r-- | soh/soh/Enhancements/Minigames/LostWoodsOcarinaGame.cpp | 105 | ||||
| -rw-r--r-- | soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h | 41 | ||||
| -rw-r--r-- | soh/src/code/code_800EC960.c | 56 | ||||
| -rw-r--r-- | soh/src/overlays/actors/ovl_En_Skj/z_en_skj.c | 24 |
4 files changed, 164 insertions, 62 deletions
diff --git a/soh/soh/Enhancements/Minigames/LostWoodsOcarinaGame.cpp b/soh/soh/Enhancements/Minigames/LostWoodsOcarinaGame.cpp new file mode 100644 index 000000000..18f926c3d --- /dev/null +++ b/soh/soh/Enhancements/Minigames/LostWoodsOcarinaGame.cpp @@ -0,0 +1,105 @@ +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" + +extern "C" { +#include "functions.h" +#include "variables.h" +#include "src/overlays/actors/ovl_En_Skj/z_en_skj.h" +extern PlayState* gPlayState; + +void EnSkj_WaitForPlayback(EnSkj* enSkj, PlayState* play); +} + +typedef enum { + OCARINA_GAME_STARTING_NOTES = 3, + OCARINA_GAME_ROUND_ONE_NOTES = 5, + OCARINA_GAME_ROUND_TWO_NOTES = 6, + OCARINA_GAME_ROUND_THREE_NOTES = 8, +} OcarinaGameDefaults; + +#define CVAR_CUSTOMIZE_NAME CVAR_ENHANCEMENT("CustomizeOcarinaGame") +#define CVAR_CUSTOMIZE_VALUE CVarGetInteger(CVAR_CUSTOMIZE_NAME, 0) + +#define CVAR_STARTING_NOTES_NAME CVAR_ENHANCEMENT("OcarinaGame.StartingNotes") +#define CVAR_STARTING_NOTES_VALUE CVarGetInteger(CVAR_STARTING_NOTES_NAME, OCARINA_GAME_STARTING_NOTES) + +#define CVAR_ROUND_ONE_NOTES_NAME CVAR_ENHANCEMENT("OcarinaGame.RoundOneNotes") +#define CVAR_ROUND_ONE_NOTES_VALUE CVarGetInteger(CVAR_ROUND_ONE_NOTES_NAME, OCARINA_GAME_ROUND_ONE_NOTES) + +#define CVAR_ROUND_TWO_NOTES_NAME CVAR_ENHANCEMENT("OcarinaGame.RoundTwoNotes") +#define CVAR_ROUND_TWO_NOTES_VALUE CVarGetInteger(CVAR_ROUND_TWO_NOTES_NAME, OCARINA_GAME_ROUND_TWO_NOTES) + +#define CVAR_ROUND_THREE_NOTES_NAME CVAR_ENHANCEMENT("OcarinaGame.RoundThreeNotes") +#define CVAR_ROUND_THREE_NOTES_VALUE CVarGetInteger(CVAR_ROUND_THREE_NOTES_NAME, OCARINA_GAME_ROUND_THREE_NOTES) + +#define CVAR_NOTE_SPEED_NAME CVAR_ENHANCEMENT("OcarinaGame.NoteSpeed") +#define CVAR_NOTE_SPEED_VALUE CVarGetInteger(CVAR_NOTE_SPEED_NAME, 1) + +#define CVAR_INFINITE_TIME_NAME CVAR_ENHANCEMENT("OcarinaUnlimitedFailTime") +#define CVAR_INFINITE_TIME_VALUE CVarGetInteger(CVAR_INFINITE_TIME_NAME, 0) + +#define CVAR_INSTANT_WIN_NAME CVAR_ENHANCEMENT("InstantOcarinaGameWin") +#define CVAR_INSTANT_WIN_VALUE CVarGetInteger(CVAR_INSTANT_WIN_NAME, 0) + +static void RegisterLostWoodsOcarinaGameRoundNotesSetup() { + COND_VB_SHOULD(VB_SET_LOST_WOODS_OCARINA_GAME_NOTES, CVAR_CUSTOMIZE_VALUE, { + s32 minigameRound = va_arg(args, s32); + u8* roundNotes = va_arg(args, u8*); + + switch (minigameRound) { + case 0: + *roundNotes = CVAR_ROUND_ONE_NOTES_VALUE; + break; + case 1: + *roundNotes = CVAR_ROUND_TWO_NOTES_VALUE; + break; + default: + *roundNotes = CVAR_ROUND_THREE_NOTES_VALUE; + break; + } + + *should = false; + }); +} + +static void RegisterLostWoodsOcarinaGameStartingNotesSetup() { + COND_VB_SHOULD(VB_SET_LOST_WOODS_OCARINA_GAME_STARTING_NOTES, + CVAR_CUSTOMIZE_VALUE && (CVAR_STARTING_NOTES_VALUE != OCARINA_GAME_STARTING_NOTES), { + for (u8 i = 0; i < CVAR_STARTING_NOTES_VALUE; i++) { + AudioOcarina_MemoryGameNextNote(); + } + *should = false; + }); +} + +static void RegisterLostWoodsOcarinaGameModifyNoteSpeed() { + COND_VB_SHOULD(VB_MODIFY_LOST_WOODS_OCARINA_GAME_NOTE_SPEED, CVAR_CUSTOMIZE_VALUE && (CVAR_NOTE_SPEED_VALUE != 1), { + s32 appendPos = va_arg(args, s32); + sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][appendPos].length /= CVAR_NOTE_SPEED_VALUE; + }); +} + +static void RegisterLostWoodsOcarinaGameInfiniteTime() { + COND_VB_SHOULD(VB_LOST_WOODS_OCARINA_GAME_TIMER_TICK, CVAR_CUSTOMIZE_VALUE && CVAR_INFINITE_TIME_VALUE, + { *should = false; }); +} + +static void RegisterLostWoodsOcarinaGameInstantWin() { + COND_VB_SHOULD(VB_PLAY_LOST_WOODS_OCARINA_GAME, CVAR_CUSTOMIZE_VALUE && CVAR_INSTANT_WIN_VALUE, { + EnSkj* enSkj = va_arg(args, EnSkj*); + gPlayState->msgCtx.ocarinaMode = OCARINA_MODE_0F; + enSkj->multiuseTimer = 160; + enSkj->actionFunc = EnSkj_WaitForPlayback; + *should = false; + }); +} + +static RegisterShipInitFunc initFunc_Notes(RegisterLostWoodsOcarinaGameRoundNotesSetup, { CVAR_CUSTOMIZE_NAME }); +static RegisterShipInitFunc initFunc_StartingNotes(RegisterLostWoodsOcarinaGameStartingNotesSetup, + { CVAR_CUSTOMIZE_NAME, CVAR_STARTING_NOTES_NAME }); +static RegisterShipInitFunc initFunc_ModifyTime(RegisterLostWoodsOcarinaGameModifyNoteSpeed, + { CVAR_CUSTOMIZE_NAME, CVAR_NOTE_SPEED_NAME }); +static RegisterShipInitFunc initFunc_InfiniteTime(RegisterLostWoodsOcarinaGameInfiniteTime, + { CVAR_CUSTOMIZE_NAME, CVAR_INFINITE_TIME_NAME }); +static RegisterShipInitFunc initFunc_InstantWin(RegisterLostWoodsOcarinaGameInstantWin, + { CVAR_CUSTOMIZE_NAME, CVAR_INSTANT_WIN_NAME });
\ No newline at end of file diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index ceeb4068c..58c60ba67 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -1557,6 +1557,14 @@ typedef enum { // true // ``` // #### `args` + // - None + VB_LOST_WOODS_OCARINA_GAME_TIMER_TICK, + + // #### `result` + // ```c + // true + // ``` + // #### `args` // - `*EnMs` VB_MAGIC_BEAN_SALESMAN_TAKE_MONEY, @@ -1602,6 +1610,14 @@ typedef enum { // #### `result` // ```c + // false + // ``` + // #### `args` + // - `s32` (note append position) + VB_MODIFY_LOST_WOODS_OCARINA_GAME_NOTE_SPEED, + + // #### `result` + // ```c // this->interactInfo.talkState == NPC_TALK_STATE_ACTION // ``` // #### `args` @@ -1938,6 +1954,14 @@ typedef enum { // true // ``` // #### `args` + // - `*EnSkj` + VB_PLAY_LOST_WOODS_OCARINA_GAME, + + // #### `result` + // ```c + // true + // ``` + // #### `args` // - None VB_PLAY_MINUET_OF_FOREST_CS, @@ -2418,6 +2442,23 @@ typedef enum { // true // ``` // #### `args` + // - `s32` (round number, zero-based) + // - `*u8` (note end position) + VB_SET_LOST_WOODS_OCARINA_GAME_NOTES, + + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - None + VB_SET_LOST_WOODS_OCARINA_GAME_STARTING_NOTES, + + // #### `result` + // ```c + // true + // ``` + // #### `args` // - `*s32` (ammo count) VB_SET_SHOOTING_GALLERY_AMMO, diff --git a/soh/src/code/code_800EC960.c b/soh/src/code/code_800EC960.c index 402e5c822..d1ec266d6 100644 --- a/soh/src/code/code_800EC960.c +++ b/soh/src/code/code_800EC960.c @@ -2403,35 +2403,16 @@ void AudioOcarina_RecordSong(void) { void AudioOcarina_MemoryGameInit(u8 minigameRound) { u8 i; - // #region SOH [Enhancement] - if (CVarGetInteger(CVAR_ENHANCEMENT("CustomizeOcarinaGame"), 0)) { - u8 startingNotes = 3; - u8 roundOneCount = CVarGetInteger(CVAR_ENHANCEMENT("OcarinaGame.RoundOneNotes"), 5); - u8 roundTwoCount = CVarGetInteger(CVAR_ENHANCEMENT("OcarinaGame.RoundTwoNotes"), 6); - u8 roundThreeCount = CVarGetInteger(CVAR_ENHANCEMENT("OcarinaGame.RoundThreeNotes"), 8); - u8 modMinigameNoteCnts[] = { roundOneCount, roundTwoCount, roundThreeCount }; - - startingNotes = CVarGetInteger(CVAR_ENHANCEMENT("OcarinaGame.StartingNotes"), 3); - - if (minigameRound > 2) { - minigameRound = 2; - } - - sOcaMemoryGameAppendPos = 0; - sOcaMemoryGameEndPos = modMinigameNoteCnts[minigameRound]; - - for (i = 0; i < startingNotes; i++) { - AudioOcarina_MemoryGameNextNote(); - } - // #endregion - } else { - if (minigameRound > 2) { - minigameRound = 2; - } + if (minigameRound > 2) { + minigameRound = 2; + } - sOcaMemoryGameAppendPos = 0; + sOcaMemoryGameAppendPos = 0; + if (GameInteractor_Should(VB_SET_LOST_WOODS_OCARINA_GAME_NOTES, true, minigameRound, &sOcaMemoryGameEndPos)) { sOcaMemoryGameEndPos = sOcaMemoryGameNumNotes[minigameRound]; + } + if (GameInteractor_Should(VB_SET_LOST_WOODS_OCARINA_GAME_STARTING_NOTES, true)) { for (i = 0; i < 3; i++) { AudioOcarina_MemoryGameNextNote(); } @@ -2453,24 +2434,13 @@ s32 AudioOcarina_MemoryGameNextNote(void) { randomPitch = sButtonToPitchMap[(randomButtonIndex + 1) % 5]; } - // #region SOH [Enhancement] - if (CVarGetInteger(CVAR_ENHANCEMENT("CustomizeOcarinaGame"), 0)) { - int noteSpeed = 0x2D; - noteSpeed = noteSpeed / CVarGetInteger(CVAR_ENHANCEMENT("OcarinaGame.NoteSpeed"), 1); + sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].pitch = randomPitch; + sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].length = 0x2D; + sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].volume = 0x50; + sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].vibrato = 0; + sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].bend = 0; - sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].pitch = randomPitch; - sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].length = noteSpeed; - sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].volume = 0x50; - sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].vibrato = 0; - sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].bend = 0; - // #endregion - } else { - sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].pitch = randomPitch; - sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].length = 0x2D; - sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].volume = 0x50; - sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].vibrato = 0; - sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcaMemoryGameAppendPos].bend = 0; - } + GameInteractor_Should(VB_MODIFY_LOST_WOODS_OCARINA_GAME_NOTE_SPEED, false, sOcaMemoryGameAppendPos); sOcaMemoryGameAppendPos++; diff --git a/soh/src/overlays/actors/ovl_En_Skj/z_en_skj.c b/soh/src/overlays/actors/ovl_En_Skj/z_en_skj.c index 8a0e41ec4..507bdfdac 100644 --- a/soh/src/overlays/actors/ovl_En_Skj/z_en_skj.c +++ b/soh/src/overlays/actors/ovl_En_Skj/z_en_skj.c @@ -1414,21 +1414,12 @@ void EnSkj_StartOcarinaMinigame(EnSkj* this, PlayState* play) { EnSkj_TurnPlayer(this, player); - if (dialogState == TEXT_STATE_CLOSING) { - // #region SOH [Enhancement] - if (CVarGetInteger(CVAR_ENHANCEMENT("InstantOcarinaGameWin"), 0) && - CVarGetInteger(CVAR_ENHANCEMENT("CustomizeOcarinaGame"), 0)) { - play->msgCtx.ocarinaMode = OCARINA_MODE_0F; + if (dialogState == TEXT_STATE_CLOSING && GameInteractor_Should(VB_PLAY_LOST_WOODS_OCARINA_GAME, true, this)) { + func_8010BD58(play, OCARINA_ACTION_MEMORY_GAME); + if (sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid != NULL) { + sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid->minigameState = SKULL_KID_OCARINA_PLAY_NOTES; this->songFailTimer = 160; this->actionFunc = EnSkj_WaitForPlayback; - // #endregion - } else { - func_8010BD58(play, OCARINA_ACTION_MEMORY_GAME); - if (sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid != NULL) { - sOcarinaMinigameSkullKids[SKULL_KID_LEFT].skullkid->minigameState = SKULL_KID_OCARINA_PLAY_NOTES; - this->songFailTimer = 160; - this->actionFunc = EnSkj_WaitForPlayback; - } } } } @@ -1478,12 +1469,7 @@ void EnSkj_WaitForPlayback(EnSkj* this, PlayState* play) { break; case MSGMODE_MEMORY_GAME_PLAYER_PLAYING: if (this->songFailTimer != 0) { - // #region SOH [Enhancement] - if (CVarGetInteger(CVAR_ENHANCEMENT("OcarinaUnlimitedFailTime"), 0) == 1 && - CVarGetInteger(CVAR_ENHANCEMENT("CustomizeOcarinaGame"), 0) == 1) { - // don't decrement timer - // #endregion - } else { + if (GameInteractor_Should(VB_LOST_WOODS_OCARINA_GAME_TIMER_TICK, true)) { this->songFailTimer--; } } else { // took too long, game failed |
