invert TerrainCueState, removing userData / init / cleanup from AccessibleActor

This commit is contained in:
Demur Rumed 2025-06-12 03:57:30 +00:00
commit d8cbb74284
4 changed files with 67 additions and 70 deletions

View file

@ -1160,12 +1160,10 @@ void ActorAccessibility_InitActors() {
temp->policy.ydist = 100; temp->policy.ydist = 100;
temp->policy.sound = NA_SE_EV_BLOCK_SHAKE; temp->policy.sound = NA_SE_EV_BLOCK_SHAKE;
ActorAccessibility_InitPolicy(&policy, "Terrain cue helper", accessible_va_terrain_cue); ActorAccessibility_InitPolicy(&policy, "Terrain cue helper", nullptr);
policy.n = 1; policy.n = 1;
policy.runsAlways = true; policy.runsAlways = true;
policy.distance = 500; policy.distance = 500;
policy.initUserData = ActorAccessibility_InitTerrainCueState;
policy.cleanupUserData = ActorAccessibility_CleanupTerrainCueState;
ActorAccessibility_AddSupportedActor(VA_TERRAIN_CUE, policy); ActorAccessibility_AddSupportedActor(VA_TERRAIN_CUE, policy);
AccessibleActor* actor = new AccessibleActor; AccessibleActor* actor = new AccessibleActor;
@ -1185,6 +1183,5 @@ void ActorAccessibility_InitActors() {
actor->aimAssist.framesSinceAimAssist = 0; actor->aimAssist.framesSinceAimAssist = 0;
actor->aimAssist.frequency = 10; actor->aimAssist.frequency = 10;
actor->policy = policy; actor->policy = policy;
ActorAccessibility_InitTerrainCueState(actor);
ActorAccessibility_AddTerrainCues(actor); ActorAccessibility_AddTerrainCues(actor);
} }

View file

@ -94,7 +94,7 @@ class ActorAccessibility {
Vec3f prevPos = { 0, 0, 0 }; Vec3f prevPos = { 0, 0, 0 };
s16 prevYaw = 0; s16 prevYaw = 0;
bool extractSfx = false; bool extractSfx = false;
AccessibleActor* terrainCues = nullptr; TerrainCueState* terrainCues = nullptr;
VirtualActorList* currentSceneGlobal = nullptr; VirtualActorList* currentSceneGlobal = nullptr;
VirtualActorList* currentRoomLocal = nullptr; VirtualActorList* currentRoomLocal = nullptr;
}; };
@ -161,8 +161,6 @@ void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char*
policy->pitch = 1.5; policy->pitch = 1.5;
policy->runsAlways = false; policy->runsAlways = false;
policy->volume = 1.0; policy->volume = 1.0;
policy->initUserData = NULL;
policy->cleanupUserData = NULL;
policy->pitchModifier = 0.1; policy->pitchModifier = 0.1;
policy->aimAssist.isProvider = false; policy->aimAssist.isProvider = false;
policy->aimAssist.sfx = NA_SE_SY_HITPOINT_ALARM; policy->aimAssist.sfx = NA_SE_SY_HITPOINT_ALARM;
@ -187,7 +185,7 @@ void ActorAccessibility_AddSupportedActor(s16 type, ActorAccessibilityPolicy pol
} }
void ActorAccessibility_AddTerrainCues(AccessibleActor* actor) { void ActorAccessibility_AddTerrainCues(AccessibleActor* actor) {
aa->terrainCues = actor; aa->terrainCues = InitTerrainCueState(actor);
} }
ActorAccessibilityPolicy* ActorAccessibility_GetPolicyForActor(s16 type) { ActorAccessibilityPolicy* ActorAccessibility_GetPolicyForActor(s16 type) {
@ -226,10 +224,6 @@ void ActorAccessibility_TrackNewActor(Actor* actor) {
aa->trackedActors[actor] = accessibleActor.instanceID; aa->trackedActors[actor] = accessibleActor.instanceID;
aa->accessibleActorList[accessibleActor.instanceID] = accessibleActor; aa->accessibleActorList[accessibleActor.instanceID] = accessibleActor;
if (policy->initUserData) {
AccessibleActor& savedActor = aa->accessibleActorList[accessibleActor.instanceID];
policy->initUserData(&savedActor);
}
} }
void ActorAccessibility_RemoveTrackedActor(Actor* actor) { void ActorAccessibility_RemoveTrackedActor(Actor* actor) {
@ -241,8 +235,6 @@ void ActorAccessibility_RemoveTrackedActor(Actor* actor) {
AccessibleActorList_t::iterator i2 = aa->accessibleActorList.find(id); AccessibleActorList_t::iterator i2 = aa->accessibleActorList.find(id);
if (i2 == aa->accessibleActorList.end()) if (i2 == aa->accessibleActorList.end())
return; return;
if (i2->second.policy.cleanupUserData)
i2->second.policy.cleanupUserData(&i2->second);
ActorAccessibility_StopAllSoundsForActor(&i2->second); ActorAccessibility_StopAllSoundsForActor(&i2->second);
aa->accessibleActorList.erase(i2); aa->accessibleActorList.erase(i2);
} }
@ -446,7 +438,7 @@ void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play) {
ActorAccessibility_RunAccessibilityForActor(play, &i->second); ActorAccessibility_RunAccessibilityForActor(play, &i->second);
if (aa->terrainCues) { if (aa->terrainCues) {
ActorAccessibility_RunAccessibilityForActor(play, aa->terrainCues); RunTerrainCueState(aa->terrainCues, play);
} }
// Virtual actors for the current room and scene. // Virtual actors for the current room and scene.
@ -642,11 +634,7 @@ AccessibleActor* ActorAccessibility_AddVirtualActor(VirtualActorList* list, VIRT
VAList_t* l = (VAList_t*)list; VAList_t* l = (VAList_t*)list;
l->push_back(actor); l->push_back(actor);
size_t index = l->size() - 1; return &(*l)[l->size() - 1];
AccessibleActor* savedActor = &(*l)[l->size() - 1];
if (policy->initUserData)
policy->initUserData(savedActor);
return savedActor;
} }
void ActorAccessibility_InterpretCurrentScene(PlayState* play) { void ActorAccessibility_InterpretCurrentScene(PlayState* play) {
@ -760,9 +748,8 @@ bool ActorAccessibility_InitAudio() {
void ActorAccessibility_ShutdownAudio() { void ActorAccessibility_ShutdownAudio() {
if (aa->isOn) { if (aa->isOn) {
delete aa->audioEngine; delete aa->audioEngine;
if (aa->terrainCues) { if (aa->terrainCues) {
ActorAccessibility_CleanupTerrainCueState(aa->terrainCues); DeleteTerrainCueState(aa->terrainCues);
delete aa->terrainCues;
} }
aa->isOn = false; aa->isOn = false;
} }

View file

@ -5,10 +5,6 @@ struct 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.
typedef void (*ActorAccessibilityCallback)(AccessibleActor*); typedef void (*ActorAccessibilityCallback)(AccessibleActor*);
// A callback which allows AccessibleActor instances to initialize custom user data (called once per instantiation).
typedef void (*ActorAccessibilityUserDataInit)(AccessibleActor*);
// A callback that can be used to clean up user data when an actor is destroyed.
typedef void (*ActorAccessibilityUserDataCleanup)(AccessibleActor*);
struct VirtualActorList; struct VirtualActorList;
@ -26,8 +22,6 @@ struct ActorAccessibilityPolicy {
f32 volume; f32 volume;
f32 pitchModifier; f32 pitchModifier;
bool runsAlways; // If set, then the distance policy is ignored. bool runsAlways; // If set, then the distance policy is ignored.
ActorAccessibilityUserDataInit initUserData;
ActorAccessibilityUserDataCleanup cleanupUserData;
// Aim assist settings. // Aim assist settings.
struct { struct {
bool isProvider; // determines whether or not this actor supports aim assist. bool isProvider; // determines whether or not this actor supports aim assist.
@ -45,8 +39,8 @@ struct ActorAccessibilityPolicy {
struct AccessibleActor { struct AccessibleActor {
uint64_t instanceID; uint64_t instanceID;
Actor* actor; // This can be null for a virtual actor. Actor* actor; // null for virtual actors
s16 id; // For real actors, we copy the ID of the actor. For virtual actors we have our own table of values which s16 id; // For real actors, copy actor ID. For virtual actors we have our own table of values which
// are out of range for real actors. // are out of range for real actors.
f32 yDistToPlayer; f32 yDistToPlayer;
f32 xzDistToPlayer; f32 xzDistToPlayer;
@ -75,7 +69,6 @@ struct AccessibleActor {
// Add more state as needed. // Add more state as needed.
ActorAccessibilityPolicy policy; // A copy, so it can be customized on a per-actor basis if needed. ActorAccessibilityPolicy policy; // A copy, so it can be customized on a per-actor basis if needed.
void* userData; // Set by the policy. Can be anything.
}; };
struct AimAssistProps { struct AimAssistProps {
@ -84,6 +77,11 @@ struct AimAssistProps {
f32 pan; f32 pan;
}; };
struct TerrainCueState;
void DeleteTerrainCueState(TerrainCueState*);
TerrainCueState* InitTerrainCueState(AccessibleActor*);
void RunTerrainCueState(TerrainCueState*, PlayState*);
// Initialize accessibility. // Initialize accessibility.
void ActorAccessibility_Init(); void ActorAccessibility_Init();
void ActorAccessibility_InitActors(); void ActorAccessibility_InitActors();
@ -92,9 +90,6 @@ void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char*
void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char* englishName, void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char* englishName,
ActorAccessibilityCallback callback); ActorAccessibilityCallback callback);
void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char* englishName, s16 sfx); void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char* englishName, s16 sfx);
void ActorAccessibility_InitTerrainCueState(AccessibleActor* actor);
void ActorAccessibility_CleanupTerrainCueState(AccessibleActor* actor);
void accessible_va_terrain_cue(AccessibleActor* actor);
uint64_t ActorAccessibility_GetNextID(); uint64_t ActorAccessibility_GetNextID();
void ActorAccessibility_TrackNewActor(Actor* actor); void ActorAccessibility_TrackNewActor(Actor* actor);

View file

@ -10,8 +10,8 @@ void Player_GetSlopeDirection(CollisionPoly* floorPoly, Vec3f* slopeNormal, s16*
void CollisionPoly_GetVertices(CollisionPoly* poly, Vec3s* vtxList, Vec3f* dest); void CollisionPoly_GetVertices(CollisionPoly* poly, Vec3s* vtxList, Vec3f* dest);
f32 BgCheck_RaycastFloorImpl(PlayState* play, CollisionContext* colCtx, u16 xpFlags, CollisionPoly** outPoly, f32 BgCheck_RaycastFloorImpl(PlayState* play, CollisionContext* colCtx, u16 xpFlags, CollisionPoly** outPoly,
s32* outBgId, Vec3f* pos, Actor* actor, u32 arg7, f32 chkDist); s32* outBgId, Vec3f* pos, Actor* actor, u32 arg7, f32 chkDist);
#include "soh/Enhancements/speechsynthesizer/SpeechSynthesizer.h" //#include "soh/Enhancements/speechsynthesizer/SpeechSynthesizer.h"
#include "soh/Enhancements/tts/tts.h" //#include "soh/Enhancements/tts/tts.h"
} }
#define DETECTION_DISTANCE 500.0 #define DETECTION_DISTANCE 500.0
#define MIN_INCLINE_DISTANCE 5.0 #define MIN_INCLINE_DISTANCE 5.0
@ -34,6 +34,7 @@ enum DiscoveredTerrain {
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 // 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. // constructed in static memory owned by the TerrainCueDirection object.
class TerrainCueSound { class TerrainCueSound {
@ -91,6 +92,7 @@ class TerrainCueSound {
run(); run();
} }
}; };
class Incline : protected TerrainCueSound { class Incline : protected TerrainCueSound {
float pitchModifier; float pitchModifier;
@ -151,6 +153,7 @@ class Decline : protected TerrainCueSound {
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.
Vec3s probeRot; Vec3s probeRot;
@ -195,6 +198,7 @@ class Ledge : protected TerrainCueSound {
} }
} }
}; };
class Platform : protected TerrainCueSound { class Platform : protected TerrainCueSound {
public: public:
Platform(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) { Platform(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) {
@ -259,6 +263,7 @@ class Wall : protected TerrainCueSound {
ActorAccessibility_SetSoundPitch(this, 0, pitchModifier); ActorAccessibility_SetSoundPitch(this, 0, pitchModifier);
} }
}; };
class Spike : protected TerrainCueSound { class Spike : protected TerrainCueSound {
public: public:
Spike(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) { Spike(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) {
@ -276,6 +281,7 @@ class Spike : protected TerrainCueSound {
restFrames--; restFrames--;
} }
}; };
class Water : protected TerrainCueSound { class Water : protected TerrainCueSound {
public: public:
Water(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) { Water(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) {
@ -394,8 +400,8 @@ class TerrainCueDirection final {
currentSound = NULL; currentSound = NULL;
terrainDiscovered = DISCOVERED_NOTHING; terrainDiscovered = DISCOVERED_NOTHING;
} }
// Play a sound from the position of a previously discovered incline.
// Play a sound from the position of a previously discovered incline.
void discoverIncline(Vec3f pos, float pitchModifier = 0) { void discoverIncline(Vec3f pos, float pitchModifier = 0) {
if (terrainDiscovered == DISCOVERED_INCLINE) { if (terrainDiscovered == DISCOVERED_INCLINE) {
incline.setPitchModifier(pitchModifier); incline.setPitchModifier(pitchModifier);
@ -409,8 +415,8 @@ class TerrainCueDirection final {
currentSound = (TerrainCueSound*)&incline; currentSound = (TerrainCueSound*)&incline;
terrainDiscovered = DISCOVERED_INCLINE; terrainDiscovered = DISCOVERED_INCLINE;
} }
// Play a sound from the position of a previously discovered decline.
// Play a sound from the position of a previously discovered decline.
void discoverDecline(Vec3f pos, float pitchModifier = 0) { void discoverDecline(Vec3f pos, float pitchModifier = 0) {
if (terrainDiscovered == DISCOVERED_DECLINE) { if (terrainDiscovered == DISCOVERED_DECLINE) {
incline.setPitchModifier(pitchModifier); incline.setPitchModifier(pitchModifier);
@ -424,8 +430,8 @@ class TerrainCueDirection final {
currentSound = (TerrainCueSound*)&decline; currentSound = (TerrainCueSound*)&decline;
terrainDiscovered = DISCOVERED_DECLINE; terrainDiscovered = DISCOVERED_DECLINE;
} }
// Play a sound from the position of a previously discovered ledge.
// Play a sound from the position of a previously discovered ledge.
void discoverLedge(Vec3f pos, s8 type = 0) { void discoverLedge(Vec3f pos, s8 type = 0) {
if (terrainDiscovered == DISCOVERED_LEDGE && ledge.type() == type) if (terrainDiscovered == DISCOVERED_LEDGE && ledge.type() == type)
return; return;
@ -436,8 +442,8 @@ class TerrainCueDirection final {
currentSound = (TerrainCueSound*)&ledge; currentSound = (TerrainCueSound*)&ledge;
terrainDiscovered = DISCOVERED_LEDGE; terrainDiscovered = DISCOVERED_LEDGE;
} }
// Play a sound from the position of a previously discovered wall.
// Play a sound from the position of a previously discovered wall.
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) {
@ -454,6 +460,7 @@ class TerrainCueDirection final {
currentSound = (TerrainCueSound*)&wall; currentSound = (TerrainCueSound*)&wall;
terrainDiscovered = DISCOVERED_WALL; terrainDiscovered = DISCOVERED_WALL;
} }
void discoverSpike(Vec3f pos) { void discoverSpike(Vec3f pos) {
if (terrainDiscovered == DISCOVERED_SPIKE) if (terrainDiscovered == DISCOVERED_SPIKE)
return; return;
@ -494,6 +501,7 @@ class TerrainCueDirection final {
currentSound = (TerrainCueSound*)&lava; currentSound = (TerrainCueSound*)&lava;
terrainDiscovered = DISCOVERED_LAVA; terrainDiscovered = DISCOVERED_LAVA;
} }
// Find out how high a wall goes. // Find out how high a wall goes.
f32 findWallHeight(Vec3f& pos, CollisionPoly* poly) { f32 findWallHeight(Vec3f& pos, CollisionPoly* poly) {
Player* player = GET_PLAYER(actor->play); Player* player = GET_PLAYER(actor->play);
@ -552,9 +560,9 @@ class TerrainCueDirection final {
&wallBgId, NULL, wallCheckHeight); &wallBgId, NULL, wallCheckHeight);
return wallPoly; return wallPoly;
} }
// Another copy/modify job from z_player.c. This function sets windspeed and wind direction, which are used for // Another copy/modify job from z_player.c. This function sets windspeed and wind direction, which are used for
// pushing the player up and down slopes. "Inspired" by func_8083E318. // pushing the player up and down slopes. "Inspired" by func_8083E318.
s32 computePushedSpeedEtc() { s32 computePushedSpeedEtc() {
s32 pad; s32 pad;
s16 sp4A; s16 sp4A;
@ -662,6 +670,7 @@ class TerrainCueDirection final {
} }
return false; return false;
} }
// Check if we're being pushed away from our intended destination. // Check if we're being pushed away from our intended destination.
bool isPushedAway() { bool isPushedAway() {
f32 dist = Math_Vec3f_DistXZ(&velocity, &expectedVelocity); f32 dist = Math_Vec3f_DistXZ(&velocity, &expectedVelocity);
@ -669,6 +678,7 @@ class TerrainCueDirection final {
return true; return true;
return false; return false;
} }
bool proveClimbableStep() { bool proveClimbableStep() {
setVelocity(); setVelocity();
if (!move()) if (!move())
@ -680,6 +690,7 @@ class TerrainCueDirection final {
return false; return false;
return true; return true;
} }
bool proveClimbable() { bool proveClimbable() {
Vec3s ogRot = rot; Vec3s ogRot = rot;
Vec3f ogPos = pos; Vec3f ogPos = pos;
@ -796,6 +807,7 @@ class TerrainCueDirection final {
return true; return true;
} }
bool isHeadOnCollision(Vec3f& wallPos, Vec3f& velocity) { bool isHeadOnCollision(Vec3f& wallPos, Vec3f& velocity) {
return true; return true;
@ -810,7 +822,6 @@ class TerrainCueDirection final {
} }
// Perform all terrain detection and sound book keeping. Call once per frame. // Perform all terrain detection and sound book keeping. Call once per frame.
float rdist(Vec3f pos) { float rdist(Vec3f pos) {
Player* player = GET_PLAYER(actor->play); Player* player = GET_PLAYER(actor->play);
float xdist = fabs(pos.x - player->actor.world.pos.x); float xdist = fabs(pos.x - player->actor.world.pos.x);
@ -879,9 +890,9 @@ class TerrainCueDirection final {
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 // 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. // 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;
floorHeight = BgCheck_EntityRaycastFloor3(&actor->play->colCtx, &floorPoly, &floorBgId, &pos); floorHeight = BgCheck_EntityRaycastFloor3(&actor->play->colCtx, &floorPoly, &floorBgId, &pos);
@ -1033,7 +1044,6 @@ class TerrainCueDirection final {
} }
// this means that either the wall poly found above is not a vine or is NULL // this means that either the wall poly found above is not a vine or is NULL
// the next three secections check infront and behind the probe for wall polys // the next three secections check infront and behind the probe for wall polys
//
if (moveMethod != 2) { if (moveMethod != 2) {
prevPos = pos; prevPos = pos;
rot.y = player->actor.shape.rot.y; rot.y = player->actor.shape.rot.y;
@ -1157,7 +1167,6 @@ class TerrainCueDirection final {
} }
if (isPushedAway() && player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) { if (isPushedAway() && player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) {
// Call this a wall for now.
discoverWall(pos); discoverWall(pos);
break; break;
} }
@ -1272,16 +1281,16 @@ class TerrainCueDirection final {
CollisionPoly* wallPoly = checkWall(pos, prevPos, wallPos); CollisionPoly* wallPoly = checkWall(pos, prevPos, wallPos);
if (wallPoly == NULL) if (wallPoly == NULL)
continue; continue;
// Is this a spiked wall?
Vec3f polyVerts[3]; Vec3f polyVerts[3];
// Is this a spiked wall?
CollisionPoly_GetVertices(wallPoly, colCtx->colHeader->vtxList, polyVerts); CollisionPoly_GetVertices(wallPoly, colCtx->colHeader->vtxList, polyVerts);
if (SurfaceType_IsWallDamage(&actor->play->colCtx, wallPoly, BGCHECK_SCENE)) { if (SurfaceType_IsWallDamage(&actor->play->colCtx, wallPoly, BGCHECK_SCENE)) {
discoverSpike(pos); discoverSpike(pos);
break; break;
} }
// is this a ladder or vine wall?
// is this a ladder or vine wall?
wallHeight = findWallHeight(pos, wallPoly); wallHeight = findWallHeight(pos, wallPoly);
if (wallHeight <= player->ageProperties->unk_0C && if (wallHeight <= player->ageProperties->unk_0C &&
player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) { player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) {
@ -1342,24 +1351,6 @@ class TerrainCueDirection final {
} }
}; };
typedef struct {
TerrainCueDirection directions[3]; // Directly ahead of Link, 90 degrees to his left and 90 degrees to his right.
} TerrainCueState;
// Callback for initialization of terrain cue state.
void ActorAccessibility_InitTerrainCueState(AccessibleActor* actor) {
TerrainCueState* state = new TerrainCueState{ {
{ actor, { 0, 0, 0 } },
{ actor, { 0, 16384, 0 } },
{ actor, { 0, -16384, 0 } },
} };
actor->userData = state;
}
void ActorAccessibility_CleanupTerrainCueState(AccessibleActor* actor) {
delete (TerrainCueState*)actor->userData;
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) {
Vec3s rot = *origin; Vec3s rot = *origin;
@ -1369,9 +1360,36 @@ Vec3s ActorAccessibility_ComputeRelativeAngle(Vec3s* origin, Vec3s* offset) {
return rot; return rot;
} }
void accessible_va_terrain_cue(AccessibleActor* actor) { struct TerrainCueState {
TerrainCueState* state = (TerrainCueState*)actor->userData; AccessibleActor* actor;
TerrainCueDirection directions[3]; // Directly ahead of Link, 90 degrees to his left and 90 degrees to his right
for (int i = 0; i < 3; i++) TerrainCueState(AccessibleActor* actor) : actor(actor), directions{
state->directions[i].scan(); { actor, { 0, 0, 0 } },
{ actor, { 0, 16384, 0 } },
{ actor, { 0, -16384, 0 } },
} {}
~TerrainCueState() {
delete actor;
}
void Run(PlayState* play) {
ActorAccessibility_RunAccessibilityForActor(play, actor);
for (int i = 0; i < 3; i++) {
directions[i].scan();
}
}
};
TerrainCueState* InitTerrainCueState(AccessibleActor* actor) {
return new TerrainCueState(actor);
}
void DeleteTerrainCueState(TerrainCueState* terrainCues) {
delete terrainCues;
}
void RunTerrainCueState(TerrainCueState* terrainCues, PlayState* play) {
terrainCues->Run(play);
} }