aimAssist: allow masking which items have aim assist

This commit is contained in:
Demur Rumed 2025-06-27 03:10:15 +00:00
commit 5b9a0215ae
4 changed files with 93 additions and 61 deletions

View file

@ -107,12 +107,12 @@ void accessible_switch(AccessibleActor* actor) {
}
} else if ((actor->actor->params & 7) == OBJSWITCH_TYPE_EYE) {
if (sw->eyeTexIndex == 0) {
actor->policy.aimAssist.isProvider = true;
actor->policy.aimAssist.isProvider = AIM_SHOOT;
actor->policy.ydist = 1000;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FOOT_SWITCH);
}
} else if (actor->xyzDistToPlayer < 1000) {
actor->policy.aimAssist.isProvider = true;
actor->policy.aimAssist.isProvider = AIM_ALL;
actor->policy.ydist = 1000;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH);
}
@ -479,7 +479,7 @@ void ActorAccessibility_InitActors() {
});
policy.distance = 2000;
policy.n = 1;
policy.aimAssist.isProvider = true;
policy.aimAssist.isProvider = AIM_HOOK;
ActorAccessibility_AddSupportedActor(ACTOR_EN_KAKASI2, policy);
ActorAccessibility_InitPolicy(&policy, "Chest", [](AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play);
@ -584,7 +584,7 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FLUTTER_FLAG);
}
});
policy.aimAssist.isProvider = true;
policy.aimAssist.isProvider = AIM_HOOK;
policy.distance = 1000;
policy.volume = 1.5;
policy.n = 1;
@ -654,7 +654,7 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_InitPolicy(&policy, "Jabu Switch", [](AccessibleActor* actor) {
int type = actor->actor->params & 0xFF;
if (type == YELLOW_TALL_1 || type == YELLOW_TALL_2) {
actor->policy.aimAssist.isProvider = true;
actor->policy.aimAssist.isProvider = AIM_ALL;
}
if ((actor->frameCount & 31) == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH);
@ -730,7 +730,7 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_PO_CRY);
}
});
policy.aimAssist.isProvider = true;
policy.aimAssist.isProvider = AIM_BOW;
policy.aimAssist.tolerance = 50.0f;
policy.n = 1;
policy.ydist = 1000;
@ -738,15 +738,15 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_AddSupportedActor(ACTOR_BG_PO_EVENT, policy);
ActorAccessibility_InitPolicy(&policy, "Poe Sister", [](AccessibleActor* actor) {
if (actor->actor->category == ACTORCAT_PROP) {
actor->policy.aimAssist.isProvider = false;
actor->policy.aimAssist.isProvider = 0;
}
});
policy.aimAssist.isProvider = true;
policy.aimAssist.isProvider = AIM_ALL;
policy.aimAssist.tolerance = 20.0f;
policy.n = 1;
ActorAccessibility_AddSupportedActor(ACTOR_EN_PO_SISTERS, policy);
ActorAccessibility_InitPolicy(&policy, "Lake Hylia Object", nullptr);
policy.aimAssist.isProvider = true;
policy.aimAssist.isProvider = AIM_HOOK;
policy.n = 1;
policy.ydist = 600;
policy.distance = 600;
@ -804,7 +804,7 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_InitPolicy(&policy, "Statue Eye", [](AccessibleActor* actor) {
actor->policy.aimAssist.isProvider =
ABS((s16)(actor->actor->yawTowardsPlayer - actor->actor->shape.rot.y)) < 0x2000;
ABS((s16)(actor->actor->yawTowardsPlayer - actor->actor->shape.rot.y)) < 0x2000 ? AIM_BOW : 0;
});
policy.n = 1;
policy.ydist = 500;
@ -822,7 +822,7 @@ void ActorAccessibility_InitActors() {
ActorAccessibility_InitPolicy(&policy, "gold skulltula token", NA_SE_EN_NUTS_DAMAGE);
ActorAccessibility_AddSupportedActor(ACTOR_EN_SI, policy);
ActorAccessibility_InitPolicy(&policy, "Gold and Wall skulltulas", nullptr);
policy.aimAssist.isProvider = true;
policy.aimAssist.isProvider = AIM_ALL | AIM_CUP;
policy.n = 1;
policy.ydist = 500;
policy.distance = 750;
@ -837,7 +837,7 @@ void ActorAccessibility_InitActors() {
});
policy.ydist = 100;
ActorAccessibility_AddSupportedActor(ACTOR_EN_ST, policy);
ActorAccessibility_InitPolicy(&policy, "goma larva egg", [](AccessibleActor* actor) {
ActorAccessibility_InitPolicy(&policy, "goma larva egg", [](AccessibleActor* actor) {
if (actor->actor->bgCheckFlags == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_GOMA_BJR_EGG1);
}
@ -890,7 +890,7 @@ void ActorAccessibility_InitActors() {
}
});
policy.n = 20;
policy.aimAssist.isProvider = true;
policy.aimAssist.isProvider = AIM_ALL;
ActorAccessibility_AddSupportedActor(ACTOR_EN_FZ, policy);
ActorAccessibility_InitPolicy(&policy, "Iron Knuckle", [](AccessibleActor* actor) {
EnIk* ik = (EnIk*)actor->actor;
@ -949,7 +949,7 @@ void ActorAccessibility_InitActors() {
}
}
});
policy.aimAssist.isProvider = true;
policy.aimAssist.isProvider = AIM_SHOOT | AIM_CUP;
policy.distance = 1000;
policy.n = 1;
ActorAccessibility_AddSupportedActor(ACTOR_EN_G_SWITCH, policy);
@ -1007,7 +1007,7 @@ void ActorAccessibility_InitActors() {
list = ActorAccessibility_GetVirtualActorList(SCENE_LOST_WOODS, 1);
temp = ActorAccessibility_AddVirtualActor(list, VA_MARKER, { 1348, 25, -25 });
temp->policy.aimAssist.isProvider = true;
temp->policy.aimAssist.isProvider = AIM_SLING;
temp->policy.distance = 700;
temp->policy.n = 1;
@ -1191,8 +1191,8 @@ void ActorAccessibility_InitActors() {
actor->pos = { 0, 0, 0 };
actor->sceneIndex = 0;
actor->managedSoundSlots = 0;
actor->aimAssist.framesSinceAimAssist = 0;
actor->aimAssist.frequency = 10;
actor->aimFramesSinceAimAssist = 0;
actor->aimFrequency = 10;
actor->policy = policy;
ActorAccessibility_AddTerrainCues(actor);
}

View file

@ -67,10 +67,10 @@ class AudioGlossaryData {
AccessibleActorList_t accessibleActorList;
AccessibleActorList_t::iterator current = accessibleActorList.begin();
bool GlossaryStarted = false;
int cooldown = 0;
int frameCount = 0;
u16 frameCount = 0;
s16 currentScene = -1;
s8 currentRoom = -1;
s8 cooldown = 0;
};
class ActorAccessibility {
@ -85,12 +85,12 @@ class ActorAccessibility {
SceneList_t sceneList;
AccessibleAudioEngine* audioEngine;
SfxExtractor sfxExtractor;
// Maps internal sfx to external (prerendered) resources.
// Maps internal sfx to external (prerendered) resources
std::unordered_map<s16, SfxRecord> sfxMap;
int framesUntilChime = 0;
s16 currentScene = -1;
s8 currentRoom = -1;
bool currentRoomClear = false;
u8 framesUntilChime = 0;
Vec3f prevPos = { 0, 0, 0 };
s16 prevYaw = 0;
bool extractSfx = false;
@ -162,7 +162,7 @@ void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char*
policy->runsAlways = false;
policy->volume = 1.0;
policy->pitchModifier = 0.1;
policy->aimAssist.isProvider = false;
policy->aimAssist.isProvider = 0;
policy->aimAssist.sfx = NA_SE_SY_HITPOINT_ALARM;
policy->aimAssist.tolerance = 0.0;
}
@ -219,8 +219,8 @@ void ActorAccessibility_TrackNewActor(Actor* actor) {
accessibleActor.currentVolume = accessibleActor.policy.volume;
accessibleActor.sceneIndex = 0;
accessibleActor.managedSoundSlots = 0;
accessibleActor.aimAssist.framesSinceAimAssist = 32768;
accessibleActor.aimAssist.frequency = 10;
accessibleActor.aimFramesSinceAimAssist = 255;
accessibleActor.aimFrequency = 10;
aa->trackedActors[actor] = accessibleActor.instanceID;
aa->accessibleActorList[accessibleActor.instanceID] = accessibleActor;
@ -377,18 +377,46 @@ void ActorAccessibility_RunAccessibilityForActor(PlayState* play, AccessibleActo
if (actor->policy.aimAssist.isProvider) {
Player* player = GET_PLAYER(play);
if ((player->stateFlags1 & PLAYER_STATE1_FIRST_PERSON) &&
(player->stateFlags1 & (PLAYER_STATE1_USING_BOOMERANG | PLAYER_STATE1_ITEM_IN_HAND))) {
auto aimAssistProps = ActorAccessibility_ProvideAimAssistForActor(actor);
if (++actor->aimAssist.framesSinceAimAssist >= actor->aimAssist.frequency) {
actor->aimAssist.framesSinceAimAssist = 0;
ActorAccessibility_PlaySoundForActor(actor, 7, actor->policy.aimAssist.sfx);
((actor->policy.aimAssist.isProvider & AIM_CUP) ||
(player->stateFlags1 & (PLAYER_STATE1_USING_BOOMERANG | PLAYER_STATE1_ITEM_IN_HAND)))) {
bool aim = false;
switch (player->heldItemAction) {
case PLAYER_IA_BOW:
case PLAYER_IA_BOW_FIRE:
case PLAYER_IA_BOW_ICE:
case PLAYER_IA_BOW_LIGHT:
case PLAYER_IA_BOW_0C:
case PLAYER_IA_BOW_0D:
case PLAYER_IA_BOW_0E:
aim = actor->policy.aimAssist.isProvider & AIM_BOW;
break;
case PLAYER_IA_SLINGSHOT:
aim = actor->policy.aimAssist.isProvider & AIM_SLING;
break;
case PLAYER_IA_HOOKSHOT:
case PLAYER_IA_LONGSHOT:
aim = actor->policy.aimAssist.isProvider & AIM_HOOK;
break;
case PLAYER_IA_BOOMERANG:
aim = actor->policy.aimAssist.isProvider & AIM_BOOM;
break;
case PLAYER_IA_NONE:
aim = actor->policy.aimAssist.isProvider & AIM_CUP;
break;
}
if (aim) {
auto aimAssistProps = ActorAccessibility_ProvideAimAssistForActor(actor);
if (++actor->aimFramesSinceAimAssist >= actor->aimFrequency) {
actor->aimFramesSinceAimAssist = 0;
ActorAccessibility_PlaySoundForActor(actor, 7, actor->policy.aimAssist.sfx);
}
ActorAccessibility_SetSoundPitch(actor, 7, aimAssistProps.pitch);
ActorAccessibility_SetSoundVolume(actor, 7, aimAssistProps.volume);
ActorAccessibility_SetSoundPan(actor, 7, aimAssistProps.pan);
}
ActorAccessibility_SetSoundPitch(actor, 7, aimAssistProps.pitch);
ActorAccessibility_SetSoundVolume(actor, 7, aimAssistProps.volume);
ActorAccessibility_SetSoundPan(actor, 7, aimAssistProps.pan);
} else {
// Make sure there's no delay the next time you draw your bow or whatever.
actor->aimAssist.framesSinceAimAssist = 32768;
actor->aimFramesSinceAimAssist = 255;
}
}
@ -472,7 +500,8 @@ void ActorAccessibility_GeneralHelper(PlayState* play) {
ActorAccessibility_AnnounceRoomNumber(play);
}
if (player->actor.wallPoly && player->actor.speedXZ > 0 && (player->yDistToLedge == 0 || player->yDistToLedge >= 79.0f)) {
if (player->actor.wallPoly && player->actor.speedXZ > 0 &&
(player->yDistToLedge == 0 || player->yDistToLedge >= 79.0f)) {
f32 movedsq = SQ(aa->prevPos.x - player->actor.world.pos.x) + SQ(aa->prevPos.z - player->actor.world.pos.z);
if (movedsq < 0.125) {
ActorAccessibility_PlaySound(nullptr, 3, NA_SE_IT_WALL_HIT_SOFT);
@ -623,8 +652,8 @@ AccessibleActor* ActorAccessibility_AddVirtualActor(VirtualActorList* list, VIRT
actor.pos = where;
actor.sceneIndex = 0;
actor.managedSoundSlots = 0;
actor.aimAssist.framesSinceAimAssist = 0;
actor.aimAssist.frequency = 10;
actor.aimFramesSinceAimAssist = 0;
actor.aimFrequency = 10;
actor.policy = *policy;
VAList_t* l = (VAList_t*)list;
@ -710,9 +739,9 @@ AimAssistProps ActorAccessibility_ProvideAimAssistForActor(AccessibleActor* acto
yDiff = std::max(yDiff - correction, 0);
}
if (yDiff > 300) {
actor->aimAssist.frequency = 30;
actor->aimFrequency = 30;
} else {
actor->aimAssist.frequency = 1 + (uint8_t)(yDiff / 5);
actor->aimFrequency = 1 + (uint8_t)(yDiff / 5);
}
s16 yawdiff =
player->yaw - Math_Atan2S(actor->pos.z - player->actor.world.pos.z, actor->pos.x - player->actor.world.pos.x);
@ -741,7 +770,7 @@ bool ActorAccessibility_InitAudio() {
void ActorAccessibility_ShutdownAudio() {
if (aa->isOn) {
delete aa->audioEngine;
if (aa->terrainCues) {
if (aa->terrainCues) {
DeleteTerrainCueState(aa->terrainCues);
}
aa->isOn = false;

View file

@ -8,12 +8,20 @@ typedef void (*ActorAccessibilityCallback)(AccessibleActor*);
struct VirtualActorList;
#define AIM_ALL 0x0F
#define AIM_BOW 0x01
#define AIM_SLING 0x02
#define AIM_SHOOT 0x03
#define AIM_HOOK 0x04
#define AIM_BOOM 0x08
#define AIM_CUP 0x10
struct ActorAccessibilityPolicy {
const char* englishName;
ActorAccessibilityCallback callback; // If set, it will be called once every n frames. If null, then sfx will be
// played once every n frames.
ActorAccessibilityCallback callback; // If set, it will be called once every n frames.
// If null, then sfx will be played once every n frames.
s16 sound; // The ID of a sound to play. Ignored if the callback is set.
bool runsAlways; // If set, then the distance policy is ignored.
int n; // How often to run the callback in frames.
f32 distance; // Maximum xz distance from player before the actor should be considered out of range.
@ -21,13 +29,11 @@ struct ActorAccessibilityPolicy {
f32 pitch;
f32 volume;
f32 pitchModifier;
bool runsAlways; // If set, then the distance policy is ignored.
// Aim assist settings.
struct {
bool isProvider; // determines whether or not this actor supports aim assist.
s16 sfx; // The sound to play when this actor provides aim assist. Uses sound slot 9.
f32 tolerance; // How close to the center of the actor does Link have to aim for aim assist to consider
// it lined up.
u8 isProvider; // determines whether or not this actor supports aim assist.
s16 sfx; // The sound to play when this actor provides aim assist. Uses sound slot 9.
f32 tolerance; // How close to center of actor does Link have to aim to consider it lined up.
} aimAssist;
};
@ -40,8 +46,8 @@ struct AccessibleActor {
uint64_t instanceID;
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.
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;
f32 xyzDistToPlayer;
@ -60,14 +66,9 @@ struct AccessibleActor {
s16 sceneIndex; // If this actor represents a scene transition, then this will contain the destination scene index.
// Zero otherwise.
u8 managedSoundSlots; // These have their attenuation and panning parameters updated every frame automatically.
struct {
u16 framesSinceAimAssist; // Allows rate-based vertical aim assist. Incremented every frame for aim assist
// actors. Manually reset by aim assist provider.
u8 frequency; // How often the sound will be played. Lower frequencies indicate that Link's vertical aim is
// closer to the actor.
} aimAssist;
u8 aimFramesSinceAimAssist; // Used for rate-based vertical aim assist.
u8 aimFrequency; // How often the sound will be played. Lower frequencies indicate vertical aim is getting closer.
// Add more state as needed.
ActorAccessibilityPolicy policy; // A copy, so it can be customized on a per-actor basis if needed.
};

View file

@ -1364,11 +1364,13 @@ struct TerrainCueState {
AccessibleActor* actor;
TerrainCueDirection directions[3]; // Directly ahead of Link, 90 degrees to his left and 90 degrees to his right
TerrainCueState(AccessibleActor* actor) : actor(actor), directions{
{ actor, { 0, 0, 0 } },
{ actor, { 0, 16384, 0 } },
{ actor, { 0, -16384, 0 } },
} {}
TerrainCueState(AccessibleActor* actor)
: actor(actor), directions{
{ actor, { 0, 0, 0 } },
{ actor, { 0, 16384, 0 } },
{ actor, { 0, -16384, 0 } },
} {
}
~TerrainCueState() {
delete actor;