fix archive creation, must be o2r

This commit is contained in:
Demur Rumed 2025-04-20 21:25:39 +00:00
commit 17d2e39a57
9 changed files with 1598 additions and 1765 deletions

View file

@ -35,21 +35,18 @@ void EnDog_FollowPlayer(EnDog*, PlayState*);
s8 EnDog_CanFollow(EnDog*, PlayState*); s8 EnDog_CanFollow(EnDog*, PlayState*);
} }
// User data for the general helper VA. // User data for the general helper VA.
typedef struct typedef struct {
{
s16 currentScene; s16 currentScene;
s8 currentRoom; s8 currentRoom;
bool currentRoomClear; bool currentRoomClear;
} GeneralHelperData; } GeneralHelperData;
typedef struct typedef struct {
{
f32 linearVelocity; f32 linearVelocity;
int framesUntilChime; int framesUntilChime;
} AudioCompassData; } AudioCompassData;
typedef struct typedef struct {
{
int framesUntilAboveChime; int framesUntilAboveChime;
} SwitchData; } SwitchData;
@ -63,11 +60,9 @@ void accessible_en_ishi(AccessibleActor* actor) {
void accessible_en_NPC_Gen(AccessibleActor* actor) { void accessible_en_NPC_Gen(AccessibleActor* actor) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_VO_NB_LAUGH, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_VO_NB_LAUGH, false);
} }
void accessible_en_chest(AccessibleActor* actor) { void accessible_en_chest(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play); Player* player = GET_PLAYER(actor->play);
EnBox* chest = (EnBox*)actor->actor; EnBox* chest = (EnBox*)actor->actor;
if (chest->actionFunc != EnBox_WaitOpen) if (chest->actionFunc != EnBox_WaitOpen)
@ -82,7 +77,8 @@ void accessible_en_chest(AccessibleActor* actor) {
if (!(treasureFlag >= 20 && treasureFlag < 32)) { if (!(treasureFlag >= 20 && treasureFlag < 32)) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_TBOX_UNLOCK, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_TBOX_UNLOCK, false);
} }
//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. // 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.
f32 leftAngle = actor->actor->world.rot.y - 16384; f32 leftAngle = actor->actor->world.rot.y - 16384;
f32 velocityXRight = Math_SinS(leftAngle); f32 velocityXRight = Math_SinS(leftAngle);
f32 velocityZRight = Math_CosS(leftAngle); f32 velocityZRight = Math_CosS(leftAngle);
@ -96,14 +92,11 @@ void accessible_en_chest(AccessibleActor* actor) {
f32 zdist = fabs((player->actor.world.pos.x - actor->actor->world.pos.x) * velocityXRight + f32 zdist = fabs((player->actor.world.pos.x - actor->actor->world.pos.x) * velocityXRight +
(player->actor.world.pos.z - actor->actor->world.pos.z) * velocityZRight); (player->actor.world.pos.z - actor->actor->world.pos.z) * velocityZRight);
if ((xdist - size / 2) < 0) { if ((xdist - size / 2) < 0) {
ActorAccessibility_SetSoundPitch(actor, 0, 0.5); ActorAccessibility_SetSoundPitch(actor, 0, 0.5);
} else if ((xdist + size / 2) > 0 && zdist < size / 2 && xdist < 150.0) { } 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, false);
} }
} }
void accessible_en_gerudo(AccessibleActor* actor) { void accessible_en_gerudo(AccessibleActor* actor) {
@ -190,12 +183,9 @@ bool accessible_switch_init(AccessibleActor* actor) {
return false; // failure to allocate memory. return false; // failure to allocate memory.
actor->userData = (void*)data; actor->userData = (void*)data;
return true; return true;
} }
void accessible_switch_cleanup(AccessibleActor* actor) void accessible_switch_cleanup(AccessibleActor* actor) {
{
free(actor->userData); free(actor->userData);
} }
void accessible_switch(AccessibleActor* actor) { void accessible_switch(AccessibleActor* actor) {
@ -211,26 +201,24 @@ void accessible_switch_cleanup(AccessibleActor* actor)
} }
if (scale.y >= 33.0f / 200.0f) { if (scale.y >= 33.0f / 200.0f) {
if (actor->play->sceneNum == 0 && actor->play->roomCtx.curRoom.num == 5 && actor->xzDistToPlayer < 20) { if (actor->play->sceneNum == 0 && actor->play->roomCtx.curRoom.num == 5 && actor->xzDistToPlayer < 20) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);//Should result in same behaviour. ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH,
false); // Should result in same behaviour.
} }
if (actor->frameCount % 30 != 0) { if (actor->frameCount % 30 != 0) {
return; return;
} }
ActorAccessibility_PlaySoundForActor(actor, 1, NA_SE_EV_FOOT_SWITCH, false); ActorAccessibility_PlaySoundForActor(actor, 1, NA_SE_EV_FOOT_SWITCH, false);
} }
} } else if (actor->frameCount % 30 != 0) {
else if (actor->frameCount % 30 != 0) {
return; return;
} } else if ((actor->actor->params & 7) == 1) {
else if ((actor->actor->params & 7) == 1) {
if (actor->xyzDistToPlayer > 800) { if (actor->xyzDistToPlayer > 800) {
return; return;
} }
if (scale.y >= 33.0f / 200.0f) { //(!(Flags_GetSwitch(actor->play, (actor->params >> 8 & 0x3F)))) { if (scale.y >= 33.0f / 200.0f) { //(!(Flags_GetSwitch(actor->play, (actor->params >> 8 & 0x3F)))) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_HAMMER_HIT, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_HAMMER_HIT, false);
} }
} } else if ((actor->actor->params & 7) == 2) {
else if ((actor->actor->params & 7) == 2) {
if (sw->eyeTexIndex == 0) { //(!(Flags_GetSwitch(actor->play, (actor->params >> 8 & 0x3F)))) if (sw->eyeTexIndex == 0) { //(!(Flags_GetSwitch(actor->play, (actor->params >> 8 & 0x3F))))
// make it only play for open eye // make it only play for open eye
actor->policy.aimAssist.isProvider = true; actor->policy.aimAssist.isProvider = true;
@ -243,9 +231,7 @@ void accessible_switch_cleanup(AccessibleActor* actor)
return; return;
} }
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
} }
} }
void accessible_larva(AccessibleActor* actor) { void accessible_larva(AccessibleActor* actor) {
@ -261,7 +247,6 @@ void accessible_va_prototype(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play); Player* player = GET_PLAYER(actor->play);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_BOMB_EXPLOSION, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_BOMB_EXPLOSION, false);
} }
void accessible_maruta(AccessibleActor* actor) { void accessible_maruta(AccessibleActor* actor) {
@ -325,8 +310,7 @@ void accessible_area_change(AccessibleActor* actor) {
} else if (actor->sceneIndex == 8) { } else if (actor->sceneIndex == 8) {
if (!(((gSaveContext.eventChkInf[6]) >> (7)) & 1)) if (!(((gSaveContext.eventChkInf[6]) >> (7)) & 1))
return; return;
} } else {
else {
actor->policy.ydist = 500; actor->policy.ydist = 500;
actor->policy.distance = 1000; actor->policy.distance = 1000;
if (actor->xzDistToPlayer > 1000) { if (actor->xzDistToPlayer > 1000) {
@ -335,7 +319,6 @@ void accessible_area_change(AccessibleActor* actor) {
} }
} }
else if (actor->play->sceneNum == 91 || actor->play->sceneNum == 69 || actor->play->sceneNum == 70) { else if (actor->play->sceneNum == 91 || actor->play->sceneNum == 69 || actor->play->sceneNum == 70) {
actor->policy.distance = 1000; actor->policy.distance = 1000;
if (actor->xzDistToPlayer > 1000) { if (actor->xzDistToPlayer > 1000) {
@ -396,7 +379,8 @@ void accessible_area_change(AccessibleActor* actor) {
} else if (actor->sceneIndex == 83) { } else if (actor->sceneIndex == 83) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_PO_APPEAR, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_PO_APPEAR, false);
// graveyard sound // graveyard sound
} else if (actor->sceneIndex == 84 || actor->sceneIndex == 88 || actor->sceneIndex == 89) { //last one is zora fountain maybe seperate? } else if (actor->sceneIndex == 84 || actor->sceneIndex == 88 ||
actor->sceneIndex == 89) { // last one is zora fountain maybe seperate?
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_RIVER_STREAM_S, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_RIVER_STREAM_S, false);
// zora sound // zora sound
} else if (actor->sceneIndex == 86) { // might not need to exist } else if (actor->sceneIndex == 86) { // might not need to exist
@ -428,14 +412,12 @@ void accessible_area_change(AccessibleActor* actor) {
// Lon Lon // Lon Lon
} else if (actor->sceneIndex >= 17 && actor->sceneIndex <= 25) { } else if (actor->sceneIndex >= 17 && actor->sceneIndex <= 25) {
return; // boss rooms return; // boss rooms
} } else {
else {
actor->policy.distance = 500; actor->policy.distance = 500;
if (actor->play->sceneNum == 83) { if (actor->play->sceneNum == 83) {
actor->policy.ydist = 0; actor->policy.ydist = 0;
} }
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_OC_DOOR_OPEN, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_OC_DOOR_OPEN, false);
} }
} }
@ -455,7 +437,6 @@ void accessible_231_dekus(AccessibleActor* actor) {
} else { } else {
return; return;
} }
} }
void accessible_hana(AccessibleActor* actor) { void accessible_hana(AccessibleActor* actor) {
@ -464,7 +445,6 @@ void accessible_hana(AccessibleActor* actor) {
} else if (actor->actor->params == 0) { } 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, false);
} }
} }
void accessible_climable(AccessibleActor* actor) { void accessible_climable(AccessibleActor* actor) {
@ -482,7 +462,8 @@ void accessible_en_guard(AccessibleActor* actor) {
f32 guardsfx = NA_SE_IT_SWORD_IMPACT; f32 guardsfx = NA_SE_IT_SWORD_IMPACT;
if (fabs(actor->actor->world.pos.x - player->actor.world.pos.x) > if (fabs(actor->actor->world.pos.x - player->actor.world.pos.x) >
fabs(actor->actor->world.pos.z - player->actor.world.pos.z)) { 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) { 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, false);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0); ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
} else { } else {
@ -523,8 +504,6 @@ void accessible_en_guard(AccessibleActor* actor) {
ActorAccessibility_SetSoundPitch(actor, 0, 1.0); ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
} }
} }
} }
void accessible_en_dogs(AccessibleActor* actor) { void accessible_en_dogs(AccessibleActor* actor) {
@ -533,14 +512,12 @@ void accessible_en_dogs(AccessibleActor* actor) {
dog->actionFunc = EnDog_FollowPlayer; dog->actionFunc = EnDog_FollowPlayer;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
ActorAccessibility_SetSoundPitch(actor, 0, 1.0); ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
} }
if (actor->frameCount % 30 != 0) { if (actor->frameCount % 30 != 0) {
return; return;
} }
if (actor->actor->params == 608 || actor->actor->params == 336 || actor->actor->params == 304 || if (actor->actor->params == 608 || actor->actor->params == 336 || actor->actor->params == 304 ||
actor->actor->params == 3088 || actor->actor->params == 3088 || actor->actor->params == 2576 || actor->actor->params < 0) {
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, false);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0); ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
@ -548,7 +525,6 @@ void accessible_en_dogs(AccessibleActor* actor) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
ActorAccessibility_SetSoundPitch(actor, 0, 0.5); ActorAccessibility_SetSoundPitch(actor, 0, 0.5);
} }
} }
void accessible_goma(AccessibleActor* actor) { void accessible_goma(AccessibleActor* actor) {
@ -574,7 +550,6 @@ void accessible_sticks(AccessibleActor* actor) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_DAMAGE, false); ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_DAMAGE, false);
} }
} }
void accessible_graveyard_soil(AccessibleActor* actor) { void accessible_graveyard_soil(AccessibleActor* actor) {
@ -602,40 +577,31 @@ bool accessible_general_helper_init(AccessibleActor* actor) {
actor->userData = data; actor->userData = data;
return true; return true;
} }
void accessible_general_helper_cleanup(AccessibleActor* actor) void accessible_general_helper_cleanup(AccessibleActor* actor) {
{
free(actor->userData); free(actor->userData);
actor->userData = NULL; actor->userData = NULL;
} }
void accessible_va_general_helper(AccessibleActor* actor) void accessible_va_general_helper(AccessibleActor* actor) {
{
GeneralHelperData* data = (GeneralHelperData*)actor->userData; GeneralHelperData* data = (GeneralHelperData*)actor->userData;
if (data->currentScene == actor->play->sceneNum && data->currentRoom != actor->play->roomCtx.curRoom.num) if (data->currentScene == actor->play->sceneNum && data->currentRoom != actor->play->roomCtx.curRoom.num) {
{
ActorAccessibility_AnnounceRoomNumber(actor->play); ActorAccessibility_AnnounceRoomNumber(actor->play);
data->currentRoom = actor->play->roomCtx.curRoom.num; data->currentRoom = actor->play->roomCtx.curRoom.num;
data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom); data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom);
} }
if (data->currentScene != actor->play->sceneNum) if (data->currentScene != actor->play->sceneNum) {
{
ActorAccessibility_InterpretCurrentScene(actor->play); ActorAccessibility_InterpretCurrentScene(actor->play);
data->currentScene = actor->play->sceneNum; data->currentScene = actor->play->sceneNum;
data->currentRoom = actor->play->roomCtx.curRoom.num; data->currentRoom = actor->play->roomCtx.curRoom.num;
data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom); data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom);
} }
// Report when a room is completed. // Report when a room is completed.
if (!data->currentRoomClear && Flags_GetClear(actor->play, data->currentRoom)) if (!data->currentRoomClear && Flags_GetClear(actor->play, data->currentRoom)) {
{
data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom); data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom);
ActorAccessibility_AnnounceRoomNumber(actor->play); ActorAccessibility_AnnounceRoomNumber(actor->play);
} }
} }
bool accessible_audio_compass_init(AccessibleActor* actor) bool accessible_audio_compass_init(AccessibleActor* actor) {
{
AudioCompassData* data = (AudioCompassData*)malloc(sizeof(AudioCompassData)); AudioCompassData* data = (AudioCompassData*)malloc(sizeof(AudioCompassData));
if (data == NULL) if (data == NULL)
return false; return false;
@ -644,24 +610,22 @@ bool accessible_audio_compass_init(AccessibleActor* actor)
actor->userData = data; actor->userData = data;
return true; return true;
} }
void accessible_audio_compass_cleanup(AccessibleActor* actor) void accessible_audio_compass_cleanup(AccessibleActor* actor) {
{
free(actor->userData); free(actor->userData);
} }
void accessible_audio_compass(AccessibleActor* actor) { void accessible_audio_compass(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play); Player* player = GET_PLAYER(actor->play);
if (player->stateFlags1 & PLAYER_STATE1_Z_TARGETING || player->stateFlags1 & PLAYER_STATE1_CLIMBING_LADDER) if (player->stateFlags1 & PLAYER_STATE1_Z_TARGETING || player->stateFlags1 & PLAYER_STATE1_CLIMBING_LADDER)
return; return;
OSContPad* trackerButtonsPressed = std::dynamic_pointer_cast<LUS::ControlDeck>(Ship::Context::GetInstance()->GetControlDeck())->GetPads(); OSContPad* trackerButtonsPressed =
std::dynamic_pointer_cast<LUS::ControlDeck>(Ship::Context::GetInstance()->GetControlDeck())->GetPads();
AudioCompassData* data = (AudioCompassData*)actor->userData; AudioCompassData* data = (AudioCompassData*)actor->userData;
bool compassCombo = trackerButtonsPressed != nullptr && trackerButtonsPressed[0].button & buttonList[11] && bool compassCombo = trackerButtonsPressed != nullptr && trackerButtonsPressed[0].button & buttonList[11] &&
trackerButtonsPressed[0].button & buttonList[6]; trackerButtonsPressed[0].button & buttonList[6];
actor->world.pos = player->actor.world.pos; actor->world.pos = player->actor.world.pos;
actor->world.pos.z -= 50; actor->world.pos.z -= 50;
if (data->framesUntilChime > 0) if (data->framesUntilChime > 0)
data->framesUntilChime--; data->framesUntilChime--;
if (compassCombo && data->framesUntilChime <= 0) { if (compassCombo && data->framesUntilChime <= 0) {
@ -670,8 +634,6 @@ void accessible_audio_compass(AccessibleActor* actor) {
data->framesUntilChime = 30; data->framesUntilChime = 30;
} }
/* Player* player = GET_PLAYER(actor->play); /* Player* player = GET_PLAYER(actor->play);
if (player->stateFlags1 & PLAYER_STATE1_Z_TARGETING || player->stateFlags1 & PLAYER_STATE1_CLIMBING_LADDER) if (player->stateFlags1 & PLAYER_STATE1_Z_TARGETING || player->stateFlags1 & PLAYER_STATE1_CLIMBING_LADDER)
return; return;
@ -698,7 +660,6 @@ void accessible_audio_compass(AccessibleActor* actor) {
data->framesUntilChime = 10; data->framesUntilChime = 10;
}*/ }*/
} }
void accessible_stick_warning(AccessibleActor* actor) { void accessible_stick_warning(AccessibleActor* actor) {
@ -882,7 +843,6 @@ void accessible_stick_warning(AccessibleActor* actor) {
policy.ydist = 200; policy.ydist = 200;
policy.pitch = 1.1; policy.pitch = 1.1;
ActorAccessibility_AddSupportedActor(ACTOR_OBJ_SWITCH, policy); ActorAccessibility_AddSupportedActor(ACTOR_OBJ_SWITCH, policy);
ActorAccessibility_InitPolicy(&policy, "Ocarina Spots", NULL, NA_SE_EV_DIAMOND_SWITCH); ActorAccessibility_InitPolicy(&policy, "Ocarina Spots", NULL, NA_SE_EV_DIAMOND_SWITCH);
policy.n = 30; policy.n = 30;
@ -978,8 +938,7 @@ void accessible_stick_warning(AccessibleActor* actor) {
policy.n = 60; policy.n = 60;
policy.distance = 100000; policy.distance = 100000;
ActorAccessibility_AddSupportedActor(VA_AREA_CHANGE, policy); ActorAccessibility_AddSupportedActor(VA_AREA_CHANGE, policy);
ActorAccessibility_InitPolicy(&policy, "marker", NULL, ActorAccessibility_InitPolicy(&policy, "marker", NULL, NA_SE_EV_DIAMOND_SWITCH);
NA_SE_EV_DIAMOND_SWITCH);
policy.distance = 1000; policy.distance = 1000;
policy.pitch = 1.7; policy.pitch = 1.7;
ActorAccessibility_AddSupportedActor(VA_MARKER, policy); ActorAccessibility_AddSupportedActor(VA_MARKER, policy);
@ -1005,14 +964,14 @@ void accessible_stick_warning(AccessibleActor* actor) {
policy.sound = NA_SE_EV_SHIP_BELL; // Setting this here so it's easy to change if we ever decide to change it. 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; policy.pitch = 0.5;
ActorAccessibility_AddSupportedActor(VA_AUDIO_COMPASS, policy); ActorAccessibility_AddSupportedActor(VA_AUDIO_COMPASS, policy);
// Now query a list of virtual actors for a given // Now query a list of virtual actors for a given
// location (scene // location (scene
// and room // and room
// number). // number).
VirtualActorList* list = (VirtualActorList*)ActorAccessibility_GetVirtualActorList(EVERYWHERE, 0);//Global/ omnipresent. VirtualActorList* list =
(VirtualActorList*)ActorAccessibility_GetVirtualActorList(EVERYWHERE, 0); // Global/ omnipresent.
// Now place the actor. // Now place the actor.
ActorAccessibility_AddVirtualActor(list, VA_GENERAL_HELPER, { { 0.0, 0.0, 0.0 }, { 0, 0, 0 } }); ActorAccessibility_AddVirtualActor(list, VA_GENERAL_HELPER, { { 0.0, 0.0, 0.0 }, { 0, 0, 0 } });
@ -1030,9 +989,11 @@ void accessible_stick_warning(AccessibleActor* actor) {
ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 1046.0, 0.0, 549.00 }, { 0, 14702, 0 } }); ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 1046.0, 0.0, 549.00 }, { 0, 14702, 0 } });
ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 848.0, 0.0, -323.00 }, { 0, 14702, 0 } }); ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 848.0, 0.0, -323.00 }, { 0, 14702, 0 } });
*/ */
//ActorAccessibility_AddVirtualActor(list, VA_AREA_CHANGE,{ { -317.0, 373.2, -1542.00 }, {0, 14702, 0 }}, AREA_KORIRI); // ActorAccessibility_AddVirtualActor(list, VA_AREA_CHANGE,{ { -317.0, 373.2, -1542.00 }, {0, 14702, 0 }},
// AREA_KORIRI);
//ActorAccessibility_AddVirtualActor(list, VA_AREA_CHANGE, { { -1380.0, -67.0, -288.00 }, { 0, 14702, 0 } }, AREA_HYRULE_FIELD); // ActorAccessibility_AddVirtualActor(list, VA_AREA_CHANGE, { { -1380.0, -67.0, -288.00 }, { 0, 14702, 0 } },
// AREA_HYRULE_FIELD);
list = ActorAccessibility_GetVirtualActorList(85, 2); // Kokiri Forest Room with boulder and kokiri sword list = ActorAccessibility_GetVirtualActorList(85, 2); // Kokiri Forest Room with boulder and kokiri sword
ActorAccessibility_AddVirtualActor(list, VA_CRAWLSPACE, { { -788.0, 120.0, 1392.00 }, { 0, 14702, 0 } }); ActorAccessibility_AddVirtualActor(list, VA_CRAWLSPACE, { { -788.0, 120.0, 1392.00 }, { 0, 14702, 0 } });
@ -1117,5 +1078,4 @@ void accessible_stick_warning(AccessibleActor* actor) {
temp->policy.pitch = 1.8; temp->policy.pitch = 1.8;
temp->policy.volume = 0.5; temp->policy.volume = 0.5;
ActorAccessibility_InitCues(); ActorAccessibility_InitCues();
} }

View file

@ -53,12 +53,11 @@ static float lerp_aae(float x, float y, float z) {
gain -= lerp_aae(0, leftover, normDist); gain -= lerp_aae(0, leftover, normDist);
return gain; 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 the pan calculation from the game itself. Todo: this is technical debt, so copy/ revise it or something at
// some point.
extern "C" int8_t Audio_ComputeSoundPanSigned(float x, float z, uint8_t token); 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, static void positioner_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn,
float** ppFramesOut, float** ppFramesOut, ma_uint32* pFrameCountOut) {
ma_uint32* pFrameCountOut)
{
const float* framesIn = ppFramesIn[0]; const float* framesIn = ppFramesIn[0];
float* framesOut = ppFramesOut[0]; float* framesOut = ppFramesOut[0];
@ -68,8 +67,10 @@ static float lerp_aae(float x, float y, float z) {
// Pan the sound based on its projected position. // Pan the sound based on its projected position.
float pan; float pan;
// Use the game's panning mechanism, which returns a signed 8-bit integer between 0 (far-left) and 127 (far-right). // Use the game's panning mechanism, which returns a signed 8-bit integer between 0 (far-left) and 127 (far-right).
//It would appear that the correct thing to do is interpret this value as a gain factor in decibels. In practice, values below 38 or above 90 are never seen, so a sound that's panned far to one side or the other amounts to about -25DB worth of attenuation. // It would appear that the correct thing to do is interpret this value as a gain factor in decibels. In practice,
//Also: lie about the value of Z and give it a constant value to prevent weird behaviour when Z is far away. // values below 38 or above 90 are never seen, so a sound that's panned far to one side or the other amounts to
// about -25DB worth of attenuation. Also: lie about the value of Z and give it a constant value to prevent weird
// behaviour when Z is far away.
s8 panSigned = Audio_ComputeSoundPanSigned(extras->x, extras->z, 4); s8 panSigned = Audio_ComputeSoundPanSigned(extras->x, extras->z, 4);
int db; int db;
if (panSigned < 64) if (panSigned < 64)
@ -82,18 +83,20 @@ static float lerp_aae(float x, float y, float z) {
ma_panner_set_pan(&extras->panner, pan); ma_panner_set_pan(&extras->panner, pan);
ma_panner_process_pcm_frames(&extras->panner, framesOut, framesOut, *pFrameCountIn); ma_panner_process_pcm_frames(&extras->panner, framesOut, framesOut, *pFrameCountIn);
//Next we'll apply the gain based on the object's distance relationship to the player. The strategy here is to use a combination of decibel-based and linear attenuation, so that the gain reaches 0 at the exact point when the object is at exactly the maximum distance from the player. // Next we'll apply the gain based on the object's distance relationship to the player. The strategy here is to use
// a combination of decibel-based and linear attenuation, so that the gain reaches 0 at the exact point when the
// object is at exactly the maximum distance from the player.
float gain = computeGain(extras); float gain = computeGain(extras);
ma_gainer_set_gain(&extras->gainer, gain); ma_gainer_set_gain(&extras->gainer, gain);
ma_gainer_process_pcm_frames(&extras->gainer, framesOut, framesOut, *pFrameCountIn); ma_gainer_process_pcm_frames(&extras->gainer, framesOut, framesOut, *pFrameCountIn);
//Run LPF only when necessary because we can't afford to run a 4th-order lowpass on every single sound. This probably causes minor glitches when the filter switches on and off. Todo: cross that bridge. // Run LPF only when necessary because we can't afford to run a 4th-order lowpass on every single sound. This
// probably causes minor glitches when the filter switches on and off. Todo: cross that bridge.
if (extras->cutoff != 1.0) if (extras->cutoff != 1.0)
ma_lpf_process_pcm_frames(&extras->filter, framesOut, framesOut, *pFrameCountIn); ma_lpf_process_pcm_frames(&extras->filter, framesOut, framesOut, *pFrameCountIn);
} }
static ma_node_vtable positioner_vtable = { static ma_node_vtable positioner_vtable = { positioner_process_pcm_frames, NULL, 1, 1, 0 };
positioner_process_pcm_frames, NULL, 1, 1, 0};
static ma_uint32 positioner_channels[1] = { 2 }; static ma_uint32 positioner_channels[1] = { 2 };
void AccessibleAudioEngine::destroy() { void AccessibleAudioEngine::destroy() {
@ -130,14 +133,11 @@ throw std::runtime_error(exceptionText);
buffer += framesObtained * AAE_CHANNELS; buffer += framesObtained * AAE_CHANNELS;
nFrames -= framesObtained; nFrames -= framesObtained;
ma_pcm_rb_commit_read(&preparedOutput, framesObtained); ma_pcm_rb_commit_read(&preparedOutput, framesObtained);
} }
return ogNFrames; return ogNFrames;
} }
void AccessibleAudioEngine::doPrepare(SoundAction& action) void AccessibleAudioEngine::doPrepare(SoundAction& action) {
{
framesUntilGC--; framesUntilGC--;
int nFrames = ma_pcm_rb_available_write(&preparedOutput); int nFrames = ma_pcm_rb_available_write(&preparedOutput);
if (nFrames <= 0) if (nFrames <= 0)
@ -147,7 +147,9 @@ void AccessibleAudioEngine::doPrepare(SoundAction& action)
while (nFrames > 0) { while (nFrames > 0) {
// This should not loop more than twice. // This should not loop more than twice.
uint32_t nextChunk = nFrames; uint32_t nextChunk = nFrames;
ma_pcm_rb_acquire_write(&preparedOutput, &nextChunk, (void**)&chunk);//Might reduce nextChunk if there isn't enough buffer space available to accommodate the request. ma_pcm_rb_acquire_write(&preparedOutput, &nextChunk,
(void**)&chunk); // Might reduce nextChunk if there isn't enough buffer space available
// to accommodate the request.
ma_uint64 framesRead = 0; ma_uint64 framesRead = 0;
ma_engine_read_pcm_frames(&engine, chunk, nextChunk, &framesRead); ma_engine_read_pcm_frames(&engine, chunk, nextChunk, &framesRead);
// Even if we get fewer frames than expected, we should still submit a full buffer of silence. // Even if we get fewer frames than expected, we should still submit a full buffer of silence.
@ -155,9 +157,7 @@ void AccessibleAudioEngine::doPrepare(SoundAction& action)
ma_silence_pcm_frames(chunk + (framesRead * 2), (nextChunk - framesRead), ma_format_f32, 2); ma_silence_pcm_frames(chunk + (framesRead * 2), (nextChunk - framesRead), ma_format_f32, 2);
ma_pcm_rb_commit_write(&preparedOutput, (uint32_t)nextChunk); ma_pcm_rb_commit_write(&preparedOutput, (uint32_t)nextChunk);
nFrames -= nextChunk; nFrames -= nextChunk;
} }
} }
int AccessibleAudioEngine::getSoundActions(SoundAction* dest, int limit) { int AccessibleAudioEngine::getSoundActions(SoundAction* dest, int limit) {
std::unique_lock<std::mutex> lock(mtx); std::unique_lock<std::mutex> lock(mtx);
@ -171,7 +171,6 @@ int AccessibleAudioEngine::getSoundActions(SoundAction* dest, int limit) {
limit--; limit--;
} }
return actionsOut; return actionsOut;
} }
void AccessibleAudioEngine::postSoundActions() { void AccessibleAudioEngine::postSoundActions() {
{ {
@ -245,14 +244,11 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
case AAE_PREPARE: case AAE_PREPARE:
doPrepare(action); doPrepare(action);
break; break;
} }
} }
} }
} }
SoundSlot* AccessibleAudioEngine::findSound(SoundAction& action) SoundSlot* AccessibleAudioEngine::findSound(SoundAction& action) {
{
if (action.slot < 0 || action.slot >= AAE_SLOTS_PER_HANDLE) if (action.slot < 0 || action.slot >= AAE_SLOTS_PER_HANDLE)
return NULL; return NULL;
auto i = sounds.find(action.handle); auto i = sounds.find(action.handle);
@ -262,7 +258,6 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
if (!target.active) if (!target.active)
return NULL; return NULL;
return &target; return &target;
} }
void AccessibleAudioEngine::doPlaySound(SoundAction& action) { void AccessibleAudioEngine::doPlaySound(SoundAction& action) {
SoundSlot* sound; SoundSlot* sound;
@ -282,7 +277,8 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
sounds[action.handle] = temp; sounds[action.handle] = temp;
sound = &sounds[action.handle][action.slot]; sound = &sounds[action.handle][action.slot];
} }
if (ma_sound_init_from_file(&engine, action.path.c_str(), MA_SOUND_FLAG_NO_SPATIALIZATION|MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT, NULL, NULL, if (ma_sound_init_from_file(&engine, action.path.c_str(),
MA_SOUND_FLAG_NO_SPATIALIZATION | MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT, NULL, NULL,
&sound->sound) != MA_SUCCESS) &sound->sound) != MA_SUCCESS)
return; return;
@ -301,22 +297,18 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
return; return;
destroySound(slot); destroySound(slot);
} }
void AccessibleAudioEngine::doStopAllSounds(SoundAction& action) void AccessibleAudioEngine::doStopAllSounds(SoundAction& action) {
{
auto it = sounds.find(action.handle); auto it = sounds.find(action.handle);
if (it == sounds.end()) if (it == sounds.end())
return; return;
SoundSlots& slots = it->second; SoundSlots& slots = it->second;
for (int i = 0; i < AAE_SLOTS_PER_HANDLE; i++) for (int i = 0; i < AAE_SLOTS_PER_HANDLE; i++) {
{
if (slots[i].active) if (slots[i].active)
destroySound(&slots[i]); destroySound(&slots[i]);
} }
sounds.erase(it); sounds.erase(it);
} }
void AccessibleAudioEngine::doSetPitch(SoundAction& action) void AccessibleAudioEngine::doSetPitch(SoundAction& action) {
{
SoundSlot* slot = findSound(action); SoundSlot* slot = findSound(action);
if (slot == NULL) if (slot == NULL)
return; return;
@ -325,55 +317,44 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
if (slot->extras.z < 0) if (slot->extras.z < 0)
pitch *= (1.0 - slot->extras.pitchBehindModifier); pitch *= (1.0 - slot->extras.pitchBehindModifier);
ma_sound_set_pitch(&slot->sound, pitch); ma_sound_set_pitch(&slot->sound, pitch);
} }
void AccessibleAudioEngine::doSetPitchBehindModifier(SoundAction& action) void AccessibleAudioEngine::doSetPitchBehindModifier(SoundAction& action) {
{
SoundSlot* slot = findSound(action); SoundSlot* slot = findSound(action);
if (slot == NULL) if (slot == NULL)
return; return;
slot->extras.pitchBehindModifier = action.pitch; slot->extras.pitchBehindModifier = action.pitch;
} }
void AccessibleAudioEngine::doSetVolume(SoundAction& action) void AccessibleAudioEngine::doSetVolume(SoundAction& action) {
{
SoundSlot* slot = findSound(action); SoundSlot* slot = findSound(action);
if (slot == NULL) if (slot == NULL)
return; return;
ma_sound_set_volume(&slot->sound, action.pitch); ma_sound_set_volume(&slot->sound, action.pitch);
} }
void AccessibleAudioEngine::doSetPan(SoundAction& action) void AccessibleAudioEngine::doSetPan(SoundAction& action) {
{
SoundSlot* slot = findSound(action); SoundSlot* slot = findSound(action);
if (slot == NULL) if (slot == NULL)
return; return;
ma_sound_set_pan(&slot->sound, action.pan); ma_sound_set_pan(&slot->sound, action.pan);
} }
void AccessibleAudioEngine::doSetFilter(SoundAction& action) void AccessibleAudioEngine::doSetFilter(SoundAction& action) {
{
SoundSlot* slot = findSound(action); SoundSlot* slot = findSound(action);
if (slot == NULL) if (slot == NULL)
return; return;
slot->extras.cutoff = action.cutoff; slot->extras.cutoff = action.cutoff;
ma_lpf_config config = ma_lpf_config config = ma_lpf_config_init(ma_format_f32, AAE_CHANNELS, AAE_SAMPLE_RATE,
ma_lpf_config_init(ma_format_f32, AAE_CHANNELS, AAE_SAMPLE_RATE, lerp_aae(0.0, AAE_SAMPLE_RATE / 2, action.cutoff), AAE_LPF_ORDER); lerp_aae(0.0, AAE_SAMPLE_RATE / 2, action.cutoff), AAE_LPF_ORDER);
ma_lpf_reinit(&config, &slot->extras.filter); ma_lpf_reinit(&config, &slot->extras.filter);
} }
void AccessibleAudioEngine::doSeekSound(SoundAction& action) void AccessibleAudioEngine::doSeekSound(SoundAction& action) {
{
SoundSlot* slot = findSound(action); SoundSlot* slot = findSound(action);
if (slot == NULL) if (slot == NULL)
return; return;
ma_sound_seek_to_pcm_frame(&slot->sound, action.offset); ma_sound_seek_to_pcm_frame(&slot->sound, action.offset);
} }
void AccessibleAudioEngine::doSetListenerPos(SoundAction& action) void AccessibleAudioEngine::doSetListenerPos(SoundAction& action) {
{
} }
void AccessibleAudioEngine::doSetSoundPos(SoundAction& action) void AccessibleAudioEngine::doSetSoundPos(SoundAction& action) {
{
SoundSlot* slot = findSound(action); SoundSlot* slot = findSound(action);
if (slot == NULL) if (slot == NULL)
return; return;
@ -387,8 +368,7 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
pitch *= (1.0 - slot->extras.pitchBehindModifier); pitch *= (1.0 - slot->extras.pitchBehindModifier);
ma_sound_set_pitch(&slot->sound, pitch); ma_sound_set_pitch(&slot->sound, pitch);
} }
void AccessibleAudioEngine::garbageCollect() void AccessibleAudioEngine::garbageCollect() {
{
for (auto i = sounds.begin(); i != sounds.end();) { for (auto i = sounds.begin(); i != sounds.end();) {
int deadSlots = 0; int deadSlots = 0;
for (int x = 0; x < AAE_SLOTS_PER_HANDLE; x++) { for (int x = 0; x < AAE_SLOTS_PER_HANDLE; x++) {
@ -398,7 +378,6 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
destroySound(&i->second[x]); destroySound(&i->second[x]);
i->second[x].active = false; i->second[x].active = false;
deadSlots++; deadSlots++;
} }
} }
if (deadSlots == AAE_SLOTS_PER_HANDLE) // Entire batch is garbage. if (deadSlots == AAE_SLOTS_PER_HANDLE) // Entire batch is garbage.
@ -408,12 +387,10 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
} }
framesUntilGC = AAE_GC_INTERVAL; framesUntilGC = AAE_GC_INTERVAL;
} }
void AccessibleAudioEngine::processAudioJobs() void AccessibleAudioEngine::processAudioJobs() {
{
ma_job job; ma_job job;
while (ma_resource_manager_next_job(&resourceManager, &job) == MA_SUCCESS) while (ma_resource_manager_next_job(&resourceManager, &job) == MA_SUCCESS)
ma_job_process(&job); ma_job_process(&job);
} }
bool AccessibleAudioEngine::initSoundExtras(SoundSlot* slot) { bool AccessibleAudioEngine::initSoundExtras(SoundSlot* slot) {
ma_node_config config = ma_node_config_init(); ma_node_config config = ma_node_config_init();
@ -428,10 +405,13 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
ma_panner_config pc = ma_panner_config_init(ma_format_f32, AAE_CHANNELS); ma_panner_config pc = ma_panner_config_init(ma_format_f32, AAE_CHANNELS);
pc.mode = ma_pan_mode_balance; pc.mode = ma_pan_mode_balance;
ma_panner_init(&pc, &slot->extras.panner); ma_panner_init(&pc, &slot->extras.panner);
ma_gainer_config gc = ma_gainer_config_init(AAE_CHANNELS, AAE_SAMPLE_RATE / 20);//Allow one in-game frame for the gain to work its way towards the target value. ma_gainer_config gc = ma_gainer_config_init(
AAE_CHANNELS,
AAE_SAMPLE_RATE / 20); // Allow one in-game frame for the gain to work its way towards the target value.
if (ma_gainer_init(&gc, NULL, &slot->extras.gainer) != MA_SUCCESS) if (ma_gainer_init(&gc, NULL, &slot->extras.gainer) != MA_SUCCESS)
return false; return false;
ma_lpf_config fc = ma_lpf_config_init(ma_format_f32, AAE_CHANNELS, AAE_SAMPLE_RATE, AAE_SAMPLE_RATE / 2, AAE_LPF_ORDER); ma_lpf_config fc =
ma_lpf_config_init(ma_format_f32, AAE_CHANNELS, AAE_SAMPLE_RATE, AAE_SAMPLE_RATE / 2, AAE_LPF_ORDER);
ma_lpf_init(&fc, NULL, &slot->extras.filter); ma_lpf_init(&fc, NULL, &slot->extras.filter);
slot->extras.cutoff = 1.0f; slot->extras.cutoff = 1.0f;
slot->extras.pitch = 1.0f; slot->extras.pitch = 1.0f;
@ -439,7 +419,6 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
// ma_node_attach_output_bus(&slot->sound, 0, &slot->extras.filter, 0); // ma_node_attach_output_bus(&slot->sound, 0, &slot->extras.filter, 0);
ma_node_attach_output_bus(&slot->sound, 0, &slot->extras, 0); ma_node_attach_output_bus(&slot->sound, 0, &slot->extras, 0);
return true; return true;
} }
void AccessibleAudioEngine::destroySound(SoundSlot* slot) { void AccessibleAudioEngine::destroySound(SoundSlot* slot) {
ma_node_detach_all_output_buses(&slot->extras); ma_node_detach_all_output_buses(&slot->extras);
@ -447,7 +426,6 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
ma_gainer_uninit(&slot->extras.gainer, NULL); ma_gainer_uninit(&slot->extras.gainer, NULL);
slot->active = false; slot->active = false;
} }
AccessibleAudioEngine::AccessibleAudioEngine() { AccessibleAudioEngine::AccessibleAudioEngine() {
@ -477,7 +455,6 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
nextOutgoingSoundAction = 0; nextOutgoingSoundAction = 0;
framesUntilGC = AAE_GC_INTERVAL; framesUntilGC = AAE_GC_INTERVAL;
thread = std::thread(&AccessibleAudioEngine::runThread, this); thread = std::thread(&AccessibleAudioEngine::runThread, this);
} }
AccessibleAudioEngine::~AccessibleAudioEngine() { AccessibleAudioEngine::~AccessibleAudioEngine() {
// Place a terminate command on the top of the pile, then wait for thread to die. // Place a terminate command on the top of the pile, then wait for thread to die.
@ -486,7 +463,6 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
postHighPrioritySoundAction(action); postHighPrioritySoundAction(action);
thread.join(); thread.join();
destroy(); destroy();
} }
void AccessibleAudioEngine::mix(int16_t* ogBuffer, uint32_t nFrames) { void AccessibleAudioEngine::mix(int16_t* ogBuffer, uint32_t nFrames) {
uint32_t framesAvailable = ma_pcm_rb_available_read(&preparedOutput); uint32_t framesAvailable = ma_pcm_rb_available_read(&preparedOutput);
@ -494,10 +470,13 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
float mixedChunk[AAE_MIX_CHUNK_SIZE * AAE_CHANNELS]; float mixedChunk[AAE_MIX_CHUNK_SIZE * AAE_CHANNELS];
while (nFrames > 0) { while (nFrames > 0) {
uint32_t nextChunk = std::min<uint32_t>(AAE_MIX_CHUNK_SIZE, nFrames); uint32_t nextChunk = std::min<uint32_t>(AAE_MIX_CHUNK_SIZE, nFrames);
ma_silence_pcm_frames(sourceChunk, nextChunk, ma_format_f32, AAE_CHANNELS);//This is so that it doesn't matter if we have less output available than expected. ma_silence_pcm_frames(
sourceChunk, nextChunk, ma_format_f32,
AAE_CHANNELS); // This is so that it doesn't matter if we have less output available than expected.
ma_silence_pcm_frames(mixedChunk, nextChunk, ma_format_f32, AAE_CHANNELS); ma_silence_pcm_frames(mixedChunk, nextChunk, ma_format_f32, AAE_CHANNELS);
retrieve(sourceChunk, nextChunk); retrieve(sourceChunk, nextChunk);
ma_pcm_s16_to_f32(mixedChunk, ogBuffer, nextChunk * AAE_CHANNELS, ma_dither_mode_none);//The game's output is changed to 32-bit floating point samples. ma_pcm_s16_to_f32(mixedChunk, ogBuffer, nextChunk * AAE_CHANNELS,
ma_dither_mode_none); // The game's output is changed to 32-bit floating point samples.
ma_mix_pcm_frames_f32(mixedChunk, sourceChunk, nextChunk, AAE_CHANNELS, 1.0); ma_mix_pcm_frames_f32(mixedChunk, sourceChunk, nextChunk, AAE_CHANNELS, 1.0);
// If we've gone over 1.0, we'll need to scale back before we go back to 16-bit or we'll distort. // If we've gone over 1.0, we'll need to scale back before we go back to 16-bit or we'll distort.
float scalar = 1.0; float scalar = 1.0;
@ -508,11 +487,11 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
for (int i = 0; i < nextChunk * AAE_CHANNELS; i++) for (int i = 0; i < nextChunk * AAE_CHANNELS; i++)
mixedChunk[i] *= scalar; mixedChunk[i] *= scalar;
} }
ma_pcm_f32_to_s16(ogBuffer, mixedChunk, nextChunk * AAE_CHANNELS, ma_dither_mode_triangle);//Chunk is ready to go out via the game's usual channels. ma_pcm_f32_to_s16(ogBuffer, mixedChunk, nextChunk * AAE_CHANNELS,
ma_dither_mode_triangle); // Chunk is ready to go out via the game's usual channels.
ogBuffer += nextChunk * AAE_CHANNELS; ogBuffer += nextChunk * AAE_CHANNELS;
nFrames -= nextChunk; nFrames -= nextChunk;
} }
} }
void AccessibleAudioEngine::playSound(uintptr_t handle, int slot, const char* path, bool looping) { void AccessibleAudioEngine::playSound(uintptr_t handle, int slot, const char* path, bool looping) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE) if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
@ -546,7 +525,6 @@ void AccessibleAudioEngine::stopAllSounds(uintptr_t handle) {
action.handle = handle; action.handle = handle;
action.slot = slot; action.slot = slot;
action.pitch = pitch; action.pitch = pitch;
} }
void AccessibleAudioEngine::setPitchBehindModifier(uintptr_t handle, int slot, float mod) { void AccessibleAudioEngine::setPitchBehindModifier(uintptr_t handle, int slot, float mod) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE) if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
@ -557,8 +535,6 @@ void AccessibleAudioEngine::stopAllSounds(uintptr_t handle) {
action.handle = handle; action.handle = handle;
action.slot = slot; action.slot = slot;
action.pitch = mod; action.pitch = mod;
} }
void AccessibleAudioEngine::setVolume(uintptr_t handle, int slot, float volume) { void AccessibleAudioEngine::setVolume(uintptr_t handle, int slot, float volume) {
@ -600,9 +576,9 @@ void AccessibleAudioEngine::setFilter(uintptr_t handle, int slot, float cutoff)
action.slot = slot; action.slot = slot;
action.command = AAE_SEEK; action.command = AAE_SEEK;
action.offset = offset; action.offset = offset;
} }
void AccessibleAudioEngine::setSoundPosition(uintptr_t handle, int slot, float posX, float posY, float posZ, float distToPlayer, float maxDistance) { void AccessibleAudioEngine::setSoundPosition(uintptr_t handle, int slot, float posX, float posY, float posZ,
float distToPlayer, float maxDistance) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE) if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return; return;
SoundAction& action = getNextOutgoingSoundAction(); SoundAction& action = getNextOutgoingSoundAction();
@ -614,7 +590,6 @@ void AccessibleAudioEngine::setSoundPosition(uintptr_t handle, int slot, float p
action.posZ = posZ; action.posZ = posZ;
action.distToPlayer = distToPlayer; action.distToPlayer = distToPlayer;
action.maxDistance = maxDistance; action.maxDistance = maxDistance;
} }
void AccessibleAudioEngine::prepare() { void AccessibleAudioEngine::prepare() {
SoundAction& action = getNextOutgoingSoundAction(); SoundAction& action = getNextOutgoingSoundAction();
@ -623,6 +598,7 @@ void AccessibleAudioEngine::setSoundPosition(uintptr_t handle, int slot, float p
postSoundActions(); postSoundActions();
} }
void AccessibleAudioEngine::cacheDecodedSample(std::string& path, void* data, size_t size) { void AccessibleAudioEngine::cacheDecodedSample(std::string& path, void* data, size_t size) {
//The data is stored in wave format, so we register it with MiniAudio as an encoded asset as opposed to a decoded one. // The data is stored in wave format, so we register it with MiniAudio as an encoded asset as opposed to a decoded
// one.
ma_resource_manager_register_encoded_data(&resourceManager, path.c_str(), data, size); ma_resource_manager_register_encoded_data(&resourceManager, path.c_str(), data, size);
} }

View file

@ -41,8 +41,7 @@ struct SoundAction {
uint32_t frames; // If command is AAE_PREPARE, this tells the engine how many PCM frames to get ready. uint32_t frames; // If command is AAE_PREPARE, this tells the engine how many PCM frames to get ready.
}; };
typedef struct typedef struct {
{
ma_node_base base; ma_node_base base;
ma_panner panner; ma_panner panner;
ma_gainer gainer; ma_gainer gainer;
@ -57,8 +56,7 @@ typedef struct
float pitchBehindModifier; float pitchBehindModifier;
} SoundExtras; // Used for attenuation and other effects. } SoundExtras; // Used for attenuation and other effects.
typedef struct typedef struct {
{
ma_sound sound; ma_sound sound;
SoundExtras extras; SoundExtras extras;
@ -76,14 +74,17 @@ class AccessibleAudioEngine {
std::condition_variable cv; std::condition_variable cv;
std::mutex mtx; std::mutex mtx;
std::unordered_map<uintptr_t, SoundSlots> sounds; std::unordered_map<uintptr_t, SoundSlots> sounds;
SoundAction outgoingSoundActions[AAE_SOUND_ACTION_BATCH_SIZE];//Allows batch delivery of SoundActions to the FIFO to minimize the amount of time spent locking and unlocking. SoundAction
outgoingSoundActions[AAE_SOUND_ACTION_BATCH_SIZE]; // Allows batch delivery of SoundActions to the FIFO to
// minimize the amount of time spent locking and unlocking.
int nextOutgoingSoundAction; int nextOutgoingSoundAction;
int framesUntilGC; int framesUntilGC;
void destroy(); // Called by the destructor, or if a throw occurs during construction. void destroy(); // Called by the destructor, or if a throw occurs during construction.
// Dismantal a partial initialization and throw an exception. // Dismantal a partial initialization and throw an exception.
void destroyAndThrow(const char* exceptionText); void destroyAndThrow(const char* exceptionText);
//Retrieve some audio from the output buffer. This is to be performed by the audio thread. May return less data than requested. // Retrieve some audio from the output buffer. This is to be performed by the audio thread. May return less data
// than requested.
uint32_t retrieve(float* buffer, uint32_t nFrames); uint32_t retrieve(float* buffer, uint32_t nFrames);
// Functions dealing with the command queue. // Functions dealing with the command queue.
int getSoundActions(SoundAction* dest, int limit); int getSoundActions(SoundAction* dest, int limit);
@ -124,7 +125,9 @@ SoundSlot* findSound(SoundAction& action);
public: public:
AccessibleAudioEngine(); AccessibleAudioEngine();
~AccessibleAudioEngine(); ~AccessibleAudioEngine();
//Mix the game's audio with this engine's audio to produce the final mix. To be performed exclusively in the audio thread. Mixing is done in-place (meaning the buffer containing the game's audio is overwritten with the mixed content). // Mix the game's audio with this engine's audio to produce the final mix. To be performed exclusively in the audio
// thread. Mixing is done in-place (meaning the buffer containing the game's audio is overwritten with the mixed
// content).
void mix(int16_t* ogBuffer, uint32_t nFrames); void mix(int16_t* ogBuffer, uint32_t nFrames);
// Start playing a sound. // Start playing a sound.
void playSound(uintptr_t handle, int slot, const char* path, bool looping); void playSound(uintptr_t handle, int slot, const char* path, bool looping);
@ -140,10 +143,10 @@ SoundSlot* findSound(SoundAction& action);
void setFilter(uintptr_t handle, int slot, float cutoff); void setFilter(uintptr_t handle, int slot, float cutoff);
// Seek the sound to a particular PCM frame. // Seek the sound to a particular PCM frame.
void seekSound(uintptr_t handle, int slot, size_t offset); 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, float maxDistance); void setSoundPosition(uintptr_t handle, int slot, float posX, float posY, float posZ, float distToPlayer,
float maxDistance);
// Schedule the preparation of output for delivery. // Schedule the preparation of output for delivery.
void prepare(); void prepare();
void cacheDecodedSample(std::string& path, void* data, size_t size); void cacheDecodedSample(std::string& path, void* data, size_t size);
}; };
#endif #endif

View file

@ -31,10 +31,12 @@ extern bool freezeActors;
const char* GetLanguageCode(); const char* GetLanguageCode();
#define MAX_DB_REDUCTION 35// This is the amount in DB that a sound will be reduced by when it is at the maximum distance #define MAX_DB_REDUCTION \
35 // This is the amount in DB that a sound will be reduced by when it is at the maximum distance
// from the player. // from the player.
extern "C" { extern "C" {
void CollisionPoly_GetVertices(CollisionPoly* poly, Vec3s* vtxList, Vec3f* dest);//Used to tell where polygons are located. void CollisionPoly_GetVertices(CollisionPoly* poly, Vec3s* vtxList,
Vec3f* dest); // Used to tell where polygons are located.
} }
typedef struct { typedef struct {
@ -47,12 +49,16 @@ extern "C" {
}; };
} SceneAndRoom; } SceneAndRoom;
typedef std::map<s16, ActorAccessibilityPolicy> SupportedActors_t;//Maps actors to their accessibility policies, which describe how accessibility should treat them. typedef std::map<s16, ActorAccessibilityPolicy> SupportedActors_t; // Maps actors to their accessibility policies, which
// describe how accessibility should treat them.
typedef std::map<Actor*, uint64_t> TrackedActors_t; // Maps real actors to internal IDs specific to accessibility. typedef std::map<Actor*, uint64_t> TrackedActors_t; // Maps real actors to internal IDs specific to accessibility.
typedef std::map<uint64_t, AccessibleActor> AccessibleActorList_t;//Maps internal IDs to wrapped actor objects. These actors can be real or virtual. typedef std::map<uint64_t, AccessibleActor>
AccessibleActorList_t; // Maps internal IDs to wrapped actor objects. These actors can be real or virtual.
typedef std::vector<AccessibleActor> VAList_t; // Denotes a list of virtual actors specific to a single room. typedef std::vector<AccessibleActor> VAList_t; // Denotes a list of virtual actors specific to a single room.
typedef std::map<s32, VAList_t> VAZones_t; // Maps room/ scene indices to their corresponding virtual actor collections. typedef std::map<s32, VAList_t> VAZones_t; // Maps room/ scene indices to their corresponding virtual actor collections.
typedef std::unordered_set<s16> SceneList_t;//A list of scenes which have already been visited (since the game was launched). Used to prevent re-creation of terrain VAs every time the player reloads a scene. typedef std::unordered_set<s16>
SceneList_t; // A list of scenes which have already been visited (since the game was launched). Used to prevent
// re-creation of terrain VAs every time the player reloads a scene.
typedef struct { typedef struct {
std::string path; std::string path;
@ -84,7 +90,8 @@ class ActorAccessibility {
AccessibleAudioEngine* audioEngine; AccessibleAudioEngine* audioEngine;
SfxExtractor sfxExtractor; SfxExtractor sfxExtractor;
std::unordered_map<s16, SfxRecord> sfxMap; // Maps internal sfx to external (prerendered) resources. std::unordered_map<s16, SfxRecord> sfxMap; // Maps internal sfx to external (prerendered) resources.
std::unordered_map<std::string, SfxRecord> sampleMap;//Similar to above, but this one maps raw audio samples as opposed to SFX. std::unordered_map<std::string, SfxRecord>
sampleMap; // Similar to above, but this one maps raw audio samples as opposed to SFX.
int extractSfx = 0; int extractSfx = 0;
s16 currentScene = -1; s16 currentScene = -1;
s8 currentRoom = -1; s8 currentRoom = -1;
@ -94,9 +101,6 @@ class ActorAccessibility {
}; };
static ActorAccessibility* aa; static ActorAccessibility* aa;
uint64_t ActorAccessibility_GetNextID() { uint64_t ActorAccessibility_GetNextID() {
uint64_t result = aa->nextActorID; uint64_t result = aa->nextActorID;
aa->nextActorID++; aa->nextActorID++;
@ -115,18 +119,14 @@ void ActorAccessibility_OnGameFrameUpdate() {
ActorAccessibility_RunAccessibilityForAllActors(gPlayState); ActorAccessibility_RunAccessibilityForAllActors(gPlayState);
} }
void ActorAccessibility_OnActorDestroy(void* actor) void ActorAccessibility_OnActorDestroy(void* actor) {
{
ActorAccessibility_RemoveTrackedActor((Actor*)actor); ActorAccessibility_RemoveTrackedActor((Actor*)actor);
} }
void ActorAccessibility_OnGameStillFrozen() void ActorAccessibility_OnGameStillFrozen() {
{
if (gPlayState == NULL) if (gPlayState == NULL)
return; return;
if (aa->extractSfx) if (aa->extractSfx)
ActorAccessibility_HandleSoundExtractionMode(gPlayState); ActorAccessibility_HandleSoundExtractionMode(gPlayState);
} }
void ActorAccessibility_Init() { void ActorAccessibility_Init() {
@ -167,12 +167,10 @@ void ActorAccessibility_Shutdown() {
policy->aimAssist.isProvider = false; policy->aimAssist.isProvider = false;
policy->aimAssist.sfx = NA_SE_SY_HITPOINT_ALARM; policy->aimAssist.sfx = NA_SE_SY_HITPOINT_ALARM;
policy->aimAssist.tolerance = 0.0; policy->aimAssist.tolerance = 0.0;
} }
void ActorAccessibility_AddSupportedActor(s16 type, ActorAccessibilityPolicy policy) { void ActorAccessibility_AddSupportedActor(s16 type, ActorAccessibilityPolicy policy) {
aa->supportedActors[type] = policy; aa->supportedActors[type] = policy;
} }
ActorAccessibilityPolicy* ActorAccessibility_GetPolicyForActor(s16 type) { ActorAccessibilityPolicy* ActorAccessibility_GetPolicyForActor(s16 type) {
@ -180,13 +178,11 @@ ActorAccessibilityPolicy* ActorAccessibility_GetPolicyForActor(s16 type) {
if (i == aa->supportedActors.end()) if (i == aa->supportedActors.end())
return NULL; return NULL;
return &(i->second); return &(i->second);
} }
int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) { int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
static std::mt19937 gen; static std::mt19937 gen;
std::uniform_int_distribution<> dist(min, max); std::uniform_int_distribution<> dist(min, max);
return dist(gen); return dist(gen);
} }
void ActorAccessibility_TrackNewActor(Actor* actor) { void ActorAccessibility_TrackNewActor(Actor* actor) {
@ -220,7 +216,6 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
return; // Probably a malloc error preventing user data initialization. return; // Probably a malloc error preventing user data initialization.
} }
} }
void ActorAccessibility_RemoveTrackedActor(Actor* actor) { void ActorAccessibility_RemoveTrackedActor(Actor* actor) {
TrackedActors_t::iterator i = aa->trackedActors.find(actor); TrackedActors_t::iterator i = aa->trackedActors.find(actor);
@ -235,7 +230,6 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
i2->second.policy.cleanupUserData(&i2->second); i2->second.policy.cleanupUserData(&i2->second);
ActorAccessibility_StopAllSoundsForActor(&i2->second); ActorAccessibility_StopAllSoundsForActor(&i2->second);
aa->accessibleActorList.erase(i2); aa->accessibleActorList.erase(i2);
} }
f32 ActorAccessibility_DBToLinear(float gain) { f32 ActorAccessibility_DBToLinear(float gain) {
@ -249,11 +243,9 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
f32 db = LERP(0.0 - MAX_DB_REDUCTION, 0.0, (maxDistance - absDistance) / maxDistance); f32 db = LERP(0.0 - MAX_DB_REDUCTION, 0.0, (maxDistance - absDistance) / maxDistance);
return ActorAccessibility_DBToLinear(db); return ActorAccessibility_DBToLinear(db);
} }
const char* ActorAccessibility_MapSfxToExternalAudio(s16 sfxId); 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, bool looping) {
{
const char* path = ActorAccessibility_MapSfxToExternalAudio(sfxId); const char* path = ActorAccessibility_MapSfxToExternalAudio(sfxId);
if (path == NULL) if (path == NULL)
return; return;
@ -261,88 +253,64 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
} }
const char* ActorAccessibility_MapRawSampleToExternalAudio(const char* name); const char* ActorAccessibility_MapRawSampleToExternalAudio(const char* name);
void ActorAccessibility_PlayRawSample(void* handle, int slot, const char* name, bool looping) void ActorAccessibility_PlayRawSample(void* handle, int slot, const char* name, bool looping) {
{
const char* path = ActorAccessibility_MapRawSampleToExternalAudio(name); const char* path = ActorAccessibility_MapRawSampleToExternalAudio(name);
if (path == NULL) if (path == NULL)
return; return;
aa->audioEngine->playSound((uintptr_t)handle, slot, path, looping); aa->audioEngine->playSound((uintptr_t)handle, slot, path, looping);
} }
void ActorAccessibility_StopSound(void* handle, int slot) void ActorAccessibility_StopSound(void* handle, int slot) {
{
aa->audioEngine->stopSound((uintptr_t)handle, slot); aa->audioEngine->stopSound((uintptr_t)handle, slot);
} }
void ActorAccessibility_StopAllSounds(void* handle) void ActorAccessibility_StopAllSounds(void* handle) {
{
aa->audioEngine->stopAllSounds((uintptr_t)handle); aa->audioEngine->stopAllSounds((uintptr_t)handle);
} }
void ActorAccessibility_SetSoundPitch(void* handle, int slot, float pitch) void ActorAccessibility_SetSoundPitch(void* handle, int slot, float pitch) {
{
aa->audioEngine->setPitch((uintptr_t)handle, slot, pitch); aa->audioEngine->setPitch((uintptr_t)handle, slot, pitch);
} }
void ActorAccessibility_SetPitchBehindModifier(void* handle, int slot, float mod) void ActorAccessibility_SetPitchBehindModifier(void* handle, int slot, float mod) {
{
aa->audioEngine->setPitchBehindModifier((uintptr_t)handle, slot, mod); aa->audioEngine->setPitchBehindModifier((uintptr_t)handle, slot, mod);
} }
void ActorAccessibility_SetSoundPos(void* handle, int slot, Vec3f* pos, f32 distToPlayer, f32 maxDistance) { void ActorAccessibility_SetSoundPos(void* handle, int slot, Vec3f* pos, f32 distToPlayer, f32 maxDistance) {
aa->audioEngine->setSoundPosition((uintptr_t)handle, slot, pos->x, pos->y, pos->z, distToPlayer, maxDistance); aa->audioEngine->setSoundPosition((uintptr_t)handle, slot, pos->x, pos->y, pos->z, distToPlayer, maxDistance);
} }
void ActorAccessibility_SetSoundVolume(void* handle, int slot, float volume) void ActorAccessibility_SetSoundVolume(void* handle, int slot, float volume) {
{
aa->audioEngine->setVolume((uintptr_t)handle, slot, volume); aa->audioEngine->setVolume((uintptr_t)handle, slot, volume);
} }
void ActorAccessibility_SetSoundPan(void* handle, int slot, Vec3f* projectedPos) void ActorAccessibility_SetSoundPan(void* handle, int slot, Vec3f* projectedPos) {
{
float pan = projectedPos->x / 270; float pan = projectedPos->x / 270;
if (pan < -1.0) if (pan < -1.0)
pan = -1.0; pan = -1.0;
if (pan > 1.0) if (pan > 1.0)
pan = 1.0; pan = 1.0;
aa->audioEngine->setPan((uintptr_t)handle, slot, pan); aa->audioEngine->setPan((uintptr_t)handle, slot, pan);
} }
void ActorAccessibility_SetSoundFilter(void* handle, int slot, float cutoff) void ActorAccessibility_SetSoundFilter(void* handle, int slot, float cutoff) {
{
aa->audioEngine->setFilter((uintptr_t)handle, slot, cutoff); aa->audioEngine->setFilter((uintptr_t)handle, slot, cutoff);
} }
void ActorAccessibility_SeekSound(void* handle, int slot, size_t offset) void ActorAccessibility_SeekSound(void* handle, int slot, size_t offset) {
{
aa->audioEngine->seekSound((uintptr_t)handle, slot, offset); aa->audioEngine->seekSound((uintptr_t)handle, slot, offset);
} }
void ActorAccessibility_ConfigureSoundForActor(AccessibleActor* actor, int slot) void ActorAccessibility_ConfigureSoundForActor(AccessibleActor* actor, int slot) {
{
ActorAccessibility_SetSoundPitch(actor, slot, actor->policy.pitch); ActorAccessibility_SetSoundPitch(actor, slot, actor->policy.pitch);
ActorAccessibility_SetPitchBehindModifier(actor, slot, actor->policy.pitchModifier); ActorAccessibility_SetPitchBehindModifier(actor, slot, actor->policy.pitchModifier);
ActorAccessibility_SetSoundPos(actor, slot, &actor->projectedPos, actor->xyzDistToPlayer, ActorAccessibility_SetSoundPos(actor, slot, &actor->projectedPos, actor->xyzDistToPlayer, actor->policy.distance);
actor->policy.distance);
ActorAccessibility_SetSoundVolume(actor, slot, actor->policy.volume); ActorAccessibility_SetSoundVolume(actor, slot, actor->policy.volume);
actor->managedSoundSlots[slot] = true; actor->managedSoundSlots[slot] = true;
} }
void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId, bool looping) void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId, bool looping) {
{
if (slot < 0 || slot > NUM_MANAGED_SOUND_SLOTS) if (slot < 0 || slot > NUM_MANAGED_SOUND_SLOTS)
return; return;
ActorAccessibility_PlaySound(actor, slot, sfxId, looping); ActorAccessibility_PlaySound(actor, slot, sfxId, looping);
ActorAccessibility_ConfigureSoundForActor(actor, slot); ActorAccessibility_ConfigureSoundForActor(actor, slot);
} }
void ActorAccessibility_PlaySampleForActor(AccessibleActor* actor, int slot, const char* name, bool looping) void ActorAccessibility_PlaySampleForActor(AccessibleActor* actor, int slot, const char* name, bool looping) {
{
if (slot < 0 || slot > NUM_MANAGED_SOUND_SLOTS) if (slot < 0 || slot > NUM_MANAGED_SOUND_SLOTS)
return; return;
ActorAccessibility_PlayRawSample(actor, slot, name, looping); ActorAccessibility_PlayRawSample(actor, slot, name, looping);
ActorAccessibility_ConfigureSoundForActor(actor, slot); ActorAccessibility_ConfigureSoundForActor(actor, slot);
} }
void ActorAccessibility_StopSoundForActor(AccessibleActor* actor, int slot) void ActorAccessibility_StopSoundForActor(AccessibleActor* actor, int slot) {
{
if (slot < 0 || slot >= NUM_MANAGED_SOUND_SLOTS) if (slot < 0 || slot >= NUM_MANAGED_SOUND_SLOTS)
return; return;
ActorAccessibility_StopSound(actor, slot); ActorAccessibility_StopSound(actor, slot);
@ -358,7 +326,6 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
bool ActorAccessibility_IsRealActor(AccessibleActor* actor) { bool ActorAccessibility_IsRealActor(AccessibleActor* actor) {
return actor->actor != NULL; return actor->actor != NULL;
} }
void ActorAccessibility_CopyParamsFromRealActor(AccessibleActor* actor) { void ActorAccessibility_CopyParamsFromRealActor(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play); Player* player = GET_PLAYER(actor->play);
@ -370,15 +337,13 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
actor->xyzDistToPlayer = Math_Vec3f_DistXYZ(&actor->actor->world.pos, &player->actor.world.pos); actor->xyzDistToPlayer = Math_Vec3f_DistXYZ(&actor->actor->world.pos, &player->actor.world.pos);
} }
void ActorAccessibility_PrepareNextAudioFrame(); void ActorAccessibility_PrepareNextAudioFrame();
void ActorAccessibility_StopAllVirtualActors(VirtualActorList* list) void ActorAccessibility_StopAllVirtualActors(VirtualActorList* list) {
{
if (list == NULL) if (list == NULL)
return; return;
VAList_t* val = (VAList_t*)list; VAList_t* val = (VAList_t*)list;
for (auto i = val->begin(); i != val->end(); i++) for (auto i = val->begin(); i != val->end(); i++)
ActorAccessibility_StopAllSounds((void*)&(*i)); ActorAccessibility_StopAllSounds((void*)&(*i));
} }
void ActorAccessibility_RunAccessibilityForActor(PlayState* play, AccessibleActor* actor) { void ActorAccessibility_RunAccessibilityForActor(PlayState* play, AccessibleActor* actor) {
Player* player = GET_PLAYER(play); Player* player = GET_PLAYER(play);
@ -390,8 +355,7 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
// Perform calculations that the game would normally take care of for real actors. // Perform calculations that the game would normally take care of for real actors.
f32 w = 0.0f; f32 w = 0.0f;
// Set actor->projectedPos. // Set actor->projectedPos.
SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, &actor->world.pos, &actor->projectedPos, SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, &actor->world.pos, &actor->projectedPos, &w);
&w);
// Set actor->xzDistToPlayer. // Set actor->xzDistToPlayer.
actor->xzDistToPlayer = Math_Vec3f_DistXZ(&actor->world.pos, &player->actor.world.pos); actor->xzDistToPlayer = Math_Vec3f_DistXZ(&actor->world.pos, &player->actor.world.pos);
@ -403,13 +367,12 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
return; return;
} }
// Send sound parameters to the new audio engine. Eventually remove the old stuff once all actors are carried over. // Send sound parameters to the new audio engine. Eventually remove the old stuff once all actors are carried over.
for (int i = 0; i < NUM_MANAGED_SOUND_SLOTS; i++) for (int i = 0; i < NUM_MANAGED_SOUND_SLOTS; i++) {
{ if (actor->managedSoundSlots[i]) {
if (actor->managedSoundSlots[i]) ActorAccessibility_SetSoundPos(actor, i, &actor->projectedPos, actor->xyzDistToPlayer,
{ actor->policy.distance);
ActorAccessibility_SetSoundPos(actor, i, &actor->projectedPos, actor->xyzDistToPlayer, actor->policy.distance); // Judgement call: pitch changes are rare enough that it doesn't make sense to pay the cost of updating it
//Judgement call: pitch changes are rare enough that it doesn't make sense to pay the cost of updating it every frame. If you want a pitch change, call the function as needed. // every frame. If you want a pitch change, call the function as needed.
} }
} }
actor->frameCount++; actor->frameCount++;
@ -425,8 +388,7 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
return; return;
if (actor->policy.aimAssist.isProvider) { if (actor->policy.aimAssist.isProvider) {
if (player->stateFlags1 & PLAYER_STATE1_FIRST_PERSON && if (player->stateFlags1 & PLAYER_STATE1_FIRST_PERSON &&
(player->stateFlags1 & PLAYER_STATE1_USING_BOOMERANG || (player->stateFlags1 & PLAYER_STATE1_USING_BOOMERANG || player->stateFlags1 & PLAYER_STATE1_ITEM_IN_HAND)) {
player->stateFlags1 & PLAYER_STATE1_ITEM_IN_HAND)) {
ActorAccessibility_SetSoundPitch(actor, 9, actor->aimAssist.pitch); ActorAccessibility_SetSoundPitch(actor, 9, actor->aimAssist.pitch);
actor->aimAssist.framesSinceAimAssist++; actor->aimAssist.framesSinceAimAssist++;
ActorAccessibility_ProvideAimAssistForActor(actor); ActorAccessibility_ProvideAimAssistForActor(actor);
@ -438,21 +400,19 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
ActorAccessibility_PlaySoundForActor(actor, 9, actor->policy.aimAssist.sfx, false); ActorAccessibility_PlaySoundForActor(actor, 9, actor->policy.aimAssist.sfx, false);
} }
} else } else
actor->aimAssist.framesSinceAimAssist = 32768;//Make sure there's no delay the next time you draw your bow or whatever. actor->aimAssist.framesSinceAimAssist =
32768; // Make sure there's no delay the next time you draw your bow or whatever.
} }
if (actor->policy.callback != NULL) if (actor->policy.callback != NULL)
actor->policy.callback(actor); actor->policy.callback(actor);
else else
ActorAccessibility_PlaySoundForActor(actor, 0, actor->policy.sound, false); ActorAccessibility_PlaySoundForActor(actor, 0, actor->policy.sound, false);
} }
void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play) { void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play) {
Player* player = GET_PLAYER(play); Player* player = GET_PLAYER(play);
if (play->sceneNum != aa->currentScene) if (play->sceneNum != aa->currentScene) {
{
ActorAccessibility_StopAllVirtualActors(aa->currentEverywhere); ActorAccessibility_StopAllVirtualActors(aa->currentEverywhere);
ActorAccessibility_StopAllVirtualActors(aa->currentSceneGlobal); ActorAccessibility_StopAllVirtualActors(aa->currentSceneGlobal);
ActorAccessibility_StopAllVirtualActors(aa->currentRoomLocal); ActorAccessibility_StopAllVirtualActors(aa->currentRoomLocal);
@ -461,23 +421,18 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
aa->currentScene = play->sceneNum; aa->currentScene = play->sceneNum;
aa->currentRoomLocal = NULL; aa->currentRoomLocal = NULL;
aa->currentRoom = -1; aa->currentRoom = -1;
} }
if (aa->currentRoom != play->roomCtx.curRoom.num) if (aa->currentRoom != play->roomCtx.curRoom.num) {
{
ActorAccessibility_StopAllVirtualActors(aa->currentRoomLocal); ActorAccessibility_StopAllVirtualActors(aa->currentRoomLocal);
aa->currentRoomLocal = ActorAccessibility_GetVirtualActorList(play->sceneNum, play->roomCtx.curRoom.num); aa->currentRoomLocal = ActorAccessibility_GetVirtualActorList(play->sceneNum, play->roomCtx.curRoom.num);
aa->currentRoom = play->roomCtx.curRoom.num; aa->currentRoom = play->roomCtx.curRoom.num;
} }
if (aa->glossary->currentScene != play->sceneNum || aa->glossary->currentRoom != play->roomCtx.curRoom.num) { if (aa->glossary->currentScene != play->sceneNum || aa->glossary->currentRoom != play->roomCtx.curRoom.num) {
if (aa->glossary->GlossaryStarted = true) { if (aa->glossary->GlossaryStarted = true) {
aa->glossary->cooldown = 0; aa->glossary->cooldown = 0;
aa->glossary->GlossaryStarted = false; aa->glossary->GlossaryStarted = false;
freezeActors = false; freezeActors = false;
} }
} }
if (player->stateFlags1 & PLAYER_STATE1_IN_CUTSCENE) { if (player->stateFlags1 & PLAYER_STATE1_IN_CUTSCENE) {
return; return;
@ -499,13 +454,12 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
list = (VAList_t*)aa->currentRoomLocal; list = (VAList_t*)aa->currentRoomLocal;
for (VAList_t::iterator i = list->begin(); i != list->end(); i++) for (VAList_t::iterator i = list->begin(); i != list->end(); i++)
ActorAccessibility_RunAccessibilityForActor(play, &(*i)); ActorAccessibility_RunAccessibilityForActor(play, &(*i));
//Scene-global virtual actors. Most of these are automatically generated VAs from polygons, because there's no way to sort these into rooms. // Scene-global virtual actors. Most of these are automatically generated VAs from polygons, because there's no way
// to sort these into rooms.
list = (VAList_t*)aa->currentSceneGlobal; list = (VAList_t*)aa->currentSceneGlobal;
for (VAList_t::iterator i = list->begin(); i != list->end(); i++) for (VAList_t::iterator i = list->begin(); i != list->end(); i++)
ActorAccessibility_RunAccessibilityForActor(play, &(*i)); ActorAccessibility_RunAccessibilityForActor(play, &(*i));
// Processes external audio engine. // Processes external audio engine.
ActorAccessibility_PrepareNextAudioFrame(); ActorAccessibility_PrepareNextAudioFrame();
} }
@ -527,7 +481,8 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
return; return;
} }
OSContPad* trackerButtonsPressed = std::dynamic_pointer_cast<LUS::ControlDeck>(Ship::Context::GetInstance()->GetControlDeck())->GetPads(); OSContPad* trackerButtonsPressed =
std::dynamic_pointer_cast<LUS::ControlDeck>(Ship::Context::GetInstance()->GetControlDeck())->GetPads();
bool comboStartGlossary = trackerButtonsPressed != nullptr && trackerButtonsPressed[0].button & buttons[10] && bool comboStartGlossary = trackerButtonsPressed != nullptr && trackerButtonsPressed[0].button & buttons[10] &&
trackerButtonsPressed[0].button & buttons[6]; trackerButtonsPressed[0].button & buttons[6];
if (comboStartGlossary) { if (comboStartGlossary) {
@ -556,9 +511,7 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
} }
aa->glossary->cooldown = 5; aa->glossary->cooldown = 5;
SpeechSynthesizer::Instance->Speak((*aa->glossary->current).second.policy.englishName, GetLanguageCode()); SpeechSynthesizer::Instance->Speak((*aa->glossary->current).second.policy.englishName, GetLanguageCode());
} }
bool comboDisableGlossary = trackerButtonsPressed != nullptr && trackerButtonsPressed[0].button & buttons[11] && bool comboDisableGlossary = trackerButtonsPressed != nullptr && trackerButtonsPressed[0].button & buttons[11] &&
trackerButtonsPressed[0].button & buttons[6]; trackerButtonsPressed[0].button & buttons[6];
@ -569,13 +522,10 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
} }
// Processes external audio engine. // Processes external audio engine.
ActorAccessibility_PrepareNextAudioFrame(); ActorAccessibility_PrepareNextAudioFrame();
} }
// Virtual actor config. // Virtual actor config.
VirtualActorList* ActorAccessibility_GetVirtualActorList(s16 sceneNum, s8 roomNum) VirtualActorList* ActorAccessibility_GetVirtualActorList(s16 sceneNum, s8 roomNum) {
{
SceneAndRoom sr; SceneAndRoom sr;
sr.values.sceneIndex = sceneNum; sr.values.sceneIndex = sceneNum;
sr.values.roomIndex = roomNum; sr.values.roomIndex = roomNum;
@ -584,10 +534,8 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
VAList_t* l = &aa->vaZones[sr.raw]; VAList_t* l = &aa->vaZones[sr.raw];
return (VirtualActorList*)l; return (VirtualActorList*)l;
} }
AccessibleActor* ActorAccessibility_AddVirtualActor(VirtualActorList* list, VIRTUAL_ACTOR_TABLE type, PosRot where) AccessibleActor* ActorAccessibility_AddVirtualActor(VirtualActorList* list, VIRTUAL_ACTOR_TABLE type, PosRot where) {
{
ActorAccessibilityPolicy* policy = ActorAccessibility_GetPolicyForActor(type); ActorAccessibilityPolicy* policy = ActorAccessibility_GetPolicyForActor(type);
if (policy == NULL) if (policy == NULL)
return NULL; return NULL;
@ -622,21 +570,19 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
return NULL; // Probably a malloc error preventing user data initialization. return NULL; // Probably a malloc error preventing user data initialization.
} }
return savedActor; return savedActor;
} }
void ActorAccessibility_InterpretCurrentScene(PlayState* play) void ActorAccessibility_InterpretCurrentScene(PlayState* play) {
{
if (aa->sceneList.contains(play->sceneNum)) if (aa->sceneList.contains(play->sceneNum))
return; // Scene interpretation already complete for this scene. return; // Scene interpretation already complete for this scene.
aa->sceneList.insert(play->sceneNum); aa->sceneList.insert(play->sceneNum);
VirtualActorList* list = ActorAccessibility_GetVirtualActorList(play->sceneNum, -1); // Scene-global VAs. VirtualActorList* list = ActorAccessibility_GetVirtualActorList(play->sceneNum, -1); // Scene-global VAs.
if (list == NULL) if (list == NULL)
return; return;
for (int i = 0; i < play->colCtx.colHeader->numPolygons; i++) for (int i = 0; i < play->colCtx.colHeader->numPolygons; i++) {
{
CollisionPoly* poly = &play->colCtx.colHeader->polyList[i]; CollisionPoly* poly = &play->colCtx.colHeader->polyList[i];
// checks if climable // checks if climable
if ((func_80041DB8(&play->colCtx, poly, BGCHECK_SCENE) == 8 || func_80041DB8(&play->colCtx, poly, BGCHECK_SCENE) == 3)) { if ((func_80041DB8(&play->colCtx, poly, BGCHECK_SCENE) == 8 ||
func_80041DB8(&play->colCtx, poly, BGCHECK_SCENE) == 3)) {
ActorAccessibility_PolyToVirtualActor(play, poly, VA_CLIMB, list); ActorAccessibility_PolyToVirtualActor(play, poly, VA_CLIMB, list);
} }
if (SurfaceType_IsWallDamage(&play->colCtx, poly, BGCHECK_SCENE)) { if (SurfaceType_IsWallDamage(&play->colCtx, poly, BGCHECK_SCENE)) {
@ -649,11 +595,10 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
ActorAccessibility_PolyToVirtualActor(play, poly, VA_SPIKE, list); ActorAccessibility_PolyToVirtualActor(play, poly, VA_SPIKE, list);
}*/ }*/
} }
} }
// Convert poly to VA. // Convert poly to VA.
void ActorAccessibility_PolyToVirtualActor(PlayState* play, CollisionPoly* poly, VIRTUAL_ACTOR_TABLE va, VirtualActorList* destination) void ActorAccessibility_PolyToVirtualActor(PlayState* play, CollisionPoly* poly, VIRTUAL_ACTOR_TABLE va,
{ VirtualActorList* destination) {
Vec3f polyVerts[3]; Vec3f polyVerts[3];
CollisionPoly_GetVertices(poly, play->colCtx.colHeader->vtxList, polyVerts); CollisionPoly_GetVertices(poly, play->colCtx.colHeader->vtxList, polyVerts);
PosRot where; PosRot where;
@ -674,8 +619,7 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
actor->sceneIndex = gEntranceTable[nextEntranceIndex].scene; actor->sceneIndex = gEntranceTable[nextEntranceIndex].scene;
} }
} }
void ActorAccessibility_AnnounceRoomNumber(PlayState* play) void ActorAccessibility_AnnounceRoomNumber(PlayState* play) {
{
std::stringstream ss; std::stringstream ss;
ss << "Room" << (int)play->roomCtx.curRoom.num; ss << "Room" << (int)play->roomCtx.curRoom.num;
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) if (Flags_GetClear(play, play->roomCtx.curRoom.num))
@ -683,11 +627,9 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
else else
ss << "." << std::endl; ss << "." << std::endl;
SpeechSynthesizer::Instance->Speak(ss.str().c_str(), GetLanguageCode()); SpeechSynthesizer::Instance->Speak(ss.str().c_str(), GetLanguageCode());
} }
// Aim cue support. // Aim cue support.
void ActorAccessibility_ProvideAimAssistForActor(AccessibleActor* actor) void ActorAccessibility_ProvideAimAssistForActor(AccessibleActor* actor) {
{
Player* player = GET_PLAYER(actor->play); Player* player = GET_PLAYER(actor->play);
// 16384 // 16384
s32 angle = player->actor.focus.rot.x; s32 angle = player->actor.focus.rot.x;
@ -738,19 +680,17 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
return; return;
aa->audioEngine->mix(ogBuffer, nFrames); aa->audioEngine->mix(ogBuffer, nFrames);
} }
// Map one of the game's sfx to a path which as understood by the external audio engine. The returned token is a // Map one of the game's sfx to a path which as understood by the external audio engine. The returned token is a
// short hex string that can be passed directly to the audio engine. // short hex string that can be passed directly to the audio engine.
const char* ActorAccessibility_MapSfxToExternalAudio(s16 sfxId) const char* ActorAccessibility_MapSfxToExternalAudio(s16 sfxId) {
{
SfxRecord* record; SfxRecord* record;
auto it = aa->sfxMap.find(sfxId); auto it = aa->sfxMap.find(sfxId);
if (it == aa->sfxMap.end()) if (it == aa->sfxMap.end()) {
{
SfxRecord tempRecord; SfxRecord tempRecord;
std::string fullPath = SfxExtractor::getExternalFileName(sfxId); std::string fullPath = SfxExtractor::getExternalFileName(sfxId);
auto res = std::static_pointer_cast<Ship::Blob>(Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fullPath)); auto res = std::static_pointer_cast<Ship::Blob>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fullPath));
if (res == nullptr) if (res == nullptr)
return NULL; // Resource doesn't exist, user's gotta run the extractor. return NULL; // Resource doesn't exist, user's gotta run the extractor.
@ -766,12 +706,9 @@ return NULL;//Resource doesn't exist, user's gotta run the extractor.
record = &it->second; record = &it->second;
return record->path.c_str(); return record->path.c_str();
} }
// Map the path to a raw sample to the external audio engine. // Map the path to a raw sample to the external audio engine.
const char* ActorAccessibility_MapRawSampleToExternalAudio(const char* name) const char* ActorAccessibility_MapRawSampleToExternalAudio(const char* name) {
{
SfxRecord* record; SfxRecord* record;
std::string key(name); std::string key(name);
auto it = aa->sampleMap.find(key); auto it = aa->sampleMap.find(key);
@ -792,8 +729,7 @@ return NULL; // Resource doesn't exist, user's gotta run the extractor.
tempRecord.decodedSample = std::make_shared<s16*>(wav); tempRecord.decodedSample = std::make_shared<s16*>(wav);
aa->sampleMap[key] = tempRecord; aa->sampleMap[key] = tempRecord;
record = &aa->sampleMap[key]; record = &aa->sampleMap[key];
aa->audioEngine->cacheDecodedSample(record->path, wav, aa->audioEngine->cacheDecodedSample(record->path, wav, wavSize);
wavSize);
} else } else
record = &it->second; record = &it->second;
@ -803,18 +739,11 @@ return NULL; // Resource doesn't exist, user's gotta run the extractor.
void ActorAccessibility_PrepareNextAudioFrame() { void ActorAccessibility_PrepareNextAudioFrame() {
aa->audioEngine->prepare(); aa->audioEngine->prepare();
} }
void ActorAccessibility_HandleSoundExtractionMode(PlayState* play) void ActorAccessibility_HandleSoundExtractionMode(PlayState* play) {
{
aa->sfxExtractor.frameCallback(); aa->sfxExtractor.frameCallback();
} }
void ActorAccessibility_DoSoundExtractionStep() void ActorAccessibility_DoSoundExtractionStep() {
{
aa->sfxExtractor.captureCallback(); aa->sfxExtractor.captureCallback();
} }

View file

@ -4,7 +4,9 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#define NUM_MANAGED_SOUND_SLOTS 10 //How many auto-managed sound slots can any given actor have? this can differ from AAE_SLOTS_PER_HANDLE, but cannot be greater. #define NUM_MANAGED_SOUND_SLOTS \
10 // How many auto-managed sound slots can any given actor have? this can differ from AAE_SLOTS_PER_HANDLE, but
// cannot be greater.
struct AccessibleActor; struct AccessibleActor;
typedef struct AccessibleActor AccessibleActor; typedef struct AccessibleActor AccessibleActor;
// A callback that is run regularely as the game progresses in order to provide accessibility services for an actor. // A callback that is run regularely as the game progresses in order to provide accessibility services for an actor.
@ -71,8 +73,10 @@ struct AccessibleActor {
f32 basePitch; f32 basePitch;
f32 currentPitch; f32 currentPitch;
s16 sceneIndex;//If this actor represents a scene transition, then this will contain the destination scene index. Zero otherwise. s16 sceneIndex; // If this actor represents a scene transition, then this will contain the destination scene index.
bool managedSoundSlots[NUM_MANAGED_SOUND_SLOTS];//These have their attenuation and panning parameters updated every frame automatically. // Zero otherwise.
bool managedSoundSlots[NUM_MANAGED_SOUND_SLOTS]; // These have their attenuation and panning parameters updated
// every frame automatically.
struct { struct {
u16 framesSinceAimAssist; // Allows rate-based vertical aim assist. Incremented every frame for aim assist u16 framesSinceAimAssist; // Allows rate-based vertical aim assist. Incremented every frame for aim assist
// actors. Manually reset by aim assist provider. // actors. Manually reset by aim assist provider.
@ -99,11 +103,13 @@ void ActorAccessibility_AddSupportedActor(s16 type, ActorAccessibilityPolicy pol
void ActorAccessibility_RunAccessibilityForActor(PlayState* play, AccessibleActor* actor); void ActorAccessibility_RunAccessibilityForActor(PlayState* play, AccessibleActor* actor);
void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play); void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play);
/* /*
*Play sounds (usually from the game) using the external sound engine. This is probably not the function you want to call most of the time (see below). *Play sounds (usually from the game) using the external sound engine. This is probably not the function you want to
* handle: pointer to an arbitrary object. This object can be anything as it's only used as a classifier, but it's recommended that you use an AccessibleActor* as your handle whenever possible. Using AccessibleActor* as the handle gives you automatic cleanup when the actor is killed. *call most of the time (see below). handle: pointer to an arbitrary object. This object can be anything as it's only
* slot: Allows multiple sounds to be assigned to a single handle. The maximum number of slots per actor is 10 by default (but can be controlled by modifying AAE_SLOTS_PER_HANDLE). *used as a classifier, but it's recommended that you use an AccessibleActor* as your handle whenever possible. Using
* sfxId: one of the game's sfx IDs. Note that this plays prerendered sounds which you must have previously prepared. *AccessibleActor* as the handle gives you automatic cleanup when the actor is killed. slot: Allows multiple sounds to
*looping: whether to play the sound just once or on a continuous loop. *be assigned to a single handle. The maximum number of slots per actor is 10 by default (but can be controlled by
*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, bool looping);
// Play one of the game's internal samples. // Play one of the game's internal samples.
@ -114,7 +120,8 @@ void ActorAccessibility_StopSound(void* handle, int slot);
void ActorAccessibility_StopAllSounds(void* handle); void ActorAccessibility_StopAllSounds(void* handle);
void ActorAccessibility_SetSoundPitch(void* handle, int slot, float pitch); void ActorAccessibility_SetSoundPitch(void* handle, int slot, float pitch);
//When we don't have access to something super fancy (such as HRTF), blind-accessible games generally use a change in pitch to tell the player that an object is behind the player. // When we don't have access to something super fancy (such as HRTF), blind-accessible games generally use a change in
// pitch to tell the player that an object is behind the player.
void ActorAccessibility_SetPitchBehindModifier(void* handle, int slot, float mod); void ActorAccessibility_SetPitchBehindModifier(void* handle, int slot, float mod);
void ActorAccessibility_SetListenerPos(Vec3f* pos, Vec3f* rot); void ActorAccessibility_SetListenerPos(Vec3f* pos, Vec3f* rot);
@ -127,7 +134,8 @@ void ActorAccessibility_SeekSound(void* handle, int slot, size_t offset);
/* /*
* Play a sound on behalf of an AccessibleActor. * Play a sound on behalf of an AccessibleActor.
* This version includes automatic sound management: pitch, panning and attenuation parameters will be updated automatically based on the actor's position. * This version includes automatic sound management: pitch, panning and attenuation parameters will be updated
* 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, bool looping);
@ -160,7 +168,6 @@ typedef enum {
} VIRTUAL_ACTOR_TABLE; } VIRTUAL_ACTOR_TABLE;
#define EVERYWHERE -32768 // Denotes a virtual actor that is global/ omnipresent. #define EVERYWHERE -32768 // Denotes a virtual actor that is global/ omnipresent.
// Get the list of virtual actors for a given scene and room index. // Get the list of virtual actors for a given scene and room index.
@ -169,7 +176,8 @@ AccessibleActor* ActorAccessibility_AddVirtualActor(VirtualActorList* list, VIRT
// Parses the loaded seen and converts select polygons (like ladders, spikes and scene exits) into virtual actors. // Parses the loaded seen and converts select polygons (like ladders, spikes and scene exits) into virtual actors.
void ActorAccessibility_InterpretCurrentScene(PlayState* play); void ActorAccessibility_InterpretCurrentScene(PlayState* play);
// Convert a collision polygon into a virtual actor. // Convert a collision polygon into a virtual actor.
void ActorAccessibility_PolyToVirtualActor(PlayState* play, CollisionPoly* poly, VIRTUAL_ACTOR_TABLE va, VirtualActorList* destination); void ActorAccessibility_PolyToVirtualActor(PlayState* play, CollisionPoly* poly, VIRTUAL_ACTOR_TABLE va,
VirtualActorList* destination);
// Report which room of a dungeon the player is in. // Report which room of a dungeon the player is in.
void ActorAccessibility_AnnounceRoomNumber(PlayState* play); void ActorAccessibility_AnnounceRoomNumber(PlayState* play);
// Aim cue support. // Aim cue support.
@ -184,7 +192,6 @@ void ActorAccessibility_HandleSoundExtractionMode(PlayState* play);
// This is called by the audio thread when it's ready to try to pull sfx from the game. // This is called by the audio thread when it's ready to try to pull sfx from the game.
void ActorAccessibility_DoSoundExtractionStep(); void ActorAccessibility_DoSoundExtractionStep();
void ActorAccessibility_AudioGlossary(PlayState* play); void ActorAccessibility_AudioGlossary(PlayState* play);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -92,13 +92,13 @@ void SfxExtractor::renderOutput() {
void SfxExtractor::setup() { void SfxExtractor::setup() {
try { try {
SpeechSynthesizer::Instance->Speak(
SpeechSynthesizer::Instance->Speak("Sfx extraction speedrun initiated. Please wait. This will take a few minutes.", GetLanguageCode()); "Sfx extraction speedrun initiated. Please wait. This will take a few minutes.", GetLanguageCode());
// Kill the audio thread so we can take control. // Kill the audio thread so we can take control.
captureThreadState = CT_WAITING; captureThreadState = CT_WAITING;
OTRAudio_InstallSfxCaptureThread(); OTRAudio_InstallSfxCaptureThread();
// Make sure we're starting from a clean slate. // Make sure we're starting from a clean slate.
std::string sohAccessibilityPath = Ship::Context::GetPathRelativeToAppDirectory("accessibility.otr"); std::string sohAccessibilityPath = Ship::Context::GetPathRelativeToAppDirectory("accessibility.o2r");
if (std::filesystem::exists(sohAccessibilityPath)) { if (std::filesystem::exists(sohAccessibilityPath)) {
currentStep = STEP_ERROR_OTR; currentStep = STEP_ERROR_OTR;
return; return;
@ -115,10 +115,11 @@ void SfxExtractor::setup() {
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
progressMilestones[i - 1] = sfxToRip.size() - ((int)ceil(sfxToRip.size() * (i / 10.0f))); progressMilestones[i - 1] = sfxToRip.size() - ((int)ceil(sfxToRip.size() * (i / 10.0f)));
} }
archive = Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->AddArchive("accessibility.otr"); archive = std::make_shared<Ship::O2rArchive>("accessibility.o2r");
archive->Open();
} catch (...) { currentStep = STEP_ERROR; } } catch (...) { currentStep = STEP_ERROR; }
} }
void SfxExtractor::ripNextSfx() { void SfxExtractor::ripNextSfx() {
{ {
auto lock = OTRAudio_Lock(); auto lock = OTRAudio_Lock();
@ -143,7 +144,8 @@ void SfxExtractor::ripNextSfx() {
sfxToRip.pop(); sfxToRip.pop();
startOfInput = 0; startOfInput = 0;
endOfInput = 0; endOfInput = 0;
Audio_PlaySoundGeneral(currentSfx, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); Audio_PlaySoundGeneral(currentSfx, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultReverb);
{ {
auto lock = OTRAudio_Lock(); auto lock = OTRAudio_Lock();
@ -161,17 +163,18 @@ void SfxExtractor::finished() {
Audio_QueueSeqCmd(NA_BGM_TITLE); Audio_QueueSeqCmd(NA_BGM_TITLE);
if (currentStep == STEP_ERROR || currentStep == STEP_ERROR_OTR) { if (currentStep == STEP_ERROR || currentStep == STEP_ERROR_OTR) {
Audio_PlaySoundGeneral(NA_SE_SY_ERROR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); Audio_PlaySoundGeneral(NA_SE_SY_ERROR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
Audio_PlaySoundGeneral(NA_SE_EN_GANON_LAUGH, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
Audio_PlaySoundGeneral(NA_SE_EN_GANON_LAUGH, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
std::stringstream ss; std::stringstream ss;
ss << "Sorry, we tried to extract the sound effects, but Ganondorf overruled us with an iron fist." ss << "Sorry, we tried to extract the sound effects, but Ganondorf overruled us with an iron fist."
<< std::endl; << std::endl;
if (currentStep == STEP_ERROR_OTR) if (currentStep == STEP_ERROR_OTR)
ss << "In all seriousness, please delete accessibility.otr and try again."; ss << "In all seriousness, please delete accessibility.o2r and try again.";
SpeechSynthesizer::Instance->Speak(ss.str().c_str(), GetLanguageCode()); SpeechSynthesizer::Instance->Speak(ss.str().c_str(), GetLanguageCode());
} else } else
Audio_PlayFanfare(NA_BGM_ITEM_GET); Audio_PlayFanfare(NA_BGM_ITEM_GET);
} }
void SfxExtractor::maybeGiveProgressReport() { void SfxExtractor::maybeGiveProgressReport() {
size_t ripsRemaining = sfxToRip.size() + 1; size_t ripsRemaining = sfxToRip.size() + 1;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
// A big nasty array containing every SFX ID in the game. // A big nasty array containing every SFX ID in the game.
//All of the "DUMMY's" and "YOBI's" have been removed as they produce duplicate sounds at best, and cause errors or even crashes at worst. // All of the "DUMMY's" and "YOBI's" have been removed as they produce duplicate sounds at best, and cause errors or
// even crashes at worst.
const s16 sfxTable[1207] = { const s16 sfxTable[1207] = {
NA_SE_PL_WALK_GROUND, NA_SE_PL_WALK_GROUND,

View file

@ -23,7 +23,8 @@ static Vec3f D_80854798 = { 0.0f, 18.0f, 0.0f }; // From z_player.c.
const char* GetLanguageCode(); const char* GetLanguageCode();
enum { DISCOVERED_NOTHING = 0, enum {
DISCOVERED_NOTHING = 0,
DISCOVERED_INCLINE, DISCOVERED_INCLINE,
DISCOVERED_DECLINE, DISCOVERED_DECLINE,
DISCOVERED_LEDGE, DISCOVERED_LEDGE,
@ -33,7 +34,8 @@ DISCOVERED_WATER,
DISCOVERED_GROUND, DISCOVERED_GROUND,
DISCOVERED_LAVA, DISCOVERED_LAVA,
}; };
//Abstract class for terrain cue sound handling. Implementations should not allocate memory. These are always in-place constructed in static memory owned by the TerrainCueDirection object. // Abstract class for terrain cue sound handling. Implementations should not allocate memory. These are always in-place
// constructed in static memory owned by the TerrainCueDirection object.
class TerrainCueSound { class TerrainCueSound {
protected: protected:
AccessibleActor* actor; AccessibleActor* actor;
@ -50,7 +52,6 @@ class TerrainCueSound {
ActorAccessibility_PlaySound(this, 0, currentSFX, shouldLoop); ActorAccessibility_PlaySound(this, 0, currentSFX, shouldLoop);
ActorAccessibility_SetSoundPos(this, 0, &terrainProjectedPos, xzDistToPlayer, actor->policy.distance); ActorAccessibility_SetSoundPos(this, 0, &terrainProjectedPos, xzDistToPlayer, actor->policy.distance);
ActorAccessibility_SetSoundPitch(this, 0, currentPitch); ActorAccessibility_SetSoundPitch(this, 0, currentPitch);
} }
// Call when terrain is no longer present to stop playback. // Call when terrain is no longer present to stop playback.
@ -73,7 +74,6 @@ class TerrainCueSound {
xzDistToPlayer = Math_Vec3f_DistXZ(&terrainPos, &player->actor.world.pos); xzDistToPlayer = Math_Vec3f_DistXZ(&terrainPos, &player->actor.world.pos);
ActorAccessibility_SetSoundPos(this, 0, &terrainProjectedPos, xzDistToPlayer, actor->policy.distance); ActorAccessibility_SetSoundPos(this, 0, &terrainProjectedPos, xzDistToPlayer, actor->policy.distance);
ActorAccessibility_SetSoundPitch(this, 0, currentPitch); ActorAccessibility_SetSoundPitch(this, 0, currentPitch);
} }
public: public:
@ -84,16 +84,13 @@ class TerrainCueSound {
restFrames = 0; restFrames = 0;
xzDistToPlayer = 0; xzDistToPlayer = 0;
currentSFX = 0; currentSFX = 0;
} }
virtual ~TerrainCueSound() { virtual ~TerrainCueSound() {
stop(); stop();
} }
void update(Vec3f& pos) { void update(Vec3f& pos) {
updatePositions(pos); updatePositions(pos);
run(); run();
} }
}; };
class Incline : protected TerrainCueSound { class Incline : protected TerrainCueSound {
@ -125,10 +122,8 @@ class Incline : protected TerrainCueSound {
restFrames = 5; restFrames = 5;
}*/ }*/
} }
void setPitchModifier(float modifier) void setPitchModifier(float modifier) {
{
pitchModifier = modifier; pitchModifier = modifier;
} }
}; };
@ -162,12 +157,9 @@ class Decline : protected TerrainCueSound {
restFrames = 5; restFrames = 5;
}*/ }*/
} }
void setPitchModifier(float mod) void setPitchModifier(float mod) {
{
pitchModifier = mod; pitchModifier = mod;
} }
}; };
class Ledge : protected TerrainCueSound { class Ledge : protected TerrainCueSound {
s8 savedType; // Distinguishes between a ledge link can fall from and one he can climb up. s8 savedType; // Distinguishes between a ledge link can fall from and one he can climb up.
@ -209,27 +201,21 @@ class Ledge :protected TerrainCueSound {
} }
play(); play();
} }
virtual ~Ledge() { virtual ~Ledge() {
} }
s8 type() { s8 type() {
return savedType; return savedType;
} }
void run() { void run() {
if (savedType == 0) if (savedType == 0)
return; // Downward ledges play a looping sound and do not need ongoing maintenance. return; // Downward ledges play a looping sound and do not need ongoing maintenance.
if (restFrames == 0) if (restFrames == 0) {
{
play(); play();
restFrames = 10; restFrames = 10;
return; return;
} }
restFrames--; restFrames--;
} }
}; };
class Platform : protected TerrainCueSound { class Platform : protected TerrainCueSound {
@ -239,17 +225,13 @@ class Platform: protected TerrainCueSound {
// actor->policy.volume = 1.5; // actor->policy.volume = 1.5;
currentSFX = NA_SE_IT_SHIELD_REFLECT_SW; currentSFX = NA_SE_IT_SHIELD_REFLECT_SW;
shouldLoop = false; shouldLoop = false;
} }
virtual ~Platform() { virtual ~Platform() {
} }
void setActor(AccessibleActor* actor) void setActor(AccessibleActor* actor) {
{
this->actor = actor; this->actor = actor;
} }
void setPosition(Vec3f& pos) void setPosition(Vec3f& pos) {
{
updatePositions(pos); updatePositions(pos);
} }
void run() { void run() {
@ -266,6 +248,7 @@ class Wall: protected TerrainCueSound {
int frames; int frames;
Vec3s probeRot; Vec3s probeRot;
f32 targetPitch; f32 targetPitch;
public: public:
Wall(AccessibleActor* actor, Vec3f pos, Vec3s rot) : TerrainCueSound(actor, pos) { Wall(AccessibleActor* actor, Vec3f pos, Vec3s rot) : TerrainCueSound(actor, pos) {
probeRot = rot; probeRot = rot;
@ -341,6 +324,7 @@ class Water : protected TerrainCueSound {
class Ground : protected TerrainCueSound { class Ground : protected TerrainCueSound {
float pitchModifier; float pitchModifier;
public: public:
Ground(AccessibleActor* actor, Vec3f pos, float pitchModifier) : TerrainCueSound(actor, pos) { Ground(AccessibleActor* actor, Vec3f pos, float pitchModifier) : TerrainCueSound(actor, pos) {
currentPitch = 1.0; currentPitch = 1.0;
@ -385,7 +369,8 @@ class Lava : protected TerrainCueSound {
class TerrainCueDirection { class TerrainCueDirection {
AccessibleActor* actor; 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. int startingBodyPart; // Decides where the probe starts from. Probes going out to the left or right of the player
// start from the shoulders.
Vec3f pos; Vec3f pos;
Vec3f prevPos; Vec3f prevPos;
Vec3s relRot; // Relative angle. Vec3s relRot; // Relative angle.
@ -484,8 +469,7 @@ class Lava : protected TerrainCueSound {
void discoverWall(Vec3f pos) { void discoverWall(Vec3f pos) {
Player* player = GET_PLAYER(actor->play); Player* player = GET_PLAYER(actor->play);
if (player->stateFlags1 & PLAYER_STATE1_FIRST_PERSON) if (player->stateFlags1 & PLAYER_STATE1_FIRST_PERSON) {
{
if (terrainDiscovered == DISCOVERED_WALL) if (terrainDiscovered == DISCOVERED_WALL)
destroyCurrentSound(); destroyCurrentSound();
return; return;
@ -658,7 +642,6 @@ class Lava : protected TerrainCueSound {
move(false); move(false);
move(false); move(false);
rot = ogRot; rot = ogRot;
rot.y += 16384; rot.y += 16384;
rot.y += 16384; rot.y += 16384;
@ -807,7 +790,6 @@ class Lava : protected TerrainCueSound {
return false; // Out of bounds. return false; // Out of bounds.
} }
return true; return true;
} }
bool isHeadOnCollision(Vec3f& wallPos, Vec3f& velocity) { bool isHeadOnCollision(Vec3f& wallPos, Vec3f& velocity) {
@ -886,8 +868,7 @@ class Lava : protected TerrainCueSound {
if (!trackingModeStarted) { if (!trackingModeStarted) {
pos = player->actor.world.pos; pos = player->actor.world.pos;
// If a starting body part has been specified, then set the probe's initial X and Z position only. // If a starting body part has been specified, then set the probe's initial X and Z position only.
if (startingBodyPart != PLAYER_BODYPART_MAX) if (startingBodyPart != PLAYER_BODYPART_MAX) {
{
pos.x = player->bodyPartsPos[startingBodyPart].x; pos.x = player->bodyPartsPos[startingBodyPart].x;
pos.z = player->bodyPartsPos[startingBodyPart].y; pos.z = player->bodyPartsPos[startingBodyPart].y;
} }
@ -901,7 +882,8 @@ class Lava : protected TerrainCueSound {
distToTravel = 1.0; distToTravel = 1.0;
Vec3f collisionResult; Vec3f collisionResult;
s32 bgId = 0; s32 bgId = 0;
//Don't be fooled: link being in the air does not mean we've found a dropoff. I mean... it could mean that, but it's a little too late to do anything about it at that point anyway. // Don't be fooled: link being in the air does not mean we've found a dropoff. I mean... it could mean that, but
// it's a little too late to do anything about it at that point anyway.
if (player->stateFlags3 & PLAYER_STATE3_MIDAIR || player->stateFlags2 & PLAYER_STATE2_HOPPING) { if (player->stateFlags3 & PLAYER_STATE3_MIDAIR || player->stateFlags2 & PLAYER_STATE2_HOPPING) {
f32 floorHeight = 0; f32 floorHeight = 0;
@ -952,7 +934,6 @@ class Lava : protected TerrainCueSound {
// checks for new wall poly // checks for new wall poly
wallPoly = checkWall(pos, prevPos, wallPos); wallPoly = checkWall(pos, prevPos, wallPos);
// if not climable and exists then treats it as a wall // if not climable and exists then treats it as a wall
if (wallPoly != NULL) { if (wallPoly != NULL) {
discoverWall(pos); discoverWall(pos);
@ -997,7 +978,8 @@ class Lava : protected TerrainCueSound {
rot.y = ogRot.y; rot.y = ogRot.y;
pos = ogPos; pos = ogPos;
if (clockwiseTest && counterclockwiseTest && (forwardTest || wallHeight < 44.0) && wallHeight < 48 && //probably have to change for adult if (clockwiseTest && counterclockwiseTest && (forwardTest || wallHeight < 44.0) &&
wallHeight < 48 && // probably have to change for adult
(fabs(clockwiseY - counterclockwiseY) < 2.0 || (fabs(clockwiseY - counterclockwiseY) < 2.0 ||
fabs(clockwiseY - counterclockwiseY) > wallHeight - 5.0)) { fabs(clockwiseY - counterclockwiseY) > wallHeight - 5.0)) {
discoverLedge(pos, true); discoverLedge(pos, true);
@ -1008,7 +990,8 @@ class Lava : protected TerrainCueSound {
} }
// link is climbing // link is climbing
} else if (player->stateFlags1 == PLAYER_STATE1_CLIMBING_LADDER) { } else if (player->stateFlags1 == PLAYER_STATE1_CLIMBING_LADDER) {
f32 playerHeight = BgCheck_EntityRaycastFloor3(&actor->play->colCtx, &floorPoly, &floorBgId, &player->actor.world.pos); f32 playerHeight =
BgCheck_EntityRaycastFloor3(&actor->play->colCtx, &floorPoly, &floorBgId, &player->actor.world.pos);
f32 floorHeight; f32 floorHeight;
s8 moveMethod = false; s8 moveMethod = false;
Vec3s_ ogRot = rot; Vec3s_ ogRot = rot;
@ -1017,7 +1000,6 @@ class Lava : protected TerrainCueSound {
if (ogRot.y == player->actor.world.rot.y) { if (ogRot.y == player->actor.world.rot.y) {
// sets forward probe to look above link // sets forward probe to look above link
moveMethod = 2; moveMethod = 2;
} }
player->actor.world.rot.y = player->actor.shape.rot.y; // corrects links rotation player->actor.world.rot.y = player->actor.shape.rot.y; // corrects links rotation
@ -1150,7 +1132,6 @@ class Lava : protected TerrainCueSound {
discoverWall(pos); discoverWall(pos);
break; break;
} }
} }
destroyCurrentSound(); destroyCurrentSound();
break; /*else { break; /*else {
@ -1159,7 +1140,6 @@ class Lava : protected TerrainCueSound {
break; break;
} }
}*/ // not needed? }*/ // not needed?
} }
if (moveMethod != 2 && checkPerpendicularWall(pos, ogRot)) { if (moveMethod != 2 && checkPerpendicularWall(pos, ogRot)) {
discoverWall(pos); discoverWall(pos);
@ -1182,7 +1162,6 @@ class Lava : protected TerrainCueSound {
} }
// link is on land // link is on land
else { else {
@ -1191,7 +1170,6 @@ class Lava : protected TerrainCueSound {
break; // Probe is out of bounds. break; // Probe is out of bounds.
} }
if (isPushedAway() && player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) { if (isPushedAway() && player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) {
// Call this a wall for now. // Call this a wall for now.
discoverWall(pos); discoverWall(pos);
@ -1207,8 +1185,7 @@ class Lava : protected TerrainCueSound {
(player->actor.yDistToWater < 0)) { (player->actor.yDistToWater < 0)) {
discoverLedge(pos, 2); discoverLedge(pos, 2);
foundLiquid = true; foundLiquid = true;
} } else if (rdist(pos) < 100.0) {
else if (rdist(pos) < 100.0) {
s8 i = 50; s8 i = 50;
Vec3f_ oldPos = pos; Vec3f_ oldPos = pos;
while (i > 0) { while (i > 0) {
@ -1243,7 +1220,6 @@ class Lava : protected TerrainCueSound {
discoverLedge(pos); discoverLedge(pos);
} }
if (pos.y > prevPos.y && fabs(pos.y - prevPos.y) < 20 && fabs(pos.y - prevPos.y) > 1.2 && if (pos.y > prevPos.y && fabs(pos.y - prevPos.y) < 20 && fabs(pos.y - prevPos.y) > 1.2 &&
player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) { player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) {
// This is an incline. // This is an incline.
@ -1334,8 +1310,6 @@ class Lava : protected TerrainCueSound {
break; break;
} }
else { else {
continue; continue;
} }
@ -1344,8 +1318,6 @@ class Lava : protected TerrainCueSound {
discoverWall(pos); discoverWall(pos);
break; break;
} }
} }
} }
if (trackingMode) if (trackingMode)
@ -1358,11 +1330,8 @@ disabled = true;
trackingMode = false; trackingMode = false;
trackingModeStarted = false; trackingModeStarted = false;
} }
} }
void testForPlatform() void testForPlatform() {
{
Player* player = GET_PLAYER(actor->play); Player* player = GET_PLAYER(actor->play);
f32 ledgeCheckDistance = 200.0; f32 ledgeCheckDistance = 200.0;
@ -1405,13 +1374,10 @@ bool ActorAccessibility_InitTerrainCueState(AccessibleActor* actor) {
actor->userData = state; actor->userData = state;
return true; return true;
} }
void ActorAccessibility_CleanupTerrainCueState(AccessibleActor* actor) { void ActorAccessibility_CleanupTerrainCueState(AccessibleActor* actor) {
free(actor->userData); free(actor->userData);
actor->userData = NULL; actor->userData = NULL;
} }
// Computes a relative angle based on Link's (or some other actor's) current angle. // Computes a relative angle based on Link's (or some other actor's) current angle.
Vec3s ActorAccessibility_ComputeRelativeAngle(Vec3s* origin, Vec3s* offset) { Vec3s ActorAccessibility_ComputeRelativeAngle(Vec3s* origin, Vec3s* offset) {
@ -1420,10 +1386,8 @@ Vec3s ActorAccessibility_ComputeRelativeAngle(Vec3s* origin, Vec3s* offset) {
rot.y += offset->y; rot.y += offset->y;
rot.z += offset->z; rot.z += offset->z;
return rot; return rot;
} }
void accessible_va_terrain_cue(AccessibleActor* actor) { void accessible_va_terrain_cue(AccessibleActor* actor) {
TerrainCueState* state = (TerrainCueState*)actor->userData; TerrainCueState* state = (TerrainCueState*)actor->userData;
@ -1457,23 +1421,20 @@ void accessible_va_terrain_cue(AccessibleActor * actor) {
SpeechSynthesizer::Instance->Speak("Speak", GetLanguageCode()); SpeechSynthesizer::Instance->Speak("Speak", GetLanguageCode());
break; break;
case DO_ACTION_STOP: case DO_ACTION_STOP:
SpeechSynthesizer::Instance->Speak("Stop", GetLanguageCode()); // possibly disable? not sure what it does SpeechSynthesizer::Instance->Speak("Stop",
GetLanguageCode()); // possibly disable? not sure what it does
break; break;
default: default:
SpeechSynthesizer::Instance->Speak(" ", GetLanguageCode()); SpeechSynthesizer::Instance->Speak(" ", GetLanguageCode());
break; break;
} }
state->previousAction = currentState; state->previousAction = currentState;
} else { } else {
state->previousAction = currentState; state->previousAction = currentState;
} }
} }
/* /*
void accessible_va_wall_cue(AccessibleActor* actor) { void accessible_va_wall_cue(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play); Player* player = GET_PLAYER(actor->play);
@ -1545,11 +1506,6 @@ Vec3s rot = computeRelativeAngle(player->actor.world.rot, actor->world.rot);
} }
*/ */
void ActorAccessibility_InitCues() { void ActorAccessibility_InitCues() {
ActorAccessibilityPolicy policy; ActorAccessibilityPolicy policy;
@ -1563,6 +1519,4 @@ ActorAccessibilityPolicy policy;
ActorAccessibility_AddSupportedActor(VA_TERRAIN_CUE, policy); ActorAccessibility_AddSupportedActor(VA_TERRAIN_CUE, policy);
VirtualActorList* list = ActorAccessibility_GetVirtualActorList(EVERYWHERE, 0); VirtualActorList* list = ActorAccessibility_GetVirtualActorList(EVERYWHERE, 0);
ActorAccessibility_AddVirtualActor(list, VA_TERRAIN_CUE, { { 0, 0, 0 }, { 0, 0, 0 } }); ActorAccessibility_AddVirtualActor(list, VA_TERRAIN_CUE, { { 0, 0, 0 }, { 0, 0, 0 } });
} }

View file

@ -274,7 +274,7 @@ OTRGlobals::OTRGlobals() {
if (std::filesystem::exists(ootPath)) { if (std::filesystem::exists(ootPath)) {
OTRFiles.push_back(ootPath); OTRFiles.push_back(ootPath);
} }
std::string sohOtrPath = Ship::Context::GetPathRelativeToAppBundle("soh.otr"); std::string sohOtrPath = Ship::Context::GetPathRelativeToAppBundle("soh.o2r");
if (std::filesystem::exists(sohOtrPath)) { if (std::filesystem::exists(sohOtrPath)) {
OTRFiles.push_back(sohOtrPath); OTRFiles.push_back(sohOtrPath);
} }