mirror of
https://github.com/zeldaret/oot.git
synced 2025-07-03 06:24:30 +00:00
Improve River_Sound Docs (#1100)
* river_sound docs * Small touch-up * PR Suggestions * Improve comments on river line calculations * More PR Feedback * after analyzing the filter data for MM, lowPassFilter is reverse to what I thought it was
This commit is contained in:
parent
9fec455805
commit
9450272503
5 changed files with 255 additions and 178 deletions
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* File: z_en_river_sound.c
|
||||
* Overlay: ovl_En_River_Sound
|
||||
* Description: Ambient Sound Effects
|
||||
* Description: Controls various sounds. Includes sound effects and bgms
|
||||
*/
|
||||
|
||||
#include "z_en_river_sound.h"
|
||||
|
@ -28,17 +28,18 @@ const ActorInit En_River_Sound_InitVars = {
|
|||
void EnRiverSound_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
EnRiverSound* this = (EnRiverSound*)thisx;
|
||||
|
||||
this->playSound = 0;
|
||||
this->playSound = false;
|
||||
this->pathIndex = (this->actor.params >> 8) & 0xFF;
|
||||
this->actor.params = this->actor.params & 0xFF;
|
||||
|
||||
if (this->actor.params >= RS_MAX) { // used for ganon and ganon_boss scenes
|
||||
func_800F4870(this->actor.params - RS_MAX);
|
||||
if (this->actor.params >= RS_GANON_TOWER_0) {
|
||||
// Incrementally increase volume of NA_BGM_GANON_TOWER for each new room during the climb of Ganon's Tower
|
||||
Audio_SetGanonsTowerBgmVolumeLevel(this->actor.params - RS_GANON_TOWER_0);
|
||||
Actor_Kill(&this->actor);
|
||||
} else if (this->actor.params == RS_UNK_F7) {
|
||||
} else if (this->actor.params == RS_NATURE_AMBIENCE) {
|
||||
Audio_PlayNatureAmbienceSequence(NATURE_ID_KOKIRI_REGION);
|
||||
Actor_Kill(&this->actor);
|
||||
} else if (this->actor.params == RS_SARIAS_SONG) {
|
||||
} else if (this->actor.params == RS_LOST_WOODS_SARIAS_SONG) {
|
||||
if (!CHECK_QUEST_ITEM(QUEST_SONG_LULLABY) || CHECK_QUEST_ITEM(QUEST_SONG_SARIA)) {
|
||||
Actor_Kill(&this->actor);
|
||||
}
|
||||
|
@ -48,37 +49,57 @@ void EnRiverSound_Init(Actor* thisx, GlobalContext* globalCtx) {
|
|||
void EnRiverSound_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
||||
EnRiverSound* this = (EnRiverSound*)thisx;
|
||||
|
||||
if (this->actor.params == RS_SARIAS_SONG) {
|
||||
if (this->actor.params == RS_LOST_WOODS_SARIAS_SONG) {
|
||||
Audio_ClearSariaBgmAtPos(&this->actor.projectedPos);
|
||||
} else if (this->actor.params == RS_UNK_13) {
|
||||
} else if (this->actor.params == RS_GORON_CITY_SARIAS_SONG) {
|
||||
Audio_ClearSariaBgm2();
|
||||
}
|
||||
}
|
||||
|
||||
s32 func_80AE6A54(Vec3f* arg0, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3) {
|
||||
Vec3f vec[3];
|
||||
/**
|
||||
* Determines the closest point to hearPos that is contained on the line connecting points A & B
|
||||
* If the closest point on the line will not be on the line segment connecting points A or B, return false.
|
||||
* Otherwise, calculate the point between A & B, assign it to `newSoundPos`, and return true
|
||||
*/
|
||||
s32 EnRiverSound_FindClosestPointOnLineSegment(Vec3f* pointA, Vec3f* pointB, Vec3f* hearPos, Vec3f* newSoundPos) {
|
||||
Vec3f lineSeg[3];
|
||||
f32 temp;
|
||||
|
||||
vec[0].x = arg0->x - arg2->x;
|
||||
vec[0].y = arg0->y - arg2->y;
|
||||
vec[0].z = arg0->z - arg2->z;
|
||||
// Line Segment from the hearPos to the first point in the path
|
||||
lineSeg[0].x = pointA->x - hearPos->x;
|
||||
lineSeg[0].y = pointA->y - hearPos->y;
|
||||
lineSeg[0].z = pointA->z - hearPos->z;
|
||||
|
||||
vec[1].x = arg1->x - arg2->x;
|
||||
vec[1].y = arg1->y - arg2->y;
|
||||
vec[1].z = arg1->z - arg2->z;
|
||||
// Line Segment from the hearPos to the second point in the path
|
||||
lineSeg[1].x = pointB->x - hearPos->x;
|
||||
lineSeg[1].y = pointB->y - hearPos->y;
|
||||
lineSeg[1].z = pointB->z - hearPos->z;
|
||||
|
||||
vec[2].x = vec[1].x - vec[0].x;
|
||||
vec[2].y = vec[1].y - vec[0].y;
|
||||
vec[2].z = vec[1].z - vec[0].z;
|
||||
// Line Segment from the first point to the second point in the path
|
||||
lineSeg[2].x = lineSeg[1].x - lineSeg[0].x;
|
||||
lineSeg[2].y = lineSeg[1].y - lineSeg[0].y;
|
||||
lineSeg[2].z = lineSeg[1].z - lineSeg[0].z;
|
||||
|
||||
temp = DOTXYZ(vec[2], vec[0]);
|
||||
temp = DOTXYZ(lineSeg[2], lineSeg[0]);
|
||||
|
||||
if ((DOTXYZ(vec[2], vec[1]) * temp) < 0.0f) {
|
||||
temp = -temp / (SQ(vec[2].x) + SQ(vec[2].y) + SQ(vec[2].z));
|
||||
/**
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* A ----------------- B
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* This condition uses dot products to check to see that `hearPos` is contained within the above region
|
||||
* i.e. The closest point on line AB must be between A & B
|
||||
*/
|
||||
if ((DOTXYZ(lineSeg[2], lineSeg[1]) * temp) < 0.0f) {
|
||||
temp = -temp / SQXYZ(lineSeg[2]);
|
||||
|
||||
arg3->x = (vec[2].x * temp) + arg0->x;
|
||||
arg3->y = (vec[2].y * temp) + arg0->y;
|
||||
arg3->z = (vec[2].z * temp) + arg0->z;
|
||||
// Closest point to hearPos contained on line segment A-B
|
||||
newSoundPos->x = (lineSeg[2].x * temp) + pointA->x;
|
||||
newSoundPos->y = (lineSeg[2].y * temp) + pointA->y;
|
||||
newSoundPos->z = (lineSeg[2].z * temp) + pointA->z;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -93,70 +114,78 @@ s32 func_80AE6A54(Vec3f* arg0, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3) {
|
|||
*/
|
||||
s32 EnRiverSound_GetSoundPos(Vec3s* points, s32 numPoints, Vec3f* hearPos, Vec3f* soundPos) {
|
||||
s32 i;
|
||||
s32 pointIdx;
|
||||
s32 sp78[2] = { 0, 0 };
|
||||
Vec3f pointLoc;
|
||||
Vec3f sp60;
|
||||
Vec3f sp54;
|
||||
Vec3f vec;
|
||||
f32 pointDist = 10000.0f;
|
||||
Vec3s* point;
|
||||
s32 closestPointIdx;
|
||||
s32 useAdjacentPoints[2] = {
|
||||
false, // use previous point
|
||||
false, // use next point
|
||||
};
|
||||
Vec3f closestPointPos;
|
||||
Vec3f nextLineSegClosestPos;
|
||||
Vec3f prevLineSegClosestPos;
|
||||
Vec3f point;
|
||||
f32 closestPointDist = 10000.0f;
|
||||
Vec3s* closestPoint;
|
||||
|
||||
for (i = 0; i < numPoints; i++) {
|
||||
f32 dist;
|
||||
|
||||
vec.x = points[i].x;
|
||||
vec.y = points[i].y;
|
||||
vec.z = points[i].z;
|
||||
dist = Math_Vec3f_DistXYZ(hearPos, &vec);
|
||||
point.x = points[i].x;
|
||||
point.y = points[i].y;
|
||||
point.z = points[i].z;
|
||||
dist = Math_Vec3f_DistXYZ(hearPos, &point);
|
||||
|
||||
if (dist < pointDist) {
|
||||
pointDist = dist;
|
||||
pointIdx = i;
|
||||
if (dist < closestPointDist) {
|
||||
closestPointDist = dist;
|
||||
closestPointIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (pointDist >= 10000.0f) {
|
||||
if (closestPointDist >= 10000.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
point = &points[pointIdx];
|
||||
pointLoc.x = point->x;
|
||||
pointLoc.y = point->y;
|
||||
pointLoc.z = point->z;
|
||||
closestPoint = &points[closestPointIdx];
|
||||
closestPointPos.x = closestPoint->x;
|
||||
closestPointPos.y = closestPoint->y;
|
||||
closestPointPos.z = closestPoint->z;
|
||||
|
||||
if (pointIdx != 0) {
|
||||
vec.x = point[-1].x;
|
||||
vec.y = point[-1].y;
|
||||
vec.z = point[-1].z;
|
||||
sp78[0] = func_80AE6A54(&vec, &pointLoc, hearPos, &sp54);
|
||||
// point on path before closest point
|
||||
if (closestPointIdx != 0) {
|
||||
point.x = closestPoint[-1].x;
|
||||
point.y = closestPoint[-1].y;
|
||||
point.z = closestPoint[-1].z;
|
||||
useAdjacentPoints[0] =
|
||||
EnRiverSound_FindClosestPointOnLineSegment(&point, &closestPointPos, hearPos, &prevLineSegClosestPos);
|
||||
}
|
||||
|
||||
if (pointIdx + 1 != numPoints) {
|
||||
vec.x = point[1].x;
|
||||
vec.y = point[1].y;
|
||||
vec.z = point[1].z;
|
||||
sp78[1] = func_80AE6A54(&pointLoc, &vec, hearPos, &sp60);
|
||||
// point on path after closest point
|
||||
if (closestPointIdx + 1 != numPoints) {
|
||||
point.x = closestPoint[1].x;
|
||||
point.y = closestPoint[1].y;
|
||||
point.z = closestPoint[1].z;
|
||||
useAdjacentPoints[1] =
|
||||
EnRiverSound_FindClosestPointOnLineSegment(&closestPointPos, &point, hearPos, &nextLineSegClosestPos);
|
||||
}
|
||||
|
||||
if (sp78[0] && sp78[1]) {
|
||||
if (!func_80AE6A54(&sp54, &sp60, hearPos, soundPos)) {
|
||||
soundPos->x = (sp54.x + sp60.x) * 0.5f;
|
||||
soundPos->y = (sp54.y + sp60.y) * 0.5f;
|
||||
soundPos->z = (sp54.z + sp60.z) * 0.5f;
|
||||
if (useAdjacentPoints[0] && useAdjacentPoints[1]) {
|
||||
if (!EnRiverSound_FindClosestPointOnLineSegment(&prevLineSegClosestPos, &nextLineSegClosestPos, hearPos,
|
||||
soundPos)) {
|
||||
soundPos->x = (prevLineSegClosestPos.x + nextLineSegClosestPos.x) * 0.5f;
|
||||
soundPos->y = (prevLineSegClosestPos.y + nextLineSegClosestPos.y) * 0.5f;
|
||||
soundPos->z = (prevLineSegClosestPos.z + nextLineSegClosestPos.z) * 0.5f;
|
||||
}
|
||||
} else if (sp78[0]) {
|
||||
soundPos->x = sp54.x;
|
||||
soundPos->y = sp54.y;
|
||||
soundPos->z = sp54.z;
|
||||
} else if (sp78[1]) {
|
||||
soundPos->x = sp60.x;
|
||||
soundPos->y = sp60.y;
|
||||
soundPos->z = sp60.z;
|
||||
} else if (useAdjacentPoints[0]) {
|
||||
soundPos->x = prevLineSegClosestPos.x;
|
||||
soundPos->y = prevLineSegClosestPos.y;
|
||||
soundPos->z = prevLineSegClosestPos.z;
|
||||
} else if (useAdjacentPoints[1]) {
|
||||
soundPos->x = nextLineSegClosestPos.x;
|
||||
soundPos->y = nextLineSegClosestPos.y;
|
||||
soundPos->z = nextLineSegClosestPos.z;
|
||||
} else {
|
||||
soundPos->x = pointLoc.x;
|
||||
soundPos->y = pointLoc.y;
|
||||
soundPos->z = pointLoc.z;
|
||||
soundPos->x = closestPointPos.x;
|
||||
soundPos->y = closestPointPos.y;
|
||||
soundPos->z = closestPointPos.z;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -167,35 +196,37 @@ void EnRiverSound_Update(Actor* thisx, GlobalContext* globalCtx) {
|
|||
Vec3f* pos;
|
||||
Player* player = GET_PLAYER(globalCtx);
|
||||
EnRiverSound* this = (EnRiverSound*)thisx;
|
||||
s32 sp34;
|
||||
s32 bgId;
|
||||
|
||||
if ((thisx->params == RS_UNK_0) || (thisx->params == RS_UNK_4) || (thisx->params == RS_UNK_5)) {
|
||||
if ((thisx->params == RS_RIVER_DEFAULT_LOW_FREQ) || (thisx->params == RS_RIVER_DEFAULT_MEDIUM_FREQ) ||
|
||||
(thisx->params == RS_RIVER_DEFAULT_HIGH_FREQ)) {
|
||||
path = &globalCtx->setupPathList[this->pathIndex];
|
||||
pos = &thisx->world.pos;
|
||||
|
||||
if (EnRiverSound_GetSoundPos(SEGMENTED_TO_VIRTUAL(path->points), path->count, &player->actor.world.pos, pos)) {
|
||||
if (BgCheck_EntityRaycastFloor4(&globalCtx->colCtx, &thisx->floorPoly, &sp34, thisx, pos) !=
|
||||
if (BgCheck_EntityRaycastFloor4(&globalCtx->colCtx, &thisx->floorPoly, &bgId, thisx, pos) !=
|
||||
BGCHECK_Y_MIN) {
|
||||
// Get the sound volume pitch based on the speed of the river current under the actor
|
||||
this->soundPitchIndex = SurfaceType_GetConveyorSpeed(&globalCtx->colCtx, thisx->floorPoly, sp34);
|
||||
// Get the river sfx frequency based on the speed of the river current under the actor
|
||||
this->soundFreqIndex = SurfaceType_GetConveyorSpeed(&globalCtx->colCtx, thisx->floorPoly, bgId);
|
||||
} else {
|
||||
this->soundPitchIndex = 0;
|
||||
this->soundFreqIndex = 0;
|
||||
}
|
||||
|
||||
if (this->soundPitchIndex == 0) {
|
||||
if (thisx->params == RS_UNK_4) {
|
||||
this->soundPitchIndex = 0;
|
||||
} else if (thisx->params == RS_UNK_0) {
|
||||
this->soundPitchIndex = 1;
|
||||
if (this->soundFreqIndex == 0) {
|
||||
if (thisx->params == RS_RIVER_DEFAULT_MEDIUM_FREQ) {
|
||||
this->soundFreqIndex = 0;
|
||||
} else if (thisx->params == RS_RIVER_DEFAULT_LOW_FREQ) {
|
||||
this->soundFreqIndex = 1;
|
||||
} else {
|
||||
this->soundPitchIndex = 2;
|
||||
// RS_RIVER_DEFAULT_HIGH_FREQ
|
||||
this->soundFreqIndex = 2;
|
||||
}
|
||||
} else {
|
||||
this->soundPitchIndex--;
|
||||
this->soundPitchIndex = CLAMP_MAX(this->soundPitchIndex, 2);
|
||||
this->soundFreqIndex--;
|
||||
this->soundFreqIndex = CLAMP_MAX(this->soundFreqIndex, 2);
|
||||
}
|
||||
}
|
||||
} else if ((thisx->params == RS_UNK_13) || (thisx->params == RS_UNK_19)) {
|
||||
} else if ((thisx->params == RS_GORON_CITY_SARIAS_SONG) || (thisx->params == RS_GREAT_FAIRY)) {
|
||||
func_8002DBD0(&player->actor, &thisx->home.pos, &thisx->world.pos);
|
||||
} else if (globalCtx->sceneNum == SCENE_DDAN_BOSS && Flags_GetClear(globalCtx, thisx->room)) {
|
||||
Actor_Kill(thisx);
|
||||
|
@ -227,26 +258,37 @@ void EnRiverSound_Draw(Actor* thisx, GlobalContext* globalCtx) {
|
|||
NA_SE_EV_TORCH - SFX_FLAG,
|
||||
NA_SE_EV_COW_CRY_LV - SFX_FLAG,
|
||||
};
|
||||
static f32 soundPitch[] = { 0.7f, 1.0f, 1.4f };
|
||||
static f32 soundFreq[] = { 0.7f, 1.0f, 1.4f };
|
||||
EnRiverSound* this = (EnRiverSound*)thisx;
|
||||
|
||||
if (!(this->playSound)) {
|
||||
this->playSound = true;
|
||||
} else if ((this->actor.params == RS_UNK_0) || (this->actor.params == RS_UNK_4) ||
|
||||
(this->actor.params == RS_UNK_5)) {
|
||||
Audio_PlaySoundRiver(&this->actor.projectedPos, soundPitch[this->soundPitchIndex]);
|
||||
} else if (this->actor.params == RS_UNK_11) {
|
||||
func_800F4A54(90);
|
||||
} else if (this->actor.params == RS_SARIAS_SONG) {
|
||||
} else if ((this->actor.params == RS_RIVER_DEFAULT_LOW_FREQ) ||
|
||||
(this->actor.params == RS_RIVER_DEFAULT_MEDIUM_FREQ) ||
|
||||
(this->actor.params == RS_RIVER_DEFAULT_HIGH_FREQ)) {
|
||||
Audio_PlaySoundRiver(&this->actor.projectedPos, soundFreq[this->soundFreqIndex]);
|
||||
} else if (this->actor.params == RS_LOWER_MAIN_BGM_VOLUME) {
|
||||
// Responsible for lowering market bgm in Child Market Entrance and Child Market Back Alley
|
||||
// Lower volume from default 127 to a volume of 90
|
||||
Audio_LowerMainBgmVolume(90);
|
||||
} else if (this->actor.params == RS_LOST_WOODS_SARIAS_SONG) {
|
||||
// Play Sarias Song at the next correct Lost Woods path to Sacred Forest Meadow
|
||||
// Volume depends on distance to source
|
||||
func_800F4E30(&this->actor.projectedPos, this->actor.xzDistToPlayer);
|
||||
} else if (this->actor.params == RS_UNK_13) {
|
||||
} else if (this->actor.params == RS_GORON_CITY_SARIAS_SONG) {
|
||||
// Play Sarias Song in Goron City at the entrance to lost woods
|
||||
// Volume depends on distance to source
|
||||
Audio_PlaySariaBgm(&this->actor.home.pos, NA_BGM_SARIA_THEME, 1000);
|
||||
} else if (this->actor.params == RS_UNK_19) {
|
||||
} else if (this->actor.params == RS_GREAT_FAIRY) {
|
||||
// Play the Great Fairy Song inside the fairy fountain
|
||||
// Volume depends on distance to source
|
||||
Audio_PlaySariaBgm(&this->actor.home.pos, NA_BGM_GREAT_FAIRY, 800);
|
||||
} else if ((this->actor.params == RS_SANDSTORM) || (this->actor.params == RS_CHAMBER_OF_SAGES_1) ||
|
||||
(this->actor.params == RS_CHAMBER_OF_SAGES_2) || (this->actor.params == RS_RUMBLING)) {
|
||||
// Play sfx in the fixed center of the screen
|
||||
func_800788CC(soundEffects[this->actor.params]);
|
||||
} else {
|
||||
// Play sfx at the location of riverSounds projected position
|
||||
Audio_PlayActorSound2(&this->actor, soundEffects[this->actor.params]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,35 +9,42 @@ struct EnRiverSound;
|
|||
typedef struct EnRiverSound {
|
||||
/* 0x0000 */ Actor actor;
|
||||
/* 0x014C */ u8 playSound;
|
||||
/* 0x014D */ u8 soundPitchIndex;
|
||||
/* 0x014D */ u8 soundFreqIndex;
|
||||
/* 0x014E */ s16 pathIndex;
|
||||
} EnRiverSound; // size = 0x0150
|
||||
|
||||
typedef enum {
|
||||
/* 0x00 */ RS_UNK_0,
|
||||
/* 0x00 */ RS_RIVER_DEFAULT_LOW_FREQ,
|
||||
/* 0x01 */ RS_SMALL_WATERFALL,
|
||||
/* 0x02 */ RS_LAVA_BUBBLES_1,
|
||||
/* 0x03 */ RS_LARGE_WATERFALL,
|
||||
/* 0x04 */ RS_UNK_4,
|
||||
/* 0x05 */ RS_UNK_5,
|
||||
/* 0x04 */ RS_RIVER_DEFAULT_MEDIUM_FREQ,
|
||||
/* 0x05 */ RS_RIVER_DEFAULT_HIGH_FREQ,
|
||||
/* 0x06 */ RS_LAVA_BUBBLES_2,
|
||||
/* 0x07 */ RS_LAVA_BUBBLES_3,
|
||||
/* 0x08 */ RS_DRIPPING_WATER,
|
||||
/* 0x09 */ RS_FOUNTAIN_WATER,
|
||||
/* 0x0A */ RS_MARKET_CROWD,
|
||||
/* 0x0B */ RS_UNK_11,
|
||||
/* 0x0C */ RS_SARIAS_SONG,
|
||||
/* 0x0D */ RS_UNK_13,
|
||||
/* 0x0B */ RS_LOWER_MAIN_BGM_VOLUME,
|
||||
/* 0x0C */ RS_LOST_WOODS_SARIAS_SONG,
|
||||
/* 0x0D */ RS_GORON_CITY_SARIAS_SONG,
|
||||
/* 0x0E */ RS_SANDSTORM,
|
||||
/* 0x0F */ RS_LAKESIDE_LAB_TANK,
|
||||
/* 0x10 */ RS_CHAMBER_OF_SAGES_1,
|
||||
/* 0x11 */ RS_CHAMBER_OF_SAGES_2,
|
||||
/* 0x12 */ RS_RUMBLING,
|
||||
/* 0x13 */ RS_UNK_19,
|
||||
/* 0x13 */ RS_GREAT_FAIRY,
|
||||
/* 0x14 */ RS_TORCH_CRACKLING,
|
||||
/* 0x15 */ RS_COW_MOOING,
|
||||
/* 0xF7 */ RS_UNK_F7 = 0xF7,
|
||||
/* 0xF8 */ RS_MAX
|
||||
/* 0xF7 */ RS_NATURE_AMBIENCE = 0xF7,
|
||||
/* 0xF8 */ RS_GANON_TOWER_0, // Ganondorf's Lair
|
||||
/* 0xF9 */ RS_GANON_TOWER_1, // Top of Ganon's Tower
|
||||
/* 0xFA */ RS_GANON_TOWER_2,
|
||||
/* 0xFB */ RS_GANON_TOWER_3,
|
||||
/* 0xFC */ RS_GANON_TOWER_4,
|
||||
/* 0xFD */ RS_GANON_TOWER_5,
|
||||
/* 0xFE */ RS_GANON_TOWER_6,
|
||||
/* 0xFF */ RS_GANON_TOWER_7 // Bottom of Ganon's Tower
|
||||
} RiverSoundType;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue