diff options
| author | engineer124 <47598039+engineer124@users.noreply.github.com> | 2022-03-28 01:42:19 +1100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-27 11:42:19 -0300 |
| commit | f1d1173558e6fc01dfe7e884e29643d640db5a77 (patch) | |
| tree | d37e23af94d195ae6be43775b49865333169a498 /src | |
| parent | 9e230005b06a581983983fb8ab0a64860097a34d (diff) | |
River_Sound OK and Documented + River_Sound Related `z_actor`/`Audio` Functions (#661)
* First pass of `func_800BCCDC`
* river_sound OK (copy progress from audio WIP)
* Copy progress from `code_8019AF00.c` (still waiting for data to be imported)
* More docs
* feedback
* Add in `code_8019AF00.c` functions
* format
* params
* Minor cleanup
* Small fix
* one more
* Better names
* Add comment, cleanup Idx
* Fix bss
* Fix BSS
Diffstat (limited to 'src')
| -rw-r--r-- | src/code/audio/code_80192BE0.c | 2 | ||||
| -rw-r--r-- | src/code/audio/code_8019AF00.c | 293 | ||||
| -rw-r--r-- | src/code/audio/code_801A5BD0.c | 2 | ||||
| -rw-r--r-- | src/code/audio/code_801A7B10.c | 2 | ||||
| -rw-r--r-- | src/code/z_actor.c | 214 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_Bg_Hakugin_Post/z_bg_hakugin_post.c | 1 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.c | 69 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.h | 37 | ||||
| -rw-r--r-- | src/overlays/actors/ovl_En_Weather_Tag/z_en_weather_tag.c | 4 |
9 files changed, 514 insertions, 110 deletions
diff --git a/src/code/audio/code_80192BE0.c b/src/code/audio/code_80192BE0.c index cd430b5ce..d088db607 100644 --- a/src/code/audio/code_80192BE0.c +++ b/src/code/audio/code_80192BE0.c @@ -18,7 +18,7 @@ #pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_8019387C.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_801938A0.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/Audio_QueueCmdS8.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_801938D0.s") diff --git a/src/code/audio/code_8019AF00.c b/src/code/audio/code_8019AF00.c index 17404280b..0006122c2 100644 --- a/src/code/audio/code_8019AF00.c +++ b/src/code/audio/code_8019AF00.c @@ -66,6 +66,9 @@ typedef struct { /* 0xC */ s32 remainingFrames; } FreqLerp; // size = 0x10 +s32 Audio_SetGanonsTowerBgmVolume(u8 targetVolume); +void func_801A3238(s8 playerIndex, u16 seqId, u8 fadeTimer, s8 arg3, u8 arg4); + // Sfx bss SfxSettings sSfxSettings[8]; u8 sSfxSettingsFlags; @@ -2071,11 +2074,50 @@ const char sAudioOcarinaUnusedText7[] = "check is over!!! %d %d %d\n"; #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019FF38.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019FF9C.s") +/** + * Used for EnRiverSound + */ +void Audio_PlaySfxForRiver(Vec3f* pos, f32 freqScale) { + if (!Audio_IsSfxPlaying(NA_SE_EV_RIVER_STREAM - SFX_FLAG)) { + sRiverFreqScaleLerp.value = freqScale; + } else if (freqScale != sRiverFreqScaleLerp.value) { + sRiverFreqScaleLerp.target = freqScale; + sRiverFreqScaleLerp.remainingFrames = 40; + sRiverFreqScaleLerp.step = (sRiverFreqScaleLerp.target - sRiverFreqScaleLerp.value) / 40; + } + Audio_PlaySfxGeneral(NA_SE_EV_RIVER_STREAM - SFX_FLAG, pos, 4, &sRiverFreqScaleLerp.value, &D_801DB4B0, + &D_801DB4B8); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0048.s") +/** + * Unused remnant of OoT's EnRiverSound + * Used for Zora's River Waterfall + */ +void Audio_PlaySfxForWaterfall(Vec3f* pos, f32 freqScale) { + if (!Audio_IsSfxPlaying(NA_SE_EV_WATER_WALL_BIG - SFX_FLAG)) { + sWaterfallFreqScaleLerp.value = freqScale; + } else if (freqScale != sWaterfallFreqScaleLerp.value) { + sWaterfallFreqScaleLerp.target = freqScale; + sWaterfallFreqScaleLerp.remainingFrames = 40; + sWaterfallFreqScaleLerp.step = (sWaterfallFreqScaleLerp.target - sWaterfallFreqScaleLerp.value) / 40; + } + Audio_PlaySfxGeneral(NA_SE_EV_WATER_WALL_BIG - SFX_FLAG, pos, 4, &sWaterfallFreqScaleLerp.value, + &sWaterfallFreqScaleLerp.value, &D_801DB4B8); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A00EC.s") +/** + * Used for EnRiverSound variables + */ +void Audio_StepFreqLerp(FreqLerp* lerp) { + if (lerp->remainingFrames != 0) { + lerp->remainingFrames--; + if (lerp->remainingFrames != 0) { + lerp->value += lerp->step; + } else { + lerp->value = lerp->target; + } + } +} #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0124.s") @@ -2087,13 +2129,131 @@ const char sAudioOcarinaUnusedText7[] = "check is over!!! %d %d %d\n"; #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0238.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A026C.s") +/** + * Unused remnant from OoT's EnRiverSound + * Was designed to incrementally increase volume of NA_BGM_GANON_TOWER for each new room during the climb of Ganon's + * Tower + */ +void Audio_SetGanonsTowerBgmVolumeLevel(u8 ganonsTowerLevel) { + u8 channelIndex; + s8 pan = 0; + + // Ganondorfs's Lair + if (ganonsTowerLevel == 0) { + pan = 0x7F; + } + + for (channelIndex = 0; channelIndex < 16; channelIndex++) { + // CHAN_UPD_PAN_UNSIGNED + Audio_QueueCmdS8(((u8)(u32)channelIndex << 8) | 0x7000000, pan); + } + + // Lowest room in Ganon's Tower (Entrance Room) + if (ganonsTowerLevel == 7) { + // Adds a delay to setting the volume in the first room + sEnterGanonsTowerTimer = 2; + } else { + Audio_SetGanonsTowerBgmVolume(sGanonsTowerLevelsVol[ganonsTowerLevel % ARRAY_COUNTU(sGanonsTowerLevelsVol)]); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0318.s") +/** + * Unused remnant from OoT's EnRiverSound + * If a new volume is requested for ganon's tower, update the volume and + * calculate a new low-pass filter cutoff and reverb based on the new volume + */ +s32 Audio_SetGanonsTowerBgmVolume(u8 targetVolume) { + u8 lowPassFilterCutoff; + u8 channelIndex; + u16 reverb; + + if (sGanonsTowerVol != targetVolume) { + // Sets the volume + Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 0, targetVolume, 2); + + // Sets the filter cutoff of the form (lowPassFilterCutoff << 4) | (highPassFilter & 0xF). highPassFilter is + // always set to 0 + if (targetVolume < 0x40) { + // Only the first room + lowPassFilterCutoff = 0x10; + } else { + // Higher volume leads to a higher cut-off frequency in the low-pass filtering + lowPassFilterCutoff = (((targetVolume - 0x40) >> 2) + 1) << 4; + } + + Audio_QueueSeqCmd((8 << 28) | ((u8)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u8)(4) << 16) | ((u8)(15) << 8) | + (u8)(lowPassFilterCutoff)); + + // Sets the reverb + for (channelIndex = 0; channelIndex < ARRAY_COUNT(gAudioContext.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels); + channelIndex++) { + if (&gAudioContext.sequenceChannelNone != + gAudioContext.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels[channelIndex]) { + // soundScriptIO[5] was set to 0x40 in channels 0, 1, and 4 (BGM no longer in OoT) + if ((u8)gAudioContext.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels[channelIndex]->soundScriptIO[5] != + 0xFF) { + // Higher volume leads to lower reverb + reverb = + (((u16)gAudioContext.seqPlayers[SEQ_PLAYER_BGM_MAIN].channels[channelIndex]->soundScriptIO[5] - + targetVolume) + + 0x7F); + + if (reverb > 0x7F) { + reverb = 0x7F; + } + + // CHAN_UPD_REVERB + Audio_QueueCmdS8(_SHIFTL(5, 24, 8) | _SHIFTL(SEQ_PLAYER_BGM_MAIN, 16, 8) | + _SHIFTL(channelIndex, 8, 8), + (u8)reverb); + } + } + } + + sGanonsTowerVol = targetVolume; + } + return -1; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0450.s") +/** + * Unused remnant from OoT's EnRiverSound + * Responsible for lowering market bgm in Child Market Entrance and Child Market Back Alley + * Only lowers volume for 1 frame, so must be called every frame to maintain lower volume + */ +void Audio_LowerMainBgmVolume(u8 volume) { + sRiverSoundMainBgmVol = volume; + sRiverSoundMainBgmLower = true; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A046C.s") +/** + * Unused remnant from OoT's EnRiverSound + * Still called by Audio_Update every frame, but none of these processes get initialized + */ +void Audio_UpdateRiverSoundVolumes(void) { + // Updates Main Bgm Volume (RiverSound of type RS_LOWER_MAIN_BGM_VOLUME) + if (sRiverSoundMainBgmLower == true) { + if (sRiverSoundMainBgmCurrentVol != sRiverSoundMainBgmVol) { + // lowers the volume for 1 frame + Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 0, sRiverSoundMainBgmVol, 10); + sRiverSoundMainBgmCurrentVol = sRiverSoundMainBgmVol; + sRiverSoundMainBgmRestore = true; + } + sRiverSoundMainBgmLower = false; + } else if ((sRiverSoundMainBgmRestore == true) && !sAudioIsWindowOpen) { + // restores the volume every frame + Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 0, 0x7F, 10); + sRiverSoundMainBgmCurrentVol = 0x7F; + sRiverSoundMainBgmRestore = false; + } + + // Update Ganon's Tower Volume (RiverSound of type RS_GANON_TOWER_7) + if (sEnterGanonsTowerTimer != 0) { + sEnterGanonsTowerTimer--; + if (sEnterGanonsTowerTimer == 0) { + Audio_SetGanonsTowerBgmVolume(sGanonsTowerLevelsVol[7]); + } + } +} #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0554.s") @@ -2107,13 +2267,71 @@ const char sAudioOcarinaUnusedText7[] = "check is over!!! %d %d %d\n"; #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0868.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A09D4.s") +/** + * Unused remnant of OoT's EnRiverSound (func_800F4E30) + */ +void func_801A09D4(Vec3f* pos, f32 xzDistToPlayer) { + f32 volumeRel; + s8 pan; + u8 channelIndex; + + if (sRiverSoundBgmPos == NULL) { + sRiverSoundBgmPos = pos; + sRiverSoundXZDistToPlayer = xzDistToPlayer; + } else if (sRiverSoundBgmPos != pos) { + if (sRiverSoundXZDistToPlayer > xzDistToPlayer) { + sRiverSoundBgmPos = pos; + sRiverSoundXZDistToPlayer = xzDistToPlayer; + } + } else { + sRiverSoundXZDistToPlayer = xzDistToPlayer; + } + + if (sRiverSoundBgmPos->x > 100.0f) { + pan = 0x7F; + } else if (sRiverSoundBgmPos->x < -100.0f) { + pan = 0; + } else { + pan = ((sRiverSoundBgmPos->x / 100.0f) * 64.0f) + 64.0f; + } + + if (sRiverSoundXZDistToPlayer > 400.0f) { + volumeRel = 0.1f; + } else if (sRiverSoundXZDistToPlayer < 120.0f) { + volumeRel = 1.0f; + } else { + volumeRel = ((1.0f - ((sRiverSoundXZDistToPlayer - 120.0f) / 280.0f)) * 0.9f) + 0.1f; + } + + for (channelIndex = 0; channelIndex < 16; channelIndex++) { + if (channelIndex != 9) { + Audio_QueueSeqCmd(((u32)(6) << 28) | ((u32)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u32)(2) << 16) | + ((u32)(channelIndex) << 8) | ((u8)(127.0f * volumeRel))); + Audio_QueueCmdS8(0x03000000 | ((u8)((u32)channelIndex) << 8), pan); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0C70.s") +/** + * Unused remnant of OoT's EnRiverSound + */ +void Audio_ClearSariaBgm(void) { + if (sRiverSoundBgmPos != NULL) { + sRiverSoundBgmPos = NULL; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0C90.s") +/** + * Unused remnant of OoT's EnRiverSound + */ +void Audio_ClearSariaBgmAtPos(Vec3f* pos) { + if (sRiverSoundBgmPos == pos) { + sRiverSoundBgmPos = NULL; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0CB0.s") +void Audio_SplitBgmChannels(s8 volumeSplit); +#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/Audio_SplitBgmChannels.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0E44.s") @@ -2147,9 +2365,58 @@ const char sAudioOcarinaUnusedText7[] = "check is over!!! %d %d %d\n"; #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A2090.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A21FC.s") +/** + * Unused remnant of OoT's EnRiverSound + */ +void Audio_PlaySariaBgm(Vec3f* pos, u16 seqId, u16 distMax) { + f32 absY; + f32 dist; + u8 targetVolume; + f32 prevDist; + + if (sRiverSoundBgmTimer != 0) { + sRiverSoundBgmTimer--; + return; + } + + dist = sqrtf(SQ(pos->z) + (SQ(pos->x) + SQ(pos->y))); + + if (sRiverSoundBgmPos == NULL) { + sRiverSoundBgmPos = pos; + func_801A3238(SEQ_PLAYER_BGM_SUB, seqId, 0, 7, 2); + } else { + prevDist = sqrtf(SQ(sRiverSoundBgmPos->z) + SQ(sRiverSoundBgmPos->x)); + if (dist < prevDist) { + sRiverSoundBgmPos = pos; + } else { + dist = prevDist; + } + } + + absY = ABS_ALT(pos->y); + + if ((distMax / 15.0f) < absY) { + targetVolume = 0; + } else if (dist < distMax) { + targetVolume = (1.0f - (dist / distMax)) * 127.0f; + } else { + targetVolume = 0; + } + + if (seqId != NA_BGM_FAIRY_FOUNTAIN) { + Audio_SplitBgmChannels(targetVolume); + } + + Audio_SetVolumeScale(SEQ_PLAYER_BGM_SUB, 3, targetVolume, 0); + Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 3, 0x7F - targetVolume, 0); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A2460.s") +/** + * Unused remnant of OoT's EnRiverSound + */ +void Audio_ClearSariaBgm2(void) { + sRiverSoundBgmPos = NULL; +} #pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A246C.s") diff --git a/src/code/audio/code_801A5BD0.c b/src/code/audio/code_801A5BD0.c index 7d796aa9f..8397fd52e 100644 --- a/src/code/audio/code_801A5BD0.c +++ b/src/code/audio/code_801A5BD0.c @@ -40,6 +40,6 @@ #pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A787C.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A78E4.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_IsSfxPlaying.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A794C.s") diff --git a/src/code/audio/code_801A7B10.c b/src/code/audio/code_801A7B10.c index d2d9a71a2..6d3faaeab 100644 --- a/src/code/audio/code_801A7B10.c +++ b/src/code/audio/code_801A7B10.c @@ -18,7 +18,7 @@ #pragma GLOBAL_ASM("asm/non_matchings/code/code_801A7B10/func_801A8B2C.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A7B10/func_801A8BD0.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A7B10/Audio_SetVolumeScale.s") #pragma GLOBAL_ASM("asm/non_matchings/code/code_801A7B10/func_801A8D5C.s") diff --git a/src/code/z_actor.c b/src/code/z_actor.c index c8e490311..6b7c863aa 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -3908,104 +3908,148 @@ Hilite* func_800BCC68(Vec3f* arg0, GlobalContext* globalCtx) { return Hilite_DrawXlu(arg0, &globalCtx->view.eye, &lightDir, globalCtx->state.gfxCtx); } -void func_800BCCDC(Vec3s* points, s32 pathCount, Vec3f* pos1, Vec3f* pos2, s32 arg4) { - s32 spB4; - s32 spB0; - s32 spA8[2] = { 0, 0 }; - s32 spA0[2] = { 0, 0 }; - Vec3f sp94; - Vec3f sp7C[2]; - Vec3f sp70; - Vec3f sp64; - f32 sp60; - f32 sp5C; - f32 sp54[2]; - - spB0 = 0; - sp5C = SQ(40000.0f); - - for (spB4 = 0; spB4 < pathCount; spB4++) { - sp60 = Math3D_XZDistanceSquared(pos1->x, pos1->z, points[spB4].x, points[spB4].z); - if (sp60 < sp5C) { - sp5C = sp60; - spB0 = spB4; - } - } - - sp94.x = (points + spB0)->x; - sp94.z = (points + spB0)->z; - pos2->y = (points + spB0)->y; - if (spB0 != 0) { - sp64.x = (points + spB0 - 1)->x; - sp64.z = (points + spB0 - 1)->z; - } else if (arg4) { - sp64.x = (points + pathCount - 1)->x; - sp64.z = (points + pathCount - 1)->z; - } - - if ((spB0 != 0) || arg4) { - spA8[0] = - Math3D_PointDistToLine2D(pos1->x, pos1->z, sp64.x, sp64.z, sp94.x, sp94.z, &sp7C[0].x, &sp7C[0].z, &sp60); - } +/** + * Calculates the closest position `dstPos` to the input position `srcPos` along the path given by `points`/`numPoints` + * Whether the points provided forms a closed-loop path is indicated by `isPathLoop` + */ +void Actor_GetClosestPosOnPath(Vec3s* points, s32 numPoints, Vec3f* srcPos, Vec3f* dstPos, s32 isPathLoop) { + s32 pointIndex; + s32 closestPointIndex; + s32 useAdjacentLines[2] = { + false, // determines whether to use line connecting to previous point in calculations + false, // determines whether to use line connecting to next point in calculations + }; + s32 isRightSideOfAdjacentLines[2] = { + false, // determines whether srcPos is on the right side of the line from prev to curr point + false, // determines whether srcPos is on the right side of the line from curr to next point + }; + Vec3f closestPoint; + Vec3f closestPos[2]; + Vec3f closestPointNext; + Vec3f closestPointPrev; + f32 distSq; // First used as distSq to closest point, then used as distSq to closest position + f32 closestPointDistSq; + f32 loopDistSq[2]; + s32 i; - if (spB0 + 1 != pathCount) { - sp70.x = (points + spB0 + 1)->x; - sp70.z = (points + spB0 + 1)->z; - } else if (arg4) { - sp70.x = points->x; - sp70.z = points->z; - } + closestPointIndex = 0; + closestPointDistSq = SQ(40000.0f); - if ((spB0 + 1 != pathCount) || arg4) { - spA8[1] = - Math3D_PointDistToLine2D(pos1->x, pos1->z, sp94.x, sp94.z, sp70.x, sp70.z, &sp7C[1].x, &sp7C[1].z, &sp60); + // Find the point closest to srcPos + for (pointIndex = 0; pointIndex < numPoints; pointIndex++) { + distSq = Math3D_XZDistanceSquared(srcPos->x, srcPos->z, points[pointIndex].x, points[pointIndex].z); + if (distSq < closestPointDistSq) { + closestPointDistSq = distSq; + closestPointIndex = pointIndex; + } } - if (arg4) { - s32 phi_s0_2; - - spA0[0] = ((sp64.x - pos1->x) * (sp94.z - pos1->z)) < ((sp64.z - pos1->z) * (sp94.x - pos1->x)); - spA0[1] = ((sp70.z - pos1->z) * (sp94.x - pos1->x)) < ((sp94.z - pos1->z) * (sp70.x - pos1->x)); - - for (phi_s0_2 = 0; phi_s0_2 < ARRAY_COUNT(sp54); phi_s0_2++) { - if (spA8[phi_s0_2] != 0) { - sp54[phi_s0_2] = Math3D_XZDistanceSquared(pos1->x, pos1->z, sp7C[phi_s0_2].x, sp7C[phi_s0_2].z); + closestPoint.x = (points + closestPointIndex)->x; + closestPoint.z = (points + closestPointIndex)->z; + dstPos->y = (points + closestPointIndex)->y; + + // Analyze point on path immediately previous to the closest point + if (closestPointIndex != 0) { + // The point previous to the closest point + closestPointPrev.x = (points + closestPointIndex - 1)->x; + closestPointPrev.z = (points + closestPointIndex - 1)->z; + } else if (isPathLoop) { + // Closest point is the first point in the path list + // Set the previous point to loop around to the the final point on the path + closestPointPrev.x = (points + numPoints - 1)->x; + closestPointPrev.z = (points + numPoints - 1)->z; + } + if ((closestPointIndex != 0) || isPathLoop) { + // Use the adjacent line + useAdjacentLines[0] = + Math3D_PointDistToLine2D(srcPos->x, srcPos->z, closestPointPrev.x, closestPointPrev.z, closestPoint.x, + closestPoint.z, &closestPos[0].x, &closestPos[0].z, &distSq); + } + + // Analyze point on path immediately next to the closest point + if (closestPointIndex + 1 != numPoints) { + // The point next to the closest point + closestPointNext.x = (points + closestPointIndex + 1)->x; + closestPointNext.z = (points + closestPointIndex + 1)->z; + } else if (isPathLoop) { + // Closest point is the final point in the path list + // Set the next point to loop around to the the first point on the path + closestPointNext.x = (points + 0)->x; + closestPointNext.z = (points + 0)->z; + } + if ((closestPointIndex + 1 != numPoints) || isPathLoop) { + useAdjacentLines[1] = + Math3D_PointDistToLine2D(srcPos->x, srcPos->z, closestPoint.x, closestPoint.z, closestPointNext.x, + closestPointNext.z, &closestPos[1].x, &closestPos[1].z, &distSq); + } + + /** + * For close-looped paths, they must be defined in a clockwise orientation looking from the top down. + * Therefore, `srcPos` being interior of the loop will lead to both lines of `isRightSideOfAdjacentLines` + * returning true. + */ + if (isPathLoop) { + isRightSideOfAdjacentLines[0] = ((closestPointPrev.x - srcPos->x) * (closestPoint.z - srcPos->z)) < + ((closestPointPrev.z - srcPos->z) * (closestPoint.x - srcPos->x)); + + isRightSideOfAdjacentLines[1] = ((closestPointNext.z - srcPos->z) * (closestPoint.x - srcPos->x)) < + ((closestPoint.z - srcPos->z) * (closestPointNext.x - srcPos->x)); + + for (i = 0; i < ARRAY_COUNT(loopDistSq); i++) { + if (useAdjacentLines[i]) { + // Get distSq from srcPos to closestPos + loopDistSq[i] = Math3D_XZDistanceSquared(srcPos->x, srcPos->z, closestPos[i].x, closestPos[i].z); } else { - sp54[phi_s0_2] = SQ(40000.0f); + // The closest Pos is not contained within the line-segment + loopDistSq[i] = SQ(40000.0f); } } } - if (arg4 && (((spA0[0] != 0) && (spA0[1] != 0)) || ((spA0[0] != 0) && (spA8[0] != 0) && (sp54[0] < sp54[1])) || - ((spA0[1] != 0) && (spA8[1] != 0) && (sp54[1] < sp54[0])))) { - pos2->x = pos1->x; - pos2->z = pos1->z; - } else if ((spA8[0] != 0) && (spA8[1] != 0)) { - if ((spA0[0] == 0) && (spA0[1] == 0)) { - if (Math3D_PointDistToLine2D(pos1->x, pos1->z, sp7C[0].x, sp7C[0].z, sp7C[1].x, sp7C[1].z, &pos2->x, - &pos2->z, &sp60) == 0) { - pos2->x = (sp7C[1].x + sp7C[0].x) * 0.5f; - pos2->z = (sp7C[1].z + sp7C[0].z) * 0.5f; + // Calculate closest position along path + if (isPathLoop && ((isRightSideOfAdjacentLines[0] && isRightSideOfAdjacentLines[1]) || + (isRightSideOfAdjacentLines[0] && useAdjacentLines[0] && (loopDistSq[0] < loopDistSq[1])) || + (isRightSideOfAdjacentLines[1] && useAdjacentLines[1] && (loopDistSq[1] < loopDistSq[0])))) { + // srcPos is contained within the closed loop + dstPos->x = srcPos->x; + dstPos->z = srcPos->z; + } else if (useAdjacentLines[0] && useAdjacentLines[1]) { + // srcPos is somewhere withing the bend of the path + if (!isRightSideOfAdjacentLines[0] && !isRightSideOfAdjacentLines[1]) { + // srcPos is not inside a loop + if (!Math3D_PointDistToLine2D(srcPos->x, srcPos->z, closestPos[0].x, closestPos[0].z, closestPos[1].x, + closestPos[1].z, &dstPos->x, &dstPos->z, &distSq)) { + // The dstPos calculated in Math3D_PointDistToLine2D was not valid. + // Take the midpoint of the two closest ponits instead + dstPos->x = (closestPos[1].x + closestPos[0].x) * 0.5f; + dstPos->z = (closestPos[1].z + closestPos[0].z) * 0.5f; } - } else if (sp54[1] < sp54[0]) { - pos2->x = sp7C[1].x; - pos2->z = sp7C[1].z; + } else if (loopDistSq[1] < loopDistSq[0]) { + // Use closest position along the line in the loop connecting the closest point and the next point + dstPos->x = closestPos[1].x; + dstPos->z = closestPos[1].z; } else { - pos2->x = sp7C[0].x; - pos2->z = sp7C[0].z; + // Use closest position along the ling in the loop connecting the closest point and the prev point + dstPos->x = closestPos[0].x; + dstPos->z = closestPos[0].z; } - } else if (spA8[0] != 0) { - pos2->x = sp7C[0].x; - pos2->z = sp7C[0].z; - } else if (spA8[1] != 0) { - pos2->x = sp7C[1].x; - pos2->z = sp7C[1].z; - } else if (arg4 && ((((sp64.x - pos1->x) * (sp70.z - pos1->z)) < ((sp64.z - pos1->z) * (sp70.x - pos1->x))))) { - pos2->x = pos1->x; - pos2->z = pos1->z; + } else if (useAdjacentLines[0]) { + // Use closest position along line segment connecting the closest point and the prev point + dstPos->x = closestPos[0].x; + dstPos->z = closestPos[0].z; + } else if (useAdjacentLines[1]) { + // Use closest position along line segment connecting the closest point and the next point + dstPos->x = closestPos[1].x; + dstPos->z = closestPos[1].z; + } else if (isPathLoop && ((((closestPointPrev.x - srcPos->x) * (closestPointNext.z - srcPos->z)) < + ((closestPointPrev.z - srcPos->z) * (closestPointNext.x - srcPos->x))))) { + // Inside the line that directly connects the previous point to the next point (inside the bend of a corner) + dstPos->x = srcPos->x; + dstPos->z = srcPos->z; } else { - pos2->x = sp94.x; - pos2->z = sp94.z; + // The closest point and the closest position are the same (srcPos is near the outer region of a corner) + dstPos->x = closestPoint.x; + dstPos->z = closestPoint.z; } } diff --git a/src/overlays/actors/ovl_Bg_Hakugin_Post/z_bg_hakugin_post.c b/src/overlays/actors/ovl_Bg_Hakugin_Post/z_bg_hakugin_post.c index 1139f6ef4..1ad88f3f8 100644 --- a/src/overlays/actors/ovl_Bg_Hakugin_Post/z_bg_hakugin_post.c +++ b/src/overlays/actors/ovl_Bg_Hakugin_Post/z_bg_hakugin_post.c @@ -7,6 +7,7 @@ #include "prevent_bss_reordering.h" #include "z_bg_hakugin_post.h" #include "objects/object_hakugin_obj/object_hakugin_obj.h" +#include "prevent_bss_reordering.h" #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20) diff --git a/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.c b/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.c index db20137b1..2084130ce 100644 --- a/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.c +++ b/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.c @@ -1,7 +1,7 @@ /* * File: z_en_river_sound.c * Overlay: ovl_En_River_Sound - * Description: Various environment Sfx (e.g., ocean waves, gulls, waterfall, lava, etc) + * Description: Various environment Sfx along a path (e.g., ocean waves, gulls, waterfall, lava, etc) */ #include "z_en_river_sound.h" @@ -14,7 +14,6 @@ void EnRiverSound_Init(Actor* thisx, GlobalContext* globalCtx); void EnRiverSound_Update(Actor* thisx, GlobalContext* globalCtx); void EnRiverSound_Draw(Actor* thisx, GlobalContext* globalCtx); -#if 0 const ActorInit En_River_Sound_InitVars = { ACTOR_EN_RIVER_SOUND, ACTORCAT_ITEMACTION, @@ -27,10 +26,68 @@ const ActorInit En_River_Sound_InitVars = { (ActorFunc)EnRiverSound_Draw, }; -#endif +void EnRiverSound_Init(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnRiverSound* this = THIS; + Path* path; + s32 pathIndex; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_River_Sound/EnRiverSound_Init.s") + this->playSound = false; + pathIndex = RS_GET_PATH_INDEX(&this->actor); + this->actor.params = RS_GET_TYPE(&this->actor); + if (pathIndex == 0xFF) { + Actor_MarkForDeath(&this->actor); + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_River_Sound/EnRiverSound_Update.s") + path = &globalCtx->setupPathList[pathIndex]; + this->pathPoints = Lib_SegmentedToVirtual(path->points); + this->numPoints = path->count; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_River_Sound/EnRiverSound_Draw.s") +void EnRiverSound_Update(Actor* thisx, GlobalContext* globalCtx) { + EnRiverSound* this = THIS; + Vec3f* worldPos = &this->actor.world.pos; + Vec3f eye; + s32 bgId; + + Math_Vec3f_Copy(&eye, &globalCtx->view.eye); + + if (this->actor.params < RS_RIVER_DEFAULT_LOW_FREQ) { + // All sfx from river_sound that accesses gAudioEnvironmentalSfx is associated with a closed-loop + // path that is used to play a regional sfx + Actor_GetClosestPosOnPath(this->pathPoints, this->numPoints, &eye, worldPos, true); + } else { + Actor_GetClosestPosOnPath(this->pathPoints, this->numPoints, &eye, worldPos, false); + if (BgCheck_EntityRaycastFloor5(&globalCtx->colCtx, &this->actor.floorPoly, &bgId, &this->actor, worldPos) != + BGCHECK_Y_MIN) { + this->soundFreqIndex = SurfaceType_GetConveyorSpeed(&globalCtx->colCtx, this->actor.floorPoly, bgId); + } else { + this->soundFreqIndex = 0; + } + + if (this->soundFreqIndex == 0) { + this->soundFreqIndex = this->actor.params - RS_RIVER_DEFAULT_LOW_FREQ; + } else { + this->soundFreqIndex--; + } + + this->soundFreqIndex = CLAMP_MAX(this->soundFreqIndex, 2); + } +} + +void EnRiverSound_Draw(Actor* thisx, GlobalContext* globalCtx) { + static f32 freqScale[] = { + 0.7f, // 1 / sqrt(2) + 1.0f, // 1 + 1.4f, // sqrt(2) + }; + EnRiverSound* this = THIS; + s16 params = this->actor.params; + + if (params < RS_RIVER_DEFAULT_LOW_FREQ) { + Actor_PlaySfxAtPos(&this->actor, gAudioEnvironmentalSfx[params]); + } else { + Audio_PlaySfxForRiver(&this->actor.projectedPos, freqScale[this->soundFreqIndex]); + } +} diff --git a/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.h b/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.h index dc02f58fa..b8dbcc513 100644 --- a/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.h +++ b/src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.h @@ -5,9 +5,44 @@ struct EnRiverSound; +#define RS_GET_TYPE(thisx) ((thisx)->params & 0xFF); +#define RS_GET_PATH_INDEX(thisx) (((thisx)->params >> 8) & 0xFF); + +// Any param not as one of these values will result in UB +typedef enum { + /* 0x00 */ RS_RIVER_STREAM, + /* 0x01 */ RS_WAVE, + /* 0x02 */ RS_WATER_WALL_BIG, + /* 0x03 */ RS_WATER_WALL, + /* 0x04 */ RS_MAGMA_LEVEL, + /* 0x05 */ RS_MAGMA_LEVEL_M, + /* 0x06 */ RS_MAGMA_LEVEL_L, + /* 0x07 */ RS_TORCH, + /* 0x08 */ RS_FOUNTAIN, + /* 0x09 */ RS_DRAIN, + /* 0x0A */ RS_CROWD, + /* 0x0B */ RS_WATER_CONVECTION, + /* 0x0C */ RS_GORON_CHEER, + /* 0x0D */ RS_WATER_WALL_BIG_SILENT, + /* 0x0E */ RS_WATER_BUBBLE, + /* 0x0F */ RS_COW_CRY_LV, + /* 0x10 */ RS_MAKE_TURRET, + /* 0x11 */ RS_BOILED_WATER_S, + /* 0x12 */ RS_BOILED_WATER_L, + /* 0x13 */ RS_WAVE_0, + /* 0x14 */ RS_WAVE_1, + /* 0x15 */ RS_WAVE_2, + /* 0xFD */ RS_RIVER_DEFAULT_LOW_FREQ = 0xFD, + /* 0xFE */ RS_RIVER_DEFAULT_MEDIUM_FREQ, + /* 0xFF */ RS_RIVER_DEFAULT_HIGH_FREQ +} RiverSoundType; + typedef struct EnRiverSound { /* 0x000 */ Actor actor; - /* 0x144 */ char unk_144[0x8]; + /* 0x144 */ u8 playSound; // Unused remnant of OoT + /* 0x145 */ u8 soundFreqIndex; + /* 0x146 */ u8 numPoints; + /* 0x148 */ Vec3s* pathPoints; } EnRiverSound; // size = 0x14C extern const ActorInit En_River_Sound_InitVars; diff --git a/src/overlays/actors/ovl_En_Weather_Tag/z_en_weather_tag.c b/src/overlays/actors/ovl_En_Weather_Tag/z_en_weather_tag.c index 7e025ce43..88c7a3778 100644 --- a/src/overlays/actors/ovl_En_Weather_Tag/z_en_weather_tag.c +++ b/src/overlays/actors/ovl_En_Weather_Tag/z_en_weather_tag.c @@ -422,8 +422,8 @@ void func_809672DC(EnWeatherTag* this, GlobalContext* globalCtx) { f32 range; f32 strength = 0.0f; - func_800BCCDC(this->pathPoints, this->pathCount, &GET_PLAYER(globalCtx)->actor.world.pos, &this->actor.world.pos, - 0); + Actor_GetClosestPosOnPath(this->pathPoints, this->pathCount, &GET_PLAYER(globalCtx)->actor.world.pos, + &this->actor.world.pos, false); distance = Actor_XZDistanceBetweenActors(&player->actor, &this->actor); range = WEATHER_TAG_RANGE100(this); |
