summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorengineer124 <47598039+engineer124@users.noreply.github.com>2022-03-28 01:42:19 +1100
committerGitHub <noreply@github.com>2022-03-27 11:42:19 -0300
commitf1d1173558e6fc01dfe7e884e29643d640db5a77 (patch)
treed37e23af94d195ae6be43775b49865333169a498 /src
parent9e230005b06a581983983fb8ab0a64860097a34d (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.c2
-rw-r--r--src/code/audio/code_8019AF00.c293
-rw-r--r--src/code/audio/code_801A5BD0.c2
-rw-r--r--src/code/audio/code_801A7B10.c2
-rw-r--r--src/code/z_actor.c214
-rw-r--r--src/overlays/actors/ovl_Bg_Hakugin_Post/z_bg_hakugin_post.c1
-rw-r--r--src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.c69
-rw-r--r--src/overlays/actors/ovl_En_River_Sound/z_en_river_sound.h37
-rw-r--r--src/overlays/actors/ovl_En_Weather_Tag/z_en_weather_tag.c4
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);