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.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.runsAlways = true;
policy.distance = 500;
policy.initUserData = ActorAccessibility_InitTerrainCueState;
policy.cleanupUserData = ActorAccessibility_CleanupTerrainCueState;
ActorAccessibility_AddSupportedActor(VA_TERRAIN_CUE, policy);
AccessibleActor* actor = new AccessibleActor;
@ -1185,6 +1183,5 @@ void ActorAccessibility_InitActors() {
actor->aimAssist.framesSinceAimAssist = 0;
actor->aimAssist.frequency = 10;
actor->policy = policy;
ActorAccessibility_InitTerrainCueState(actor);
ActorAccessibility_AddTerrainCues(actor);
}

View file

@ -94,7 +94,7 @@ class ActorAccessibility {
Vec3f prevPos = { 0, 0, 0 };
s16 prevYaw = 0;
bool extractSfx = false;
AccessibleActor* terrainCues = nullptr;
TerrainCueState* terrainCues = nullptr;
VirtualActorList* currentSceneGlobal = nullptr;
VirtualActorList* currentRoomLocal = nullptr;
};
@ -161,8 +161,6 @@ void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char*
policy->pitch = 1.5;
policy->runsAlways = false;
policy->volume = 1.0;
policy->initUserData = NULL;
policy->cleanupUserData = NULL;
policy->pitchModifier = 0.1;
policy->aimAssist.isProvider = false;
policy->aimAssist.sfx = NA_SE_SY_HITPOINT_ALARM;
@ -187,7 +185,7 @@ void ActorAccessibility_AddSupportedActor(s16 type, ActorAccessibilityPolicy pol
}
void ActorAccessibility_AddTerrainCues(AccessibleActor* actor) {
aa->terrainCues = actor;
aa->terrainCues = InitTerrainCueState(actor);
}
ActorAccessibilityPolicy* ActorAccessibility_GetPolicyForActor(s16 type) {
@ -226,10 +224,6 @@ void ActorAccessibility_TrackNewActor(Actor* actor) {
aa->trackedActors[actor] = accessibleActor.instanceID;
aa->accessibleActorList[accessibleActor.instanceID] = accessibleActor;
if (policy->initUserData) {
AccessibleActor& savedActor = aa->accessibleActorList[accessibleActor.instanceID];
policy->initUserData(&savedActor);
}
}
void ActorAccessibility_RemoveTrackedActor(Actor* actor) {
@ -241,8 +235,6 @@ void ActorAccessibility_RemoveTrackedActor(Actor* actor) {
AccessibleActorList_t::iterator i2 = aa->accessibleActorList.find(id);
if (i2 == aa->accessibleActorList.end())
return;
if (i2->second.policy.cleanupUserData)
i2->second.policy.cleanupUserData(&i2->second);
ActorAccessibility_StopAllSoundsForActor(&i2->second);
aa->accessibleActorList.erase(i2);
}
@ -446,7 +438,7 @@ void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play) {
ActorAccessibility_RunAccessibilityForActor(play, &i->second);
if (aa->terrainCues) {
ActorAccessibility_RunAccessibilityForActor(play, aa->terrainCues);
RunTerrainCueState(aa->terrainCues, play);
}
// Virtual actors for the current room and scene.
@ -642,11 +634,7 @@ AccessibleActor* ActorAccessibility_AddVirtualActor(VirtualActorList* list, VIRT
VAList_t* l = (VAList_t*)list;
l->push_back(actor);
size_t index = l->size() - 1;
AccessibleActor* savedActor = &(*l)[l->size() - 1];
if (policy->initUserData)
policy->initUserData(savedActor);
return savedActor;
return &(*l)[l->size() - 1];
}
void ActorAccessibility_InterpretCurrentScene(PlayState* play) {
@ -761,8 +749,7 @@ void ActorAccessibility_ShutdownAudio() {
if (aa->isOn) {
delete aa->audioEngine;
if (aa->terrainCues) {
ActorAccessibility_CleanupTerrainCueState(aa->terrainCues);
delete aa->terrainCues;
DeleteTerrainCueState(aa->terrainCues);
}
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.
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;
@ -26,8 +22,6 @@ struct ActorAccessibilityPolicy {
f32 volume;
f32 pitchModifier;
bool runsAlways; // If set, then the distance policy is ignored.
ActorAccessibilityUserDataInit initUserData;
ActorAccessibilityUserDataCleanup cleanupUserData;
// Aim assist settings.
struct {
bool isProvider; // determines whether or not this actor supports aim assist.
@ -45,8 +39,8 @@ struct ActorAccessibilityPolicy {
struct AccessibleActor {
uint64_t instanceID;
Actor* actor; // This can be null for a virtual actor.
s16 id; // For real actors, we copy the ID of the actor. For virtual actors we have our own table of values which
Actor* actor; // null for virtual actors
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.
f32 yDistToPlayer;
f32 xzDistToPlayer;
@ -75,7 +69,6 @@ struct AccessibleActor {
// Add more state as 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 {
@ -84,6 +77,11 @@ struct AimAssistProps {
f32 pan;
};
struct TerrainCueState;
void DeleteTerrainCueState(TerrainCueState*);
TerrainCueState* InitTerrainCueState(AccessibleActor*);
void RunTerrainCueState(TerrainCueState*, PlayState*);
// Initialize accessibility.
void ActorAccessibility_Init();
void ActorAccessibility_InitActors();
@ -92,9 +90,6 @@ void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char*
void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char* englishName,
ActorAccessibilityCallback callback);
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();
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);
f32 BgCheck_RaycastFloorImpl(PlayState* play, CollisionContext* colCtx, u16 xpFlags, CollisionPoly** outPoly,
s32* outBgId, Vec3f* pos, Actor* actor, u32 arg7, f32 chkDist);
#include "soh/Enhancements/speechsynthesizer/SpeechSynthesizer.h"
#include "soh/Enhancements/tts/tts.h"
//#include "soh/Enhancements/speechsynthesizer/SpeechSynthesizer.h"
//#include "soh/Enhancements/tts/tts.h"
}
#define DETECTION_DISTANCE 500.0
#define MIN_INCLINE_DISTANCE 5.0
@ -34,6 +34,7 @@ enum DiscoveredTerrain {
DISCOVERED_GROUND,
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.
class TerrainCueSound {
@ -91,6 +92,7 @@ class TerrainCueSound {
run();
}
};
class Incline : protected TerrainCueSound {
float pitchModifier;
@ -151,6 +153,7 @@ class Decline : protected TerrainCueSound {
pitchModifier = mod;
}
};
class Ledge : protected TerrainCueSound {
s8 savedType; // Distinguishes between a ledge link can fall from and one he can climb up.
Vec3s probeRot;
@ -195,6 +198,7 @@ class Ledge : protected TerrainCueSound {
}
}
};
class Platform : protected TerrainCueSound {
public:
Platform(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) {
@ -259,6 +263,7 @@ class Wall : protected TerrainCueSound {
ActorAccessibility_SetSoundPitch(this, 0, pitchModifier);
}
};
class Spike : protected TerrainCueSound {
public:
Spike(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) {
@ -276,6 +281,7 @@ class Spike : protected TerrainCueSound {
restFrames--;
}
};
class Water : protected TerrainCueSound {
public:
Water(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) {
@ -394,8 +400,8 @@ class TerrainCueDirection final {
currentSound = NULL;
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) {
if (terrainDiscovered == DISCOVERED_INCLINE) {
incline.setPitchModifier(pitchModifier);
@ -409,8 +415,8 @@ class TerrainCueDirection final {
currentSound = (TerrainCueSound*)&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) {
if (terrainDiscovered == DISCOVERED_DECLINE) {
incline.setPitchModifier(pitchModifier);
@ -424,8 +430,8 @@ class TerrainCueDirection final {
currentSound = (TerrainCueSound*)&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) {
if (terrainDiscovered == DISCOVERED_LEDGE && ledge.type() == type)
return;
@ -436,8 +442,8 @@ class TerrainCueDirection final {
currentSound = (TerrainCueSound*)&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) {
Player* player = GET_PLAYER(actor->play);
if (player->stateFlags1 & PLAYER_STATE1_FIRST_PERSON) {
@ -454,6 +460,7 @@ class TerrainCueDirection final {
currentSound = (TerrainCueSound*)&wall;
terrainDiscovered = DISCOVERED_WALL;
}
void discoverSpike(Vec3f pos) {
if (terrainDiscovered == DISCOVERED_SPIKE)
return;
@ -494,6 +501,7 @@ class TerrainCueDirection final {
currentSound = (TerrainCueSound*)&lava;
terrainDiscovered = DISCOVERED_LAVA;
}
// Find out how high a wall goes.
f32 findWallHeight(Vec3f& pos, CollisionPoly* poly) {
Player* player = GET_PLAYER(actor->play);
@ -552,9 +560,9 @@ class TerrainCueDirection final {
&wallBgId, NULL, wallCheckHeight);
return wallPoly;
}
// 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.
s32 computePushedSpeedEtc() {
s32 pad;
s16 sp4A;
@ -662,6 +670,7 @@ class TerrainCueDirection final {
}
return false;
}
// Check if we're being pushed away from our intended destination.
bool isPushedAway() {
f32 dist = Math_Vec3f_DistXZ(&velocity, &expectedVelocity);
@ -669,6 +678,7 @@ class TerrainCueDirection final {
return true;
return false;
}
bool proveClimbableStep() {
setVelocity();
if (!move())
@ -680,6 +690,7 @@ class TerrainCueDirection final {
return false;
return true;
}
bool proveClimbable() {
Vec3s ogRot = rot;
Vec3f ogPos = pos;
@ -796,6 +807,7 @@ class TerrainCueDirection final {
return true;
}
bool isHeadOnCollision(Vec3f& wallPos, Vec3f& velocity) {
return true;
@ -810,7 +822,6 @@ class TerrainCueDirection final {
}
// Perform all terrain detection and sound book keeping. Call once per frame.
float rdist(Vec3f pos) {
Player* player = GET_PLAYER(actor->play);
float xdist = fabs(pos.x - player->actor.world.pos.x);
@ -879,9 +890,9 @@ class TerrainCueDirection final {
distToTravel = 1.0;
Vec3f collisionResult;
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.
if (player->stateFlags3 & PLAYER_STATE3_MIDAIR || player->stateFlags2 & PLAYER_STATE2_HOPPING) {
f32 floorHeight = 0;
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
// the next three secections check infront and behind the probe for wall polys
//
if (moveMethod != 2) {
prevPos = pos;
rot.y = player->actor.shape.rot.y;
@ -1157,7 +1167,6 @@ class TerrainCueDirection final {
}
if (isPushedAway() && player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) {
// Call this a wall for now.
discoverWall(pos);
break;
}
@ -1272,16 +1281,16 @@ class TerrainCueDirection final {
CollisionPoly* wallPoly = checkWall(pos, prevPos, wallPos);
if (wallPoly == NULL)
continue;
// Is this a spiked wall?
Vec3f polyVerts[3];
// Is this a spiked wall?
CollisionPoly_GetVertices(wallPoly, colCtx->colHeader->vtxList, polyVerts);
if (SurfaceType_IsWallDamage(&actor->play->colCtx, wallPoly, BGCHECK_SCENE)) {
discoverSpike(pos);
break;
}
// is this a ladder or vine wall?
// is this a ladder or vine wall?
wallHeight = findWallHeight(pos, wallPoly);
if (wallHeight <= player->ageProperties->unk_0C &&
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.
Vec3s ActorAccessibility_ComputeRelativeAngle(Vec3s* origin, Vec3s* offset) {
Vec3s rot = *origin;
@ -1369,9 +1360,36 @@ Vec3s ActorAccessibility_ComputeRelativeAngle(Vec3s* origin, Vec3s* offset) {
return rot;
}
void accessible_va_terrain_cue(AccessibleActor* actor) {
TerrainCueState* state = (TerrainCueState*)actor->userData;
struct TerrainCueState {
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++)
state->directions[i].scan();
TerrainCueState(AccessibleActor* actor) : actor(actor), directions{
{ 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);
}