From 99194a75f1f77a101669aff860eb98255644393f Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Tue, 26 Dec 2023 13:30:49 -0500 Subject: [PATCH 01/12] docs: update `func_800FADF8` to `Audio_ResetActiveSequences` (#3471) --- soh/include/functions.h | 2 +- soh/include/variables.h | 2 +- soh/include/z64audio.h | 62 +++--- soh/soh/Enhancements/savestates.cpp | 6 +- soh/src/code/code_800EC960.c | 24 +-- soh/src/code/code_800F9280.c | 319 ++++++++++++++-------------- 6 files changed, 209 insertions(+), 206 deletions(-) diff --git a/soh/include/functions.h b/soh/include/functions.h index 037ba9d08..6f188a842 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -2171,7 +2171,7 @@ void func_800FA18C(u8, u8); void Audio_SetVolScale(u8 playerIdx, u8 scaleIdx, u8 targetVol, u8 volFadeTimer); void func_800FA3DC(void); u8 func_800FAD34(void); -void func_800FADF8(void); +void Audio_ResetActiveSequences(void); void func_800FAEB4(void); void GfxPrint_SetColor(GfxPrint* this, u32 r, u32 g, u32 b, u32 a); void GfxPrint_SetPosPx(GfxPrint* this, s32 x, s32 y); diff --git a/soh/include/variables.h b/soh/include/variables.h index 154ef578a..9fd6b7247 100644 --- a/soh/include/variables.h +++ b/soh/include/variables.h @@ -224,7 +224,7 @@ extern "C" extern u16 gAudioSfxSwapSource[10]; extern u16 gAudioSfxSwapTarget[10]; extern u8 gAudioSfxSwapMode[10]; - extern unk_D_8016E750 D_8016E750[4]; + extern ActiveSequence gActiveSeqs[4]; extern AudioContext gAudioContext; extern void(*D_801755D0)(void); diff --git a/soh/include/z64audio.h b/soh/include/z64audio.h index a7587ea2c..81775feba 100644 --- a/soh/include/z64audio.h +++ b/soh/include/z64audio.h @@ -970,43 +970,43 @@ typedef struct { } AudioContextInitSizes; // size = 0xC typedef struct { - /* 0x00 */ f32 unk_00; - /* 0x04 */ f32 unk_04; - /* 0x08 */ f32 unk_08; - /* 0x0C */ u16 unk_0C; - /* 0x10 */ f32 unk_10; - /* 0x14 */ f32 unk_14; - /* 0x18 */ f32 unk_18; - /* 0x1C */ u16 unk_1C; -} unk_50_s; // size = 0x20 + /* 0x00 */ f32 volCur; + /* 0x04 */ f32 volTarget; + /* 0x08 */ f32 volStep; + /* 0x0C */ u16 volTimer; + /* 0x10 */ f32 freqScaleCur; + /* 0x14 */ f32 freqScaleTarget; + /* 0x18 */ f32 freqScaleStep; + /* 0x1C */ u16 freqScaleTimer; +} ActiveSequenceChannelData; // size = 0x20 typedef struct { /* 0x000 */ f32 volCur; /* 0x004 */ f32 volTarget; - /* 0x008 */ f32 unk_08; - /* 0x00C */ u16 unk_0C; - /* 0x00E */ u8 volScales[0x4]; + /* 0x008 */ f32 volStep; + /* 0x00C */ u16 volTimer; + /* 0x00E */ u8 volScales[4]; /* 0x012 */ u8 volFadeTimer; /* 0x013 */ u8 fadeVolUpdate; - /* 0x014 */ u32 unk_14; - /* 0x018 */ u16 unk_18; - /* 0x01C */ f32 unk_1C; - /* 0x020 */ f32 unk_20; - /* 0x024 */ f32 unk_24; - /* 0x028 */ u16 unk_28; - /* 0x02C */ u32 unk_2C[8]; - /* 0x04C */ u8 unk_4C; - /* 0x04D */ u8 unk_4D; - /* 0x04E */ u8 unk_4E; - /* 0x050 */ unk_50_s unk_50[0x10]; - /* 0x250 */ u16 unk_250; - /* 0x252 */ u16 unk_252; - /* 0x254 */ u16 unk_254; - /* 0x256 */ u16 unk_256; - /* 0x258 */ u16 unk_258; - /* 0x25C */ u32 unk_25C; - /* 0x260 */ u8 unk_260; -} unk_D_8016E750; // size = 0x264 + /* 0x014 */ u32 tempoCmd; + /* 0x018 */ u16 tempoOriginal; // stores the original tempo before modifying it (to reset back to) + /* 0x01C */ f32 tempoCur; + /* 0x020 */ f32 tempoTarget; + /* 0x024 */ f32 tempoStep; + /* 0x028 */ u16 tempoTimer; + /* 0x02C */ u32 setupCmd[8]; // a queue of cmds to execute once the player is disabled + /* 0x04C */ u8 setupCmdTimer; // only execute setup commands when the timer is at 0. + /* 0x04D */ u8 setupCmdNum; // number of setup commands requested once the player is disabled + /* 0x04E */ u8 setupFadeTimer; + /* 0x050 */ ActiveSequenceChannelData channelData[16]; + /* 0x250 */ u16 freqScaleChannelFlags; + /* 0x252 */ u16 volChannelFlags; + /* 0x254 */ u16 seqId; // active seqId currently playing. Resets when sequence stops + /* 0x256 */ u16 prevSeqId; // last seqId played on a player. Does not reset when sequence stops + /* 0x258 */ u16 channelPortMask; + /* 0x25C */ u32 startSeqCmd; // This name comes from MM + /* 0x260 */ u8 isWaitingForFonts; // This name comes from MM +} ActiveSequence; // size = 0x264 typedef enum { /* 0 */ BANK_PLAYER, diff --git a/soh/soh/Enhancements/savestates.cpp b/soh/soh/Enhancements/savestates.cpp index c96df2154..54dd56860 100644 --- a/soh/soh/Enhancements/savestates.cpp +++ b/soh/soh/Enhancements/savestates.cpp @@ -64,7 +64,7 @@ typedef struct SaveStateInfo { int16_t blueWarpTimerCopy; /* From door_warp_1 */ SeqScriptState seqScriptStateCopy[4];// Unrelocated - unk_D_8016E750 unk_D_8016E750Copy[4]; + ActiveSequence gActiveSeqsCopy[4]; ActiveSound gActiveSoundsCopy[7][MAX_CHANNELS_PER_BANK]; uint8_t gSoundBankMutedCopy[7]; @@ -905,7 +905,7 @@ void SaveState::Save(void) { memcpy(&info->audioHeapCopy, gAudioHeap, AUDIO_HEAP_SIZE /* sizeof(gAudioContext) */); memcpy(&info->audioContextCopy, &gAudioContext, sizeof(AudioContext)); - memcpy(&info->unk_D_8016E750Copy, D_8016E750, sizeof(info->unk_D_8016E750Copy)); + memcpy(&info->gActiveSeqsCopy, gActiveSeqs, sizeof(info->gActiveSeqsCopy)); BackupSeqScriptState(); memcpy(info->gActiveSoundsCopy, gActiveSounds, sizeof(gActiveSounds)); @@ -944,7 +944,7 @@ void SaveState::Load(void) { memcpy(gAudioHeap, &info->audioHeapCopy, AUDIO_HEAP_SIZE); memcpy(&gAudioContext, &info->audioContextCopy, sizeof(AudioContext)); - memcpy(D_8016E750, &info->unk_D_8016E750Copy, sizeof(info->unk_D_8016E750Copy)); + memcpy(gActiveSeqs, &info->gActiveSeqsCopy, sizeof(info->gActiveSeqsCopy)); LoadSeqScriptState(); memcpy(&gSaveContext, &info->saveContextCopy, sizeof(gSaveContext)); diff --git a/soh/src/code/code_800EC960.c b/soh/src/code/code_800EC960.c index f2f72885d..27de9b2d5 100644 --- a/soh/src/code/code_800EC960.c +++ b/soh/src/code/code_800EC960.c @@ -4735,7 +4735,7 @@ void Audio_SetSequenceMode(u8 seqMode) { seqMode = SEQ_MODE_IGNORE; } - seqId = D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254; + seqId = gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId; if (seqId == NA_BGM_FIELD_LOGIC && func_800FA0B4(SEQ_PLAYER_BGM_SUB) == (NA_BGM_ENEMY | 0x800)) { seqMode = SEQ_MODE_IGNORE; @@ -4746,10 +4746,10 @@ void Audio_SetSequenceMode(u8 seqMode) { if (seqMode != (sPrevSeqMode & 0x7F)) { if (seqMode == SEQ_MODE_ENEMY) { // Start playing enemy bgm - if (D_8016E750[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol < 0) { - volumeFadeInTimer = -(D_8016E750[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol); + if (gActiveSeqs[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol < 0) { + volumeFadeInTimer = -(gActiveSeqs[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol); } else { - volumeFadeInTimer = D_8016E750[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol; + volumeFadeInTimer = gActiveSeqs[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol; } Audio_SetVolScale(SEQ_PLAYER_BGM_SUB, 3, sAudioEnemyVol, volumeFadeInTimer); @@ -4812,11 +4812,11 @@ void Audio_SetBgmEnemyVolume(f32 dist) { sAudioEnemyVol = ((350.0f - adjDist) * 127.0f) / 350.0f; Audio_SetVolScale(SEQ_PLAYER_BGM_SUB, 3, sAudioEnemyVol, 10); - if (D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254 != NA_BGM_NATURE_AMBIENCE) { + if (gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId != NA_BGM_NATURE_AMBIENCE) { Audio_SetVolScale(SEQ_PLAYER_BGM_MAIN, 3, (0x7F - sAudioEnemyVol), 10); } } - if (D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254 != NA_BGM_NATURE_AMBIENCE) { + if (gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId != NA_BGM_NATURE_AMBIENCE) { Audio_SplitBgmChannels(sAudioEnemyVol); } } @@ -4973,7 +4973,7 @@ void Audio_SetExtraFilter(u8 filter) { sAudioExtraFilter2 = filter; sAudioExtraFilter = filter; - if (D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254 == NA_BGM_NATURE_AMBIENCE) { + if (gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId == NA_BGM_NATURE_AMBIENCE) { for (i = 0; i < 16; i++) { t = i; // CHAN_UPD_SCRIPT_IO (seq player 0, all channels, slot 6) @@ -5097,7 +5097,7 @@ void Audio_SetNatureAmbienceChannelIO(u8 channelIdxRange, u8 port, u8 val) { u8 lastChannelIdx; u8 channelIdx; - if ((D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254 != NA_BGM_NATURE_AMBIENCE) && func_800FA11C(1, 0xF00000FF)) { + if ((gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId != NA_BGM_NATURE_AMBIENCE) && func_800FA11C(1, 0xF00000FF)) { sAudioNatureFailed = true; return; } @@ -5159,8 +5159,8 @@ void Audio_PlayNatureAmbienceSequence(u8 natureAmbienceId) { u8 port; u8 val; - if ((D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254 == NA_BGM_DISABLED) || - !(sSeqFlags[((u8)D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254) & 0xFF] & 0x80)) { + if ((gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId == NA_BGM_DISABLED) || + !(sSeqFlags[((u8)gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId) & 0xFF] & 0x80)) { Audio_StartNatureAmbienceSequence(sNatureAmbienceDataIO[natureAmbienceId].playerIO, sNatureAmbienceDataIO[natureAmbienceId].channelMask); @@ -5202,12 +5202,12 @@ void func_800F71BC(s32 arg0) { func_800F6C34(); func_800EE930(); Audio_ResetSfxChannelState(); - func_800FADF8(); + Audio_ResetActiveSequences(); Audio_ResetSounds(); } void func_800F7208(void) { - func_800FADF8(); + Audio_ResetActiveSequences(); Audio_QueueCmdS32(0xF2000000, 1); func_800F6C34(); Audio_ResetSfxChannelState(); diff --git a/soh/src/code/code_800F9280.c b/soh/src/code/code_800F9280.c index 4b519dc77..4c604ec26 100644 --- a/soh/src/code/code_800F9280.c +++ b/soh/src/code/code_800F9280.c @@ -12,9 +12,9 @@ typedef struct { #define GET_PLAYER_IDX(cmd) (cmd & 0xF000000) >> 24 Struct_8016E320 D_8016E320[4][5]; -u8 D_8016E348[4]; +u8 sNumSeqRequests[4]; u32 sAudioSeqCmds[0x100]; -unk_D_8016E750 D_8016E750[4]; +ActiveSequence gActiveSeqs[4]; u8 sSeqCmdWrPos = 0; u8 sSeqCmdRdPos = 0; @@ -51,33 +51,33 @@ void func_800F9280(u8 playerIdx, u8 seqId, u8 arg2, u16 fadeTimer) { (fadeTimer * (u16)gAudioContext.audioBufferParameters.updatesPerFrame) / 4); } - D_8016E750[playerIdx].unk_254 = seqId | (arg2 << 8); - D_8016E750[playerIdx].unk_256 = seqId | (arg2 << 8); + gActiveSeqs[playerIdx].seqId = seqId | (arg2 << 8); + gActiveSeqs[playerIdx].prevSeqId = seqId | (arg2 << 8); - if (D_8016E750[playerIdx].volCur != 1.0f) { - Audio_QueueCmdF32(0x41000000 | _SHIFTL(playerIdx, 16, 8), D_8016E750[playerIdx].volCur); + if (gActiveSeqs[playerIdx].volCur != 1.0f) { + Audio_QueueCmdF32(0x41000000 | _SHIFTL(playerIdx, 16, 8), gActiveSeqs[playerIdx].volCur); } - D_8016E750[playerIdx].unk_28 = 0; - D_8016E750[playerIdx].unk_18 = 0; - D_8016E750[playerIdx].unk_14 = 0; + gActiveSeqs[playerIdx].tempoTimer = 0; + gActiveSeqs[playerIdx].tempoOriginal = 0; + gActiveSeqs[playerIdx].tempoCmd = 0; for (i = 0; i < 0x10; i++) { - D_8016E750[playerIdx].unk_50[i].unk_00 = 1.0f; - D_8016E750[playerIdx].unk_50[i].unk_0C = 0; - D_8016E750[playerIdx].unk_50[i].unk_10 = 1.0f; - D_8016E750[playerIdx].unk_50[i].unk_1C = 0; + gActiveSeqs[playerIdx].channelData[i].volCur = 1.0f; + gActiveSeqs[playerIdx].channelData[i].volTimer = 0; + gActiveSeqs[playerIdx].channelData[i].freqScaleCur = 1.0f; + gActiveSeqs[playerIdx].channelData[i].freqScaleTimer = 0; } - D_8016E750[playerIdx].unk_250 = 0; - D_8016E750[playerIdx].unk_252 = 0; + gActiveSeqs[playerIdx].freqScaleChannelFlags = 0; + gActiveSeqs[playerIdx].volChannelFlags = 0; } } void func_800F9474(u8 playerIdx, u16 arg1) { Audio_QueueCmdS32(0x83000000 | ((u8)playerIdx << 16), (arg1 * (u16)gAudioContext.audioBufferParameters.updatesPerFrame) / 4); - D_8016E750[playerIdx].unk_254 = NA_BGM_DISABLED; + gActiveSeqs[playerIdx].seqId = NA_BGM_DISABLED; } typedef enum { @@ -133,7 +133,7 @@ void Audio_ProcessSeqCmd(u32 cmd) { seqId = cmd & 0xFF; seqArgs = (cmd & 0xFF00) >> 8; fadeTimer = (cmd & 0xFF0000) >> 13; - if ((D_8016E750[playerIdx].unk_260 == 0) && (seqArgs < 0x80)) { + if ((gActiveSeqs[playerIdx].isWaitingForFonts == 0) && (seqArgs < 0x80)) { func_800F9280(playerIdx, seqId, seqArgs, fadeTimer); } break; @@ -150,7 +150,7 @@ void Audio_ProcessSeqCmd(u32 cmd) { seqArgs = (cmd & 0xFF00) >> 8; fadeTimer = (cmd & 0xFF0000) >> 13; new_var = seqArgs; - for (i = 0; i < D_8016E348[playerIdx]; i++) { + for (i = 0; i < sNumSeqRequests[playerIdx]; i++) { if (D_8016E320[playerIdx][i].unk_0 == seqId) { if (i == 0) { func_800F9280(playerIdx, seqId, seqArgs, fadeTimer); @@ -159,18 +159,18 @@ void Audio_ProcessSeqCmd(u32 cmd) { } } - found = D_8016E348[playerIdx]; - for (i = 0; i < D_8016E348[playerIdx]; i++) { + found = sNumSeqRequests[playerIdx]; + for (i = 0; i < sNumSeqRequests[playerIdx]; i++) { if (D_8016E320[playerIdx][i].unk_1 <= new_var) { found = i; - i = D_8016E348[playerIdx]; // "break;" + i = sNumSeqRequests[playerIdx]; // "break;" } } - if (D_8016E348[playerIdx] < 5) { - D_8016E348[playerIdx]++; + if (sNumSeqRequests[playerIdx] < 5) { + sNumSeqRequests[playerIdx]++; } - for (i = D_8016E348[playerIdx] - 1; i != found; i--) { + for (i = sNumSeqRequests[playerIdx] - 1; i != found; i--) { D_8016E320[playerIdx][i].unk_1 = D_8016E320[playerIdx][i - 1].unk_1; D_8016E320[playerIdx][i].unk_0 = D_8016E320[playerIdx][i - 1].unk_0; } @@ -187,25 +187,25 @@ void Audio_ProcessSeqCmd(u32 cmd) { seqId = cmd & 0xFF; fadeTimer = (cmd & 0xFF0000) >> 13; - found = D_8016E348[playerIdx]; - for (i = 0; i < D_8016E348[playerIdx]; i++) { + found = sNumSeqRequests[playerIdx]; + for (i = 0; i < sNumSeqRequests[playerIdx]; i++) { if (D_8016E320[playerIdx][i].unk_0 == seqId) { found = i; - i = D_8016E348[playerIdx]; // "break;" + i = sNumSeqRequests[playerIdx]; // "break;" } } - if (found != D_8016E348[playerIdx]) { - for (i = found; i < D_8016E348[playerIdx] - 1; i++) { + if (found != sNumSeqRequests[playerIdx]) { + for (i = found; i < sNumSeqRequests[playerIdx] - 1; i++) { D_8016E320[playerIdx][i].unk_1 = D_8016E320[playerIdx][i + 1].unk_1; D_8016E320[playerIdx][i].unk_0 = D_8016E320[playerIdx][i + 1].unk_0; } - D_8016E348[playerIdx]--; + sNumSeqRequests[playerIdx]--; } if (found == 0) { func_800F9474(playerIdx, fadeTimer); - if (D_8016E348[playerIdx] != 0) { + if (sNumSeqRequests[playerIdx] != 0) { func_800F9280(playerIdx, D_8016E320[playerIdx][0].unk_0, D_8016E320[playerIdx][0].unk_1, fadeTimer); } } @@ -218,11 +218,11 @@ void Audio_ProcessSeqCmd(u32 cmd) { if (duration == 0) { duration++; } - D_8016E750[playerIdx].volTarget = (f32)val / 127.0f; - if (D_8016E750[playerIdx].volCur != D_8016E750[playerIdx].volTarget) { - D_8016E750[playerIdx].unk_08 = - (D_8016E750[playerIdx].volCur - D_8016E750[playerIdx].volTarget) / (f32)duration; - D_8016E750[playerIdx].unk_0C = duration; + gActiveSeqs[playerIdx].volTarget = (f32)val / 127.0f; + if (gActiveSeqs[playerIdx].volCur != gActiveSeqs[playerIdx].volTarget) { + gActiveSeqs[playerIdx].volStep = + (gActiveSeqs[playerIdx].volCur - gActiveSeqs[playerIdx].volTarget) / (f32)duration; + gActiveSeqs[playerIdx].volTimer = duration; } break; @@ -235,12 +235,12 @@ void Audio_ProcessSeqCmd(u32 cmd) { } freqScale = (f32)val / 1000.0f; for (i = 0; i < 16; i++) { - D_8016E750[playerIdx].unk_50[i].unk_14 = freqScale; - D_8016E750[playerIdx].unk_50[i].unk_1C = duration; - D_8016E750[playerIdx].unk_50[i].unk_18 = - (D_8016E750[playerIdx].unk_50[i].unk_10 - freqScale) / (f32)duration; + gActiveSeqs[playerIdx].channelData[i].freqScaleTarget = freqScale; + gActiveSeqs[playerIdx].channelData[i].freqScaleTimer = duration; + gActiveSeqs[playerIdx].channelData[i].freqScaleStep = + (gActiveSeqs[playerIdx].channelData[i].freqScaleCur - freqScale) / (f32)duration; } - D_8016E750[playerIdx].unk_250 = 0xFFFF; + gActiveSeqs[playerIdx].freqScaleChannelFlags = 0xFFFF; break; case 0xD: @@ -252,11 +252,11 @@ void Audio_ProcessSeqCmd(u32 cmd) { duration++; } freqScale = (f32)val / 1000.0f; - D_8016E750[playerIdx].unk_50[chanIdx].unk_14 = freqScale; - D_8016E750[playerIdx].unk_50[chanIdx].unk_18 = - (D_8016E750[playerIdx].unk_50[chanIdx].unk_10 - freqScale) / (f32)duration; - D_8016E750[playerIdx].unk_50[chanIdx].unk_1C = duration; - D_8016E750[playerIdx].unk_250 |= 1 << chanIdx; + gActiveSeqs[playerIdx].channelData[chanIdx].freqScaleTarget = freqScale; + gActiveSeqs[playerIdx].channelData[chanIdx].freqScaleStep = + (gActiveSeqs[playerIdx].channelData[chanIdx].freqScaleCur - freqScale) / (f32)duration; + gActiveSeqs[playerIdx].channelData[chanIdx].freqScaleTimer = duration; + gActiveSeqs[playerIdx].freqScaleChannelFlags |= 1 << chanIdx; break; case 0x6: @@ -267,13 +267,13 @@ void Audio_ProcessSeqCmd(u32 cmd) { if (duration == 0) { duration++; } - D_8016E750[playerIdx].unk_50[chanIdx].unk_04 = (f32)val / 127.0f; - if (D_8016E750[playerIdx].unk_50[chanIdx].unk_00 != D_8016E750[playerIdx].unk_50[chanIdx].unk_04) { - D_8016E750[playerIdx].unk_50[chanIdx].unk_08 = - (D_8016E750[playerIdx].unk_50[chanIdx].unk_00 - D_8016E750[playerIdx].unk_50[chanIdx].unk_04) / + gActiveSeqs[playerIdx].channelData[chanIdx].volTarget = (f32)val / 127.0f; + if (gActiveSeqs[playerIdx].channelData[chanIdx].volCur != gActiveSeqs[playerIdx].channelData[chanIdx].volTarget) { + gActiveSeqs[playerIdx].channelData[chanIdx].volStep = + (gActiveSeqs[playerIdx].channelData[chanIdx].volCur - gActiveSeqs[playerIdx].channelData[chanIdx].volTarget) / (f32)duration; - D_8016E750[playerIdx].unk_50[chanIdx].unk_0C = duration; - D_8016E750[playerIdx].unk_252 |= 1 << chanIdx; + gActiveSeqs[playerIdx].channelData[chanIdx].volTimer = duration; + gActiveSeqs[playerIdx].volChannelFlags |= 1 << chanIdx; } break; @@ -289,7 +289,7 @@ void Audio_ProcessSeqCmd(u32 cmd) { chanIdx = (cmd & 0xF00) >> 8; port = (cmd & 0xFF0000) >> 16; val = cmd & 0xFF; - if ((D_8016E750[playerIdx].unk_258 & (1 << chanIdx)) == 0) { + if ((gActiveSeqs[playerIdx].channelPortMask & (1 << chanIdx)) == 0) { Audio_QueueCmdS8(0x06000000 | _SHIFTL(playerIdx, 16, 8) | _SHIFTL(chanIdx, 8, 8) | _SHIFTL(port, 0, 8), val); } @@ -297,7 +297,7 @@ void Audio_ProcessSeqCmd(u32 cmd) { case 0x9: // set channel mask for command 0x8 - D_8016E750[playerIdx].unk_258 = cmd & 0xFFFF; + gActiveSeqs[playerIdx].channelPortMask = cmd & 0xFFFF; break; case 0xA: @@ -319,22 +319,22 @@ void Audio_ProcessSeqCmd(u32 cmd) { case 0xB: // update tempo - D_8016E750[playerIdx].unk_14 = cmd; + gActiveSeqs[playerIdx].tempoCmd = cmd; break; case 0xC: // start sequence with setup commands subOp = (cmd & 0xF00000) >> 20; if (subOp != 0xF) { - if (D_8016E750[playerIdx].unk_4D < 7) { - found = D_8016E750[playerIdx].unk_4D++; + if (gActiveSeqs[playerIdx].setupCmdNum < 7) { + found = gActiveSeqs[playerIdx].setupCmdNum++; if (found < 8) { - D_8016E750[playerIdx].unk_2C[found] = cmd; - D_8016E750[playerIdx].unk_4C = 2; + gActiveSeqs[playerIdx].setupCmd[found] = cmd; + gActiveSeqs[playerIdx].setupCmdTimer = 2; } } } else { - D_8016E750[playerIdx].unk_4D = 0; + gActiveSeqs[playerIdx].setupCmdNum = 0; } break; @@ -400,7 +400,7 @@ u16 func_800FA0B4(u8 playerIdx) { if (!gAudioContext.seqPlayers[playerIdx].enabled) { return NA_BGM_DISABLED; } - return D_8016E750[playerIdx].unk_254; + return gActiveSeqs[playerIdx].seqId; } s32 func_800FA11C(u32 arg0, u32 arg1) { @@ -416,17 +416,17 @@ s32 func_800FA11C(u32 arg0, u32 arg1) { } void func_800FA174(u8 playerIdx) { - D_8016E348[playerIdx] = 0; + sNumSeqRequests[playerIdx] = 0; } void func_800FA18C(u8 playerIdx, u8 arg1) { u8 i; - for (i = 0; i < D_8016E750[playerIdx].unk_4D; i++) { - u8 unkb = (D_8016E750[playerIdx].unk_2C[i] & 0xF00000) >> 20; + for (i = 0; i < gActiveSeqs[playerIdx].setupCmdNum; i++) { + u8 unkb = (gActiveSeqs[playerIdx].setupCmd[i] & 0xF00000) >> 20; if (unkb == arg1) { - D_8016E750[playerIdx].unk_2C[i] = 0xFF000000; + gActiveSeqs[playerIdx].setupCmd[i] = 0xFF000000; } } } @@ -435,14 +435,14 @@ void Audio_SetVolScale(u8 playerIdx, u8 scaleIdx, u8 targetVol, u8 volFadeTimer) f32 volScale; u8 i; - D_8016E750[playerIdx].volScales[scaleIdx] = targetVol & 0x7F; + gActiveSeqs[playerIdx].volScales[scaleIdx] = targetVol & 0x7F; if (volFadeTimer != 0) { - D_8016E750[playerIdx].fadeVolUpdate = 1; - D_8016E750[playerIdx].volFadeTimer = volFadeTimer; + gActiveSeqs[playerIdx].fadeVolUpdate = 1; + gActiveSeqs[playerIdx].volFadeTimer = volFadeTimer; } else { for (i = 0, volScale = 1.0f; i < 4; i++) { - volScale *= D_8016E750[playerIdx].volScales[i] / 127.0f; + volScale *= gActiveSeqs[playerIdx].volScales[i] / 127.0f; } Audio_SetVolScaleNow(playerIdx, volFadeTimer, volScale); @@ -468,41 +468,41 @@ void func_800FA3DC(void) { u8 k; for (playerIdx = 0; playerIdx < 4; playerIdx++) { - if (D_8016E750[playerIdx].unk_260 != 0) { + if (gActiveSeqs[playerIdx].isWaitingForFonts != 0) { switch (func_800E5E20(&dummy)) { case 1: case 2: case 3: case 4: - D_8016E750[playerIdx].unk_260 = 0; - Audio_ProcessSeqCmd(D_8016E750[playerIdx].unk_25C); + gActiveSeqs[playerIdx].isWaitingForFonts = 0; + Audio_ProcessSeqCmd(gActiveSeqs[playerIdx].startSeqCmd); break; } } - if (D_8016E750[playerIdx].fadeVolUpdate) { + if (gActiveSeqs[playerIdx].fadeVolUpdate) { phi_f0 = 1.0f; for (j = 0; j < 4; j++) { - phi_f0 *= (D_8016E750[playerIdx].volScales[j] / 127.0f); + phi_f0 *= (gActiveSeqs[playerIdx].volScales[j] / 127.0f); } - Audio_SeqCmd4(playerIdx, D_8016E750[playerIdx].volFadeTimer, (u8)(phi_f0 * 127.0f)); - D_8016E750[playerIdx].fadeVolUpdate = 0; + Audio_SeqCmd4(playerIdx, gActiveSeqs[playerIdx].volFadeTimer, (u8)(phi_f0 * 127.0f)); + gActiveSeqs[playerIdx].fadeVolUpdate = 0; } - if (D_8016E750[playerIdx].unk_0C != 0) { - D_8016E750[playerIdx].unk_0C--; + if (gActiveSeqs[playerIdx].volTimer != 0) { + gActiveSeqs[playerIdx].volTimer--; - if (D_8016E750[playerIdx].unk_0C != 0) { - D_8016E750[playerIdx].volCur = D_8016E750[playerIdx].volCur - D_8016E750[playerIdx].unk_08; + if (gActiveSeqs[playerIdx].volTimer != 0) { + gActiveSeqs[playerIdx].volCur = gActiveSeqs[playerIdx].volCur - gActiveSeqs[playerIdx].volStep; } else { - D_8016E750[playerIdx].volCur = D_8016E750[playerIdx].volTarget; + gActiveSeqs[playerIdx].volCur = gActiveSeqs[playerIdx].volTarget; } - Audio_QueueCmdF32(0x41000000 | _SHIFTL(playerIdx, 16, 8), D_8016E750[playerIdx].volCur); + Audio_QueueCmdF32(0x41000000 | _SHIFTL(playerIdx, 16, 8), gActiveSeqs[playerIdx].volCur); } - if (D_8016E750[playerIdx].unk_14 != 0) { - temp_a1 = D_8016E750[playerIdx].unk_14; + if (gActiveSeqs[playerIdx].tempoCmd != 0) { + temp_a1 = gActiveSeqs[playerIdx].tempoCmd; phi_t0 = (temp_a1 & 0xFF0000) >> 15; phi_a2 = temp_a1 & 0xFFF; if (phi_t0 == 0) { @@ -525,8 +525,8 @@ void func_800FA3DC(void) { phi_a2 = temp_lo * (phi_a2 / 100.0f); break; case 4: - if (D_8016E750[playerIdx].unk_18) { - phi_a2 = D_8016E750[playerIdx].unk_18; + if (gActiveSeqs[playerIdx].tempoOriginal) { + phi_a2 = gActiveSeqs[playerIdx].tempoOriginal; } else { phi_a2 = temp_lo; } @@ -537,71 +537,71 @@ void func_800FA3DC(void) { phi_a2 = 300; } - if (D_8016E750[playerIdx].unk_18 == 0) { - D_8016E750[playerIdx].unk_18 = temp_lo; + if (gActiveSeqs[playerIdx].tempoOriginal == 0) { + gActiveSeqs[playerIdx].tempoOriginal = temp_lo; } - D_8016E750[playerIdx].unk_20 = phi_a2; - D_8016E750[playerIdx].unk_1C = gAudioContext.seqPlayers[playerIdx].tempo / 0x30; - D_8016E750[playerIdx].unk_24 = (D_8016E750[playerIdx].unk_1C - D_8016E750[playerIdx].unk_20) / phi_t0; - D_8016E750[playerIdx].unk_28 = phi_t0; - D_8016E750[playerIdx].unk_14 = 0; + gActiveSeqs[playerIdx].tempoTarget = phi_a2; + gActiveSeqs[playerIdx].tempoCur = gAudioContext.seqPlayers[playerIdx].tempo / 0x30; + gActiveSeqs[playerIdx].tempoStep = (gActiveSeqs[playerIdx].tempoCur - gActiveSeqs[playerIdx].tempoTarget) / phi_t0; + gActiveSeqs[playerIdx].tempoTimer = phi_t0; + gActiveSeqs[playerIdx].tempoCmd = 0; } } - if (D_8016E750[playerIdx].unk_28 != 0) { - D_8016E750[playerIdx].unk_28--; - if (D_8016E750[playerIdx].unk_28 != 0) { - D_8016E750[playerIdx].unk_1C = D_8016E750[playerIdx].unk_1C - D_8016E750[playerIdx].unk_24; + if (gActiveSeqs[playerIdx].tempoTimer != 0) { + gActiveSeqs[playerIdx].tempoTimer--; + if (gActiveSeqs[playerIdx].tempoTimer != 0) { + gActiveSeqs[playerIdx].tempoCur = gActiveSeqs[playerIdx].tempoCur - gActiveSeqs[playerIdx].tempoStep; } else { - D_8016E750[playerIdx].unk_1C = D_8016E750[playerIdx].unk_20; + gActiveSeqs[playerIdx].tempoCur = gActiveSeqs[playerIdx].tempoTarget; } // set tempo - Audio_QueueCmdS32(0x47000000 | _SHIFTL(playerIdx, 16, 8), D_8016E750[playerIdx].unk_1C); + Audio_QueueCmdS32(0x47000000 | _SHIFTL(playerIdx, 16, 8), gActiveSeqs[playerIdx].tempoCur); } - if (D_8016E750[playerIdx].unk_252 != 0) { + if (gActiveSeqs[playerIdx].volChannelFlags != 0) { for (k = 0; k < 0x10; k++) { - if (D_8016E750[playerIdx].unk_50[k].unk_0C != 0) { - D_8016E750[playerIdx].unk_50[k].unk_0C--; - if (D_8016E750[playerIdx].unk_50[k].unk_0C != 0) { - D_8016E750[playerIdx].unk_50[k].unk_00 -= D_8016E750[playerIdx].unk_50[k].unk_08; + if (gActiveSeqs[playerIdx].channelData[k].volTimer != 0) { + gActiveSeqs[playerIdx].channelData[k].volTimer--; + if (gActiveSeqs[playerIdx].channelData[k].volTimer != 0) { + gActiveSeqs[playerIdx].channelData[k].volCur -= gActiveSeqs[playerIdx].channelData[k].volStep; } else { - D_8016E750[playerIdx].unk_50[k].unk_00 = D_8016E750[playerIdx].unk_50[k].unk_04; - D_8016E750[playerIdx].unk_252 ^= (1 << k); + gActiveSeqs[playerIdx].channelData[k].volCur = gActiveSeqs[playerIdx].channelData[k].volTarget; + gActiveSeqs[playerIdx].volChannelFlags ^= (1 << k); } // CHAN_UPD_VOL_SCALE (playerIdx = seq, k = chan) Audio_QueueCmdF32(0x01000000 | _SHIFTL(playerIdx, 16, 8) | _SHIFTL(k, 8, 8), - D_8016E750[playerIdx].unk_50[k].unk_00); + gActiveSeqs[playerIdx].channelData[k].volCur); } } } - if (D_8016E750[playerIdx].unk_250 != 0) { + if (gActiveSeqs[playerIdx].freqScaleChannelFlags != 0) { for (k = 0; k < 0x10; k++) { - if (D_8016E750[playerIdx].unk_50[k].unk_1C != 0) { - D_8016E750[playerIdx].unk_50[k].unk_1C--; - if (D_8016E750[playerIdx].unk_50[k].unk_1C != 0) { - D_8016E750[playerIdx].unk_50[k].unk_10 -= D_8016E750[playerIdx].unk_50[k].unk_18; + if (gActiveSeqs[playerIdx].channelData[k].freqScaleTimer != 0) { + gActiveSeqs[playerIdx].channelData[k].freqScaleTimer--; + if (gActiveSeqs[playerIdx].channelData[k].freqScaleTimer != 0) { + gActiveSeqs[playerIdx].channelData[k].freqScaleCur -= gActiveSeqs[playerIdx].channelData[k].freqScaleStep; } else { - D_8016E750[playerIdx].unk_50[k].unk_10 = D_8016E750[playerIdx].unk_50[k].unk_14; - D_8016E750[playerIdx].unk_250 ^= (1 << k); + gActiveSeqs[playerIdx].channelData[k].freqScaleCur = gActiveSeqs[playerIdx].channelData[k].freqScaleTarget; + gActiveSeqs[playerIdx].freqScaleChannelFlags ^= (1 << k); } // CHAN_UPD_FREQ_SCALE Audio_QueueCmdF32(0x04000000 | _SHIFTL(playerIdx, 16, 8) | _SHIFTL(k, 8, 8), - D_8016E750[playerIdx].unk_50[k].unk_10); + gActiveSeqs[playerIdx].channelData[k].freqScaleCur); } } } - if (D_8016E750[playerIdx].unk_4D != 0) { + if (gActiveSeqs[playerIdx].setupCmdNum != 0) { if (func_800FA11C(0xF0000000, 0xF0000000) == 0) { - D_8016E750[playerIdx].unk_4D = 0; + gActiveSeqs[playerIdx].setupCmdNum = 0; return; } - if (D_8016E750[playerIdx].unk_4C != 0) { - D_8016E750[playerIdx].unk_4C--; + if (gActiveSeqs[playerIdx].setupCmdTimer != 0) { + gActiveSeqs[playerIdx].setupCmdTimer--; continue; } @@ -609,28 +609,28 @@ void func_800FA3DC(void) { continue; } - for (j = 0; j < D_8016E750[playerIdx].unk_4D; j++) { - temp_a0 = (D_8016E750[playerIdx].unk_2C[j] & 0x00F00000) >> 20; - temp_s1 = (D_8016E750[playerIdx].unk_2C[j] & 0x000F0000) >> 16; - temp_s0_3 = (D_8016E750[playerIdx].unk_2C[j] & 0xFF00) >> 8; - temp_a3_3 = D_8016E750[playerIdx].unk_2C[j] & 0xFF; + for (j = 0; j < gActiveSeqs[playerIdx].setupCmdNum; j++) { + temp_a0 = (gActiveSeqs[playerIdx].setupCmd[j] & 0x00F00000) >> 20; + temp_s1 = (gActiveSeqs[playerIdx].setupCmd[j] & 0x000F0000) >> 16; + temp_s0_3 = (gActiveSeqs[playerIdx].setupCmd[j] & 0xFF00) >> 8; + temp_a3_3 = gActiveSeqs[playerIdx].setupCmd[j] & 0xFF; switch (temp_a0) { case 0: Audio_SetVolScale(temp_s1, 1, 0x7F, temp_a3_3); break; case 7: - if (D_8016E348[playerIdx] == temp_a3_3) { + if (sNumSeqRequests[playerIdx] == temp_a3_3) { Audio_SetVolScale(temp_s1, 1, 0x7F, temp_s0_3); } break; case 1: - Audio_SeqCmd3(playerIdx, D_8016E750[playerIdx].unk_254); + Audio_SeqCmd3(playerIdx, gActiveSeqs[playerIdx].seqId); break; case 2: - Audio_StartSeq(temp_s1, 1, D_8016E750[temp_s1].unk_254); - D_8016E750[temp_s1].fadeVolUpdate = 1; - D_8016E750[temp_s1].volScales[1] = 0x7F; + Audio_StartSeq(temp_s1, 1, gActiveSeqs[temp_s1].seqId); + gActiveSeqs[temp_s1].fadeVolUpdate = 1; + gActiveSeqs[temp_s1].volScales[1] = 0x7F; break; case 3: Audio_SeqCmdB30(temp_s1, temp_s0_3, temp_a3_3); @@ -639,13 +639,13 @@ void func_800FA3DC(void) { Audio_SeqCmdB40(temp_s1, temp_a3_3, 0); break; case 5: - temp_v1 = D_8016E750[playerIdx].unk_2C[j] & 0xFFFF; - Audio_StartSeq(temp_s1, D_8016E750[temp_s1].unk_4E, temp_v1); + temp_v1 = gActiveSeqs[playerIdx].setupCmd[j] & 0xFFFF; + Audio_StartSeq(temp_s1, gActiveSeqs[temp_s1].setupFadeTimer, temp_v1); Audio_SetVolScale(temp_s1, 1, 0x7F, 0); - D_8016E750[temp_s1].unk_4E = 0; + gActiveSeqs[temp_s1].setupFadeTimer = 0; break; case 6: - D_8016E750[playerIdx].unk_4E = temp_s0_3; + gActiveSeqs[playerIdx].setupFadeTimer = temp_s0_3; break; case 8: Audio_SetVolScale(temp_s1, temp_s0_3, 0x7F, temp_a3_3); @@ -662,7 +662,7 @@ void func_800FA3DC(void) { } break; case 9: - temp_v1 = D_8016E750[playerIdx].unk_2C[j] & 0xFFFF; + temp_v1 = gActiveSeqs[playerIdx].setupCmd[j] & 0xFFFF; Audio_SeqCmdA(temp_s1, temp_v1); break; case 10: @@ -671,7 +671,7 @@ void func_800FA3DC(void) { } } - D_8016E750[playerIdx].unk_4D = 0; + gActiveSeqs[playerIdx].setupCmdNum = 0; } } } @@ -695,26 +695,29 @@ u8 func_800FAD34(void) { return D_80133418; } -void func_800FADF8(void) { - u8 playerIdx, j; +void Audio_ResetActiveSequences(void) { + u8 seqPlayerIndex; + u8 scaleIndex; - for (playerIdx = 0; playerIdx < 4; playerIdx++) { - D_8016E348[playerIdx] = 0; - D_8016E750[playerIdx].unk_254 = NA_BGM_DISABLED; - D_8016E750[playerIdx].unk_256 = NA_BGM_DISABLED; - D_8016E750[playerIdx].unk_28 = 0; - D_8016E750[playerIdx].unk_18 = 0; - D_8016E750[playerIdx].unk_14 = 0; - D_8016E750[playerIdx].unk_258 = 0; - D_8016E750[playerIdx].unk_4D = 0; - D_8016E750[playerIdx].unk_4E = 0; - D_8016E750[playerIdx].unk_250 = 0; - D_8016E750[playerIdx].unk_252 = 0; - for (j = 0; j < 4; j++) { - D_8016E750[playerIdx].volScales[j] = 0x7F; + for (seqPlayerIndex = 0; seqPlayerIndex < 4; seqPlayerIndex++) { + sNumSeqRequests[seqPlayerIndex] = 0; + + gActiveSeqs[seqPlayerIndex].seqId = NA_BGM_DISABLED; + gActiveSeqs[seqPlayerIndex].prevSeqId = NA_BGM_DISABLED; + gActiveSeqs[seqPlayerIndex].tempoTimer = 0; + gActiveSeqs[seqPlayerIndex].tempoOriginal = 0; + gActiveSeqs[seqPlayerIndex].tempoCmd = 0; + gActiveSeqs[seqPlayerIndex].channelPortMask = 0; + gActiveSeqs[seqPlayerIndex].setupCmdNum = 0; + gActiveSeqs[seqPlayerIndex].setupFadeTimer = 0; + gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags = 0; + gActiveSeqs[seqPlayerIndex].volChannelFlags = 0; + for (scaleIndex = 0; scaleIndex < 4; scaleIndex++) { + gActiveSeqs[seqPlayerIndex].volScales[scaleIndex] = 0x7F; } - D_8016E750[playerIdx].volFadeTimer = 1; - D_8016E750[playerIdx].fadeVolUpdate = 1; + + gActiveSeqs[seqPlayerIndex].volFadeTimer = 1; + gActiveSeqs[seqPlayerIndex].fadeVolUpdate = true; } } @@ -722,12 +725,12 @@ void func_800FAEB4(void) { u8 playerIdx, j; for (playerIdx = 0; playerIdx < 4; playerIdx++) { - D_8016E750[playerIdx].volCur = 1.0f; - D_8016E750[playerIdx].unk_0C = 0; - D_8016E750[playerIdx].fadeVolUpdate = 0; + gActiveSeqs[playerIdx].volCur = 1.0f; + gActiveSeqs[playerIdx].volTimer = 0; + gActiveSeqs[playerIdx].fadeVolUpdate = 0; for (j = 0; j < 4; j++) { - D_8016E750[playerIdx].volScales[j] = 0x7F; + gActiveSeqs[playerIdx].volScales[j] = 0x7F; } } - func_800FADF8(); + Audio_ResetActiveSequences(); } From 6a7bcc4a5e0681d7086b9d747d9a4bda4bbae4b5 Mon Sep 17 00:00:00 2001 From: Adam Bird Date: Tue, 26 Dec 2023 17:13:48 -0500 Subject: [PATCH 02/12] add more commands to dl viewer (#3504) --- soh/soh/Enhancements/debugger/dlViewer.cpp | 243 +++++++++++++++++++-- 1 file changed, 224 insertions(+), 19 deletions(-) diff --git a/soh/soh/Enhancements/debugger/dlViewer.cpp b/soh/soh/Enhancements/debugger/dlViewer.cpp index 2fce8860a..9ed250615 100644 --- a/soh/soh/Enhancements/debugger/dlViewer.cpp +++ b/soh/soh/Enhancements/debugger/dlViewer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "dlViewer.h" @@ -18,15 +19,13 @@ extern "C" { #include "variables.h" #include "functions.h" #include "macros.h" -extern PlayState* gPlayState; - -char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize); } char searchString[64] = ""; -int displayListsSearchResultsCount; -char** displayListsSearchResults; -char* activeDisplayList = nullptr; +std::string activeDisplayList = ""; +std::vector displayListSearchResults; +int16_t searchDebounceFrames = -1; +bool doSearch = false; std::map cmdMap = { { G_SETPRIMCOLOR, "gsDPSetPrimColor" }, @@ -36,8 +35,63 @@ std::map cmdMap = { { G_SETINTENSITY, "gsDPSetGrayscaleColor" }, { G_LOADTLUT, "gsDPLoadTLUT" }, { G_ENDDL, "gsSPEndDisplayList" }, + { G_TEXTURE, "gsSPTexture" }, + { G_SETTIMG, "gsDPSetTextureImage" }, + { G_SETTIMG_OTR_HASH, "gsDPSetTextureImage" }, + { G_SETTIMG_OTR_FILEPATH, "gsDPSetTextureImage" }, + { G_RDPTILESYNC, "gsDPTileSync" }, + { G_SETTILE, "gsDPSetTile" }, + { G_RDPLOADSYNC, "gsDPLoadSync" }, + { G_LOADBLOCK, "gsDPLoadBlock" }, + { G_SETTILESIZE, "gsDPSetTileSize" }, + { G_DL, "gsSPDisplayList" }, + { G_DL_OTR_FILEPATH, "gsSPDisplayList" }, + { G_DL_OTR_HASH, "gsSPDisplayList" }, + { G_MTX, "gsSPMatrix" }, + { G_MTX_OTR, "gsSPMatrix" }, + { G_VTX, "gsSPVertex" }, + { G_VTX_OTR_FILEPATH, "gsSPVertex" }, + { G_VTX_OTR_HASH, "gsSPVertex" }, + { G_GEOMETRYMODE, "gsSPSetGeometryMode" }, + { G_SETOTHERMODE_H, "gsSPSetOtherMode_H" }, + { G_SETOTHERMODE_L, "gsSPSetOtherMode_L" }, + { G_TRI1, "gsSP1Triangle" }, + { G_TRI1_OTR, "gsSP1Triangle" }, + { G_TRI2, "gsSP2Triangles" }, + { G_SETCOMBINE, "gsDPSetCombineLERP" }, + { G_CULLDL, "gsSPCullDisplayList" }, + { G_NOOP, "gsDPNoOp" }, + { G_SPNOOP, "gsSPNoOp" }, + { G_MARKER, "LUS Custom Marker" }, }; +void PerformDisplayListSearch() { + auto result = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles("*" + std::string(searchString) + "*DL*"); + + std::regex dlSearch(".*((DL)|(DL_.*))$"); + + displayListSearchResults.clear(); + + // Filter the file results even further as StormLib can only use wildcard searching + for (size_t i = 0; i < result->size(); i++) { + std::string val = result->at(i); + if (std::regex_search(val.c_str(), dlSearch)) { + displayListSearchResults.push_back(val); + } + } + + // Sort the final list + std::sort(displayListSearchResults.begin(), displayListSearchResults.end(), [](const std::string& a, const std::string& b) { + return std::lexicographical_compare( + a.begin(), a.end(), + b.begin(), b.end(), + [](char c1, char c2) { + return std::tolower(c1) < std::tolower(c2); + } + ); + }); +} + void DLViewerWindow::DrawElement() { ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Display List Viewer", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) { @@ -45,22 +99,50 @@ void DLViewerWindow::DrawElement() { return; } + ImGui::Text("%d", searchDebounceFrames); + + // Debounce the search field as listing otr files is expensive if (ImGui::InputText("Search Display Lists", searchString, ARRAY_COUNT(searchString))) { - displayListsSearchResults = ResourceMgr_ListFiles(("*" + std::string(searchString) + "*DL").c_str(), &displayListsSearchResultsCount); + doSearch = true; + searchDebounceFrames = 30; } - if (ImGui::BeginCombo("Active Display List", activeDisplayList)) { - for (int i = 0; i < displayListsSearchResultsCount; i++) { - if (ImGui::Selectable(displayListsSearchResults[i])) { - activeDisplayList = displayListsSearchResults[i]; + if (doSearch) { + if (searchDebounceFrames == 0) { + doSearch = false; + PerformDisplayListSearch(); + } + + searchDebounceFrames--; + } + + if (ImGui::BeginCombo("Active Display List", activeDisplayList.c_str())) { + for (size_t i = 0; i < displayListSearchResults.size(); i++) { + if (ImGui::Selectable(displayListSearchResults[i].c_str())) { + activeDisplayList = displayListSearchResults[i]; break; } } ImGui::EndCombo(); } - if (activeDisplayList != nullptr) { + + if (activeDisplayList == "") { + ImGui::End(); + return; + } + + try { auto res = std::static_pointer_cast(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(activeDisplayList)); - for (int i = 0; i < res->Instructions.size(); i++) { + + if (res->GetInitData()->Type != LUS::ResourceType::DisplayList) { + ImGui::Text("Resource type is not a Display List. Please choose another."); + ImGui::End(); + return; + } + + ImGui::Text("Total Instruction Size: %lu", res->Instructions.size()); + + for (size_t i = 0; i < res->Instructions.size(); i++) { std::string id = "##CMD" + std::to_string(i); Gfx* gfx = (Gfx*)&res->Instructions[i]; int cmd = gfx->words.w0 >> 24; @@ -70,10 +152,11 @@ void DLViewerWindow::DrawElement() { ImGui::BeginGroup(); ImGui::PushItemWidth(25.0f); - ImGui::Text("%d", i); + ImGui::Text("%lu", i); ImGui::PopItemWidth(); ImGui::SameLine(); - ImGui::PushItemWidth(150.0f); + ImGui::PushItemWidth(175.0f); + if (ImGui::BeginCombo(("CMD" + id).c_str(), cmdLabel.c_str())) { if (ImGui::Selectable("gsDPSetPrimColor") && cmd != G_SETPRIMCOLOR) { *gfx = gsDPSetPrimColor(0, 0, 0, 0, 0, 255); @@ -92,8 +175,10 @@ void DLViewerWindow::DrawElement() { } ImGui::EndCombo(); } + ImGui::PopItemWidth(); - if (gfx->words.w0 >> 24 == G_SETPRIMCOLOR || gfx->words.w0 >> 24 == G_SETINTENSITY || gfx->words.w0 >> 24 == G_SETENVCOLOR) { + + if (cmd == G_SETPRIMCOLOR || cmd == G_SETINTENSITY || cmd == G_SETENVCOLOR) { uint8_t r = _SHIFTR(gfx->words.w1, 24, 8); uint8_t g = _SHIFTR(gfx->words.w1, 16, 8); uint8_t b = _SHIFTR(gfx->words.w1, 8, 8); @@ -117,21 +202,141 @@ void DLViewerWindow::DrawElement() { } ImGui::PopItemWidth(); } - if (gfx->words.w0 >> 24 == G_RDPPIPESYNC) { + if (cmd == G_RDPPIPESYNC) { } - if (gfx->words.w0 >> 24 == G_SETGRAYSCALE) { + if (cmd == G_SETGRAYSCALE) { bool* state = (bool*)&gfx->words.w1; ImGui::SameLine(); if (ImGui::Checkbox(("state" + id).c_str(), state)) { // } } + if (cmd == G_SETTILE) { + ImGui::SameLine(); + ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3)); + ImGui::SameLine(); + ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2)); + ImGui::SameLine(); + ImGui::Text("LINE: %u", _SHIFTR(gfx->words.w0, 9, 9)); + ImGui::SameLine(); + ImGui::Text("TMEM: %u", _SHIFTR(gfx->words.w0, 0, 9)); + ImGui::SameLine(); + ImGui::Text("TILE: %u", _SHIFTR(gfx->words.w1, 24, 3)); + ImGui::SameLine(); + ImGui::Text("PAL: %u", _SHIFTR(gfx->words.w1, 20, 4)); + ImGui::SameLine(); + ImGui::Text("CMT: %u", _SHIFTR(gfx->words.w1, 18, 2)); + ImGui::SameLine(); + ImGui::Text("MASKT: %u", _SHIFTR(gfx->words.w1, 14, 4)); + ImGui::SameLine(); + ImGui::Text("SHIFT: %u", _SHIFTR(gfx->words.w1, 10, 4)); + ImGui::SameLine(); + ImGui::Text("CMS: %u", _SHIFTR(gfx->words.w1, 8, 2)); + ImGui::SameLine(); + ImGui::Text("MASKS: %u", _SHIFTR(gfx->words.w1, 4, 4)); + ImGui::SameLine(); + ImGui::Text("SHIFTS: %u", _SHIFTR(gfx->words.w1, 0, 4)); + } + if (cmd == G_SETTIMG) { + ImGui::SameLine(); + ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3)); + ImGui::SameLine(); + ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2)); + ImGui::SameLine(); + ImGui::Text("WIDTH: %u", _SHIFTR(gfx->words.w0, 0, 10)); + ImGui::SameLine(); + } + if (cmd == G_SETTIMG_OTR_HASH) { + gfx++; + uint64_t hash = ((uint64_t)gfx->words.w0 << 32) + (uint64_t)gfx->words.w1; + const char* fileName = ResourceGetNameByCrc(hash); + + gfx--; + ImGui::SameLine(); + ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3)); + ImGui::SameLine(); + ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2)); + ImGui::SameLine(); + ImGui::Text("WIDTH: %u", _SHIFTR(gfx->words.w0, 0, 10)); + ImGui::SameLine(); + ImGui::Text("Texture Name: %s", fileName); + } + if (cmd == G_SETTIMG_OTR_FILEPATH) { + char* fileName = (char*)gfx->words.w1; + gfx++; + ImGui::SameLine(); + ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3)); + ImGui::SameLine(); + ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2)); + ImGui::SameLine(); + ImGui::Text("WIDTH: %u", _SHIFTR(gfx->words.w0, 0, 10)); + ImGui::SameLine(); + ImGui::Text("Texture Name: %s", fileName); + } + if (cmd == G_VTX) { + ImGui::SameLine(); + ImGui::Text("Num VTX: %u", _SHIFTR(gfx->words.w0, 12, 8)); + ImGui::SameLine(); + ImGui::Text("Offset: %u", _SHIFTR(gfx->words.w0, 1, 7) - _SHIFTR(gfx->words.w0, 12, 8)); + } + if (cmd == G_VTX_OTR_HASH) { + gfx++; + uint64_t hash = ((uint64_t)gfx->words.w0 << 32) + (uint64_t)gfx->words.w1; + const char* fileName = ResourceGetNameByCrc(hash); + + gfx--; + ImGui::SameLine(); + ImGui::Text("Num VTX: %u", _SHIFTR(gfx->words.w0, 12, 8)); + ImGui::SameLine(); + ImGui::Text("Offset: %u", _SHIFTR(gfx->words.w0, 1, 7) - _SHIFTR(gfx->words.w0, 12, 8)); + + ImGui::SameLine(); + ImGui::Text("Vertex Name: %s", fileName); + } + if (cmd == G_VTX_OTR_FILEPATH) { + char* fileName = (char*)gfx->words.w1; + + gfx++; + ImGui::SameLine(); + ImGui::Text("Num VTX: %u", _SHIFTR(gfx->words.w0, 12, 8)); + ImGui::SameLine(); + ImGui::Text("Offset: %u", _SHIFTR(gfx->words.w0, 1, 7) - _SHIFTR(gfx->words.w0, 12, 8)); + + ImGui::SameLine(); + ImGui::Text("Vertex Name: %s", fileName); + } + if (cmd == G_DL) { + } + if (cmd == G_DL_OTR_HASH) { + gfx++; + uint64_t hash = ((uint64_t)gfx->words.w0 << 32) + (uint64_t)gfx->words.w1; + const char* fileName = ResourceGetNameByCrc(hash); + ImGui::SameLine(); + ImGui::Text("DL Name: %s", fileName); + } + if (cmd == G_DL_OTR_FILEPATH) { + char* fileName = (char*)gfx->words.w1; + ImGui::SameLine(); + ImGui::Text("DL Name: %s", fileName); + } + + // Skip second half of instructions that are over 128-bit wide + if (cmd == G_SETTIMG_OTR_HASH || cmd == G_DL_OTR_HASH || cmd == G_VTX_OTR_HASH || + cmd == G_BRANCH_Z_OTR || cmd == G_MARKER || cmd == G_MTX_OTR) { + i++; + ImGui::Text("%lu - Reserved - Second half of %s", i, cmdLabel.c_str()); + } ImGui::EndGroup(); } + } catch (const std::exception& e) { + ImGui::Text("Error displaying DL instructions."); + ImGui::End(); + return; } + ImGui::End(); } void DLViewerWindow::InitElement() { - displayListsSearchResults = ResourceMgr_ListFiles("*DL", &displayListsSearchResultsCount); + PerformDisplayListSearch(); } From 70e10179238f60fb5b8e15fb64d75cf43b21d9c7 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Wed, 27 Dec 2023 00:08:37 +0000 Subject: [PATCH 03/12] Add frame advance option to developer tools (#3435) --- soh/soh/SohMenuBar.cpp | 20 ++++++++++++++++++++ soh/src/code/z_frame_advance.c | 3 ++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 904a57558..614a6b690 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -1475,6 +1475,26 @@ void DrawDeveloperToolsMenu() { UIWidgets::Tooltip("Optimized debug warp screen, with the added ability to chose entrances and time of day"); UIWidgets::PaddedEnhancementCheckbox("Debug Warp Screen Translation", "gDebugWarpScreenTranslation", true, false, false, "", UIWidgets::CheckboxGraphics::Cross, true); UIWidgets::Tooltip("Translate the Debug Warp Screen based on the game language"); + if (gPlayState != NULL) { + UIWidgets::PaddedSeparator(); + ImGui::Checkbox("Frame Advance##frameAdvance", (bool*)&gPlayState->frameAdvCtx.enabled); + if (gPlayState->frameAdvCtx.enabled) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0,0)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); + if (ImGui::Button("Advance 1", ImVec2(ImGui::GetContentRegionAvail().x / 2.0f, 0.0f))) { + CVarSetInteger("gFrameAdvance", 1); + } + ImGui::SameLine(); + ImGui::Button("Advance (Hold)"); + if (ImGui::IsItemActive()) { + CVarSetInteger("gFrameAdvance", 1); + } + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(1); + } + } UIWidgets::PaddedSeparator(); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0,0)); diff --git a/soh/src/code/z_frame_advance.c b/soh/src/code/z_frame_advance.c index 930db59b3..e48bd0c35 100644 --- a/soh/src/code/z_frame_advance.c +++ b/soh/src/code/z_frame_advance.c @@ -18,9 +18,10 @@ s32 FrameAdvance_Update(FrameAdvanceContext* frameAdvCtx, Input* input) { frameAdvCtx->enabled = !frameAdvCtx->enabled; } - if (!frameAdvCtx->enabled || (CHECK_BTN_ALL(input->cur.button, BTN_Z) && + if (!frameAdvCtx->enabled || CVarGetInteger("gFrameAdvance", 0) || (CHECK_BTN_ALL(input->cur.button, BTN_Z) && (CHECK_BTN_ALL(input->press.button, BTN_R) || (CHECK_BTN_ALL(input->cur.button, BTN_R) && (++frameAdvCtx->timer >= 9))))) { + CVarClear("gFrameAdvance"); frameAdvCtx->timer = 0; return true; } From e8096a2d9467c26b73915bf1c05f1427f9ebfa3f Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Wed, 27 Dec 2023 01:09:04 +0100 Subject: [PATCH 04/12] Better actor viewer (#3544) * Update actorViewer.cpp * Add more actors * Add a search function * Update actorViewer.cpp * Add advanced mode for params --- soh/soh/ActorDB.cpp | 8 +- soh/soh/ActorDB.h | 1 + soh/soh/Enhancements/debugger/actorViewer.cpp | 835 +++++++++++++++++- 3 files changed, 840 insertions(+), 4 deletions(-) diff --git a/soh/soh/ActorDB.cpp b/soh/soh/ActorDB.cpp index a66048b32..ea8450ac4 100644 --- a/soh/soh/ActorDB.cpp +++ b/soh/soh/ActorDB.cpp @@ -74,7 +74,7 @@ static std::unordered_map actorDescriptions = { { ACTOR_EN_BUBBLE, "Shabom" }, { ACTOR_DOOR_SHUTTER, "Shutter Door" }, { ACTOR_EN_DODOJR, "Baby Dodongo" }, - { ACTOR_EN_BDFIRE, "Empty" }, + { ACTOR_EN_BDFIRE, "King Dodongo's Fire Breath" }, { ACTOR_EN_BOOM, "Boomerang" }, { ACTOR_EN_TORCH2, "Dark Link" }, { ACTOR_EN_BILI, "Biri" }, @@ -132,7 +132,7 @@ static std::unordered_map actorDescriptions = { { ACTOR_BG_TOKI_HIKARI, "Windows (Temple of Time)" }, { ACTOR_EN_YUKABYUN, "Flying Floor Tile" }, { ACTOR_BG_TOKI_SWD, "Master Sword" }, - { ACTOR_EN_FHG_FIRE, "Empty" }, + { ACTOR_EN_FHG_FIRE, "Phantom Ganon's Lighting Attack" }, { ACTOR_BG_MJIN, "Warp Song Pad" }, { ACTOR_BG_HIDAN_KOUSI, "Sliding Metal Gate" }, { ACTOR_DOOR_TOKI, "Door of Time Collision" }, @@ -548,6 +548,10 @@ int ActorDB::RetrieveId(const std::string& name) { return entry->second; } +int ActorDB::GetEntryCount() { + return db.size(); +} + ActorDB::Entry::Entry() { entry.name = nullptr; entry.desc = nullptr; diff --git a/soh/soh/ActorDB.h b/soh/soh/ActorDB.h index afb033a2f..8bcbb3f6a 100644 --- a/soh/soh/ActorDB.h +++ b/soh/soh/ActorDB.h @@ -64,6 +64,7 @@ public: static void AddBuiltInCustomActors(); + int GetEntryCount(); private: Entry& AddEntry(const std::string& name, const std::string& desc, size_t index); Entry& AddEntry(const std::string& name, const std::string& desc, const ActorInit& init); diff --git a/soh/soh/Enhancements/debugger/actorViewer.cpp b/soh/soh/Enhancements/debugger/actorViewer.cpp index f83449efe..e2b45a419 100644 --- a/soh/soh/Enhancements/debugger/actorViewer.cpp +++ b/soh/soh/Enhancements/debugger/actorViewer.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ extern PlayState* gPlayState; #include "textures/icon_item_24_static/icon_item_24_static.h" } +#define DEKUNUTS_FLOWER 10 #define DEBUG_ACTOR_NAMETAG_TAG "debug_actor_viewer" typedef struct { @@ -107,6 +109,783 @@ void PopulateActorDropdown(int i, std::vector& data) { } } +//actors that don't use params at all +static std::vector noParamsActors = { + ACTOR_ARMS_HOOK, + ACTOR_ARROW_FIRE, + ACTOR_ARROW_ICE, + ACTOR_ARROW_LIGHT, + ACTOR_BG_BOM_GUARD, + ACTOR_BG_DY_YOSEIZO, + ACTOR_BG_GATE_SHUTTER, + ACTOR_BG_GJYO_BRIDGE, + ACTOR_BG_HIDAN_FSLIFT, + ACTOR_BG_HIDAN_RSEKIZOU, + ACTOR_BG_HIDAN_SYOKU, + ACTOR_BG_JYA_GOROIWA, + ACTOR_BG_MIZU_UZU, + ACTOR_BG_MORI_RAKKATENJO, + ACTOR_BG_PUSHBOX, + ACTOR_BG_SPOT01_FUSYA, + ACTOR_BG_SPOT01_IDOHASHIRA, + ACTOR_BG_SPOT01_IDOMIZU, + ACTOR_BG_SPOT01_IDOSOKO, + ACTOR_BG_SPOT11_OASIS, + ACTOR_BG_SPOT15_SAKU, + ACTOR_BG_SPOT18_FUTA, + ACTOR_BG_TOKI_SWD, + ACTOR_BG_TREEMOUTH, + ACTOR_BG_VB_SIMA, + ACTOR_BOSS_DODONGO, + ACTOR_BOSS_FD, + ACTOR_BOSS_GOMA, + ACTOR_DEMO_EXT, + ACTOR_DEMO_SHD, + ACTOR_DEMO_TRE_LGT, + ACTOR_DOOR_TOKI, + ACTOR_EFC_ERUPC, + ACTOR_EN_ANI, + ACTOR_EN_AROW_TRAP, + ACTOR_EN_BIRD, + ACTOR_EN_BLKOBJ, + ACTOR_EN_BOM_BOWL_MAN, + ACTOR_EN_BOM_BOWL_PIT, + ACTOR_EN_BOM_CHU, + ACTOR_EN_BUBBLE, + ACTOR_EN_DIVING_GAME, + ACTOR_EN_DNT_DEMO, + ACTOR_EN_DNT_JIJI, + ACTOR_EN_DS, + ACTOR_EN_DU, + ACTOR_EN_EG, + ACTOR_EN_FU, + ACTOR_EN_GB, + ACTOR_EN_GE3, + ACTOR_EN_GUEST, + ACTOR_EN_HATA, + ACTOR_EN_HORSE_GANON, + ACTOR_EN_HORSE_LINK_CHILD, + ACTOR_EN_HORSE_ZELDA, + ACTOR_EN_HS2, + ACTOR_EN_JS, + ACTOR_EN_KAKASI, + ACTOR_EN_KAKASI3, + ACTOR_EN_MA1, + ACTOR_EN_MA2, + ACTOR_EN_MA3, + ACTOR_EN_MAG, + ACTOR_EN_MK, + ACTOR_EN_MS, + ACTOR_EN_NIW_LADY, + ACTOR_EN_NWC, + ACTOR_EN_OE2, + ACTOR_EN_OKARINA_EFFECT, + ACTOR_EN_RR, + ACTOR_EN_SA, + ACTOR_EN_SCENE_CHANGE, + ACTOR_EN_SKJNEEDLE, + ACTOR_EN_SYATEKI_ITM, + ACTOR_EN_SYATEKI_MAN, + ACTOR_EN_TAKARA_MAN, + ACTOR_EN_TORYO, + ACTOR_EN_VASE, + ACTOR_EN_ZL1, + ACTOR_MAGIC_DARK, + ACTOR_MAGIC_FIRE, + ACTOR_OBJ_DEKUJR, + ACTOR_OCEFF_SPOT, + + ACTOR_UNSET_1, + ACTOR_UNSET_3, + ACTOR_UNSET_5, + ACTOR_UNSET_6, + ACTOR_UNSET_17, + ACTOR_UNSET_1A, + ACTOR_UNSET_1F, + ACTOR_UNSET_22, + ACTOR_UNSET_31, + ACTOR_UNSET_36, + ACTOR_UNSET_53, + ACTOR_UNSET_73, + ACTOR_UNSET_74, + ACTOR_UNSET_75, + ACTOR_UNSET_76, + ACTOR_UNSET_78, + ACTOR_UNSET_79, + ACTOR_UNSET_7A, + ACTOR_UNSET_7B, + ACTOR_UNSET_7E, + ACTOR_UNSET_7F, + ACTOR_UNSET_83, + ACTOR_UNSET_A0, + ACTOR_UNSET_B2, + ACTOR_UNSET_CE, + ACTOR_UNSET_D8, + ACTOR_UNSET_EA, + ACTOR_UNSET_EB, + ACTOR_UNSET_F2, + ACTOR_UNSET_F3, + ACTOR_UNSET_FB, + ACTOR_UNSET_109, + ACTOR_UNSET_10D, + ACTOR_UNSET_10E, + ACTOR_UNSET_128, + ACTOR_UNSET_129, + ACTOR_UNSET_134, + ACTOR_UNSET_154, + ACTOR_UNSET_15D, + ACTOR_UNSET_161, + ACTOR_UNSET_180, + ACTOR_UNSET_1AA +}; + +static std::unordered_map> actorSpecificData; + +void CreateActorSpecificData() { + if (!actorSpecificData.empty()) { + return; + } + + actorSpecificData[ACTOR_EN_DEKUNUTS] = [](s16 params) -> s16 { + bool isFlower = params == DEKUNUTS_FLOWER; + s16 shotsPerRound = (params >> 8) & 0xFF; + if (shotsPerRound == 0xFF || shotsPerRound == 0) { + shotsPerRound = 1; + } + ImGui::Checkbox("Flower", &isFlower); + if (!isFlower) { + ImGui::InputScalar("Shots Per Round", ImGuiDataType_S16, &shotsPerRound); + } + + return isFlower ? DEKUNUTS_FLOWER : (shotsPerRound << 8); + }; + + actorSpecificData[ACTOR_EN_TITE] = [](s16 params) -> s16 { + static const char* items[] = { "Blue", "Red" }; + if (params == 0) { + params = -2; + } + //the + 2 is because the params are -2 & -1 instead of 0 & 1 + int selectedItem = params + 2; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem - 2; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_AM] = [](s16 params) -> s16 { + static const char* items[] = { "Statue", "Enemy" }; + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_BG_ICE_TURARA] = [](s16 params) -> s16 { + static const char* items[] = { "Stalagmite", "Stalactite", "Stalactite (Regrow)" }; + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_BG_BREAKWALL] = [](s16 params) -> s16 { + static const char* items[] = { "DC Entrance", "Wall", "KD Floor", "KD Lava Cover" }; + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_TEST] = [](s16 params) -> s16 { + static const char* items[] = { "Invisible", "1", "2", "Ceiling", "4", "5" }; + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_TANA] = [](s16 params) -> s16 { + static const char* items[] = { "Wooden", "Stone (1)", "Stone (2)" }; + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_XC] = [](s16 params) -> s16 { + static const char* items[] = { "0", "1", "2", "3", "4", "5", "Minuet", "Bolero", "Serenade", "9" }; + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_SHOT_SUN] = [](s16 params) -> s16 { + static const char* items[] = { "Sun's Song", "Song of Storms", "LH Sun" }; + if (params == 0) { + params = 0x40; + } + //the - 0x40 is because the params are 0x40 & 0x41 instead of 0 & 1 + int selectedItem = params - 0x40; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem + 0x40; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_HONOTRAP] = [](s16 params) -> s16 { + static const char* items[] = { "Eye", "Flame Move", "Flame Drop" }; + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_REEBA] = [](s16 params) -> s16 { + bool isBig = params != 0; + ImGui::Checkbox("Big", &isBig); + + return isBig; + }; + + actorSpecificData[ACTOR_EN_TK] = [](s16 params) -> s16 { + bool canTurn = params >= 0; + ImGui::Checkbox("Can Turn", &canTurn); + + return canTurn ? 0 : -1; + }; + + actorSpecificData[ACTOR_EN_ITEM00] = [](s16 params) -> s16 { + bool autoCollect = params & 0x8000; + ImGui::Checkbox("Automatically Collect", &autoCollect); + u8 collectibleFlag = (params & 0x3F00) >> 8; + ImGui::InputScalar("Collectible Flag", ImGuiDataType_U8, &collectibleFlag); + if (collectibleFlag > 0x3F) { + collectibleFlag = 0x3F; + } + + static const char* items[] = { + "Green Rupee", + "Blue Rupee", + "Red Rupee", + "Recovery Heart", + "Bombs (A)", + "Arrow", + "Heart Piece", + "Heart Container", + "Arrows (5)", + "Arrows (10)", + "Arrows (30)", + "Bombs (B)", + "Deku Nuts (5)", + "Deku Stick", + "Magic (Large)", + "Magic (Small)", + "Deku Seeds (5)", + "Small Key", + "Flexible", + "Gold Rupee", + "Purple Rupee", + "Deku Shield", + "Hylian Shield", + "Zora Tunic", + "Goron Tunic", + "Bombs (Special)", + "Bombchus" + }; + + int selectedItem = params & 0xFF; + ImGui::Combo("Item", &selectedItem, items, IM_ARRAYSIZE(items)); + + return autoCollect * 0x8000 + (collectibleFlag << 8) + selectedItem; + }; + + actorSpecificData[ACTOR_OBJ_COMB] = [](s16 params) -> s16 { + static const char* items[] = { + "Green Rupee", + "Blue Rupee", + "Red Rupee", + "Recovery Heart", + "Bombs (A)", + "Arrow", + "Heart Piece", + "Heart Container", + "Arrows (5)", + "Arrows (10)", + "Arrows (30)", + "Bombs (B)", + "Deku Nuts (5)", + "Deku Stick", + "Magic (Large)", + "Magic (Small)", + "Deku Seeds (5)", + "Small Key", + "Flexible", + "Gold Rupee", + "Purple Rupee", + "Deku Shield", + "Hylian Shield", + "Zora Tunic", + "Goron Tunic", + "Bombs (Special)", + "Bombchus" + }; + + int selectedItem = params & 0xFF; + ImGui::Combo("Item Drop", &selectedItem, items, IM_ARRAYSIZE(items)); + + u8 collectibleFlag = (params & 0x3F00) >> 8; + if (selectedItem == 6) { + ImGui::InputScalar("PoH Collectible Flag", ImGuiDataType_U8, &collectibleFlag); + if (collectibleFlag > 0x3F) { + collectibleFlag = 0x3F; + } + } + + return (collectibleFlag << 8) + selectedItem; + }; + + actorSpecificData[ACTOR_EN_GM] = [](s16 params) -> s16 { + u8 switchFlag = (params & 0x3F00) >> 8; + + ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &switchFlag); + if (switchFlag > 0x3F) { + switchFlag = 0x3F; + } + + return switchFlag << 8; + }; + + actorSpecificData[ACTOR_EN_GIRLA] = [](s16 params) -> s16 { + static const char* items[] = { + "Deku Nuts (5)", + "Arrows (30)", + "Arrows (50)", + "Bombs (5) (25 Rupees)", + "Deku Nuts (10)", + "Deku Stick", + "Bombs (10)", + "Fish", + "Red Potion (30 Rupees)", + "Green Potion", + "Blue Potion", + "Longsword", + "Hylian Shield", + "Deku Shield", + "Goron Tunic", + "Zora Tunic", + "Heart", + "Milk Bottle", + "Weird Egg", + "19", + "20", + "Bomchu (10) [1]", + "Bomchu (20) [1]", + "Bomchu (20) [2]", + "Bomchu (10) [2]", + "Bomchu (10) [3]", + "Bomchu (20) [3]", + "Bomchu (20) [4]", + "Bomchu (10) [4]", + "Deku Seeds (30)", + "Keaton Mask", + "Spooky Mask", + "Skull Mask", + "Bunny Hood", + "Mask Of Truth", + "Zora Mask", + "Goron Mask", + "Gerudo Mask", + "Sold Out", + "Blue Fire", + "Bugs", + "Big Poe", + "Poe", + "Fairy", + "Arrows (10)", + "Bombs (20)", + "Bombs (30)", + "Bombs (5) (35 Rupees)", + "Red Potion (40 Rupees)", + "Red Potion (50 Rupees)", + "Randomizer Item" + }; + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_FIRE_ROCK] = [](s16 params) -> s16 { + static const char* items[] = { + "Spawned Falling (1)", + "Broken Piece (1)", + "Broken Piece (2)", + "Spawned Falling (2)", + //"INVALID", + "Ceiling Spot Spawner", + "On Floor" + }; + int selectedItem = params > 3 ? params - 1 : params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem > 3 ? selectedItem + 1 : selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_EX_ITEM] = [](s16 params) -> s16 { + static const char* items[] = { + "Bomb Bag Bowling", + "Heart Piece Bowling", + "Bombchus Bowling", + "Bombs Bowling", + "Purple Rupee Bowling", + "Bomb Bag Counter", + "Heart Piece Counter", + "Bombchus Counter", + "Bombs Counter", + "Purple Rupee Counter", + "Green Rupee Chest", + "Blue Rupee Chest", + "Red Rupee Chest", + "13", + "14", + "Small Key Chest", + "Magic Fire", + "Magic Wind", + "Magic Dark", + "Bullet Bag" + }; + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_ELF] = [](s16 params) -> s16 { + static const char* items[] = { + "Navi", + "Revive Bottle", + "Heal Timed", + "Kokiri", + "Spawner", + "Revive Death", + "Heal", + "Heal Big" + }; + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_CLEAR_TAG] = [](s16 params) -> s16 { + static const char* items[] = { + "Cutscene", //0 + "Normal", //1 + "Laser" //100 + }; + int selectedItem = params == 100 ? 2 : params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem == 2 ? 100 : selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_BOMBF] = [](s16 params) -> s16 { + static const char* items[] = { "Flower", "Body", "Explosion" }; + //the + 1 is because the params are -1, 0 & 1 instead of 0, 1 & 2 + int selectedItem = params + 1; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem - 1; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_BOM] = [](s16 params) -> s16 { + static const char* items[] = { "Body", "Explosion" }; + + int selectedItem = params; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_DOOR_WARP1] = [](s16 params) -> s16 { + static const char* items[] = { + "Blue Crystal", // -2 + "Dungeon Adult", + "Dungeon Child", + "Clear Flag", // Activate on temp clear flag + "Sages", // Used by sages warping into chamber of sages during their cutscene + "Purple Crystal", + "Yellow", // The colored variants don't warp, they are cutscene setpieces + "Blue Ruto", + "Destination", // Spawning in after having taken a warp + "UNK 7", + "Orange", + "Green", + "Red" + }; + int selectedItem = params + 2; + if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem - 2; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_DY_EXTRA] = [](s16 params) -> s16 { + static const char* items[] = { "Orange", "Green" }; + + int selectedItem = params; + if (ImGui::Combo("Color", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; + + actorSpecificData[ACTOR_EN_SKB] = [](s16 params) -> s16 { + u8 size = params; + ImGui::InputScalar("Size", ImGuiDataType_U8, &size); + + return size; + }; + + actorSpecificData[ACTOR_EN_WF] = [](s16 params) -> s16 { + static const char* items[] = { "Normal", "White" }; + + int selectedItem = params; + ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items)); + + u8 switchFlag = (params & 0x3F00) >> 8; + ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &switchFlag); + return (switchFlag << 8) + selectedItem; + }; + + actorSpecificData[ACTOR_EN_BOX] = [](s16 params) -> s16 { + /* + trasureFlag = params & 0x1F; //0b0000 0000 0001 1111 + itemId = (params >> 5) & 0x7F; //0b0000 1111 1110 0000 + type = (params >> 12) & 0xF; //0b1111 0000 0000 0000 + */ + u8 treasureFlag = params & 0x1F; + ImGui::InputScalar("Treasure Flag", ImGuiDataType_U8, &treasureFlag); + if (treasureFlag > 0x1F) { + treasureFlag = 0x1F; + } + + u8 itemId = (params >> 5) & 0x7F; + ImGui::InputScalar("Item Id", ImGuiDataType_U8, &itemId); + if (itemId > 0x7F) { + itemId = 0x7F; + } + + static const char* items[] = { + "Big (Default)", + "Room Clear Big", + "Decorated Big", + "Switch Flag Fall Big", + "4", + "Small", + "6", + "Room Clear Small", + "Switch Flag Fall Small", + "9", + "10", + "Switch Flag Big" + }; + + int type = (params >> 12) & 0xF; + ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items)); + if (type > 0xF) { + type = 0xF; + } + + return (type << 12) + (itemId << 5) + treasureFlag; + }; + + actorSpecificData[ACTOR_EN_DOOR] = [](s16 params) -> s16 { + /** + * Actor Parameters + * + * | | | | + * | Transition Index | Type | Double Door | Switch Flag OR Text Id - 0x0200 + * |------------------|-------|-------------|--------------------------------- + * | 0 0 0 0 0 0 | 0 0 0 | 0 | 0 0 0 0 0 0 + * | 6 | 3 | 1 | 6 + * | + * + * Transition Index 1111110000000000 Set by the actor engine when the door is spawned + * Type 0000001110000000 + * Double Door 0000000001000000 + * Switch Flag 0000000000111111 For use with the `DOOR_LOCKED` type + * Text id - 0x0200 0000000000111111 For use with the `DOOR_CHECKABLE` type + * + */ + u8 transitionIndex = params >> 10; + ImGui::InputScalar("Transition Index", ImGuiDataType_U8, &transitionIndex); + if (transitionIndex > 0x3F) { + transitionIndex = 0x3F; + } + + static const char* items[] = { + "Room Load", // loads rooms + "Locked", // small key locked door + "Room Load (2)", // loads rooms + "Scene Exit", // doesn't load rooms, used for doors paired with scene transition polygons + "Ajar", // open slightly but slams shut if Link gets too close + "Checkable", // doors that display a textbox when interacting + "Evening", // unlocked between 18:00 and 21:00, Dampé's hut + "Room Load (7)" // loads rooms + }; + + int type = (params >> 7) & 7; + ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items)); + if (type > 7) { + type = 7; + } + + bool doubleDoor = ((params >> 6) & 1) != 0; + ImGui::Checkbox("Double Door", &doubleDoor); + + u8 lowerBits = params & 0x3F; + if (type == 1) { + ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &lowerBits); + if (lowerBits > 0x3F) { + lowerBits = 0x3F; + } + } else if (type == 5) { + ImGui::InputScalar("Text ID - 0x200", ImGuiDataType_U8, &lowerBits); + if (lowerBits > 0x3F) { + lowerBits = 0x3F; + } + } else { + lowerBits = 0; + } + + return (transitionIndex << 10) + (type << 7) + (doubleDoor << 6) + lowerBits; + }; + + actorSpecificData[ACTOR_EN_PO_DESERT] = [](s16 params) -> s16 { + u8 switchFlag = params >> 8; + + ImGui::InputScalar("Path", ImGuiDataType_U8, &switchFlag); + + return switchFlag << 8; + }; + + actorSpecificData[ACTOR_EN_KANBAN] = [](s16 params) -> s16 { + bool piece = params == (s16)0xFFDD; + bool fishingSign = params == 0x300; + if (ImGui::Checkbox("Piece", &piece)) { + fishingSign = false; + } + if (ImGui::Checkbox("Fishing Sign", &fishingSign)) { + piece = false; + } + + u8 textId = params; + if (!piece && !fishingSign) { + if (ImGui::InputScalar("Text ID", ImGuiDataType_U8, &textId)) { + textId |= 0x300; + } + } + + return piece ? (s16)0xFFDD : (fishingSign ? 0x300 : textId); + }; + + actorSpecificData[ACTOR_EN_KUSA] = [](s16 params) -> s16 { + static const char* items[] = { + "0", + "1", + "2" + }; + + int type = params & 3; + ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items)); + + bool bugs = ((params >> 4) & 1) != 0; + ImGui::Checkbox("Bugs", &bugs); + + u8 drop = (params >> 8) & 0xF; + if (type == 2) { + ImGui::InputScalar("Random Drop Params", ImGuiDataType_U8, &drop); + if (drop > 0xD) { + drop = 0xD; + } + } else { + drop = 0; + } + + return (drop << 8) + (bugs << 4) + type; + }; + + actorSpecificData[ActorDB::Instance->RetrieveId("En_Partner")] = [](s16 params) -> s16 { + static const char* items[] = { + "Port 1", + "Port 2", + "Port 3", + "Port 4" + }; + int selectedItem = params; + if (ImGui::Combo("Controller Port", &selectedItem, items, IM_ARRAYSIZE(items))) { + return selectedItem; + } + + return params; + }; +} + +std::vector GetActorsWithDescriptionContainingString(std::string s) { + std::locale loc; + for (size_t i = 0; i < s.length(); i += 1) { + s[i] = std::tolower(s[i], loc); + } + + std::vector actors; + for (int i = 0; i < ActorDB::Instance->GetEntryCount(); i += 1) { + ActorDB::Entry actorEntry = ActorDB::Instance->RetrieveEntry(i); + std::string desc = actorEntry.desc; + for (size_t j = 0; j < desc.length(); j += 1) { + desc[j] = std::tolower(desc[j], loc); + } + if (desc.find(s) != std::string::npos) { + actors.push_back((u16)i); + } + } + return actors; +} + void ActorViewer_AddTagForActor(Actor* actor) { int val = CVarGetInteger("gDebugActorViewerNameTags", ACTORVIEWER_NAMETAGS_NONE); auto entry = ActorDB::Instance->RetrieveEntry(actor->id); @@ -163,6 +942,9 @@ void ActorViewerWindow::DrawElement() { static std::string filler = "Please select"; static std::vector list; static u16 lastSceneId = 0; + static char searchString[64] = ""; + static s16 currentSelectedInDropdown; + static std::vector actors; if (gPlayState != nullptr) { needs_reset = lastSceneId != gPlayState->sceneNum; @@ -173,6 +955,11 @@ void ActorViewerWindow::DrawElement() { filler = "Please Select"; list.clear(); needs_reset = false; + for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) { + searchString[i] = 0; + } + currentSelectedInDropdown = -1; + actors.clear(); } lastSceneId = gPlayState->sceneNum; if (ImGui::BeginCombo("Actor Type", acMapping[category])) { @@ -316,9 +1103,48 @@ void ActorViewerWindow::DrawElement() { if (ImGui::TreeNode("New...")) { ImGui::PushItemWidth(ImGui::GetFontSize() * 10); + if (ImGui::InputText("Search Actor", searchString, ARRAY_COUNT(searchString))) { + actors = GetActorsWithDescriptionContainingString(std::string(searchString)); + currentSelectedInDropdown = -1; + } + + if (searchString[0] != 0 && !actors.empty()) { + std::string preview = currentSelectedInDropdown == -1 ? "Please Select" : ActorDB::Instance->RetrieveEntry(actors[currentSelectedInDropdown]).desc; + if (ImGui::BeginCombo("Results", preview.c_str())) { + for (u8 i = 0; i < actors.size(); i++) { + if (ImGui::Selectable( + ActorDB::Instance->RetrieveEntry(actors[i]).desc.c_str(), + i == currentSelectedInDropdown + )) { + currentSelectedInDropdown = i; + newActor.id = actors[i]; + } + } + ImGui::EndCombo(); + } + } + ImGui::Text("%s", GetActorDescription(newActor.id).c_str()); - ImGui::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one); - ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one); + if (ImGui::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one)) { + newActor.params = 0; + } + + UIWidgets::EnhancementCheckbox("Advanced mode", "gActorViewerAdvancedParams"); + UIWidgets::InsertHelpHoverText("Changes the actor specific param menus with a direct input"); + + if (CVarGetInteger("gActorViewerAdvancedParams", 0)) { + ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one); + } else if (std::find(noParamsActors.begin(), noParamsActors.end(), newActor.id) == noParamsActors.end()) { + CreateActorSpecificData(); + if (actorSpecificData.find(newActor.id) == actorSpecificData.end()) { + ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one); + } else { + DrawGroupWithBorder([&]() { + ImGui::Text("Actor Specific Data"); + newActor.params = actorSpecificData[newActor.id](newActor.params); + }); + } + } ImGui::PushItemWidth(ImGui::GetFontSize() * 6); @@ -401,6 +1227,11 @@ void ActorViewerWindow::DrawElement() { filler = "Please Select"; list.clear(); needs_reset = false; + for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) { + searchString[i] = 0; + } + currentSelectedInDropdown = -1; + actors.clear(); } } From a6bb6cf0a3aad06f926ba160016ac06aedd94600 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Wed, 27 Dec 2023 17:50:56 +0000 Subject: [PATCH 05/12] Hardcore mode v1 (#3540) --- soh/soh/Enhancements/mods.cpp | 48 +++++++++++++++++++++++++++++++++++ soh/soh/Enhancements/mods.h | 1 + soh/soh/SohMenuBar.cpp | 8 ++++++ 3 files changed, 57 insertions(+) diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 7ad8473f1..24077697f 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -400,6 +400,52 @@ void RegisterShadowTag() { }); } +static bool hasAffectedHealth = false; +void UpdatePermanentHeartLossState() { + if (!GameInteractor::IsSaveLoaded()) return; + + if (!CVarGetInteger("gPermanentHeartLoss", 0) && hasAffectedHealth) { + uint8_t heartContainers = gSaveContext.sohStats.heartContainers; // each worth 16 health + uint8_t heartPieces = gSaveContext.sohStats.heartPieces; // each worth 4 health, but only in groups of 4 + uint8_t startingHealth = 16 * 3; + + + uint8_t newCapacity = startingHealth + (heartContainers * 16) + ((heartPieces - (heartPieces % 4)) * 4); + gSaveContext.healthCapacity = MAX(newCapacity, gSaveContext.healthCapacity); + gSaveContext.health = MIN(gSaveContext.health, gSaveContext.healthCapacity); + hasAffectedHealth = false; + } +} + +void RegisterPermanentHeartLoss() { + GameInteractor::Instance->RegisterGameHook([](int16_t fileNum) { + hasAffectedHealth = false; + UpdatePermanentHeartLossState(); + }); + + GameInteractor::Instance->RegisterGameHook([]() { + if (!CVarGetInteger("gPermanentHeartLoss", 0) || !GameInteractor::IsSaveLoaded()) return; + + if (gSaveContext.healthCapacity > 16 && gSaveContext.healthCapacity - gSaveContext.health >= 16) { + gSaveContext.healthCapacity -= 16; + gSaveContext.health = MIN(gSaveContext.health, gSaveContext.healthCapacity); + hasAffectedHealth = true; + } + }); +}; + +void RegisterDeleteFileOnDeath() { + GameInteractor::Instance->RegisterGameHook([]() { + if (!CVarGetInteger("gDeleteFileOnDeath", 0) || !GameInteractor::IsSaveLoaded() || &gPlayState->gameOverCtx == NULL || &gPlayState->pauseCtx == NULL) return; + + if (gPlayState->gameOverCtx.state == GAMEOVER_DEATH_MENU && gPlayState->pauseCtx.state == 9) { + SaveManager::Instance->DeleteZeldaFile(gSaveContext.fileNum); + hasAffectedHealth = false; + std::reinterpret_pointer_cast(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))->Dispatch("reset"); + } + }); +} + struct DayTimeGoldSkulltulas { uint16_t scene; uint16_t room; @@ -1088,6 +1134,8 @@ void InitMods() { RegisterDaytimeGoldSkultullas(); RegisterRupeeDash(); RegisterShadowTag(); + RegisterPermanentHeartLoss(); + RegisterDeleteFileOnDeath(); RegisterHyperBosses(); RegisterHyperEnemies(); RegisterBonkDamage(); diff --git a/soh/soh/Enhancements/mods.h b/soh/soh/Enhancements/mods.h index 2f0430475..8125659ab 100644 --- a/soh/soh/Enhancements/mods.h +++ b/soh/soh/Enhancements/mods.h @@ -9,6 +9,7 @@ extern "C" { void UpdateDirtPathFixState(int32_t sceneNum); void UpdateMirrorModeState(int32_t sceneNum); +void UpdatePermanentHeartLossState(); void InitMods(); #ifdef __cplusplus diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 614a6b690..9a006fb86 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -660,6 +660,14 @@ void DrawEnhancementsMenu() { if (ImGui::BeginMenu("Difficulty Options")) { + UIWidgets::PaddedEnhancementCheckbox("Delete File On Death", "gDeleteFileOnDeath", true, false); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); + UIWidgets::Tooltip("Dying will delete your file\n\n " ICON_FA_EXCLAMATION_TRIANGLE " WARNING " ICON_FA_EXCLAMATION_TRIANGLE "\nTHIS IS NOT REVERSABLE\nUSE AT YOUR OWN RISK!"); + ImGui::PopStyleColor(); + if (UIWidgets::PaddedEnhancementCheckbox("Permanent heart loss", "gPermanentHeartLoss", true, false)) { + UpdatePermanentHeartLossState(); + } + UIWidgets::Tooltip("When you lose 4 quarters of a heart you will permanently lose that heart container.\n\nDisabling this after the fact will restore your heart containers."); ImGui::Text("Damage Multiplier"); UIWidgets::EnhancementCombobox("gDamageMul", allPowers, 0); UIWidgets::Tooltip( From 9b74dc28924cf5c04242c4475026f5c913ccb246 Mon Sep 17 00:00:00 2001 From: mattman107 <65982675+mattman107@users.noreply.github.com> Date: Wed, 27 Dec 2023 12:51:36 -0500 Subject: [PATCH 06/12] Update linux/appimage script to use symlinked rom files (#3483) * Update soh.sh.in Added support for symlinked rom files in linux/appimage script. * Update scripts/linux/appimage/soh.sh.in Updated to be less confusing as per Archez Co-authored-by: Adam Bird --------- Co-authored-by: Adam Bird --- scripts/linux/appimage/soh.sh.in | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/linux/appimage/soh.sh.in b/scripts/linux/appimage/soh.sh.in index bfc3cfec6..a9d6dbf8c 100644 --- a/scripts/linux/appimage/soh.sh.in +++ b/scripts/linux/appimage/soh.sh.in @@ -21,12 +21,17 @@ fi while [[ (! -e "$SHIP_HOME"/oot.otr) || (! -e "$SHIP_HOME"/oot-mq.otr) ]]; do for romfile in "$SHIP_HOME"/*.*64 do - if [[ -e $romfile ]]; then + if [[ -e "$romfile" ]] || [[ -L "$romfile" ]]; then export ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)" ln -s "$HERE"/usr/bin/{assets,soh.elf,ZAPD} "$ASSETDIR" export OLDPWD="$PWD" mkdir -p "$ASSETDIR"/tmp - ln -s "$romfile" "$ASSETDIR"/tmp/rom.z64 + if [[ -e "$romfile" ]]; then + ln -s "$romfile" "$ASSETDIR"/tmp/rom.z64 + else + ORIG_ROM_PATH=$(readlink "$romfile") + ln -s "$ORIG_ROM_PATH" "$ASSETDIR"/tmp/rom.z64 + fi cd "$ASSETDIR" ROMHASH=$(sha1sum -b "$ASSETDIR"/tmp/rom.z64 | awk '{ print $1 }') From dc4347253de83f2831e880bdb72753a0bec66687 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Wed, 27 Dec 2023 18:55:09 +0100 Subject: [PATCH 07/12] Item cycling improvements (#3456) * Simplify item cycling * Simplify selection variables * Fix adult bunny hood and gray appropriate items * Don't go into cycling mode when there's no items to cycle to * Restore updating c buttons This was previously done with `Inventory_ReplaceItem` but that led to problems when another slot had the same item as the one that's being cycled. * Address review --- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 266 +++++++++++------- .../misc/ovl_kaleido_scope/z_kaleido_scope.h | 3 +- .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 7 +- 3 files changed, 176 insertions(+), 100 deletions(-) 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 665c95b81..b04f07b38 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 @@ -14,8 +14,6 @@ u8 gAmmoItems[] = { static s16 sEquipState = 0; static s16 sEquipAnimTimer = 0; static s16 sEquipMoveTimer = 10; -bool gSelectingMask; -bool gSelectingAdultTrade; static s16 sAmmoVtxOffset[] = { 0, 2, 4, 6, 99, 99, 8, 99, 10, 99, 99, 99, 99, 99, 12, @@ -87,6 +85,10 @@ void KaleidoScope_SetItemCursorVtx(PauseContext* pauseCtx) { KaleidoScope_SetCursorVtx(pauseCtx, pauseCtx->cursorSlot[PAUSE_ITEM] * 4, pauseCtx->itemVtx); } +#pragma region Item Cycling + +s8 gCurrentItemCyclingSlot; + // Vertices for the extra items static Vtx sCycleExtraItemVtx[] = { // Left Item @@ -127,9 +129,11 @@ static Vtx sCycleAButtonVtx[] = { static sSlotCycleActiveAnimTimer[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // Renders a left and/or right item for any item slot that can support cycling -void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8 canCycle, u8 leftItem, u8 rightItem) { +void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 canCycle, u8 leftItem, u8 rightItem) { PauseContext* pauseCtx = &play->pauseCtx; + u8 isCycling = gCurrentItemCyclingSlot == slot; + OPEN_DISPS(play->state.gfxCtx); // Update active cycling animation timer @@ -208,10 +212,20 @@ void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8 gSPVertex(POLY_KAL_DISP++, sCycleExtraItemVtx, 8, 0); if (showLeftItem) { + if (!CHECK_AGE_REQ_ITEM(leftItem)) { + gDPSetGrayscaleColor(POLY_KAL_DISP++, 109, 109, 109, 255); + gSPGrayscale(POLY_KAL_DISP++, true); + } KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gItemIcons[leftItem], 32, 32, 0); + gSPGrayscale(POLY_KAL_DISP++, false); } if (showRightItem) { + if (!CHECK_AGE_REQ_ITEM(rightItem)) { + gDPSetGrayscaleColor(POLY_KAL_DISP++, 109, 109, 109, 255); + gSPGrayscale(POLY_KAL_DISP++, true); + } KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gItemIcons[rightItem], 32, 32, 4); + gSPGrayscale(POLY_KAL_DISP++, false); } Matrix_Pop(); @@ -220,6 +234,155 @@ void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8 CLOSE_DISPS(play->state.gfxCtx); } +void KaleidoScope_HandleItemCycleExtras(PlayState* play, u8 slot, bool canCycle, u8 leftItem, u8 rightItem, bool replaceCButtons) { + Input* input = &play->state.input[0]; + PauseContext* pauseCtx = &play->pauseCtx; + bool dpad = (CVarGetInteger("gDpadPause", 0) && !CHECK_BTN_ALL(input->cur.button, BTN_CUP)); + u8 slotItem = gSaveContext.inventory.items[slot]; + u8 hasLeftItem = leftItem != ITEM_NONE && slotItem != leftItem; + u8 hasRightItem = rightItem != ITEM_NONE && slotItem != rightItem && leftItem != rightItem; + + if ( + canCycle && + pauseCtx->cursorSlot[PAUSE_ITEM] == slot && + CHECK_BTN_ALL(input->press.button, BTN_A) && + (hasLeftItem || hasRightItem) + ) { + Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + gCurrentItemCyclingSlot = gCurrentItemCyclingSlot == slot ? -1 : slot; + } + if (gCurrentItemCyclingSlot == slot) { + pauseCtx->cursorColorSet = 8; + if ((pauseCtx->stickRelX > 30 || pauseCtx->stickRelY > 30) || + dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT | BTN_DUP)) { + Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + if (replaceCButtons) { + for (int i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { + if (gSaveContext.equips.buttonItems[i] == gSaveContext.inventory.items[slot]) { + if (CHECK_AGE_REQ_ITEM(rightItem)) { + gSaveContext.equips.buttonItems[i] = rightItem; + Interface_LoadItemIcon1(play, i); + } else { + gSaveContext.equips.buttonItems[i] = ITEM_NONE; + } + break; + } + } + } + gSaveContext.inventory.items[slot] = rightItem; + } else if ((pauseCtx->stickRelX < -30 || pauseCtx->stickRelY < -30) || + dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DDOWN)) { + Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + if (replaceCButtons) { + for (int i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { + if (gSaveContext.equips.buttonItems[i] == gSaveContext.inventory.items[slot]) { + if (CHECK_AGE_REQ_ITEM(leftItem)) { + gSaveContext.equips.buttonItems[i] = leftItem; + Interface_LoadItemIcon1(play, i); + } else { + gSaveContext.equips.buttonItems[i] = ITEM_NONE; + } + break; + } + } + } + gSaveContext.inventory.items[slot] = leftItem; + } + gCurrentItemCyclingSlot = pauseCtx->cursorSlot[PAUSE_ITEM] == slot ? slot : -1; + } +} + +bool CanMaskSelect() { + // only allow mask select when: + // the shop is open: + // * zelda's letter check: Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER) + // * kak gate check: Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD) + // and the mask quest is complete: Flags_GetEventChkInf(EVENTCHKINF_PAID_BACK_BUNNY_HOOD_FEE) + return CVarGetInteger("gMaskSelect", 0) && + Flags_GetEventChkInf(EVENTCHKINF_PAID_BACK_BUNNY_HOOD_FEE) && + Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER) && + Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD); +} + +void KaleidoScope_HandleItemCycles(PlayState* play) { + //handle the mask select + KaleidoScope_HandleItemCycleExtras( + play, + SLOT_TRADE_CHILD, + CanMaskSelect(), + INV_CONTENT(ITEM_TRADE_CHILD) <= ITEM_MASK_KEATON || INV_CONTENT(ITEM_TRADE_CHILD) > ITEM_MASK_TRUTH ? + ITEM_MASK_TRUTH : + INV_CONTENT(ITEM_TRADE_CHILD) - 1, + INV_CONTENT(ITEM_TRADE_CHILD) >= ITEM_MASK_TRUTH || INV_CONTENT(ITEM_TRADE_CHILD) < ITEM_MASK_KEATON ? + ITEM_MASK_KEATON : + INV_CONTENT(ITEM_TRADE_CHILD) + 1, + true + ); + + //the slot age requirement for the child trade slot has to be updated + //in case it currently holds the bunny hood + //to allow adult link to wear it if the setting is enabled + gSlotAgeReqs[SLOT_TRADE_CHILD] = + ( + ((CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) && CVarGetInteger("gAdultBunnyHood", 0)) || + CVarGetInteger("gTimelessEquipment", 0) + ) && + INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_MASK_BUNNY + ? AGE_REQ_NONE + : AGE_REQ_CHILD; + + //also update the age requirement for the bunny hood itself + gItemAgeReqs[ITEM_MASK_BUNNY] = + ((CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) && CVarGetInteger("gAdultBunnyHood", 0)) || + CVarGetInteger("gTimelessEquipment", 0) + ? AGE_REQ_NONE + : AGE_REQ_CHILD; + + //handle the adult trade select + KaleidoScope_HandleItemCycleExtras( + play, + SLOT_TRADE_ADULT, + IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE), + Randomizer_GetPrevAdultTradeItem(), + Randomizer_GetNextAdultTradeItem(), + true + ); +} + +void KaleidoScope_DrawItemCycles(PlayState* play) { + //draw the mask select + KaleidoScope_DrawItemCycleExtras( + play, + SLOT_TRADE_CHILD, + CanMaskSelect(), + INV_CONTENT(ITEM_TRADE_CHILD) <= ITEM_MASK_KEATON || INV_CONTENT(ITEM_TRADE_CHILD) > ITEM_MASK_TRUTH ? + ITEM_MASK_TRUTH : + INV_CONTENT(ITEM_TRADE_CHILD) - 1, + INV_CONTENT(ITEM_TRADE_CHILD) >= ITEM_MASK_TRUTH || INV_CONTENT(ITEM_TRADE_CHILD) < ITEM_MASK_KEATON ? + ITEM_MASK_KEATON : + INV_CONTENT(ITEM_TRADE_CHILD) + 1 + ); + + //draw the adult trade select + KaleidoScope_DrawItemCycleExtras( + play, + SLOT_TRADE_ADULT, + IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE), + Randomizer_GetPrevAdultTradeItem(), + Randomizer_GetNextAdultTradeItem() + ); +} + +bool IsItemCycling() { + return gCurrentItemCyclingSlot != -1; +} + +void KaleidoScope_ResetItemCycling() { + gCurrentItemCyclingSlot = -1; +} + +#pragma endregion + void KaleidoScope_DrawItemSelect(PlayState* play) { static s16 magicArrowEffectsR[] = { 255, 100, 255 }; static s16 magicArrowEffectsG[] = { 0, 100, 255 }; @@ -240,16 +403,6 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { bool pauseAnyCursor = (CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_RANDO_ONLY && IS_RANDO) || (CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_ALWAYS_ON); - // only allow mask select when: - // the shop is open: - // * zelda's letter check: Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER) - // * kak gate check: Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD) - // and the mask quest is complete: Flags_GetEventChkInf(EVENTCHKINF_PAID_BACK_BUNNY_HOOD_FEE) - bool canMaskSelect = CVarGetInteger("gMaskSelect", 0) && - Flags_GetEventChkInf(EVENTCHKINF_PAID_BACK_BUNNY_HOOD_FEE) && - Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER) && - Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD); - OPEN_DISPS(play->state.gfxCtx); Gfx_SetupDL_42Opa(play->state.gfxCtx); @@ -260,7 +413,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 || IsItemCycling(); oldCursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM]; cursorItem = pauseCtx->cursorItem[PAUSE_ITEM]; @@ -434,7 +587,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 || IsItemCycling(); cursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM]; cursorY = pauseCtx->cursorY[PAUSE_ITEM]; @@ -499,68 +652,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { KaleidoScope_SetCursorVtx(pauseCtx, index, pauseCtx->itemVtx); if ((pauseCtx->debugState == 0) && (pauseCtx->state == 6) && (pauseCtx->unk_1E4 == 0)) { - if (canMaskSelect && cursorSlot == SLOT_TRADE_CHILD && CHECK_BTN_ALL(input->press.button, BTN_A)) { - Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - gSelectingMask = !gSelectingMask; - } - if (gSelectingMask) { - pauseCtx->cursorColorSet = 8; - if (((pauseCtx->stickRelX > 30 || pauseCtx->stickRelY > 30) || - dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT | BTN_DUP)) && - INV_CONTENT(ITEM_TRADE_CHILD) < ITEM_MASK_TRUTH) { - Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - ++INV_CONTENT(ITEM_TRADE_CHILD); - } else if (((pauseCtx->stickRelX < -30 || pauseCtx->stickRelY < -30) || - dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DDOWN)) && - INV_CONTENT(ITEM_TRADE_CHILD) > ITEM_MASK_KEATON) { - Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - --INV_CONTENT(ITEM_TRADE_CHILD); - } else if ((pauseCtx->stickRelX < -30 || pauseCtx->stickRelX > 30 || pauseCtx->stickRelY < -30 || pauseCtx->stickRelY > 30) || - dpad && CHECK_BTN_ANY(input->press.button, BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT)) { - // Change to keaton mask if no mask is in child trade slot. Catches Zelda's letter and bottle duping over this slot. - if (INV_CONTENT(ITEM_TRADE_CHILD) < ITEM_MASK_KEATON || INV_CONTENT(ITEM_TRADE_CHILD) > ITEM_MASK_TRUTH) { - INV_CONTENT(ITEM_TRADE_CHILD) = ITEM_MASK_KEATON; - } else { - INV_CONTENT(ITEM_TRADE_CHILD) ^= ITEM_MASK_KEATON ^ ITEM_MASK_TRUTH; - } - Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - } - for (uint16_t cSlotIndex = 0; cSlotIndex < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); cSlotIndex++) { - if (gSaveContext.equips.cButtonSlots[cSlotIndex] == SLOT_TRADE_CHILD) { - if (!LINK_IS_ADULT || CVarGetInteger("gTimelessEquipment", 0)) { - gSaveContext.equips.buttonItems[cSlotIndex+1] = INV_CONTENT(ITEM_TRADE_CHILD); - } else if (INV_CONTENT(ITEM_TRADE_CHILD) != gSaveContext.equips.buttonItems[cSlotIndex+1]) { - gSaveContext.equips.cButtonSlots[cSlotIndex] = SLOT_NONE; - gSaveContext.equips.buttonItems[cSlotIndex+1] = ITEM_NONE; - } - } - } - gSelectingMask = cursorSlot == SLOT_TRADE_CHILD; - - gSlotAgeReqs[SLOT_TRADE_CHILD] = gItemAgeReqs[ITEM_MASK_BUNNY] = - ((((CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) && CVarGetInteger("gAdultBunnyHood", 0)) || CVarGetInteger("gTimelessEquipment", 0)) && - INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_MASK_BUNNY) - ? AGE_REQ_NONE - : AGE_REQ_CHILD; - } - if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) && - cursorSlot == SLOT_TRADE_ADULT && CHECK_BTN_ALL(input->press.button, BTN_A)) { - Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - gSelectingAdultTrade = !gSelectingAdultTrade; - } - if (gSelectingAdultTrade) { - pauseCtx->cursorColorSet = 8; - if (((pauseCtx->stickRelX > 30 || pauseCtx->stickRelY > 30) || - dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT | BTN_DUP))) { - Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - Inventory_ReplaceItem(play, INV_CONTENT(ITEM_TRADE_ADULT), Randomizer_GetNextAdultTradeItem()); - } else if (((pauseCtx->stickRelX < -30 || pauseCtx->stickRelY < -30) || - dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DDOWN))) { - Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); - Inventory_ReplaceItem(play, INV_CONTENT(ITEM_TRADE_ADULT), Randomizer_GetPrevAdultTradeItem()); - } - gSelectingAdultTrade = cursorSlot == SLOT_TRADE_ADULT; - } + KaleidoScope_HandleItemCycles(play); 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; @@ -678,15 +770,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { } } - // Adult trade item cycle - KaleidoScope_DrawItemCycleExtras(play, SLOT_TRADE_ADULT, gSelectingAdultTrade, - IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE), - Randomizer_GetPrevAdultTradeItem(), Randomizer_GetNextAdultTradeItem()); - // Child mask item cycle (mimics the left/right item behavior from the cycling logic above) - u8 childTradeItem = INV_CONTENT(ITEM_TRADE_CHILD); - KaleidoScope_DrawItemCycleExtras(play, SLOT_TRADE_CHILD, gSelectingMask, canMaskSelect, - childTradeItem <= ITEM_MASK_KEATON ? ITEM_MASK_TRUTH : childTradeItem - 1, - childTradeItem >= ITEM_MASK_TRUTH ? ITEM_MASK_KEATON : childTradeItem + 1); + KaleidoScope_DrawItemCycles(play); CLOSE_DISPS(play->state.gfxCtx); } @@ -694,8 +778,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) { void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, s16 animY) { Input* input = &play->state.input[0]; PauseContext* pauseCtx = &play->pauseCtx; - gSelectingMask = false; - gSelectingAdultTrade = false; + KaleidoScope_ResetItemCycling(); if (CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) { pauseCtx->equipTargetCBtn = 0; @@ -1079,9 +1162,4 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) { pauseCtx->equipAnimAlpha = 255; } } -} - -void KaleidoScope_ResetTradeSelect() { - gSelectingMask = false; - gSelectingAdultTrade = false; -} +} \ No newline at end of file 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 8c214d9b0..936f0bbdd 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 @@ -11,7 +11,6 @@ extern u8 gEquipAgeReqs[][4]; extern u8 gSlotAgeReqs[]; extern u8 gItemAgeReqs[]; extern u8 gAreaGsFlags[]; -extern bool gSelectingMask; #define MAP_48x85_TEX_WIDTH 48 #define MAP_48x85_TEX_HEIGHT 85 @@ -50,6 +49,6 @@ void PauseMapMark_Draw(PlayState* play); void KaleidoScope_UpdateCursorSize(PauseContext* pauseCtx); -void KaleidoScope_ResetTradeSelect(); +void KaleidoScope_ResetItemCycling(); #endif 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 4167324d7..b70197cc2 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 @@ -1008,7 +1008,7 @@ void KaleidoScope_SetDefaultCursor(PlayState* play) { PauseContext* pauseCtx = &play->pauseCtx; s16 s; s16 i; - gSelectingMask = false; + KaleidoScope_ResetItemCycling(); switch (pauseCtx->pageIndex) { case PAUSE_ITEM: @@ -1042,7 +1042,6 @@ void KaleidoScope_SetDefaultCursor(PlayState* play) { void KaleidoScope_SwitchPage(PauseContext* pauseCtx, u8 pt) { pauseCtx->unk_1E4 = 1; pauseCtx->unk_1EA = 0; - gSelectingMask = false; if (!pt) { pauseCtx->mode = pauseCtx->pageIndex * 2 + 1; @@ -1074,7 +1073,7 @@ void KaleidoScope_SwitchPage(PauseContext* pauseCtx, u8 pt) { gSaveContext.unk_13EA = 0; Interface_ChangeAlpha(50); - KaleidoScope_ResetTradeSelect(); + KaleidoScope_ResetItemCycling(); } void KaleidoScope_HandlePageToggles(PauseContext* pauseCtx, Input* input) { @@ -3857,7 +3856,7 @@ void KaleidoScope_Update(PlayState* play) } } - KaleidoScope_ResetTradeSelect(); + KaleidoScope_ResetItemCycling(); pauseCtx->state = 4; break; From 3f61fbc5f65bdbbc60d456b14a57707e452469af Mon Sep 17 00:00:00 2001 From: pirate486743186 <429925+pirate486743186@users.noreply.github.com> Date: Wed, 27 Dec 2023 19:37:11 +0100 Subject: [PATCH 08/12] use SHIP_BIN_DIR instead of HERE (#3469) --- scripts/linux/appimage/soh.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/linux/appimage/soh.sh.in b/scripts/linux/appimage/soh.sh.in index a9d6dbf8c..71121a5ff 100644 --- a/scripts/linux/appimage/soh.sh.in +++ b/scripts/linux/appimage/soh.sh.in @@ -23,7 +23,7 @@ while [[ (! -e "$SHIP_HOME"/oot.otr) || (! -e "$SHIP_HOME"/oot-mq.otr) ]]; do do if [[ -e "$romfile" ]] || [[ -L "$romfile" ]]; then export ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)" - ln -s "$HERE"/usr/bin/{assets,soh.elf,ZAPD} "$ASSETDIR" + ln -s "$SHIP_BIN_DIR"/{assets,soh.elf,ZAPD} "$ASSETDIR" export OLDPWD="$PWD" mkdir -p "$ASSETDIR"/tmp if [[ -e "$romfile" ]]; then From 1fff15753a9b70dd65e244015b2a9ab78037f04a Mon Sep 17 00:00:00 2001 From: PurpleHato Date: Thu, 28 Dec 2023 05:46:00 +0100 Subject: [PATCH 09/12] ADD: Enhancement-->Graphics-->Colour Temple of Time's Medallions (#3514) * First dirty testing process * Forgot a 2 for the second Dlist patching of Shadow * TWEAK: GI integration * DEL: Unucessary includes + whitespace * TWEAK: No stones refactor for now, sorry I'm kinda lazy right now, don't hate me, please! T_T * Stone removal part 2, sometime I forget to save the changes :derp: * Tiny last tweaks, hopefully * Add to rando preset * Tweak: typo * TWEAK: Trigger on toggling on/off * TWEAK: adressed reviews :100: * Please mate, excuse my British typing --- soh/soh/Enhancements/mods.cpp | 101 +++++++++++++++++++++++++++++++++ soh/soh/Enhancements/mods.h | 1 + soh/soh/Enhancements/presets.h | 4 ++ soh/soh/SohMenuBar.cpp | 4 ++ 4 files changed, 110 insertions(+) diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 24077697f..d7123c570 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -26,16 +26,30 @@ extern "C" { #include +#include "align_asset_macro.h" #include "macros.h" #include "functions.h" #include "variables.h" #include "functions.h" +void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction); +void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName); + extern SaveContext gSaveContext; extern PlayState* gPlayState; extern void Overlay_DisplayText(float duration, const char* text); uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum); } +// GreyScaleEndDlist +#define dgEndGrayscaleAndEndDlistDL "__OTR__helpers/cosmetics/gEndGrayscaleAndEndDlistDL" +static const ALIGN_ASSET(2) char gEndGrayscaleAndEndDlistDL[] = dgEndGrayscaleAndEndDlistDL; + +// This is used for the Temple of Time Medalions' color +#define dtokinoma_room_0DL_007A70 "__OTR__scenes/shared/tokinoma_scene/tokinoma_room_0DL_007A70" +static const ALIGN_ASSET(2) char tokinoma_room_0DL_007A70[] = dtokinoma_room_0DL_007A70; +#define dtokinoma_room_0DL_007FD0 "__OTR__scenes/shared/tokinoma_scene/tokinoma_room_0DL_007FD0" +static const ALIGN_ASSET(2) char tokinoma_room_0DL_007FD0[] = dtokinoma_room_0DL_007FD0; + // TODO: When there's more uses of something like this, create a new GI::RawAction? void ReloadSceneTogglingLinkAge() { gPlayState->nextEntranceIndex = gSaveContext.entranceIndex; @@ -1116,6 +1130,91 @@ void RegisterRandomizedEnemySizes() { }); } +void PatchToTMedallions() { + // TODO: Refactor the DemoEffect_UpdateJewelAdult and DemoEffect_UpdateJewelChild from z_demo_effect + // effects to take effect in there + if (CVarGetInteger("gToTMedallionsColors", 0)) { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_StartGrayscale", 7, gsSPGrayscale(true)); + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_StartGrayscale", 7, gsSPGrayscale(true)); + + if (CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER)) { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeBlue", 16, gsDPSetGrayscaleColor(0, 161, 255, 255)); + } else { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeBlue", 16, gsDPSetGrayscaleColor(255, 255, 255, 255)); + } + + if (CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT)) { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeOrange", 45, gsDPSetGrayscaleColor(255, 135, 0, 255)); + } else { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeOrange", 45, gsDPSetGrayscaleColor(255, 255, 255, 255)); + } + + if (CHECK_QUEST_ITEM(QUEST_MEDALLION_LIGHT)) { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeYellow", 69, gsDPSetGrayscaleColor(255, 255, 0, 255)); + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakeYellow", 16, gsDPSetGrayscaleColor(255, 255, 0, 255)); + } else { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeYellow", 69, gsDPSetGrayscaleColor(255, 255, 255, 255)); + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakeYellow", 16, gsDPSetGrayscaleColor(255, 255, 255, 255)); + } + + if (CHECK_QUEST_ITEM(QUEST_MEDALLION_FOREST)) { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeGreen", 94, gsDPSetGrayscaleColor(0, 255, 0, 255)); + } else { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeGreen", 94, gsDPSetGrayscaleColor(255, 255, 255, 255)); + } + + if (CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE)) { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeRed", 118, gsDPSetGrayscaleColor(255, 0, 0, 255)); + } else { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeRed", 118, gsDPSetGrayscaleColor(255, 255, 255, 255)); + } + + if (CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW)) { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakePurple", 142, gsDPSetGrayscaleColor(212, 0, 255, 255)); + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakePurple", 27, gsDPSetGrayscaleColor(212, 0, 255, 255)); + } else { + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakePurple", 142, gsDPSetGrayscaleColor(255, 255, 255, 255)); + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakePurple", 27, gsDPSetGrayscaleColor(255, 255, 255, 255)); + } + + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_EndGrayscaleAndEndDlist", 160, gsSPBranchListOTRFilePath(gEndGrayscaleAndEndDlistDL)); + ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_EndGrayscaleAndEndDlist", 51, gsSPBranchListOTRFilePath(gEndGrayscaleAndEndDlistDL)); + } else { + // Unpatch everything + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_StartGrayscale"); + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_StartGrayscale"); + + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeBlue"); + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeOrange"); + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeYellow"); + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakeYellow"); + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeRed"); + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakePurple"); + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakePurple"); + + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_EndGrayscaleAndEndDlist"); + ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_EndGrayscaleAndEndDlist"); + } +} + +void RegisterToTMedallionsFromItem() { + GameInteractor::Instance->RegisterGameHook([](GetItemEntry _unused) { + if (!CVarGetInteger("gToTMedallionsColors", 0) && gPlayState->sceneNum != SCENE_TEMPLE_OF_TIME) { + return; + } + PatchToTMedallions(); + }); +} + +void RegisterToTMedallionsFromScene() { + GameInteractor::Instance->RegisterGameHook([](int16_t sceneNum) { + if (!CVarGetInteger("gToTMedallionsColors", 0) && gPlayState->sceneNum != SCENE_TEMPLE_OF_TIME) { + return; + } + PatchToTMedallions(); + }); +} + void InitMods() { RegisterTTS(); RegisterInfiniteMoney(); @@ -1147,5 +1246,7 @@ void InitMods() { RegisterAltTrapTypes(); RegisterRandomizerSheikSpawn(); RegisterRandomizedEnemySizes(); + RegisterToTMedallionsFromItem(); + RegisterToTMedallionsFromScene(); NameTag_RegisterHooks(); } diff --git a/soh/soh/Enhancements/mods.h b/soh/soh/Enhancements/mods.h index 8125659ab..46123f968 100644 --- a/soh/soh/Enhancements/mods.h +++ b/soh/soh/Enhancements/mods.h @@ -9,6 +9,7 @@ extern "C" { void UpdateDirtPathFixState(int32_t sceneNum); void UpdateMirrorModeState(int32_t sceneNum); +void PatchToTMedallions(); void UpdatePermanentHeartLossState(); void InitMods(); diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index af836dff5..d7efeb4f3 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -243,6 +243,7 @@ const std::vector enhancementsCvars = { "gAddTraps.Speed", "gAddTraps.Tele", "gAddTraps.Void", + "gToTMedallionsColors", }; const std::vector cheatCvars = { @@ -791,6 +792,9 @@ const std::vector randomizerPresetEntries = { // Chest size & texture matches contents PRESET_ENTRY_S32("gChestSizeAndTextureMatchesContents", CSMC_BOTH), + // Color Temple of Time's Medallions + PRESET_ENTRY_S32("gToTMedallionsColors", 1), + // Pause link animation (0 to 16) PRESET_ENTRY_S32("gPauseLiveLink", 16), // Frames to wait diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 9a006fb86..a970e3686 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -994,6 +994,10 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Always shows dungeon entrance icons on the minimap"); UIWidgets::PaddedEnhancementCheckbox("Show Gauntlets in First Person", "gFPSGauntlets", true, false); UIWidgets::Tooltip("Renders Gauntlets when using the Bow and Hookshot like in OOT3D"); + if (UIWidgets::PaddedEnhancementCheckbox("Color Temple of Time's Medallions", "gToTMedallionsColors", true, false)) { + PatchToTMedallions(); + } + UIWidgets::Tooltip("When medallions are collected, the medallion imprints around the Master Sword pedestal in the Temple of Time will become colored"); UIWidgets::Spacer(0); if (ImGui::BeginMenu("Animated Link in Pause Menu")) { ImGui::Text("Rotation"); From f6a6b880c9aee1914c701ba0989e2f7884a67c39 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Thu, 28 Dec 2023 14:23:03 +0000 Subject: [PATCH 10/12] Only emit changed flags (#3489) --- soh/src/code/z_actor.c | 100 ++++++++++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 3b68f1211..cd17e1756 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -662,26 +662,32 @@ s32 Flags_GetSwitch(PlayState* play, s32 flag) { * Sets current scene switch flag. */ void Flags_SetSwitch(PlayState* play, s32 flag) { - lusprintf(__FILE__, __LINE__, 2, "Switch Flag Set - %#x", flag); + u8 previouslyOff = !Flags_GetSwitch(play, flag); if (flag < 0x20) { play->actorCtx.flags.swch |= (1 << flag); } else { play->actorCtx.flags.tempSwch |= (1 << (flag - 0x20)); } - GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_SWITCH, flag); + if (previouslyOff) { + LUSLOG_INFO("Switch Flag Set - %#x", flag); + GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_SWITCH, flag); + } } /** * Unsets current scene switch flag. */ void Flags_UnsetSwitch(PlayState* play, s32 flag) { - lusprintf(__FILE__, __LINE__, 2, "Switch Flag Unset - %#x", flag); + u8 previouslyOn = Flags_GetSwitch(play, flag); if (flag < 0x20) { play->actorCtx.flags.swch &= ~(1 << flag); } else { play->actorCtx.flags.tempSwch &= ~(1 << (flag - 0x20)); } - GameInteractor_ExecuteOnSceneFlagUnset(play->sceneNum, FLAG_SCENE_SWITCH, flag); + if (previouslyOn) { + LUSLOG_INFO("Switch Flag Unset - %#x", flag); + GameInteractor_ExecuteOnSceneFlagUnset(play->sceneNum, FLAG_SCENE_SWITCH, flag); + } } /** @@ -728,9 +734,12 @@ s32 Flags_GetTreasure(PlayState* play, s32 flag) { * Sets current scene chest flag. */ void Flags_SetTreasure(PlayState* play, s32 flag) { - lusprintf(__FILE__, __LINE__, 2, "Treasure Flag Set - %#x", flag); + u8 previouslyOff = !Flags_GetTreasure(play, flag); play->actorCtx.flags.chest |= (1 << flag); - GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_TREASURE, flag); + if (previouslyOff) { + LUSLOG_INFO("Treasure Flag Set - %#x", flag); + GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_TREASURE, flag); + } } /** @@ -744,16 +753,24 @@ s32 Flags_GetClear(PlayState* play, s32 flag) { * Sets current scene clear flag. */ void Flags_SetClear(PlayState* play, s32 flag) { + u8 previouslyOff = !Flags_GetClear(play, flag); play->actorCtx.flags.clear |= (1 << flag); - GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_CLEAR, flag); + if (previouslyOff) { + LUSLOG_INFO("Clear Flag Set - %#x", flag); + GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_CLEAR, flag); + } } /** * Unsets current scene clear flag. */ void Flags_UnsetClear(PlayState* play, s32 flag) { + u8 previouslyOn = Flags_GetClear(play, flag); play->actorCtx.flags.clear &= ~(1 << flag); - GameInteractor_ExecuteOnSceneFlagUnset(play->sceneNum, FLAG_SCENE_CLEAR, flag); + if (previouslyOn) { + LUSLOG_INFO("Clear Flag Unset - %#x", flag); + GameInteractor_ExecuteOnSceneFlagUnset(play->sceneNum, FLAG_SCENE_CLEAR, flag); + } } /** @@ -792,7 +809,7 @@ s32 Flags_GetCollectible(PlayState* play, s32 flag) { * Sets current scene collectible flag. */ void Flags_SetCollectible(PlayState* play, s32 flag) { - lusprintf(__FILE__, __LINE__, 2, "Collectible Flag Set - %#x", flag); + u8 previouslyOff = !Flags_GetCollectible(play, flag); if (flag != 0) { if (flag < 0x20) { play->actorCtx.flags.collect |= (1 << flag); @@ -800,7 +817,10 @@ void Flags_SetCollectible(PlayState* play, s32 flag) { play->actorCtx.flags.tempCollect |= (1 << (flag - 0x20)); } } - GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_COLLECTIBLE, flag); + if (previouslyOff) { + LUSLOG_INFO("Collectible Flag Set - %#x", flag); + GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_COLLECTIBLE, flag); + } } void func_8002CDE4(PlayState* play, TitleCardContext* titleCtx) { @@ -4723,16 +4743,24 @@ s32 Flags_GetEventChkInf(s32 flag) { * Sets "eventChkInf" flag. */ void Flags_SetEventChkInf(s32 flag) { + u8 previouslyOff = !Flags_GetEventChkInf(flag); gSaveContext.eventChkInf[flag >> 4] |= (1 << (flag & 0xF)); - GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_CHECK_INF, flag); + if (previouslyOff) { + LUSLOG_INFO("EventChkInf Flag Set - %#x", flag); + GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_CHECK_INF, flag); + } } /** * Unsets "eventChkInf" flag. */ void Flags_UnsetEventChkInf(s32 flag) { + u8 previouslyOn = Flags_GetEventChkInf(flag); gSaveContext.eventChkInf[flag >> 4] &= ~(1 << (flag & 0xF)); - GameInteractor_ExecuteOnFlagUnset(FLAG_EVENT_CHECK_INF, flag); + if (previouslyOn) { + LUSLOG_INFO("EventChkInf Flag Unset - %#x", flag); + GameInteractor_ExecuteOnFlagUnset(FLAG_EVENT_CHECK_INF, flag); + } } /** @@ -4746,16 +4774,24 @@ s32 Flags_GetItemGetInf(s32 flag) { * Sets "itemGetInf" flag. */ void Flags_SetItemGetInf(s32 flag) { + u8 previouslyOff = !Flags_GetItemGetInf(flag); gSaveContext.itemGetInf[flag >> 4] |= (1 << (flag & 0xF)); - GameInteractor_ExecuteOnFlagSet(FLAG_ITEM_GET_INF, flag); + if (previouslyOff) { + LUSLOG_INFO("ItemGetInf Flag Set - %#x", flag); + GameInteractor_ExecuteOnFlagSet(FLAG_ITEM_GET_INF, flag); + } } /** * Unsets "itemGetInf" flag. */ void Flags_UnsetItemGetInf(s32 flag) { + u8 previouslyOn = Flags_GetItemGetInf(flag); gSaveContext.itemGetInf[flag >> 4] &= ~(1 << (flag & 0xF)); - GameInteractor_ExecuteOnFlagUnset(FLAG_ITEM_GET_INF, flag); + if (previouslyOn) { + LUSLOG_INFO("ItemGetInf Flag Unset - %#x", flag); + GameInteractor_ExecuteOnFlagUnset(FLAG_ITEM_GET_INF, flag); + } } /** @@ -4769,16 +4805,24 @@ s32 Flags_GetInfTable(s32 flag) { * Sets "infTable" flag. */ void Flags_SetInfTable(s32 flag) { + u8 previouslyOff = !Flags_GetInfTable(flag); gSaveContext.infTable[flag >> 4] |= (1 << (flag & 0xF)); - GameInteractor_ExecuteOnFlagSet(FLAG_INF_TABLE, flag); + if (previouslyOff) { + LUSLOG_INFO("InfTable Flag Set - %#x", flag); + GameInteractor_ExecuteOnFlagSet(FLAG_INF_TABLE, flag); + } } /** * Unsets "infTable" flag. */ void Flags_UnsetInfTable(s32 flag) { + u8 previouslyOn = Flags_GetInfTable(flag); gSaveContext.infTable[flag >> 4] &= ~(1 << (flag & 0xF)); - GameInteractor_ExecuteOnFlagUnset(FLAG_INF_TABLE, flag); + if (previouslyOn) { + LUSLOG_INFO("InfTable Flag Unset - %#x", flag); + GameInteractor_ExecuteOnFlagUnset(FLAG_INF_TABLE, flag); + } } /** @@ -4792,16 +4836,24 @@ s32 Flags_GetEventInf(s32 flag) { * Sets "eventInf" flag. */ void Flags_SetEventInf(s32 flag) { + u8 previouslyOff = !Flags_GetEventInf(flag); gSaveContext.eventInf[flag >> 4] |= (1 << (flag & 0xF)); - GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_INF, flag); + if (previouslyOff) { + LUSLOG_INFO("EventInf Flag Set - %#x", flag); + GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_INF, flag); + } } /** * Unsets "eventInf" flag. */ void Flags_UnsetEventInf(s32 flag) { + u8 previouslyOn = Flags_GetEventInf(flag); gSaveContext.eventInf[flag >> 4] &= ~(1 << (flag & 0xF)); - GameInteractor_ExecuteOnFlagUnset(FLAG_EVENT_INF, flag); + if (previouslyOn) { + LUSLOG_INFO("EventInf Flag Unset - %#x", flag); + GameInteractor_ExecuteOnFlagUnset(FLAG_EVENT_INF, flag); + } } /** @@ -4815,16 +4867,24 @@ s32 Flags_GetRandomizerInf(RandomizerInf flag) { * Sets "randomizerInf" flag. */ void Flags_SetRandomizerInf(RandomizerInf flag) { + u8 previouslyOff = !Flags_GetRandomizerInf(flag); gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); - GameInteractor_ExecuteOnFlagSet(FLAG_RANDOMIZER_INF, flag); + if (previouslyOff) { + LUSLOG_INFO("RandomizerInf Flag Set - %#x", flag); + GameInteractor_ExecuteOnFlagSet(FLAG_RANDOMIZER_INF, flag); + } } /** * Unsets "randomizerInf" flag. */ void Flags_UnsetRandomizerInf(RandomizerInf flag) { + u8 previouslyOn = Flags_GetRandomizerInf(flag); gSaveContext.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); - GameInteractor_ExecuteOnFlagUnset(FLAG_RANDOMIZER_INF, flag); + if (previouslyOn) { + LUSLOG_INFO("RandomizerInf Flag Unset - %#x", flag); + GameInteractor_ExecuteOnFlagUnset(FLAG_RANDOMIZER_INF, flag); + } } u32 func_80035BFC(PlayState* play, s16 arg1) { From b80452b2b83d102fb1e9a2ddcf056a11969faf12 Mon Sep 17 00:00:00 2001 From: Patrick12115 <115201185+Patrick12115@users.noreply.github.com> Date: Thu, 28 Dec 2023 12:04:20 -0500 Subject: [PATCH 11/12] Multiplier (#3395) --- soh/soh/SohMenuBar.cpp | 2 ++ soh/src/overlays/actors/ovl_En_Niw/z_en_niw.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index a970e3686..e46051969 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -733,6 +733,8 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Always win the heart piece/purple rupee on the first dig in Dampe's grave digging game, just like in rando\nIn a rando file, this is unconditionally enabled"); UIWidgets::PaddedEnhancementCheckbox("All Dogs are Richard", "gAllDogsRichard", true, false); UIWidgets::Tooltip("All dogs can be traded in and will count as Richard."); + UIWidgets::PaddedEnhancementSliderInt("Cuccos Stay Put Multiplier: %dx", "##CuccoStayDurationMultiplier", "gCuccoStayDurationMultiplier", 1, 5, "", 1, true, true, false); + UIWidgets::Tooltip("Cuccos will stay in place longer after putting them down, by a multiple of the value of the slider."); UIWidgets::Spacer(0); if (ImGui::BeginMenu("Potion Values")) diff --git a/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.c b/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.c index ddc9aea65..91730e5bf 100644 --- a/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.c +++ b/soh/src/overlays/actors/ovl_En_Niw/z_en_niw.c @@ -666,7 +666,7 @@ void func_80AB6D08(EnNiw* this, PlayState* play) { } this->path = 1; - this->timer5 = 80; + this->timer5 = 80 * CVarGetInteger("gCuccoStayDurationMultiplier", 1); this->actor.speedXZ = 0.0f; this->actor.velocity.y = 4.0f; } else { From 81ec2805ee5b6c4fe28285750f8a174ac4691ff5 Mon Sep 17 00:00:00 2001 From: Patrick12115 <115201185+Patrick12115@users.noreply.github.com> Date: Thu, 28 Dec 2023 12:04:30 -0500 Subject: [PATCH 12/12] scaling (#3393) --- soh/soh/Enhancements/mods.cpp | 11 +++++++++++ soh/soh/SohMenuBar.cpp | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index d7123c570..275057bcf 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -1127,6 +1127,17 @@ void RegisterRandomizedEnemySizes() { } Actor_SetScale(actor, actor->scale.z * randomScale); + + if (CVarGetInteger("gEnemySizeScalesHealth", 0) && (actor->category == ACTORCAT_ENEMY)) { + // Scale the health based on a smaller factor than randomScale + float healthScalingFactor = 0.8f; // Adjust this factor as needed + float scaledHealth = actor->colChkInfo.health * (randomScale * healthScalingFactor); + + // Ensure the scaled health doesn't go below zero + actor->colChkInfo.health = fmax(scaledHealth, 1.0f); + } else { + return; + } }); } diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index e46051969..7c1f51cf1 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -1182,6 +1182,11 @@ void DrawEnhancementsMenu() { UIWidgets::PaddedEnhancementCheckbox("Randomized Enemy Sizes", "gRandomizedEnemySizes", true, false); UIWidgets::Tooltip("Enemies and Bosses spawn with random sizes."); + if (CVarGetInteger("gRandomizedEnemySizes", 0)) { + UIWidgets::EnhancementCheckbox("Scale Health with Size", "gEnemySizeScalesHealth"); + UIWidgets::Tooltip("Scales normal enemies health with their randomized size. *This will NOT affect bosses*"); + } + UIWidgets::PaddedEnhancementCheckbox("Ivan the Fairy (Coop Mode)", "gIvanCoopModeEnabled", true, false); UIWidgets::Tooltip("Enables Ivan the Fairy upon the next map change. Player 2 can control Ivan and " "press the C-Buttons to use items and mess with Player 1!");