refactor, revamp audio compass, cue when moving into walls

This commit is contained in:
Demur Rumed 2025-06-09 22:41:04 +00:00
commit 1acfbb633c
6 changed files with 358 additions and 398 deletions

View file

@ -11,23 +11,24 @@
#include <float.h>
extern "C" {
#include "overlays/actors/ovl_Obj_Switch/z_obj_switch.h"
#include "overlays/actors/ovl_Bg_Bdan_Switch/z_bg_bdan_switch.h"
#include "overlays/actors/ovl_Bg_Po_Event/z_bg_po_event.h"
#include "overlays/actors/ovl_Boss_Goma/z_boss_goma.h"
#include "overlays/actors/ovl_En_Karebaba/z_en_karebaba.h"
#include "overlays/actors/ovl_En_Ba/z_en_ba.h"
#include "overlays/actors/ovl_En_Box/z_en_box.h"
#include "overlays/actors/ovl_Obj_Syokudai/z_obj_syokudai.h"
#include "overlays/actors/ovl_Door_Shutter/z_door_shutter.h"
#include "overlays/actors/ovl_En_Dog/z_en_dog.h"
#include "overlays/actors/ovl_En_Door/z_en_door.h"
#include "overlays/actors/ovl_En_Eiyer/z_en_eiyer.h"
#include "overlays/actors/ovl_En_Elf/z_en_elf.h"
#include "overlays/actors/ovl_En_Fz/z_en_fz.h"
#include "overlays/actors/ovl_En_Ice_Hono/z_en_ice_hono.h"
#include "overlays/actors/ovl_En_Eiyer/z_en_eiyer.h"
#include "overlays/actors/ovl_En_G_Switch/z_en_g_switch.h"
#include "overlays/actors/ovl_Door_Shutter/z_door_shutter.h"
#include "overlays/actors/ovl_Bg_Po_Event/z_bg_po_event.h"
#include "overlays/actors/ovl_En_Ice_Hono/z_en_ice_hono.h"
#include "overlays/actors/ovl_En_Kakasi2/z_en_kakasi2.h"
#include "overlays/actors/ovl_En_Wood02/z_en_wood02.h"
#include "overlays/actors/ovl_Obj_Switch/z_obj_switch.h"
#include "overlays/actors/ovl_Obj_Syokudai/z_obj_syokudai.h"
void EnBox_WaitOpen(EnBox*, PlayState*);
void EnKarebaba_DeadItemDrop(EnKarebaba*, PlayState*);
@ -40,21 +41,9 @@ void EnGSwitch_SilverRupeeIdle(EnGSwitch*, PlayState*);
extern u8 sBgPoEventPuzzleState;
}
// User data for the general helper VA.
typedef struct {
s16 currentScene;
s8 currentRoom;
bool currentRoomClear;
} GeneralHelperData;
typedef struct {
f32 linearVelocity;
int framesUntilChime;
} AudioCompassData;
void accessible_grotto(AccessibleActor* actor) {
if ((actor->actor->params & 0x300) == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DROP_FALL, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DROP_FALL);
}
}
@ -68,7 +57,7 @@ void accessible_torches(AccessibleActor* actor) {
if ((actor->frameCount & 31) != 0) {
return;
}
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_BOMB_IGNIT, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_BOMB_IGNIT);
} else {
if (actor->policy.volume != 1.0) {
actor->policy.volume = 1.0;
@ -77,7 +66,7 @@ void accessible_torches(AccessibleActor* actor) {
if ((actor->frameCount & 31) != 0) {
return;
}
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_BOMB_IGNIT, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_BOMB_IGNIT);
}
if ((actor->frameCount & 31) != 0) {
return;
@ -86,9 +75,9 @@ void accessible_torches(AccessibleActor* actor) {
// unlit permanent torches
if ((actor->actor->params) == 8192) {
if (torche->litTimer == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_BOMB_IGNIT, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_BOMB_IGNIT);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_ANUBIS_FIRE, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_ANUBIS_FIRE);
}
}
// lit permanent torches
@ -96,7 +85,7 @@ void accessible_torches(AccessibleActor* actor) {
actor->policy.volume = 0.5;
actor->policy.distance = 200.0;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_ANUBIS_FIRE, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_ANUBIS_FIRE);
}
}
@ -110,35 +99,35 @@ void accessible_switch(AccessibleActor* actor) {
}
if (scale.y >= 33.0f / 200.0f) {
if (actor->play->sceneNum == 0 && actor->play->roomCtx.curRoom.num == 5 && actor->xzDistToPlayer < 20) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH);
}
if ((actor->frameCount & 31) != 0) {
return;
}
ActorAccessibility_PlaySoundForActor(actor, 1, NA_SE_EV_FOOT_SWITCH, false);
ActorAccessibility_PlaySoundForActor(actor, 1, NA_SE_EV_FOOT_SWITCH);
}
} else if ((actor->frameCount & 31) != 0) {
return;
} else if ((actor->actor->params & 7) == OBJSWITCH_TYPE_FLOOR_RUSTY) {
if (actor->xyzDistToPlayer < 800 && scale.y >= 33.0f / 200.0f) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_HAMMER_HIT, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_HAMMER_HIT);
}
} else if ((actor->actor->params & 7) == OBJSWITCH_TYPE_EYE) {
if (sw->eyeTexIndex == 0) {
actor->policy.aimAssist.isProvider = true;
actor->policy.ydist = 1000;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FOOT_SWITCH, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FOOT_SWITCH);
}
} else if (actor->xyzDistToPlayer < 1000) {
actor->policy.aimAssist.isProvider = true;
actor->policy.ydist = 1000;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH);
}
}
void accessible_larva(AccessibleActor* actor) {
if (actor->actor->bgCheckFlags == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_GOMA_BJR_EGG1, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_GOMA_BJR_EGG1);
}
}
@ -213,59 +202,59 @@ void accessible_area_change(AccessibleActor* actor) {
return;
}
if (actor->play->sceneNum == SCENE_KOKIRI_FOREST && actor->pos.y < 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_HORSE_RUN_LEVEL, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_HORSE_RUN_LEVEL);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SARIA_MELODY, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SARIA_MELODY);
}
// kokiri forest and lost woods
} else if (actor->play->sceneNum >= SCENE_DEKU_TREE_BOSS && actor->play->sceneNum <= SCENE_GANONDORF_BOSS) {
return; // dont check for entrances while in boss rooms
} else if (actor->play->sceneNum == SCENE_GROTTOS || actor->play->sceneNum == SCENE_FAIRYS_FOUNTAIN) {
actor->policy.volume = 0.1;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_WARP_HOLE, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_WARP_HOLE);
} else if (actor->sceneIndex == SCENE_HYRULE_FIELD) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_HORSE_RUN_LEVEL, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_HORSE_RUN_LEVEL);
} else if (actor->sceneIndex <= SCENE_GERUDO_TRAINING_GROUND) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FANTOM_WARP_S, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FANTOM_WARP_S);
} else if (actor->sceneIndex >= SCENE_MARKET_ENTRANCE_DAY && actor->sceneIndex <= SCENE_MARKET_ENTRANCE_RUINS) {
if (actor->play->sceneNum >= SCENE_MARKET_DAY && actor->play->sceneNum <= SCENE_MARKET_RUINS) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_HORSE_RUN_LEVEL, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_HORSE_RUN_LEVEL);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK);
}
} else if (actor->sceneIndex >= SCENE_BACK_ALLEY_DAY && actor->sceneIndex <= SCENE_MARKET_NIGHT) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK);
} else if (actor->sceneIndex >= SCENE_MARKET_RUINS && actor->sceneIndex <= SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_STONE_BOUND, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_STONE_BOUND);
} else if (actor->play->sceneNum == SCENE_TEMPLE_OF_TIME) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK);
} else if (actor->sceneIndex == SCENE_CASTLE_COURTYARD_GUARDS_DAY ||
actor->sceneIndex == SCENE_CASTLE_COURTYARD_GUARDS_NIGHT) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_MUSI_SINK, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_MUSI_SINK);
} else if (actor->sceneIndex == SCENE_KAKARIKO_VILLAGE) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHICKEN_CRY_M, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHICKEN_CRY_M);
} else if (actor->sceneIndex == SCENE_GRAVEYARD) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_PO_APPEAR, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_PO_APPEAR);
} else if (actor->sceneIndex == SCENE_ZORAS_RIVER || actor->sceneIndex == SCENE_ZORAS_DOMAIN ||
actor->sceneIndex == SCENE_ZORAS_FOUNTAIN) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_RIVER_STREAM_S, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_RIVER_STREAM_S);
} else if (actor->sceneIndex == SCENE_SACRED_FOREST_MEADOW) {
} else if (actor->sceneIndex == SCENE_LAKE_HYLIA) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_WATER_WALL, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_WATER_WALL);
} else if (actor->sceneIndex == SCENE_GERUDO_VALLEY || actor->sceneIndex == SCENE_GERUDOS_FORTRESS) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_PL_CRAWL_SAND, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_PL_CRAWL_SAND);
} else if (actor->sceneIndex == SCENE_DESERT_COLOSSUS || actor->sceneIndex == SCENE_HAUNTED_WASTELAND) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SAND_STORM, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SAND_STORM);
} else if (actor->sceneIndex == SCENE_OUTSIDE_GANONS_CASTLE || actor->sceneIndex == SCENE_HYRULE_CASTLE) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_BRIDGE_OPEN, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_BRIDGE_OPEN);
} else if (actor->sceneIndex == SCENE_DEATH_MOUNTAIN_TRAIL) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_DODO_K_ROLL, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_DODO_K_ROLL);
} else if (actor->sceneIndex == SCENE_DEATH_MOUNTAIN_CRATER) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_DODO_K_LAVA, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_DODO_K_LAVA);
} else if (actor->sceneIndex == SCENE_GORON_CITY) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_DARUNIA_HIT_BREAST, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_DARUNIA_HIT_BREAST);
} else if (actor->sceneIndex == SCENE_LON_LON_RANCH) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_COW_CRY, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_COW_CRY);
} else if (actor->sceneIndex >= SCENE_DEKU_TREE_BOSS && actor->sceneIndex <= SCENE_GANONDORF_BOSS) {
return;
} else {
@ -273,7 +262,7 @@ void accessible_area_change(AccessibleActor* actor) {
if (actor->play->sceneNum == SCENE_GRAVEYARD) {
actor->policy.ydist = 0;
}
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_OC_DOOR_OPEN, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_OC_DOOR_OPEN);
}
}
@ -284,43 +273,43 @@ void accessible_en_guard(AccessibleActor* actor) {
fabs(actor->actor->world.pos.z - player->actor.world.pos.z)) {
if (fabs(actor->actor->shape.rot.y - 16384) < 1000) {
if (actor->actor->world.pos.x < player->actor.world.pos.x) {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx);
ActorAccessibility_SetSoundPitch(actor, 0, 0.2);
}
} else if ((actor->actor->shape.rot.y + 16384) < 1000) {
if (actor->actor->world.pos.x < player->actor.world.pos.x) {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx);
ActorAccessibility_SetSoundPitch(actor, 0, 0.2);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
}
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx);
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
}
} else {
if (fabs(actor->actor->shape.rot.y) < 1000) {
if (actor->actor->world.pos.z < player->actor.world.pos.z) {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx);
ActorAccessibility_SetSoundPitch(actor, 0, 0.2);
}
} else if (fabs(actor->actor->shape.rot.y + 32768) < 1000) {
if (actor->actor->world.pos.z < player->actor.world.pos.z) {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx);
ActorAccessibility_SetSoundPitch(actor, 0, 0.2);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
}
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx);
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
}
}
@ -330,7 +319,7 @@ void accessible_en_dogs(AccessibleActor* actor) {
EnDog* dog = (EnDog*)actor->actor;
if (EnDog_CanFollow(dog, actor->play) == 1) {
dog->actionFunc = EnDog_FollowPlayer;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH);
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
}
if ((actor->frameCount & 31) != 0) {
@ -338,11 +327,11 @@ void accessible_en_dogs(AccessibleActor* actor) {
}
if (actor->actor->params == 608 || actor->actor->params == 336 || actor->actor->params == 304 ||
actor->actor->params == 3088 || actor->actor->params == 2576 || actor->actor->params < 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK);
ActorAccessibility_SetSoundPitch(actor, 0, 0.5);
}
}
@ -350,7 +339,7 @@ void accessible_en_dogs(AccessibleActor* actor) {
void accessible_goma(AccessibleActor* actor) {
BossGoma* goma = (BossGoma*)actor->actor;
if (goma->visualState == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH);
}
}
@ -360,7 +349,7 @@ void accessible_sticks(AccessibleActor* actor) {
if (baba->actionFunc != EnKarebaba_DeadItemDrop)
return;
if (actor->actor->flags == 80) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_DAMAGE, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_DAMAGE);
}
}
@ -368,112 +357,10 @@ void accessible_cucco(AccessibleActor* actor) {
if (actor->actor->params == 14) {
} else if (actor->actor->params == 13) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHICKEN_CRY_N, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHICKEN_CRY_N);
ActorAccessibility_SetSoundPitch(actor, 0, 1.5);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHICKEN_CRY_N, false);
}
}
bool accessible_general_helper_init(AccessibleActor* actor) {
GeneralHelperData* data = (GeneralHelperData*)malloc(sizeof(GeneralHelperData));
if (data == nullptr)
return false;
data->currentRoom = -1;
data->currentRoomClear = false;
data->currentScene = -1;
actor->userData = data;
return true;
}
void accessible_general_helper_cleanup(AccessibleActor* actor) {
free(actor->userData);
actor->userData = nullptr;
}
void accessible_va_general_helper(AccessibleActor* actor) {
GeneralHelperData* data = (GeneralHelperData*)actor->userData;
if (data->currentScene == actor->play->sceneNum && data->currentRoom != actor->play->roomCtx.curRoom.num) {
ActorAccessibility_AnnounceRoomNumber(actor->play);
data->currentRoom = actor->play->roomCtx.curRoom.num;
data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom);
}
if (data->currentScene != actor->play->sceneNum) {
ActorAccessibility_InterpretCurrentScene(actor->play);
data->currentScene = actor->play->sceneNum;
data->currentRoom = actor->play->roomCtx.curRoom.num;
data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom);
}
// Report when a room is completed.
if (!data->currentRoomClear && Flags_GetClear(actor->play, data->currentRoom)) {
data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom);
ActorAccessibility_AnnounceRoomNumber(actor->play);
}
}
bool accessible_audio_compass_init(AccessibleActor* actor) {
AudioCompassData* data = (AudioCompassData*)malloc(sizeof(AudioCompassData));
if (data == nullptr)
return false;
data->linearVelocity = 0;
data->framesUntilChime = 0;
actor->userData = data;
return true;
}
void accessible_audio_compass_cleanup(AccessibleActor* actor) {
free(actor->userData);
}
void accessible_audio_compass(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play);
OSContPad* trackerButtonsPressed =
std::dynamic_pointer_cast<LUS::ControlDeck>(Ship::Context::GetInstance()->GetControlDeck())->GetPads();
AudioCompassData* data = (AudioCompassData*)actor->userData;
bool compassCombo = trackerButtonsPressed != nullptr && trackerButtonsPressed[0].button & BTN_DDOWN &&
trackerButtonsPressed[0].button & BTN_L;
actor->pos = player->actor.world.pos;
actor->pos.z -= 50;
if (data->framesUntilChime > 0)
data->framesUntilChime--;
if (compassCombo && data->framesUntilChime <= 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, actor->policy.sound, false);
data->framesUntilChime = 30;
}
}
void accessible_stick_warning(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play);
actor->pos = player->actor.world.pos;
actor->pos.z -= 50;
if (fabs(player->unk_860 - 25) < 24.0 && player->heldItemId == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_SY_WARNING_COUNT_N, false);
}
if (Player_HoldsHookshot(player) && player->heldActor != NULL && player->actor.scale.y >= 0.0f &&
(player->stateFlags1 & PLAYER_STATE1_FIRST_PERSON)) {
CollisionPoly* colPoly;
s32 bgId;
Vec3f hookshotEnd;
Vec3f firstHit;
f32 hookshotLength = ((player->heldItemAction == PLAYER_IA_HOOKSHOT) ? 380.0f : 770.0f) *
CVarGetFloat(CVAR_CHEAT("HookshotReachMultiplier"), 1.0f);
hookshotEnd.x = player->heldActor->world.pos.x + Math_SinS(player->heldActor->world.rot.y) *
Math_SinS(-player->heldActor->world.rot.x) *
hookshotLength;
hookshotEnd.y = player->heldActor->world.pos.y + Math_SinS(-player->heldActor->world.rot.x) * hookshotLength;
hookshotEnd.z = player->heldActor->world.pos.z + Math_CosS(player->heldActor->world.rot.y) *
Math_CosS(-player->heldActor->world.rot.x) *
hookshotLength;
if (BgCheck_AnyLineTest3(&actor->play->colCtx, &player->heldActor->world.pos, &hookshotEnd, &firstHit, &colPoly,
1, 1, 1, 1, &bgId)) {
if (SurfaceType_IsHookshotSurface(&actor->play->colCtx, colPoly, bgId)) {
ActorAccessibility_PlaySoundForActor(actor, 1, NA_SE_IT_HOOKSHOT_STICK_OBJ, false);
}
}
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHICKEN_CRY_N);
}
}
@ -602,14 +489,21 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_AddSupportedActor(ACTOR_EN_NIW, policy);
ActorAccessibility_InitPolicy(&policy, "Bush", NA_SE_PL_PULL_UP_PLANT);
ActorAccessibility_AddSupportedActor(ACTOR_EN_KUSA, policy);
ActorAccessibility_InitPolicy(&policy, "Trees", NA_SE_EV_TREE_CUT);
ActorAccessibility_InitPolicy(&policy, "Trees", [](AccessibleActor* actor) {
EnWood02* wood = (EnWood02*)actor->actor;
if (wood->actor.params <= WOOD_TREE_KAKARIKO_ADULT) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_TREE_CUT);
} else if (wood->actor.params < WOOD_LEAF_GREEN) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_TREE_SWING);
}
});
ActorAccessibility_AddSupportedActor(ACTOR_EN_WOOD02, policy);
ActorAccessibility_InitPolicy(&policy, "Scarecrow Spawn", [](AccessibleActor* actor) {
if ((actor->frameCount & 63) == 0) {
EnKakasi2* kakasi = (EnKakasi2*)actor->actor;
actor->policy.distance = kakasi->maxSpawnDistance.x;
actor->policy.ydist = kakasi->maxSpawnDistance.y;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_KAKASHI_SWING, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_KAKASHI_SWING);
}
});
policy.distance = 2000;
@ -629,7 +523,7 @@ void ActorAccessibility_InitActors() {
size = 30; // large
}
if (!(treasureFlag >= 20 && treasureFlag < 32)) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_TBOX_UNLOCK, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_TBOX_UNLOCK);
}
// Only chests that are "waiting to be opened" should play a sound. Chests which have not yet appeared (because
// some enemy has not been killed, switch has not been hit, etc) will not be in this action mode.
@ -649,7 +543,7 @@ void ActorAccessibility_InitActors() {
if ((xdist - size / 2) < 0) {
ActorAccessibility_SetSoundPitch(actor, 0, 0.5);
} else if ((xdist + size / 2) > 0 && zdist < size / 2 && xdist < 150.0) {
ActorAccessibility_PlaySoundForActor(actor, 1, NA_SE_EV_DIAMOND_SWITCH, false);
ActorAccessibility_PlaySoundForActor(actor, 1, NA_SE_EV_DIAMOND_SWITCH);
}
});
policy.pitch = 1.1;
@ -692,7 +586,7 @@ void ActorAccessibility_InitActors() {
if (actor->actor->category == ACTORCAT_ITEMACTION) {
s16 params = actor->actor->params;
if (params == FAIRY_HEAL || params == FAIRY_HEAL_TIMED || params == FAIRY_HEAL_BIG) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_BUTTERFRY_TO_FAIRY, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_BUTTERFRY_TO_FAIRY);
}
}
});
@ -710,7 +604,7 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_AddSupportedActor(ACTOR_EN_PO_DESERT, policy);
ActorAccessibility_InitPolicy(&policy, "flag pole", [](AccessibleActor* actor) {
if ((actor->frameCount & 31) == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FLUTTER_FLAG, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FLUTTER_FLAG);
}
});
policy.aimAssist.isProvider = true;
@ -756,9 +650,9 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_InitPolicy(&policy, "Shutter Door", [](AccessibleActor* actor) {
DoorShutter* doorShutter = (DoorShutter*)actor->actor;
if (doorShutter->doorType == SHUTTER_KEY_LOCKED && !Flags_GetSwitch(actor->play, actor->actor->params & 0x3F)) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHAIN_KEY_UNLOCK_B, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHAIN_KEY_UNLOCK_B);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_OC_DOOR_OPEN, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_OC_DOOR_OPEN);
}
});
policy.n = 30;
@ -781,7 +675,7 @@ void ActorAccessibility_InitActors() {
actor->policy.aimAssist.isProvider = true;
}
if ((actor->frameCount & 31) == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH);
}
});
policy.n = 1;
@ -792,7 +686,7 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_InitPolicy(&policy, "Jabu Object", [](AccessibleActor* actor) {
if ((actor->actor->params & 0xFF) == 2 && actor->xzDistToPlayer > 50) {
// Jabu Elevator
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_PL_LAND_LADDER, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_PL_LAND_LADDER);
}
});
policy.n = 1;
@ -820,10 +714,10 @@ void ActorAccessibility_InitActors() {
if ((actor->actor->params) == 0) {
actor->policy.ydist = 1000;
actor->policy.distance = 1000;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_OCTAROCK_ROCK, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_OCTAROCK_ROCK);
} else if ((actor->actor->params) == 1) {
actor->policy.ydist = 1000;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_PL_DAMAGE, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_PL_DAMAGE);
}
});
policy.distance = 1000;
@ -834,15 +728,15 @@ void ActorAccessibility_InitActors() {
actor->policy.distance = 400;
if ((actor->frameCount & 31) == 0) {
ActorAccessibility_SetSoundPitch(actor, 0, 0.5f + 1.0f * po->index);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_PO_APPEAR, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_PO_APPEAR);
}
} else if (po->type == 1) {
actor->policy.distance = 300;
if ((actor->frameCount & 31) == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_TRAP_BOUND, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_TRAP_BOUND);
}
} else if (po->index == sBgPoEventPuzzleState && (actor->frameCount & 63) == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_PO_CRY, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_PO_CRY);
}
});
policy.aimAssist.isProvider = true;
@ -872,19 +766,19 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_AddSupportedActor(ACTOR_OBJ_LIFT, policy);
ActorAccessibility_InitPolicy(&policy, "Ladder in Slingshot Room", [](AccessibleActor* actor) {
if (actor->actor->params == 1) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_PL_LAND_LADDER, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_PL_LAND_LADDER);
}
});
ActorAccessibility_AddSupportedActor(ACTOR_BG_YDAN_MARUTA, policy);
ActorAccessibility_InitPolicy(&policy, "231 dekus", [](AccessibleActor* actor) {
if (actor->actor->params == 1) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_FAINT, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_FAINT);
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
} else if (actor->actor->params == 2) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_FAINT, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_FAINT);
ActorAccessibility_SetSoundPitch(actor, 0, 0.5);
} else if (actor->actor->params == 3) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_FAINT, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_FAINT);
ActorAccessibility_SetSoundPitch(actor, 0, 1.5);
}
});
@ -900,7 +794,7 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_InitPolicy(&policy, "Blue Fire", [](AccessibleActor* actor) {
if (actor->actor->params == -1) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_FLAME, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_FLAME);
}
});
policy.n = 60;
@ -918,7 +812,8 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_AddSupportedActor(ACTOR_BG_ICE_SHELTER, policy);
ActorAccessibility_InitPolicy(&policy, "Statue Eye", [](AccessibleActor* actor) {
actor->policy.aimAssist.isProvider = ABS((s16)(actor->actor->yawTowardsPlayer - actor->actor->shape.rot.y)) < 0x2000;
actor->policy.aimAssist.isProvider =
ABS((s16)(actor->actor->yawTowardsPlayer - actor->actor->shape.rot.y)) < 0x2000;
});
policy.n = 1;
policy.ydist = 500;
@ -927,9 +822,9 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_InitPolicy(&policy, "uninteractable rocks in kokiri forest", [](AccessibleActor* actor) {
if (actor->actor->params == 1) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_OCTAROCK_ROCK, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_OCTAROCK_ROCK);
} else if (actor->actor->params == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIG_UP, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIG_UP);
}
});
ActorAccessibility_AddSupportedActor(ACTOR_OBJ_HANA, policy);
@ -944,9 +839,9 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_InitPolicy(&policy, "Big Skulltula", [](AccessibleActor* actor) {
s16 angleTowardsLink = ABS((s16)(actor->actor->yawTowardsPlayer - actor->actor->shape.rot.y));
if (angleTowardsLink >= 0x3FFC) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_VO_ST_DAMAGE, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_VO_ST_DAMAGE);
} else if ((actor->frameCount & 63) == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_STALTU_LAUGH, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_STALTU_LAUGH);
}
});
policy.ydist = 100;
@ -965,9 +860,9 @@ void ActorAccessibility_InitActors() {
if (actionFunc == EnEiyer_Die || actionFunc == EnEiyer_Dead) {
ActorAccessibility_StopAllSoundsForActor(actor);
} else if (GET_PLAYER(actor->play)->actor.world.pos.y > actor->actor->world.pos.y - 8) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_FISHING_REEL_SLOW, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_FISHING_REEL_SLOW);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_FISHING_REEL_HIGH, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_FISHING_REEL_HIGH);
}
});
policy.n = 1;
@ -983,7 +878,7 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_InitPolicy(&policy, "tentacle", [](AccessibleActor* actor) {
if (actor->actor->params < EN_BA_DEAD_BLOB) {
actor->policy.volume = 2.5 - (actor->actor->world.pos.y - actor->actor->home.pos.y) / 200.0;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_OWL_FLUTTER, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_OWL_FLUTTER);
}
});
policy.distance = 1500;
@ -995,7 +890,7 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_InitPolicy(&policy, "freezard", [](AccessibleActor* actor) {
EnFz* fz = (EnFz*)actor->actor;
if (fz->state != 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_FREEZAD_DEAD, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_FREEZAD_DEAD);
}
});
policy.n = 20;
@ -1016,7 +911,7 @@ void ActorAccessibility_InitActors() {
: actor->xzDistToPlayer < 200 ? 31
: 63;
if ((actor->frameCount & freq) == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_BOMB_DROP_WATER, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_BOMB_DROP_WATER);
}
}
});
@ -1039,7 +934,7 @@ void ActorAccessibility_InitActors() {
if ((actor->frameCount & 31) == 0) {
EnGSwitch* gswitch = (EnGSwitch*)actor->actor;
if (gswitch->actionFunc == EnGSwitch_SilverRupeeIdle) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FIVE_COUNT_LUPY, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FIVE_COUNT_LUPY);
}
}
});
@ -1058,15 +953,15 @@ void ActorAccessibility_InitActors() {
actor->pos.y = waterLoc;
}
if (actor->yDistToPlayer < 80)
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_PL_LAND_LADDER, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_PL_LAND_LADDER);
});
policy.pitch = 1.3;
ActorAccessibility_AddSupportedActor(VA_CLIMB, policy);
ActorAccessibility_InitPolicy(&policy, "Door", [](AccessibleActor* actor) {
if (((actor->actor->params >> 7) & 7) == DOOR_LOCKED) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHAIN_KEY_UNLOCK_B, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHAIN_KEY_UNLOCK_B);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_OC_DOOR_OPEN, false);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_OC_DOOR_OPEN);
}
});
policy.n = 30;
@ -1082,35 +977,11 @@ void ActorAccessibility_InitActors() {
policy.distance = 1000;
policy.pitch = 1.7;
ActorAccessibility_AddSupportedActor(VA_MARKER, policy);
ActorAccessibility_InitPolicy(&policy, "Stick Burnout Warning", accessible_stick_warning);
policy.n = 1;
policy.runsAlways = true;
ActorAccessibility_AddSupportedActor(VA_STICK_WARNING, policy);
ActorAccessibility_InitPolicy(&policy, "System general helper", accessible_va_general_helper);
policy.n = 1;
policy.cleanupUserData = accessible_general_helper_cleanup;
policy.initUserData = accessible_general_helper_init;
policy.runsAlways = true;
ActorAccessibility_AddSupportedActor(VA_GENERAL_HELPER, policy);
ActorAccessibility_InitPolicy(&policy, "Audio Compass", accessible_audio_compass);
policy.n = 1;
policy.cleanupUserData = accessible_audio_compass_cleanup;
policy.initUserData = accessible_audio_compass_init;
policy.runsAlways = true;
policy.sound = NA_SE_EV_SHIP_BELL; // Setting this here so it's easy to change if we ever decide to change it.
policy.pitch = 0.5;
ActorAccessibility_AddSupportedActor(VA_AUDIO_COMPASS, policy);
// Now query a list of virtual actors for a given location (scene and room number).
// Virtual actors for a given location (scene and room number).
VirtualActorList* list = (VirtualActorList*)ActorAccessibility_GetVirtualActorList(EVERYWHERE, 0);
AccessibleActor* temp;
// Now place the actor.
ActorAccessibility_AddVirtualActor(list, VA_GENERAL_HELPER, { 0, 0, 0 });
ActorAccessibility_AddVirtualActor(list, VA_AUDIO_COMPASS, { 0, 0, 0 });
ActorAccessibility_AddVirtualActor(list, VA_STICK_WARNING, { 0, 0, 0 });
list = ActorAccessibility_GetVirtualActorList(SCENE_KOKIRI_FOREST, 0);
ActorAccessibility_AddVirtualActor(list, VA_CRAWLSPACE, { -784, 120, 1046 });
ActorAccessibility_AddVirtualActor(list, VA_MARKER, { 2146, 1, -142.8 });

View file

@ -17,7 +17,6 @@ int AudioPlayer_GetDesiredBuffered();
#include <math.h>
#include <algorithm>
#include <stdexcept>
#include <spdlog/spdlog.h>
enum AAE_COMMANDS {
AAE_START = 0,
@ -50,8 +49,7 @@ static float computeGain(SoundExtras* extras) {
gain -= lerp_aae(0, leftover, normDist);
return gain;
}
// Borrow the pan calculation from the game itself. Todo: this is technical debt, so copy/ revise it or something at
// some point.
// Borrow pan calculation from game itself. Todo: this is technical debt, so copy/revise or something
extern "C" int8_t Audio_ComputeSoundPanSigned(float x, float z, uint8_t token);
static void positioner_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn,
float** ppFramesOut, ma_uint32* pFrameCountOut) {
@ -275,14 +273,17 @@ void AccessibleAudioEngine::doPlaySound(SoundAction& action) {
MA_SOUND_FLAG_NO_SPATIALIZATION | MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT,
NULL, NULL, &sound->sound);
if (result != MA_SUCCESS) {
SPDLOG_ERROR("failed to play sound: {}", ma_result_description(result));
return;
}
initSoundExtras(sound);
ma_sound_set_looping(&sound->sound, action.looping);
// We actually attach the extras to the engine, not the sound itself.
ma_node_attach_output_bus(&sound->extras, 0, ma_node_graph_get_endpoint(&engine.nodeGraph), 0);
if (action.handle != 0) {
initSoundExtras(sound);
// We actually attach the extras to the engine, not the sound itself.
ma_node_attach_output_bus(&sound->extras, 0, ma_node_graph_get_endpoint(&engine.nodeGraph), 0);
} else {
sound->extras.base.pNodeGraph = NULL;
ma_node_attach_output_bus(&sound->sound, 0, ma_node_graph_get_endpoint(&engine.nodeGraph), 0);
}
ma_sound_start(&sound->sound);
@ -295,6 +296,7 @@ void AccessibleAudioEngine::doStopSound(SoundAction& action) {
return;
destroySound(slot);
}
void AccessibleAudioEngine::doStopAllSounds(SoundAction& action) {
auto it = sounds.find(action.handle);
if (it == sounds.end())
@ -306,6 +308,7 @@ void AccessibleAudioEngine::doStopAllSounds(SoundAction& action) {
}
sounds.erase(it);
}
void AccessibleAudioEngine::doSetPitch(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
@ -323,18 +326,21 @@ void AccessibleAudioEngine::doSetPitchBehindModifier(SoundAction& action) {
return;
slot->extras.pitchBehindModifier = action.pitch;
}
void AccessibleAudioEngine::doSetVolume(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
ma_sound_set_volume(&slot->sound, action.pitch);
}
void AccessibleAudioEngine::doSetPan(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
ma_sound_set_pan(&slot->sound, action.pan);
}
void AccessibleAudioEngine::doSetFilter(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
@ -344,12 +350,14 @@ void AccessibleAudioEngine::doSetFilter(SoundAction& action) {
lerp_aae(0.0, AAE_SAMPLE_RATE / 2, action.cutoff), AAE_LPF_ORDER);
ma_lpf_reinit(&config, &slot->extras.filter);
}
void AccessibleAudioEngine::doSeekSound(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
ma_sound_seek_to_pcm_frame(&slot->sound, action.offset);
}
void AccessibleAudioEngine::doSetSoundPos(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
@ -366,28 +374,31 @@ void AccessibleAudioEngine::doSetSoundPos(SoundAction& action) {
}
void AccessibleAudioEngine::garbageCollect() {
for (auto i = sounds.begin(); i != sounds.end();) {
int deadSlots = 0;
bool deadSlots = true;
for (int x = 0; x < AAE_SLOTS_PER_HANDLE; x++) {
if (!i->second[x].active)
deadSlots++;
else if (!ma_sound_is_playing(&i->second[x].sound)) {
destroySound(&i->second[x]);
i->second[x].active = false;
deadSlots++;
if (i->second[x].active) {
if (!ma_sound_is_playing(&i->second[x].sound)) {
destroySound(&i->second[x]);
} else {
deadSlots = false;
}
}
}
if (deadSlots == AAE_SLOTS_PER_HANDLE) // Entire batch is garbage.
if (deadSlots) {
i = sounds.erase(i);
else
} else {
i++;
}
}
framesUntilGC = AAE_GC_INTERVAL;
}
void AccessibleAudioEngine::processAudioJobs() {
ma_job job;
while (ma_resource_manager_next_job(&resourceManager, &job) == MA_SUCCESS)
ma_job_process(&job);
}
bool AccessibleAudioEngine::initSoundExtras(SoundSlot* slot) {
ma_node_config config = ma_node_config_init();
config.inputBusCount = 1;
@ -412,15 +423,18 @@ bool AccessibleAudioEngine::initSoundExtras(SoundSlot* slot) {
slot->extras.cutoff = 1.0f;
slot->extras.pitch = 1.0f;
slot->extras.pitchBehindModifier = 0.0f;
// ma_node_attach_output_bus(&slot->sound, 0, &slot->extras.filter, 0);
ma_node_attach_output_bus(&slot->sound, 0, &slot->extras, 0);
return true;
}
void AccessibleAudioEngine::destroySound(SoundSlot* slot) {
ma_node_detach_all_output_buses(&slot->extras);
ma_sound_uninit(&slot->sound);
ma_gainer_uninit(&slot->extras.gainer, NULL);
if (slot->extras.base.pNodeGraph != NULL) {
ma_node_detach_all_output_buses(&slot->extras);
ma_sound_uninit(&slot->sound);
ma_gainer_uninit(&slot->extras.gainer, NULL);
} else {
ma_sound_uninit(&slot->sound);
}
slot->active = false;
}
@ -453,6 +467,7 @@ AccessibleAudioEngine::AccessibleAudioEngine() {
framesUntilGC = AAE_GC_INTERVAL;
thread = std::thread(&AccessibleAudioEngine::runThread, this);
}
AccessibleAudioEngine::~AccessibleAudioEngine() {
// Place a terminate command on the top of the pile, then wait for thread to die.
SoundAction action;
@ -461,6 +476,7 @@ AccessibleAudioEngine::~AccessibleAudioEngine() {
thread.join();
destroy();
}
void AccessibleAudioEngine::mix(int16_t* ogBuffer, uint32_t nFrames) {
float sourceChunk[AAE_MIX_CHUNK_SIZE * AAE_CHANNELS];
float mixedChunk[AAE_MIX_CHUNK_SIZE * AAE_CHANNELS];
@ -489,19 +505,18 @@ void AccessibleAudioEngine::mix(int16_t* ogBuffer, uint32_t nFrames) {
}
}
void AccessibleAudioEngine::playSound(uintptr_t handle, int slot, const char* path, bool looping) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
void AccessibleAudioEngine::playSound(uintptr_t handle, uint8_t slot, const char* path) {
if (slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.handle = handle;
action.slot = slot;
action.command = AAE_START;
action.path = path;
action.looping = looping;
}
void AccessibleAudioEngine::stopSound(uintptr_t handle, int slot) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
void AccessibleAudioEngine::stopSound(uintptr_t handle, uint8_t slot) {
if (slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_STOP;
@ -515,8 +530,8 @@ void AccessibleAudioEngine::stopAllSounds(uintptr_t handle) {
action.handle = handle;
}
void AccessibleAudioEngine::setPitch(uintptr_t handle, int slot, float pitch) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
void AccessibleAudioEngine::setPitch(uintptr_t handle, uint8_t slot, float pitch) {
if (slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PITCH;
@ -525,8 +540,8 @@ void AccessibleAudioEngine::setPitch(uintptr_t handle, int slot, float pitch) {
action.pitch = pitch;
}
void AccessibleAudioEngine::setPitchBehindModifier(uintptr_t handle, int slot, float mod) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
void AccessibleAudioEngine::setPitchBehindModifier(uintptr_t handle, uint8_t slot, float mod) {
if (slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PITCH_BEHIND;
@ -535,8 +550,8 @@ void AccessibleAudioEngine::setPitchBehindModifier(uintptr_t handle, int slot, f
action.pitch = mod;
}
void AccessibleAudioEngine::setVolume(uintptr_t handle, int slot, float volume) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
void AccessibleAudioEngine::setVolume(uintptr_t handle, uint8_t slot, float volume) {
if (slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_VOLUME;
@ -545,8 +560,8 @@ void AccessibleAudioEngine::setVolume(uintptr_t handle, int slot, float volume)
action.volume = volume;
}
void AccessibleAudioEngine::setPan(uintptr_t handle, int slot, float pan) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
void AccessibleAudioEngine::setPan(uintptr_t handle, uint8_t slot, float pan) {
if (slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PAN;
@ -554,8 +569,8 @@ void AccessibleAudioEngine::setPan(uintptr_t handle, int slot, float pan) {
action.slot = slot;
action.pan = pan;
}
void AccessibleAudioEngine::setFilter(uintptr_t handle, int slot, float cutoff) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
void AccessibleAudioEngine::setFilter(uintptr_t handle, uint8_t slot, float cutoff) {
if (slot >= AAE_SLOTS_PER_HANDLE)
return;
if (cutoff < 0.0 || cutoff > 1.0)
return;
@ -566,8 +581,8 @@ void AccessibleAudioEngine::setFilter(uintptr_t handle, int slot, float cutoff)
action.cutoff = cutoff;
}
void AccessibleAudioEngine::seekSound(uintptr_t handle, int slot, size_t offset) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
void AccessibleAudioEngine::seekSound(uintptr_t handle, uint8_t slot, size_t offset) {
if (slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.handle = handle;
@ -576,9 +591,9 @@ void AccessibleAudioEngine::seekSound(uintptr_t handle, int slot, size_t offset)
action.offset = offset;
}
void AccessibleAudioEngine::setSoundPosition(uintptr_t handle, int slot, float posX, float posY, float posZ,
void AccessibleAudioEngine::setSoundPosition(uintptr_t handle, uint8_t slot, float posX, float posY, float posZ,
float distToPlayer, float maxDistance) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
if (slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_POS;

View file

@ -18,7 +18,6 @@ struct SoundAction {
// address of an object with which the sound is associated is recommended.
uint8_t slot; // Allows multiple sounds per handle. The exact number is controlled by AAE_SOUNDS_PER_HANDLE.
uint8_t command; // One of the items belonging to AAE_COMMANDS.
bool looping; // If command is AAE_START, specifies whether or not the sound should loop.
std::string path; // If command is AAE_START, this is the path to the desired resource.
union {
float pitch;
@ -126,20 +125,20 @@ class AccessibleAudioEngine {
// content).
void mix(int16_t* ogBuffer, uint32_t nFrames);
// Start playing a sound.
void playSound(uintptr_t handle, int slot, const char* path, bool looping);
void stopSound(uintptr_t handle, int slot);
void playSound(uintptr_t handle, uint8_t slot, const char* path);
void stopSound(uintptr_t handle, uint8_t slot);
// Stop all sounds belonging to a handle.
void stopAllSounds(uintptr_t handle);
void setPitch(uintptr_t handle, int slot, float pitch);
void setPitchBehindModifier(uintptr_t handle, int slot, float mod);
void setVolume(uintptr_t handle, int slot, float volume);
void setPan(uintptr_t handle, int slot, float pan);
void setPitch(uintptr_t handle, uint8_t slot, float pitch);
void setPitchBehindModifier(uintptr_t handle, uint8_t slot, float mod);
void setVolume(uintptr_t handle, uint8_t slot, float volume);
void setPan(uintptr_t handle, uint8_t slot, float pan);
// Set the lowpass filter cutoff. Set to 1.0 for no filtering.
void setFilter(uintptr_t handle, int slot, float cutoff);
void setFilter(uintptr_t handle, uint8_t slot, float cutoff);
// Seek the sound to a particular PCM frame.
void seekSound(uintptr_t handle, int slot, size_t offset);
void setSoundPosition(uintptr_t handle, int slot, float posX, float posY, float posZ, float distToPlayer,
void seekSound(uintptr_t handle, uint8_t slot, size_t offset);
void setSoundPosition(uintptr_t handle, uint8_t slot, float posX, float posY, float posZ, float distToPlayer,
float maxDistance);
// Schedule the preparation of output for delivery.
void prepare();

View file

@ -75,7 +75,7 @@ class AudioGlossaryData {
class ActorAccessibility {
public:
int isOn = 0;
bool isOn = false;
uint64_t nextActorID = 0;
SupportedActors_t supportedActors;
TrackedActors_t trackedActors;
@ -87,10 +87,13 @@ class ActorAccessibility {
SfxExtractor sfxExtractor;
// Maps internal sfx to external (prerendered) resources.
std::unordered_map<s16, SfxRecord> sfxMap;
int extractSfx = 0;
int framesUntilChime = 0;
s16 currentScene = -1;
s8 currentRoom = -1;
VirtualActorList* currentEverywhere = NULL;
bool currentRoomClear = false;
Vec3f prevPos = { 0, 0, 0 };
s16 prevYaw = 0;
bool extractSfx = false;
VirtualActorList* currentSceneGlobal = NULL;
VirtualActorList* currentRoomLocal = NULL;
};
@ -216,11 +219,9 @@ void ActorAccessibility_TrackNewActor(Actor* actor) {
aa->trackedActors[actor] = accessibleActor.instanceID;
aa->accessibleActorList[accessibleActor.instanceID] = accessibleActor;
AccessibleActor& savedActor = aa->accessibleActorList[accessibleActor.instanceID];
if (policy->initUserData && !policy->initUserData(&savedActor)) {
ActorAccessibility_RemoveTrackedActor(actor);
return; // Probably a malloc error preventing user data initialization.
if (policy->initUserData) {
AccessibleActor& savedActor = aa->accessibleActorList[accessibleActor.instanceID];
policy->initUserData(&savedActor);
}
}
void ActorAccessibility_RemoveTrackedActor(Actor* actor) {
@ -250,11 +251,11 @@ f32 ActorAccessibility_ComputeCurrentVolume(f32 maxDistance, f32 xzDistToPlayer)
return ActorAccessibility_DBToLinear(db);
}
const char* ActorAccessibility_MapSfxToExternalAudio(s16 sfxId);
void ActorAccessibility_PlaySound(void* handle, int slot, s16 sfxId, bool looping) {
void ActorAccessibility_PlaySound(void* handle, int slot, s16 sfxId) {
const char* path = ActorAccessibility_MapSfxToExternalAudio(sfxId);
if (path == NULL)
return;
aa->audioEngine->playSound((uintptr_t)handle, slot, path, looping);
aa->audioEngine->playSound((uintptr_t)handle, slot, path);
}
void ActorAccessibility_StopSound(void* handle, int slot) {
@ -291,10 +292,10 @@ void ActorAccessibility_ConfigureSoundForActor(AccessibleActor* actor, int slot)
ActorAccessibility_SetSoundVolume(actor, slot, actor->policy.volume);
actor->managedSoundSlots |= 1 << slot;
}
void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId, bool looping) {
void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId) {
if (slot < 0 || slot > AAE_SLOTS_PER_HANDLE)
return;
ActorAccessibility_PlaySound(actor, slot, sfxId, looping);
ActorAccessibility_PlaySound(actor, slot, sfxId);
ActorAccessibility_ConfigureSoundForActor(actor, slot);
}
void ActorAccessibility_StopSoundForActor(AccessibleActor* actor, int slot) {
@ -351,8 +352,6 @@ void ActorAccessibility_RunAccessibilityForActor(PlayState* play, AccessibleActo
}
// Send sound parameters to the new audio engine. Eventually remove the old stuff once all actors are carried over.
for (int i = 0; i < AAE_SLOTS_PER_HANDLE; i++) {
if (i == 9)
continue;
if (actor->managedSoundSlots & (1 << i)) {
ActorAccessibility_SetSoundPos(actor, i, &actor->projectedPos, actor->xyzDistToPlayer,
actor->policy.distance);
@ -377,16 +376,13 @@ void ActorAccessibility_RunAccessibilityForActor(PlayState* play, AccessibleActo
if (player->stateFlags1 & PLAYER_STATE1_FIRST_PERSON &&
(player->stateFlags1 & PLAYER_STATE1_USING_BOOMERANG || player->stateFlags1 & PLAYER_STATE1_ITEM_IN_HAND)) {
auto aimAssistProps = ActorAccessibility_ProvideAimAssistForActor(actor);
if (++actor->aimAssist.framesSinceAimAssist >= actor->aimAssist.frequency) {
actor->aimAssist.framesSinceAimAssist = 0;
ActorAccessibility_PlaySound(actor, 7, actor->policy.aimAssist.sfx);
}
ActorAccessibility_SetSoundPitch(actor, 7, aimAssistProps.pitch);
ActorAccessibility_SetSoundVolume(actor, 7, aimAssistProps.volume);
ActorAccessibility_SetSoundPan(actor, 7, aimAssistProps.pan);
// The above will have taken care of setting the appropriate frequency and pitch, so we'll take care of the
// audio here based on those results.
if (++actor->aimAssist.framesSinceAimAssist >= actor->aimAssist.frequency) {
actor->aimAssist.framesSinceAimAssist = 0;
ActorAccessibility_PlaySoundForActor(actor, 7, actor->policy.aimAssist.sfx, false);
}
} else {
// Make sure there's no delay the next time you draw your bow or whatever.
actor->aimAssist.framesSinceAimAssist = 32768;
@ -396,16 +392,15 @@ void ActorAccessibility_RunAccessibilityForActor(PlayState* play, AccessibleActo
if (actor->policy.callback != nullptr) {
actor->policy.callback(actor);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, actor->policy.sound, false);
ActorAccessibility_PlaySoundForActor(actor, 0, actor->policy.sound);
}
}
void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play) {
Player* player = GET_PLAYER(play);
if (play->sceneNum != aa->currentScene) {
ActorAccessibility_StopAllVirtualActors(aa->currentEverywhere);
ActorAccessibility_StopAllVirtualActors(aa->currentSceneGlobal);
ActorAccessibility_StopAllVirtualActors(aa->currentRoomLocal);
aa->currentEverywhere = ActorAccessibility_GetVirtualActorList(EVERYWHERE, 0);
aa->currentSceneGlobal = ActorAccessibility_GetVirtualActorList(play->sceneNum, -1);
aa->currentScene = play->sceneNum;
aa->currentRoomLocal = NULL;
@ -428,19 +423,17 @@ void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play) {
}
ActorAccessibility_AudioGlossary(play);
if (aa->glossary->GlossaryStarted) {
return;
}
ActorAccessibility_GeneralHelper(play);
// Real actors.
for (AccessibleActorList_t::iterator i = aa->accessibleActorList.begin(); i != aa->accessibleActorList.end(); i++)
ActorAccessibility_RunAccessibilityForActor(play, &i->second);
// Virtual actors in the "everywhere" group.
VAList_t* list = (VAList_t*)aa->currentEverywhere;
for (VAList_t::iterator i = list->begin(); i != list->end(); i++)
ActorAccessibility_RunAccessibilityForActor(play, &(*i));
// Virtual actors for the current room and scene.
list = (VAList_t*)aa->currentRoomLocal;
VAList_t* list = (VAList_t*)aa->currentRoomLocal;
for (VAList_t::iterator i = list->begin(); i != list->end(); i++)
ActorAccessibility_RunAccessibilityForActor(play, &(*i));
// Scene-global virtual actors. Most of these are automatically generated VAs from polygons, because there's no way
@ -453,6 +446,96 @@ void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play) {
ActorAccessibility_PrepareNextAudioFrame();
}
void ActorAccessibility_GeneralHelper(PlayState* play) {
Player* player = GET_PLAYER(play);
if (player == NULL)
return;
if (aa->currentScene == play->sceneNum && aa->currentRoom != play->roomCtx.curRoom.num) {
ActorAccessibility_AnnounceRoomNumber(play);
aa->currentRoom = play->roomCtx.curRoom.num;
aa->currentRoomClear = Flags_GetClear(play, aa->currentRoom);
}
if (aa->currentScene != play->sceneNum) {
ActorAccessibility_InterpretCurrentScene(play);
aa->currentScene = play->sceneNum;
aa->currentRoom = play->roomCtx.curRoom.num;
aa->currentRoomClear = Flags_GetClear(play, aa->currentRoom);
}
// Report when a room is completed.
if (!aa->currentRoomClear && Flags_GetClear(play, aa->currentRoom)) {
aa->currentRoomClear = Flags_GetClear(play, aa->currentRoom);
ActorAccessibility_AnnounceRoomNumber(play);
}
if (player->actor.wallPoly && player->actor.speedXZ > 0 && player->yDistToLedge >= 79.0f) {
f32 movedsq = SQ(aa->prevPos.x - player->actor.world.pos.x) + SQ(aa->prevPos.z - player->actor.world.pos.z);
if (movedsq < 0.125) {
ActorAccessibility_PlaySound(nullptr, 3, NA_SE_IT_WALL_HIT_SOFT);
ActorAccessibility_SetSoundVolume(nullptr, 3, 0.5);
} else if (movedsq < 9) {
ActorAccessibility_PlaySound(nullptr, 3, NA_SE_IT_SHIELD_POSTURE);
ActorAccessibility_SetSoundVolume(nullptr, 3, 0.6);
} else {
ActorAccessibility_PlaySound(nullptr, 3, NA_SE_PL_WALK_WALL);
ActorAccessibility_SetSoundVolume(nullptr, 3, std::max(0.3f, 10.0f / movedsq));
}
}
bool compassOn = false;
if (aa->prevPos.x == player->actor.world.pos.x && aa->prevPos.z == player->actor.world.pos.z) {
if (aa->prevYaw != player->yaw) {
compassOn = true;
aa->prevYaw = player->yaw;
}
} else {
aa->prevPos = player->actor.world.pos;
}
if (aa->framesUntilChime > 0) {
aa->framesUntilChime--;
} else {
if (!compassOn) {
OSContPad* trackerButtonsPressed =
std::dynamic_pointer_cast<LUS::ControlDeck>(Ship::Context::GetInstance()->GetControlDeck())->GetPads();
compassOn = trackerButtonsPressed != nullptr && (trackerButtonsPressed[0].button & BTN_DDOWN) &&
(trackerButtonsPressed[0].button & BTN_L);
}
if (compassOn) {
ActorAccessibility_PlaySound(nullptr, 0, NA_SE_EV_SHIP_BELL);
ActorAccessibility_SetSoundPitch(nullptr, 0, 1.5f + Math_CosS(player->yaw) / 2);
ActorAccessibility_SetSoundPan(nullptr, 0, -Math_SinS(player->yaw));
s16 range = ABS((player->yaw & 0x1FFF) - 0x1000);
aa->framesUntilChime = range < 0x800 ? 10 : range < 0x1000 ? 20 : 30;
}
}
if (fabs(player->unk_860 - 25) < 24.0 && player->heldItemId == 0) {
ActorAccessibility_PlaySound(nullptr, 1, NA_SE_SY_WARNING_COUNT_N);
}
if (Player_HoldsHookshot(player) && player->heldActor != NULL && player->actor.scale.y >= 0.0f &&
(player->stateFlags1 & PLAYER_STATE1_FIRST_PERSON)) {
CollisionPoly* colPoly;
s32 bgId;
Vec3f firstHit;
f32 hookshotLength = ((player->heldItemAction == PLAYER_IA_HOOKSHOT) ? 380.0f : 770.0f) *
CVarGetFloat(CVAR_CHEAT("HookshotReachMultiplier"), 1.0f);
Vec3f hookshotEnd = player->heldActor->world.pos;
hookshotEnd.x +=
Math_SinS(player->heldActor->world.rot.y) * Math_SinS(-player->heldActor->world.rot.x) * hookshotLength;
hookshotEnd.y += Math_SinS(-player->heldActor->world.rot.x) * hookshotLength;
hookshotEnd.z +=
Math_CosS(player->heldActor->world.rot.y) * Math_CosS(-player->heldActor->world.rot.x) * hookshotLength;
if (BgCheck_AnyLineTest3(&play->colCtx, &player->heldActor->world.pos, &hookshotEnd, &firstHit, &colPoly, 1, 1,
1, 1, &bgId)) {
if (SurfaceType_IsHookshotSurface(&play->colCtx, colPoly, bgId)) {
ActorAccessibility_PlaySound(nullptr, 2, NA_SE_IT_HOOKSHOT_STICK_OBJ);
}
}
}
}
void ActorAccessibility_AudioGlossary(PlayState* play) {
if (aa->glossary->GlossaryStarted) {
freezeActors = true;
@ -548,10 +631,8 @@ AccessibleActor* ActorAccessibility_AddVirtualActor(VirtualActorList* list, VIRT
l->push_back(actor);
size_t index = l->size() - 1;
AccessibleActor* savedActor = &(*l)[l->size() - 1];
if (policy->initUserData && !policy->initUserData(savedActor)) {
l->pop_back();
return NULL; // Probably a malloc error preventing user data initialization.
}
if (policy->initUserData)
policy->initUserData(savedActor);
return savedActor;
}
void ActorAccessibility_InterpretCurrentScene(PlayState* play) {
@ -664,7 +745,7 @@ bool ActorAccessibility_InitAudio() {
void ActorAccessibility_ShutdownAudio() {
if (aa->isOn) {
delete aa->audioEngine;
aa->isOn = 0;
aa->isOn = false;
}
}
void ActorAccessibility_MixAccessibleAudioWithGameAudio(int16_t* ogBuffer, uint32_t nFrames) {

View file

@ -6,7 +6,7 @@ struct AccessibleActor;
typedef void (*ActorAccessibilityCallback)(AccessibleActor*);
// A callback which allows AccessibleActor instances to initialize custom user data (called once per instantiation).
typedef bool (*ActorAccessibilityUserDataInit)(AccessibleActor*);
typedef void (*ActorAccessibilityUserDataInit)(AccessibleActor*);
// A callback that can be used to clean up user data when an actor is destroyed.
typedef void (*ActorAccessibilityUserDataCleanup)(AccessibleActor*);
@ -108,7 +108,7 @@ void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play);
*modifying AAE_SLOTS_PER_HANDLE). sfxId: one of the game's sfx IDs. Note that this plays prerendered sounds which you
*must have previously prepared. looping: whether to play the sound just once or on a continuous loop.
*/
void ActorAccessibility_PlaySound(void* actor, int slot, s16 sfxId, bool looping);
void ActorAccessibility_PlaySound(void* actor, int slot, s16 sfxId);
// Stop a sound. Todo: consider making this a short fade instead of just cutting it off.
void ActorAccessibility_StopSound(void* handle, int slot);
void ActorAccessibility_StopAllSounds(void* handle);
@ -132,7 +132,7 @@ void ActorAccessibility_SeekSound(void* handle, int slot, size_t offset);
* automatically based on the actor's position.
*
*/
void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId, bool looping);
void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId);
void ActorAccessibility_StopSoundForActor(AccessibleActor* actor, int slot);
void ActorAccessibility_StopAllSoundsForActor(AccessibleActor* actor);
@ -142,9 +142,8 @@ Vec3s ActorAccessibility_ComputeRelativeAngle(Vec3s* origin, Vec3s* offset);
void ActorAccessibility_InitCues();
// Stuff related to lists of virtual actors.
typedef enum {
// Similar to the game's actual actor table. Values here start at 10000 just to be extra safe.
// Similar to the game's actual actor table
VA_INITIAL = 1000,
VA_PROTOTYPE, // Remove this one once this thing is working.
VA_CRAWLSPACE,
VA_TERRAIN_CUE,
VA_WALL_CUE,
@ -153,9 +152,6 @@ typedef enum {
VA_AREA_CHANGE,
VA_MARKER,
VA_SPIKE,
VA_GENERAL_HELPER, // Room announcements, action icon and other misc help.
VA_AUDIO_COMPASS, // Points north.
VA_STICK_WARNING, // beep when stick is about to burn out.
VA_MAX,
} VIRTUAL_ACTOR_TABLE;
@ -183,4 +179,5 @@ void ActorAccessibility_HandleSoundExtractionMode(PlayState* play);
// This is called by the audio thread when it's ready to try to pull sfx from the game.
void ActorAccessibility_DoSoundExtractionStep();
void ActorAccessibility_GeneralHelper(PlayState* play);
void ActorAccessibility_AudioGlossary(PlayState* play);

View file

@ -23,8 +23,8 @@ static Vec3f D_80854798 = { 0.0f, 18.0f, 0.0f }; // From z_player.c.
const char* GetLanguageCode();
enum {
DISCOVERED_NOTHING = 0,
enum DiscoveredTerrain {
DISCOVERED_NOTHING,
DISCOVERED_INCLINE,
DISCOVERED_DECLINE,
DISCOVERED_LEDGE,
@ -46,10 +46,9 @@ class TerrainCueSound {
s16 currentSFX;
int restFrames; // Used to control how often sounds get played.
bool shouldLoop;
// Call to start playback.
void play() {
ActorAccessibility_PlaySound(this, 0, currentSFX, shouldLoop);
ActorAccessibility_PlaySound(this, 0, currentSFX);
ActorAccessibility_SetSoundPos(this, 0, &terrainProjectedPos, xzDistToPlayer, actor->policy.distance);
ActorAccessibility_SetSoundPitch(this, 0, currentPitch);
}
@ -80,7 +79,6 @@ class TerrainCueSound {
TerrainCueSound(AccessibleActor* actor, Vec3f pos) {
this->actor = actor;
currentPitch = 1.0;
shouldLoop = false;
restFrames = 0;
xzDistToPlayer = 0;
currentSFX = 0;
@ -104,8 +102,7 @@ class Incline : protected TerrainCueSound {
play();
}
virtual ~Incline() {
}
virtual ~Incline() = default;
virtual void run() {
if (restFrames > 0) {
restFrames--;
@ -133,8 +130,7 @@ class Decline : protected TerrainCueSound {
play();
}
virtual ~Decline() {
}
virtual ~Decline() = default;
virtual void run() {
if (restFrames > 0) {
restFrames--;
@ -167,49 +163,36 @@ class Ledge : protected TerrainCueSound {
switch (type) {
case 0:
currentSFX = NA_SE_EV_WIND_TRAP;
shouldLoop = 1;
break;
case 1:
currentSFX = NA_SE_EV_WOOD_BOUND;
shouldLoop = 0;
break;
case 2:
currentSFX = NA_SE_PL_LAND_WATER0;
shouldLoop = 0;
break;
case 3:
currentSFX = NA_SE_SY_WARNING_COUNT_N;
shouldLoop = 0;
break;
}
this->probeRot = probeRot;
if (type == 0) {
if (probeRot.y == 0)
currentPitch = 0.4;
else if (probeRot.y < 0)
currentPitch = 0.2;
else
currentPitch = 0.8;
currentPitch = probeRot.y == 0 ? 0.4 : probeRot.y < 0 ? 0.2 : 0.8;
}
play();
}
virtual ~Ledge() {
}
virtual ~Ledge() = default;
s8 type() {
return savedType;
}
void run() {
if (savedType == 0)
return; // Downward ledges play a looping sound and do not need ongoing maintenance.
if (restFrames == 0) {
play();
restFrames = 10;
return;
} else {
restFrames--;
}
restFrames--;
}
};
class Platform : protected TerrainCueSound {
@ -218,10 +201,8 @@ class Platform : protected TerrainCueSound {
currentPitch = 2.0;
// actor->policy.volume = 1.5;
currentSFX = NA_SE_IT_SHIELD_REFLECT_SW;
shouldLoop = false;
}
virtual ~Platform() {
}
virtual ~Platform() = default;
void setActor(AccessibleActor* actor) {
this->actor = actor;
}
@ -232,9 +213,9 @@ class Platform : protected TerrainCueSound {
if (restFrames == 0) {
play();
restFrames = 10;
return;
} else {
restFrames--;
}
restFrames--;
}
};
@ -258,8 +239,7 @@ class Wall : protected TerrainCueSound {
play();
}
virtual ~Wall() {
}
virtual ~Wall() = default;
void run() {
frames++;
@ -286,8 +266,7 @@ class Spike : protected TerrainCueSound {
currentSFX = NA_SE_IT_SWORD_PICKOUT;
play();
}
virtual ~Spike() {
}
virtual ~Spike() = default;
void run() {
if (restFrames == 0) {
play();
@ -304,15 +283,14 @@ class Water : protected TerrainCueSound {
currentSFX = NA_SE_PL_LAND_WATER0; // NA_SE_EN_DAIOCTA_LAND_WATER; // change?
play();
}
virtual ~Water() {
}
virtual ~Water() = default;
void run() {
if (restFrames == 0) {
play();
restFrames = 10;
return;
} else {
restFrames--;
}
restFrames--;
}
};
@ -326,16 +304,15 @@ class Ground : protected TerrainCueSound {
this->pitchModifier = 0.0;
play();
}
virtual ~Ground() {
}
virtual ~Ground() = default;
void run() {
if (restFrames == 0) {
play();
restFrames = 10;
return;
} else {
ActorAccessibility_SetSoundPitch(this, 0, 1.0 + (2 * pitchModifier));
restFrames--;
}
ActorAccessibility_SetSoundPitch(this, 0, 1.0 + (2 * pitchModifier));
restFrames--;
}
void setPitchModifier(float modifier) {
pitchModifier = modifier;
@ -349,19 +326,18 @@ class Lava : protected TerrainCueSound {
currentSFX = NA_SE_SY_WARNING_COUNT_N; // change?
play();
}
virtual ~Lava() {
}
virtual ~Lava() = default;
void run() {
if (restFrames == 0) {
play();
restFrames = 10;
return;
} else {
restFrames--;
}
restFrames--;
}
};
class TerrainCueDirection {
class TerrainCueDirection final {
AccessibleActor* actor;
int startingBodyPart; // Decides where the probe starts from. Probes going out to the left or right of the player
// start from the shoulders.
@ -375,7 +351,7 @@ class TerrainCueDirection {
f32 probeSpeed; // Approximate for now.
Vec3f velocity;
Vec3f expectedVelocity;
int terrainDiscovered = DISCOVERED_NOTHING;
DiscoveredTerrain terrainDiscovered = DISCOVERED_NOTHING;
CollisionPoly* floorPoly;
CollisionPoly* wallPoly;
s32 wallBgId;
@ -401,6 +377,7 @@ class TerrainCueDirection {
Platform platform;
TerrainCueSound* currentSound;
// Apply an offset b to a Vec3f a.
Vec3f applyVec3fOffset(Vec3f& a, Vec3f& b) {
Vec3f c;
@ -742,7 +719,8 @@ class TerrainCueDirection {
public:
// Initialize a TerrainCueDirection based on a relative angle and position offset.
void init(AccessibleActor* actor, Vec3s rot, int startingBodyPart = PLAYER_BODYPART_MAX) {
TerrainCueDirection(AccessibleActor* actor, Vec3s rot, int startingBodyPart = PLAYER_BODYPART_MAX)
: platform(actor, { 0, 0, 0 }) {
this->actor = actor;
this->relRot = rot;
this->rot = { 0, 0, 0 };
@ -750,12 +728,44 @@ class TerrainCueDirection {
terrainDiscovered = DISCOVERED_NOTHING;
currentSound = NULL;
new (&platform) Platform(actor, { 0.0, 0.0, 0.0 });
disabled = false;
trackingMode = false;
trackingModeStarted = false;
}
~TerrainCueDirection() {
switch (terrainDiscovered) {
case DISCOVERED_NOTHING:
break;
case DISCOVERED_INCLINE:
this->incline.~Incline();
break;
case DISCOVERED_DECLINE:
this->decline.~Decline();
break;
case DISCOVERED_LEDGE:
this->ledge.~Ledge();
break;
case DISCOVERED_WALL:
this->wall.~Wall();
break;
case DISCOVERED_SPIKE:
this->spike.~Spike();
break;
case DISCOVERED_WATER:
this->water.~Water();
break;
case DISCOVERED_GROUND:
this->ground.~Ground();
break;
case DISCOVERED_LAVA:
this->lava.~Lava();
break;
}
this->platform.~Platform();
}
// Move a probe to its next point along a line, ensuring that it remains on the floor. Returns false if the move
// would put the probe out of bounds. Does not take walls into account.
bool move(s8 gravity = true) {
@ -1121,12 +1131,7 @@ class TerrainCueDirection {
}
}
destroyCurrentSound();
break; /*else {
if (checkHeight < 200) {
discoverLedge(pos, true);
break;
}
}*/ // not needed?
break;
}
if (moveMethod != 2 && checkPerpendicularWall(pos, ogRot)) {
discoverWall(pos);
@ -1134,10 +1139,7 @@ class TerrainCueDirection {
}
discoverLedge(pos, false);
break;
}
else if (checkForLava(player->actor.world.pos)) {
} else if (checkForLava(player->actor.world.pos)) {
if (!move()) {
destroyCurrentSound();
break; // Probe is out of bounds.
@ -1146,12 +1148,9 @@ class TerrainCueDirection {
discoverGround(pos);
break;
}
}
// link is on land
else {
if (!move()) {
destroyCurrentSound();
break; // Probe is out of bounds.
@ -1348,19 +1347,17 @@ typedef struct {
} TerrainCueState;
// Callback for initialization of terrain cue state.
bool ActorAccessibility_InitTerrainCueState(AccessibleActor* actor) {
TerrainCueState* state = (TerrainCueState*)malloc(sizeof(TerrainCueState));
if (state == NULL)
return false;
state->directions[0].init(actor, { 0, 0, 0 });
state->directions[1].init(actor, { 0, 16384, 0 });
state->directions[2].init(actor, { 0, -16384, 0 });
void ActorAccessibility_InitTerrainCueState(AccessibleActor* actor) {
TerrainCueState* state = new TerrainCueState{ {
{ actor, { 0, 0, 0 } },
{ actor, { 0, 16384, 0 } },
{ actor, { 0, -16384, 0 } },
} };
actor->userData = state;
return true;
}
void ActorAccessibility_CleanupTerrainCueState(AccessibleActor* actor) {
free(actor->userData);
delete (TerrainCueState*)actor->userData;
actor->userData = NULL;
}
// Computes a relative angle based on Link's (or some other actor's) current angle.