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

View file

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

View file

@ -8,12 +8,20 @@ typedef void (*ActorAccessibilityCallback)(AccessibleActor*);
struct VirtualActorList; 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 { struct ActorAccessibilityPolicy {
const char* englishName; const char* englishName;
ActorAccessibilityCallback callback; // If set, it will be called once every n frames.
ActorAccessibilityCallback callback; // If set, it will be called once every n frames. If null, then sfx will be // If null, then sfx will be played once every n frames.
// played once every n frames.
s16 sound; // The ID of a sound to play. Ignored if the callback is set. 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. 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. 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 pitch;
f32 volume; f32 volume;
f32 pitchModifier; f32 pitchModifier;
bool runsAlways; // If set, then the distance policy is ignored.
// Aim assist settings. // Aim assist settings.
struct { struct {
bool isProvider; // determines whether or not this actor supports aim assist. 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. 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 f32 tolerance; // How close to center of actor does Link have to aim to consider it lined up.
// it lined up.
} aimAssist; } aimAssist;
}; };
@ -40,8 +46,8 @@ struct AccessibleActor {
uint64_t instanceID; uint64_t instanceID;
Actor* actor; // null for virtual actors 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 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;
f32 xyzDistToPlayer; 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. s16 sceneIndex; // If this actor represents a scene transition, then this will contain the destination scene index.
// Zero otherwise. // Zero otherwise.
u8 managedSoundSlots; // These have their attenuation and panning parameters updated every frame automatically. u8 managedSoundSlots; // These have their attenuation and panning parameters updated every frame automatically.
struct { u8 aimFramesSinceAimAssist; // Used for rate-based vertical aim assist.
u16 framesSinceAimAssist; // Allows rate-based vertical aim assist. Incremented every frame for aim assist u8 aimFrequency; // How often the sound will be played. Lower frequencies indicate vertical aim is getting closer.
// 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;
// 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.
}; };

View file

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