diff options
| author | Anghelo Carvajal <angheloalf95@gmail.com> | 2023-09-02 15:16:45 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-02 15:16:45 -0400 |
| commit | 9cceea48f31bdeea1c2933a1f64a74b60b80f17a (patch) | |
| tree | ce2bfd99dfc465574800930015fa0a4d987eeefd /src/code/z_actor.c | |
| parent | cbf9d98dba61924625629061f7680e3508fc2701 (diff) | |
Documentation pass for the Target system (#1281)
* cleanup
* import bss
* sActorHiliteMtx
* some cleanups on func_800BB604
* Actor_IsInTargetableRange
* rematch func_800BB604
Co-authored-by: engineer124 <engineer124engineer124@gmail.com>
* Name ACTOR_FLAG_UNFRIENDLY and ACTOR_FLAG_FRIENDLY
* Rename some Target_ functions
* cleanusp
* TargetMode enum
* Target_800B82EC
* sNaming
* more
* more naming
* fairyHintPos
* rotation
* ACTOR_FLAG_TARGETABLE
* update namefixer
* remove trailing comma
* bss
* Wall of text for Target_800BB604
* function naming
* cleanups
* Target_GetAdjustedDistSq
* NotLeash
* more comments
* minor comment
* review
* fix
* rotZTick
* review
* name last members
* fix
* review
* review
* more namefixer
* swap members
* comment
* Update src/code/z_actor.c
Co-authored-by: Derek Hensley <hensley.derek58@gmail.com>
* Update src/code/z_actor.c
Co-authored-by: Derek Hensley <hensley.derek58@gmail.com>
* review
* format
* Update src/code/z_actor.c
Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com>
* Update include/z64actor.h
Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com>
* review
* review
* fix
* fix
---------
Co-authored-by: engineer124 <engineer124engineer124@gmail.com>
Co-authored-by: Derek Hensley <hensley.derek58@gmail.com>
Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com>
Diffstat (limited to 'src/code/z_actor.c')
| -rw-r--r-- | src/code/z_actor.c | 771 |
1 files changed, 432 insertions, 339 deletions
diff --git a/src/code/z_actor.c b/src/code/z_actor.c index 5debc583d..f88f511b5 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -3,6 +3,7 @@ * Description: */ +#include "prevent_bss_reordering.h" #include "global.h" #include "fault.h" #include "sys_cfb.h" @@ -18,21 +19,26 @@ #include "objects/object_bdoor/object_bdoor.h" // bss -extern FaultClient sActorFaultClient; // 2 funcs -extern CollisionPoly* D_801ED8B0; // 1 func -extern s32 D_801ED8B4; // 2 funcs -extern Actor* D_801ED8B8; // 2 funcs -extern Actor* D_801ED8BC; // 2 funcs -extern Actor* D_801ED8C0; // 2 funcs -extern Actor* D_801ED8C4; // 2 funcs -extern f32 D_801ED8C8; // 2 funcs -extern f32 sBgmEnemyDistSq; // 2 funcs -extern f32 D_801ED8D0; // 2 funcs -extern s32 D_801ED8D4; // 2 funcs -extern s32 D_801ED8D8; // 2 funcs -extern s16 D_801ED8DC; // 2 funcs -extern Mtx D_801ED8E0; // 1 func -extern Actor* D_801ED920; // 2 funcs. 1 out of z_actor +FaultClient sActorFaultClient; // 2 funcs + +CollisionPoly* D_801ED8B0; // 1 func +s32 D_801ED8B4; // 2 funcs + +Actor* sTargetableNearestActor; +Actor* sTargetablePrioritizedActor; +Actor* D_801ED8C0; +Actor* D_801ED8C4; + +f32 sTargetableNearestActorDistSq; +f32 sBgmEnemyDistSq; +f32 D_801ED8D0; +s32 sTargetablePrioritizedPriority; +s32 D_801ED8D8; +s16 sTargetPlayerRotY; + +Mtx sActorHiliteMtx; + +Actor* D_801ED920; // 2 funcs. 1 out of z_actor #define ACTOR_AUDIO_FLAG_SFX_ACTOR_POS (1 << 0) #define ACTOR_AUDIO_FLAG_SFX_CENTERED_1 (1 << 1) @@ -52,7 +58,7 @@ extern Actor* D_801ED920; // 2 funcs. 1 out of z_actor void Actor_KillAllOnHalfDayChange(PlayState* play, ActorContext* actorCtx); Actor* Actor_SpawnEntry(ActorContext* actorCtx, ActorEntry* actorEntry, PlayState* play); Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play); -void func_800BB8EC(GameState* gameState, ActorContext* actorCtx, Actor** arg2, Actor** arg3, Player* player); +void Target_GetTargetActor(PlayState* play, ActorContext* actorCtx, Actor** targetableP, Actor** arg3, Player* player); s32 func_800BA2FC(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW); void Actor_AddToCategory(ActorContext* actorCtx, Actor* actor, u8 actorCategory); Actor* Actor_RemoveFromCategory(PlayState* play, ActorContext* actorCtx, Actor* actorToRemove); @@ -415,11 +421,11 @@ void Actor_GetProjectedPos(PlayState* play, Vec3f* worldPos, Vec3f* projectedPos *invW = (*invW < 1.0f) ? 1.0f : (1.0f / *invW); } -void Target_SetPos(TargetContext* targetCtx, s32 index, f32 x, f32 y, f32 z) { - targetCtx->unk50[index].pos.x = x; - targetCtx->unk50[index].pos.y = y; - targetCtx->unk50[index].pos.z = z; - targetCtx->unk50[index].unkC = targetCtx->unk44; +void Target_SetLockOnPos(TargetContext* targetCtx, s32 index, f32 x, f32 y, f32 z) { + targetCtx->lockOnTriangleSets[index].pos.x = x; + targetCtx->lockOnTriangleSets[index].pos.y = y; + targetCtx->lockOnTriangleSets[index].pos.z = z; + targetCtx->lockOnTriangleSets[index].radius = targetCtx->lockOnRadius; } typedef struct { @@ -427,282 +433,293 @@ typedef struct { /* 0x4 */ Color_RGBA8 outer; } TatlColor; // size = 0x8 +// For whatever reason it has an extra entry TatlColor sTatlColorList[] = { - { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, - { { 255, 255, 230, 255 }, { 220, 160, 80, 0 } }, { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, - { { 150, 150, 255, 255 }, { 150, 150, 255, 0 } }, { { 255, 255, 0, 255 }, { 200, 155, 0, 0 } }, - { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, - { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, { { 255, 255, 0, 255 }, { 200, 155, 0, 0 } }, - { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, - { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, + { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, // ACTORCAT_SWITCH + { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, // ACTORCAT_BG + { { 255, 255, 230, 255 }, { 220, 160, 80, 0 } }, // ACTORCAT_PLAYER + { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, // ACTORCAT_EXPLOSIVES + { { 150, 150, 255, 255 }, { 150, 150, 255, 0 } }, // ACTORCAT_NPC + { { 255, 255, 0, 255 }, { 200, 155, 0, 0 } }, // ACTORCAT_ENEMY + { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, // ACTORCAT_PROP + { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, // ACTORCAT_ITEMACTION + { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, // ACTORCAT_MISC + { { 255, 255, 0, 255 }, { 200, 155, 0, 0 } }, // ACTORCAT_BOSS + { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, // ACTORCAT_DOOR + { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, // ACTORCAT_CHEST + { { 0, 255, 0, 255 }, { 0, 255, 0, 0 } }, // ACTORCAT_MAX }; -void func_800B4F78(TargetContext* targetCtx, s32 type, PlayState* play) { +void Target_InitLockOn(TargetContext* targetCtx, ActorType type, PlayState* play) { TatlColor* tatlColorEntry; s32 i; - TargetContextEntry* targetEntry; + LockOnTriangleSet* triangleSet; - Math_Vec3f_Copy(&targetCtx->targetCenterPos, &play->view.eye); - targetCtx->unk48 = 0x100; + Math_Vec3f_Copy(&targetCtx->lockOnPos, &play->view.eye); + targetCtx->lockOnAlpha = 256; tatlColorEntry = &sTatlColorList[type]; - targetCtx->unk44 = 500.0f; + targetCtx->lockOnRadius = 500.0f; - targetEntry = targetCtx->unk50; - for (i = 0; i < ARRAY_COUNT(targetCtx->unk50); i++, targetEntry++) { - Target_SetPos(targetCtx, i, 0.0f, 0.0f, 0.0f); + triangleSet = targetCtx->lockOnTriangleSets; + for (i = 0; i < ARRAY_COUNT(targetCtx->lockOnTriangleSets); i++, triangleSet++) { + Target_SetLockOnPos(targetCtx, i, 0.0f, 0.0f, 0.0f); - targetEntry->color.r = tatlColorEntry->inner.r; - targetEntry->color.g = tatlColorEntry->inner.g; - targetEntry->color.b = tatlColorEntry->inner.b; + triangleSet->color.r = tatlColorEntry->inner.r; + triangleSet->color.g = tatlColorEntry->inner.g; + triangleSet->color.b = tatlColorEntry->inner.b; } } -void Target_SetColors(TargetContext* targetCtx, Actor* actor, s32 type, PlayState* play) { - targetCtx->unk0.x = actor->focus.pos.x; - targetCtx->unk0.y = actor->focus.pos.y + (actor->targetArrowOffset * actor->scale.y); - targetCtx->unk0.z = actor->focus.pos.z; +void Target_SetFairyState(TargetContext* targetCtx, Actor* actor, ActorType type, PlayState* play) { + targetCtx->fairyPos.x = actor->focus.pos.x; + targetCtx->fairyPos.y = actor->focus.pos.y + (actor->targetArrowOffset * actor->scale.y); + targetCtx->fairyPos.z = actor->focus.pos.z; - targetCtx->fairyInner.r = sTatlColorList[type].inner.r; - targetCtx->fairyInner.g = sTatlColorList[type].inner.g; - targetCtx->fairyInner.b = sTatlColorList[type].inner.b; - targetCtx->fairyInner.a = sTatlColorList[type].inner.a; - targetCtx->fairyOuter.r = sTatlColorList[type].outer.r; - targetCtx->fairyOuter.g = sTatlColorList[type].outer.g; - targetCtx->fairyOuter.b = sTatlColorList[type].outer.b; - targetCtx->fairyOuter.a = sTatlColorList[type].outer.a; + targetCtx->fairyInnerColor.r = sTatlColorList[type].inner.r; + targetCtx->fairyInnerColor.g = sTatlColorList[type].inner.g; + targetCtx->fairyInnerColor.b = sTatlColorList[type].inner.b; + targetCtx->fairyInnerColor.a = sTatlColorList[type].inner.a; + targetCtx->fairyOuterColor.r = sTatlColorList[type].outer.r; + targetCtx->fairyOuterColor.g = sTatlColorList[type].outer.g; + targetCtx->fairyOuterColor.b = sTatlColorList[type].outer.b; + targetCtx->fairyOuterColor.a = sTatlColorList[type].outer.a; } -void Actor_TargetContextInit(TargetContext* targetCtx, Actor* actor, PlayState* play) { +void Target_Init(TargetContext* targetCtx, Actor* actor, PlayState* play) { targetCtx->bgmEnemy = NULL; - targetCtx->unk8C = NULL; - targetCtx->targetedActor = NULL; - targetCtx->arrowPointedActor = NULL; - targetCtx->unk4B = 0; - targetCtx->unk4C = 0; - targetCtx->unk40 = 0.0f; - Target_SetColors(targetCtx, actor, actor->category, play); - func_800B4F78(targetCtx, actor->category, play); + targetCtx->forcedTargetActor = NULL; + targetCtx->lockOnActor = NULL; + targetCtx->fairyActor = NULL; + targetCtx->rotZTick = 0; + targetCtx->lockOnIndex = 0; + targetCtx->fairyMoveProgressFactor = 0.0f; + Target_SetFairyState(targetCtx, actor, actor->category, play); + Target_InitLockOn(targetCtx, actor->category, play); } -void Actor_DrawZTarget(TargetContext* targetCtx, PlayState* play) { +void Target_Draw(TargetContext* targetCtx, PlayState* play) { Player* player = GET_PLAYER(play); + Actor* actor; - if (!(player->stateFlags1 & (PLAYER_STATE1_2 | PLAYER_STATE1_40 | PLAYER_STATE1_80 | PLAYER_STATE1_200 | - PLAYER_STATE1_400 | PLAYER_STATE1_10000000 | PLAYER_STATE1_20000000))) { - Actor* actor = targetCtx->targetedActor; + if (player->stateFlags1 & (PLAYER_STATE1_2 | PLAYER_STATE1_40 | PLAYER_STATE1_80 | PLAYER_STATE1_200 | + PLAYER_STATE1_400 | PLAYER_STATE1_10000000 | PLAYER_STATE1_20000000)) { + return; + } - OPEN_DISPS(play->state.gfxCtx); + actor = targetCtx->lockOnActor; - if (targetCtx->unk48 != 0) { - TargetContextEntry* entry; - s16 alpha = 255; - f32 var1 = 1.0f; - Vec3f projectedPos; - s32 spB8; - f32 invW; - s32 spB0; - s32 spAC; - f32 var2; - s32 i; - - if (targetCtx->unk4B != 0) { - spB8 = 1; - } else { - spB8 = 3; - } + OPEN_DISPS(play->state.gfxCtx); - if (actor != NULL) { - Math_Vec3f_Copy(&targetCtx->targetCenterPos, &actor->focus.pos); - var1 = (500.0f - targetCtx->unk44) / 420.0f; - } else { - targetCtx->unk48 -= 120; - if (targetCtx->unk48 < 0) { - targetCtx->unk48 = 0; - } - alpha = targetCtx->unk48; + if (targetCtx->lockOnAlpha != 0) { + LockOnTriangleSet* entry; + s16 alpha = 255; + f32 projectdPosScale = 1.0f; + Vec3f projectedPos; + s32 totalEntries; + f32 invW; + s32 i; + s32 index; + f32 lockOnScaleX; + + if (targetCtx->rotZTick != 0) { + totalEntries = 1; + } else { + // Use multiple entries for the movement effect when the triangles are getting closer to the actor from the + // margin of the screen + totalEntries = ARRAY_COUNT(targetCtx->lockOnTriangleSets); + } + + if (actor != NULL) { + Math_Vec3f_Copy(&targetCtx->lockOnPos, &actor->focus.pos); + projectdPosScale = (500.0f - targetCtx->lockOnRadius) / 420.0f; + } else { + targetCtx->lockOnAlpha -= 120; + if (targetCtx->lockOnAlpha < 0) { + targetCtx->lockOnAlpha = 0; } + alpha = targetCtx->lockOnAlpha; + } - Actor_GetProjectedPos(play, &targetCtx->targetCenterPos, &projectedPos, &invW); + Actor_GetProjectedPos(play, &targetCtx->lockOnPos, &projectedPos, &invW); - projectedPos.x = ((SCREEN_WIDTH / 2) * (projectedPos.x * invW)) * var1; - projectedPos.x = CLAMP(projectedPos.x, -SCREEN_WIDTH, SCREEN_WIDTH); + projectedPos.x = ((SCREEN_WIDTH / 2) * (projectedPos.x * invW)) * projectdPosScale; + projectedPos.x = CLAMP(projectedPos.x, -SCREEN_WIDTH, SCREEN_WIDTH); - projectedPos.y = ((SCREEN_HEIGHT / 2) * (projectedPos.y * invW)) * var1; - projectedPos.y = CLAMP(projectedPos.y, -SCREEN_HEIGHT, SCREEN_HEIGHT); + projectedPos.y = ((SCREEN_HEIGHT / 2) * (projectedPos.y * invW)) * projectdPosScale; + projectedPos.y = CLAMP(projectedPos.y, -SCREEN_HEIGHT, SCREEN_HEIGHT); - projectedPos.z = projectedPos.z * var1; + projectedPos.z *= projectdPosScale; - targetCtx->unk4C--; - if (targetCtx->unk4C < 0) { - targetCtx->unk4C = 2; - } + targetCtx->lockOnIndex--; + if (targetCtx->lockOnIndex < 0) { + targetCtx->lockOnIndex = ARRAY_COUNT(targetCtx->lockOnTriangleSets) - 1; + } - Target_SetPos(targetCtx, targetCtx->unk4C, projectedPos.x, projectedPos.y, projectedPos.z); + Target_SetLockOnPos(targetCtx, targetCtx->lockOnIndex, projectedPos.x, projectedPos.y, projectedPos.z); - if ((!(player->stateFlags1 & PLAYER_STATE1_40)) || (actor != player->targetedActor)) { - OVERLAY_DISP = Gfx_SetupDL(OVERLAY_DISP, SETUPDL_57); + if (!(player->stateFlags1 & PLAYER_STATE1_40) || (actor != player->lockOnActor)) { + OVERLAY_DISP = Gfx_SetupDL(OVERLAY_DISP, SETUPDL_57); - for (spB0 = 0, spAC = targetCtx->unk4C; spB0 < spB8; spB0++, spAC = (spAC + 1) % 3) { - entry = &targetCtx->unk50[spAC]; + for (i = 0, index = targetCtx->lockOnIndex; i < totalEntries; + i++, index = (index + 1) % ARRAY_COUNT(targetCtx->lockOnTriangleSets)) { + entry = &targetCtx->lockOnTriangleSets[index]; - if (entry->unkC < 500.0f) { - if (entry->unkC <= 120.0f) { - var2 = 0.15f; - } else { - var2 = ((entry->unkC - 120.0f) * 0.001f) + 0.15f; - } + if (entry->radius < 500.0f) { + s32 triangleIndex; - Matrix_Translate(entry->pos.x, entry->pos.y, 0.0f, MTXMODE_NEW); - Matrix_Scale(var2, 0.15f, 1.0f, MTXMODE_APPLY); + if (entry->radius <= 120.0f) { + lockOnScaleX = 0.15f; + } else { + lockOnScaleX = ((entry->radius - 120.0f) * 0.001f) + 0.15f; + } - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, entry->color.r, entry->color.g, entry->color.b, - (u8)alpha); + Matrix_Translate(entry->pos.x, entry->pos.y, 0.0f, MTXMODE_NEW); + Matrix_Scale(lockOnScaleX, 0.15f, 1.0f, MTXMODE_APPLY); - Matrix_RotateZS((targetCtx->unk4B * 512), MTXMODE_APPLY); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, entry->color.r, entry->color.g, entry->color.b, (u8)alpha); - for (i = 0; i < 4; i++) { - Matrix_RotateZS(0x4000, MTXMODE_APPLY); - Matrix_Push(); - Matrix_Translate(entry->unkC, entry->unkC, 0.0f, MTXMODE_APPLY); - gSPMatrix(OVERLAY_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_MODELVIEW | G_MTX_LOAD); - gSPDisplayList(OVERLAY_DISP++, gZTargetLockOnTriangleDL); - Matrix_Pop(); - } - } + Matrix_RotateZS(targetCtx->rotZTick * 0x200, MTXMODE_APPLY); - alpha -= 255 / 3; - if (alpha < 0) { - alpha = 0; + // Draw the 4 lock-on triangles + for (triangleIndex = 0; triangleIndex < 4; triangleIndex++) { + Matrix_RotateZS(0x10000 / 4, MTXMODE_APPLY); + Matrix_Push(); + Matrix_Translate(entry->radius, entry->radius, 0.0f, MTXMODE_APPLY); + gSPMatrix(OVERLAY_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_MODELVIEW | G_MTX_LOAD); + gSPDisplayList(OVERLAY_DISP++, gZTargetLockOnTriangleDL); + Matrix_Pop(); } } + + alpha -= 255 / ARRAY_COUNT(targetCtx->lockOnTriangleSets); + if (alpha < 0) { + alpha = 0; + } } } + } - actor = targetCtx->unk_94; - if ((actor != NULL) && !(actor->flags & ACTOR_FLAG_CANT_LOCK_ON)) { - TatlColor* color = &sTatlColorList[actor->category]; - - POLY_XLU_DISP = Gfx_SetupDL(POLY_XLU_DISP, SETUPDL_7); + actor = targetCtx->arrowPointedActor; + if ((actor != NULL) && !(actor->flags & ACTOR_FLAG_CANT_LOCK_ON)) { + TatlColor* color = &sTatlColorList[actor->category]; - Matrix_Translate(actor->focus.pos.x, - actor->focus.pos.y + (actor->targetArrowOffset * actor->scale.y) + 17.0f, - actor->focus.pos.z, MTXMODE_NEW); - Matrix_RotateYS((play->gameplayFrames * 3000), MTXMODE_APPLY); - Matrix_Scale((iREG(27) + 35) / 1000.0f, (iREG(28) + 60) / 1000.0f, (iREG(29) + 50) / 1000.0f, - MTXMODE_APPLY); + POLY_XLU_DISP = Gfx_SetupDL(POLY_XLU_DISP, SETUPDL_7); - gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, color->inner.r, color->inner.g, color->inner.b, 255); - gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_MODELVIEW | G_MTX_LOAD); - gSPDisplayList(POLY_XLU_DISP++, gZTargetArrowDL); - } + Matrix_Translate(actor->focus.pos.x, actor->focus.pos.y + (actor->targetArrowOffset * actor->scale.y) + 17.0f, + actor->focus.pos.z, MTXMODE_NEW); + Matrix_RotateYS(play->gameplayFrames * 0xBB8, MTXMODE_APPLY); + Matrix_Scale((iREG(27) + 35) / 1000.0f, (iREG(28) + 60) / 1000.0f, (iREG(29) + 50) / 1000.0f, MTXMODE_APPLY); - CLOSE_DISPS(play->state.gfxCtx); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, color->inner.r, color->inner.g, color->inner.b, 255); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_MODELVIEW | G_MTX_LOAD); + gSPDisplayList(POLY_XLU_DISP++, gZTargetArrowDL); } + + CLOSE_DISPS(play->state.gfxCtx); } // OoT: func_8002C7BC -void func_800B5814(TargetContext* targetCtx, Player* player, Actor* actor, GameState* gameState) { - PlayState* play = (PlayState*)gameState; - Actor* sp68 = NULL; +void Target_Update(TargetContext* targetCtx, Player* player, Actor* lockOnActor, PlayState* play) { + s32 pad; + Actor* actor = NULL; s32 category; Vec3f projectedPos; f32 invW; - if ((player->targetedActor != NULL) && (player->unk_AE3[player->unk_ADE] == 2)) { - targetCtx->unk_94 = NULL; + // If currently not locked on to an actor and not pressing down on the analog stick then try to find a targetable + // actor + if ((player->lockOnActor != NULL) && (player->unk_AE3[player->unk_ADE] == 2)) { + targetCtx->arrowPointedActor = NULL; } else { - func_800BB8EC(gameState, &play->actorCtx, &sp68, &D_801ED920, player); - targetCtx->unk_94 = sp68; + Target_GetTargetActor(play, &play->actorCtx, &actor, &D_801ED920, player); + targetCtx->arrowPointedActor = actor; } - if (targetCtx->unk8C != NULL) { - sp68 = targetCtx->unk8C; - targetCtx->unk8C = NULL; - } else if (actor != NULL) { - sp68 = actor; + if (targetCtx->forcedTargetActor != NULL) { + actor = targetCtx->forcedTargetActor; + targetCtx->forcedTargetActor = NULL; + } else if (lockOnActor != NULL) { + actor = lockOnActor; } - if (sp68 != NULL) { - category = sp68->category; + if (actor != NULL) { + category = actor->category; } else { category = player->actor.category; } - if ((sp68 != targetCtx->arrowPointedActor) || (category != targetCtx->unk4A)) { - targetCtx->arrowPointedActor = sp68; - targetCtx->unk4A = category; - targetCtx->unk40 = 1.0f; + if ((actor != targetCtx->fairyActor) || (category != targetCtx->fairyActorCategory)) { + targetCtx->fairyActor = actor; + targetCtx->fairyActorCategory = category; + targetCtx->fairyMoveProgressFactor = 1.0f; } - if (sp68 == NULL) { - sp68 = &player->actor; + if (actor == NULL) { + actor = &player->actor; } - if (!Math_StepToF(&targetCtx->unk40, 0.0f, 0.25f)) { - f32 temp_f0; - f32 x; - f32 y; - f32 z; - - temp_f0 = 0.25f / targetCtx->unk40; - - x = sp68->focus.pos.x - targetCtx->unk0.x; - y = (sp68->focus.pos.y + (sp68->targetArrowOffset * sp68->scale.y)) - targetCtx->unk0.y; - z = sp68->focus.pos.z - targetCtx->unk0.z; + if (!Math_StepToF(&targetCtx->fairyMoveProgressFactor, 0.0f, 0.25f)) { + f32 fairyMoveScale = 0.25f / targetCtx->fairyMoveProgressFactor; + f32 x = actor->focus.pos.x - targetCtx->fairyPos.x; + f32 y = (actor->focus.pos.y + (actor->targetArrowOffset * actor->scale.y)) - targetCtx->fairyPos.y; + f32 z = actor->focus.pos.z - targetCtx->fairyPos.z; - targetCtx->unk0.x += x * temp_f0; - targetCtx->unk0.y += y * temp_f0; - targetCtx->unk0.z += z * temp_f0; + targetCtx->fairyPos.x += x * fairyMoveScale; + targetCtx->fairyPos.y += y * fairyMoveScale; + targetCtx->fairyPos.z += z * fairyMoveScale; } else { - Target_SetColors(targetCtx, sp68, category, play); + Target_SetFairyState(targetCtx, actor, category, play); } - if ((actor != NULL) && (targetCtx->unk4B == 0)) { - Actor_GetProjectedPos(play, &actor->focus.pos, &projectedPos, &invW); + if ((lockOnActor != NULL) && (targetCtx->rotZTick == 0)) { + Actor_GetProjectedPos(play, &lockOnActor->focus.pos, &projectedPos, &invW); if ((projectedPos.z <= 0.0f) || (fabsf(projectedPos.x * invW) >= 1.0f) || (fabsf(projectedPos.y * invW) >= 1.0f)) { - actor = NULL; + lockOnActor = NULL; } } - if (actor != NULL) { - if (actor != targetCtx->targetedActor) { + if (lockOnActor != NULL) { + if (lockOnActor != targetCtx->lockOnActor) { s32 sfxId; - func_800B4F78(targetCtx, actor->category, play); + // Lock On entries need to be re-initialized when changing the targeted actor + Target_InitLockOn(targetCtx, lockOnActor->category, play); - targetCtx->targetedActor = actor; + targetCtx->lockOnActor = lockOnActor; - if (actor->id == ACTOR_EN_BOOM) { - targetCtx->unk48 = 0; + if (lockOnActor->id == ACTOR_EN_BOOM) { + // Avoid drawing the lock on triangles on a zora boomerang + targetCtx->lockOnAlpha = 0; } - sfxId = - CHECK_FLAG_ALL(actor->flags, ACTOR_FLAG_4 | ACTOR_FLAG_1) ? NA_SE_SY_LOCK_ON : NA_SE_SY_LOCK_ON_HUMAN; + sfxId = CHECK_FLAG_ALL(lockOnActor->flags, ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_UNFRIENDLY) + ? NA_SE_SY_LOCK_ON + : NA_SE_SY_LOCK_ON_HUMAN; Audio_PlaySfx(sfxId); } - targetCtx->targetCenterPos.x = actor->world.pos.x; - targetCtx->targetCenterPos.y = actor->world.pos.y - (actor->shape.yOffset * actor->scale.y); - targetCtx->targetCenterPos.z = actor->world.pos.z; + targetCtx->lockOnPos.x = lockOnActor->world.pos.x; + targetCtx->lockOnPos.y = lockOnActor->world.pos.y - (lockOnActor->shape.yOffset * lockOnActor->scale.y); + targetCtx->lockOnPos.z = lockOnActor->world.pos.z; - if (targetCtx->unk4B == 0) { - f32 temp_f0_2; - f32 clampedFloat; + if (targetCtx->rotZTick == 0) { + f32 lockOnStep = (500.0f - targetCtx->lockOnRadius) * 3.0f; - temp_f0_2 = (500.0f - targetCtx->unk44) * 3.0f; - clampedFloat = CLAMP(temp_f0_2, 30.0f, 100.0f); + lockOnStep = CLAMP(lockOnStep, 30.0f, 100.0f); - if (Math_StepToF(&targetCtx->unk44, 80.0f, clampedFloat)) { - targetCtx->unk4B++; + if (Math_StepToF(&targetCtx->lockOnRadius, 80.0f, lockOnStep)) { + targetCtx->rotZTick++; } } else { - targetCtx->unk4B = (targetCtx->unk4B + 3) | 0x80; - targetCtx->unk44 = 120.0f; + // 0x80 is or'd to avoid getting this value be set to zero + // This rotation value gets multiplied by 0x200, which multiplied by 0x80 gives a full turn (0x10000) + targetCtx->rotZTick = (targetCtx->rotZTick + 3) | 0x80; + targetCtx->lockOnRadius = 120.0f; } } else { - targetCtx->targetedActor = NULL; - Math_StepToF(&targetCtx->unk44, 500.0f, 80.0f); + targetCtx->lockOnActor = NULL; + Math_StepToF(&targetCtx->lockOnRadius, 500.0f, 80.0f); } } @@ -1048,7 +1065,7 @@ void* Actor_FindSharedMemoryEntry(PlayState* play, s16 id) { void Actor_Kill(Actor* actor) { actor->draw = NULL; actor->update = NULL; - actor->flags &= ~ACTOR_FLAG_1; + actor->flags &= ~ACTOR_FLAG_TARGETABLE; } void Actor_SetWorldToHome(Actor* actor) { @@ -1089,7 +1106,7 @@ void Actor_Init(Actor* actor, PlayState* play) { Actor_SetFocus(actor, 0.0f); Math_Vec3f_Copy(&actor->prevPos, &actor->world.pos); Actor_SetScale(actor, 0.01f); - actor->targetMode = 3; + actor->targetMode = TARGET_MODE_3; actor->terminalVelocity = -20.0f; actor->xyzDistToPlayerSq = FLT_MAX; @@ -1702,18 +1719,18 @@ void Actor_UpdateBgCheckInfo(PlayState* play, Actor* actor, f32 wallCheckHeight, } } -Gfx* Hilite_Draw(Vec3f* object, Vec3f* eye, Vec3f* lightDir, GraphicsContext* gfxCtx, Gfx* dl, Hilite** hilite) { +Gfx* Hilite_Draw(Vec3f* object, Vec3f* eye, Vec3f* lightDir, GraphicsContext* gfxCtx, Gfx* dl, Hilite** hiliteP) { LookAt* lookAt = GRAPH_ALLOC(gfxCtx, sizeof(LookAt)); f32 correctedEyeX = (eye->x == object->x) && (eye->z == object->z) ? eye->x + 0.001f : eye->x; - *hilite = GRAPH_ALLOC(gfxCtx, sizeof(Hilite)); + *hiliteP = GRAPH_ALLOC(gfxCtx, sizeof(Hilite)); - guLookAtHilite(&D_801ED8E0, lookAt, *hilite, correctedEyeX, eye->y, eye->z, object->x, object->y, object->z, 0.0f, - 1.0f, 0.0f, lightDir->x, lightDir->y, lightDir->z, lightDir->x, lightDir->y, lightDir->z, 0x10, + guLookAtHilite(&sActorHiliteMtx, lookAt, *hiliteP, correctedEyeX, eye->y, eye->z, object->x, object->y, object->z, + 0.0f, 1.0f, 0.0f, lightDir->x, lightDir->y, lightDir->z, lightDir->x, lightDir->y, lightDir->z, 0x10, 0x10); gSPLookAt(dl++, lookAt); - gDPSetHilite1Tile(dl++, 1, *hilite, 0x10, 0x10); + gDPSetHilite1Tile(dl++, 1, *hiliteP, 0x10, 0x10); return dl; } @@ -1803,56 +1820,86 @@ PosRot* Actor_GetWorldPosShapeRot(PosRot* dest, Actor* actor) { return dest; } -f32 func_800B82EC(Actor* actor, Player* player, s16 angle) { - f32 temp_f12; - s16 temp_v0 = BINANG_SUB(BINANG_SUB(actor->yawTowardsPlayer, 0x8000), angle); - s16 yaw = ABS_ALT(temp_v0); +/** + * Returns the squared xyz distance from the actor to Player. + * + * This distance will be adjusted smaller if Player is already targeting an actor. The more Player is facing the actor, + * the smaller the distance is adjusted. + */ +f32 Target_GetAdjustedDistSq(Actor* actor, Player* player, s16 playerShapeYaw) { + f32 adjDistSq; + s16 yawDiff; - if (player->targetedActor != NULL) { - if ((yaw > 0x4000) || ((actor->flags & ACTOR_FLAG_CANT_LOCK_ON))) { + // The yaw, with player as the origin, from where player is facing to where the actor is positioned + yawDiff = ABS_ALT(BINANG_SUB(BINANG_SUB(actor->yawTowardsPlayer, 0x8000), playerShapeYaw)); + + if (player->lockOnActor != NULL) { + if ((yawDiff > 0x4000) || (actor->flags & ACTOR_FLAG_CANT_LOCK_ON)) { return FLT_MAX; } - temp_f12 = actor->xyzDistToPlayerSq - ((actor->xyzDistToPlayerSq * 0.8f) * ((0x4000 - yaw) * (1.0f / 0x8000))); - return temp_f12; + // Linear scaling, yaw being 90 degree means it will return the original distance, 0 degree will adjust to 60% + // of the distance + adjDistSq = + actor->xyzDistToPlayerSq - ((actor->xyzDistToPlayerSq * 0.8f) * ((0x4000 - yawDiff) * (1.0f / 0x8000))); + return adjDistSq; } - if (yaw >= 0x2AAB) { + if (yawDiff > (0x10000 / 6)) { return FLT_MAX; } return actor->xyzDistToPlayerSq; } #define TARGET_RANGE(range, leash) \ - { SQ(range), (f32)range / leash } - -TargetRangeParams gTargetRanges[] = { - TARGET_RANGE(70, 140), TARGET_RANGE(170, 255), TARGET_RANGE(280, 5600), TARGET_RANGE(350, 525), - TARGET_RANGE(700, 1050), TARGET_RANGE(1000, 1500), TARGET_RANGE(100, 105.36842), TARGET_RANGE(140, 163.33333), - TARGET_RANGE(240, 576), TARGET_RANGE(280, 280000), TARGET_RANGE(2500, 3750), + { SQ(range), (f32)(range) / (leash) } + +TargetRangeParams gTargetRanges[TARGET_MODE_MAX] = { + TARGET_RANGE(70, 140), // TARGET_MODE_0 + TARGET_RANGE(170, 255), // TARGET_MODE_1 + TARGET_RANGE(280, 5600), // TARGET_MODE_2 + TARGET_RANGE(350, 525), // TARGET_MODE_3 + TARGET_RANGE(700, 1050), // TARGET_MODE_4 + TARGET_RANGE(1000, 1500), // TARGET_MODE_5 + TARGET_RANGE(100, 105.36842), // TARGET_MODE_6 + TARGET_RANGE(140, 163.33333), // TARGET_MODE_7 + TARGET_RANGE(240, 576), // TARGET_MODE_8 + TARGET_RANGE(280, 280000), // TARGET_MODE_9 + TARGET_RANGE(2500, 3750), // TARGET_MODE_10 }; -s32 func_800B83BC(Actor* actor, f32 arg1) { - return arg1 < gTargetRanges[actor->targetMode].rangeSq; +/** + * Checks if an actor at distance `distSq` is inside the range specified by its targetMode + */ +s32 Target_IsActorInRange(Actor* actor, f32 distSq) { + return distSq < gTargetRanges[actor->targetMode].rangeSq; } -s32 func_800B83F8(Actor* actor, Player* player, s32 flag) { - if ((actor->update == NULL) || !(actor->flags & ACTOR_FLAG_1) || (actor->flags & ACTOR_FLAG_CANT_LOCK_ON)) { +/** + * Returns true if the actor is outside the leash distance to player. + * + * Passing true to ignoreLeash avoids the distance and yaw checks, and considers the actor inside the leash distance. + */ +s32 Target_OutsideLeashRange(Actor* actor, Player* player, s32 ignoreLeash) { + if ((actor->update == NULL) || !(actor->flags & ACTOR_FLAG_TARGETABLE) || + (actor->flags & ACTOR_FLAG_CANT_LOCK_ON)) { return true; } - if (!flag) { - s16 yaw = BINANG_SUB(actor->yawTowardsPlayer, 0x8000) - player->actor.shape.rot.y; - s16 phi_v1 = ABS_ALT(yaw); - f32 dist; + if (!ignoreLeash) { + s16 yawDiff; + f32 distSq; - if ((player->targetedActor == NULL) && (phi_v1 >= 0x2AAB)) { - dist = FLT_MAX; + // The yaw, with player as the origin, from where player is facing to where the actor is positioned + yawDiff = ABS_ALT(BINANG_SUB(BINANG_SUB(actor->yawTowardsPlayer, 0x8000), player->actor.shape.rot.y)); + + if ((player->lockOnActor == NULL) && (yawDiff > (0x10000 / 6))) { + distSq = FLT_MAX; } else { - dist = actor->xyzDistToPlayerSq; + distSq = actor->xyzDistToPlayerSq; } - return !func_800B83BC(actor, gTargetRanges[actor->targetMode].leashScale * dist); + return !Target_IsActorInRange(actor, gTargetRanges[actor->targetMode].leashScale * distSq); } return false; @@ -1911,7 +1958,7 @@ s32 Actor_OfferTalkExchange(Actor* actor, PlayState* play, f32 xzRange, f32 yRan if ((player->actor.flags & ACTOR_FLAG_TALK_REQUESTED) || ((exchangeItemAction > PLAYER_IA_NONE) && Player_InCsMode(play)) || - (!actor->isTargeted && + (!actor->isLockedOn && ((fabsf(actor->playerHeightRel) > fabsf(yRange)) || (actor->xzDistToPlayer > player->talkActorDistance) || (xzRange < actor->xzDistToPlayer)))) { return false; @@ -1971,7 +2018,7 @@ s32 Actor_ChangeFocus(Actor* actor1, PlayState* play, Actor* actor2) { if ((player->actor.flags & ACTOR_FLAG_TALK_REQUESTED) && (talkActor != NULL)) { player->talkActor = actor2; - player->targetedActor = actor2; + player->lockOnActor = actor2; return true; } @@ -2372,7 +2419,7 @@ void Actor_InitContext(PlayState* play, ActorContext* actorCtx, ActorEntry* acto actorCtx->absoluteSpace = NULL; Actor_SpawnEntry(actorCtx, actorEntry, play); - Actor_TargetContextInit(&actorCtx->targetContext, actorCtx->actorLists[ACTORCAT_PLAYER].first, play); + Target_Init(&actorCtx->targetCtx, actorCtx->actorLists[ACTORCAT_PLAYER].first, play); Actor_InitHalfDaysBit(actorCtx); Fault_AddClient(&sActorFaultClient, (void*)Actor_PrintLists, actorCtx, NULL); Actor_SpawnHorse(play, (Player*)actorCtx->actorLists[ACTORCAT_PLAYER].first); @@ -2473,13 +2520,13 @@ Actor* Actor_UpdateActor(UpdateActor_Params* params) { actor->flags &= ~ACTOR_FLAG_1000000; if ((DECR(actor->freezeTimer) == 0) && (actor->flags & params->unk_18)) { - if (actor == params->player->targetedActor) { - actor->isTargeted = true; + if (actor == params->player->lockOnActor) { + actor->isLockedOn = true; } else { - actor->isTargeted = false; + actor->isLockedOn = false; } - if ((actor->targetPriority != 0) && (params->player->targetedActor == NULL)) { + if ((actor->targetPriority != 0) && (params->player->lockOnActor == NULL)) { actor->targetPriority = 0; } @@ -2604,22 +2651,22 @@ void Actor_UpdateAll(PlayState* play, ActorContext* actorCtx) { } } - actor = player->targetedActor; + actor = player->lockOnActor; if ((actor != NULL) && (actor->update == NULL)) { actor = NULL; - func_80123DA4(player); + Player_Untarget(player); } if ((actor == NULL) || (player->unk_738 < 5)) { actor = NULL; - if (actorCtx->targetContext.unk4B != 0) { - actorCtx->targetContext.unk4B = 0; + if (actorCtx->targetCtx.rotZTick != 0) { + actorCtx->targetCtx.rotZTick = 0; Audio_PlaySfx(NA_SE_SY_LOCK_OFF); } } if (!(player->stateFlags1 & PLAYER_STATE1_2)) { - func_800B5814(&actorCtx->targetContext, player, actor, &play->state); + Target_Update(&actorCtx->targetCtx, player, actor, play); } TitleCard_Update(&play->state, &actorCtx->titleCtxt); @@ -3396,21 +3443,21 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) { Actor* newHead; ActorOverlay* overlayEntry = actor->overlayEntry; - if ((player != NULL) && (actor == player->targetedActor)) { - func_80123DA4(player); + if ((player != NULL) && (actor == player->lockOnActor)) { + Player_Untarget(player); Camera_ChangeMode(Play_GetCamera(play, Play_GetActiveCamId(play)), CAM_MODE_NORMAL); } - if (actor == actorCtx->targetContext.arrowPointedActor) { - actorCtx->targetContext.arrowPointedActor = NULL; + if (actor == actorCtx->targetCtx.fairyActor) { + actorCtx->targetCtx.fairyActor = NULL; } - if (actor == actorCtx->targetContext.unk8C) { - actorCtx->targetContext.unk8C = NULL; + if (actor == actorCtx->targetCtx.forcedTargetActor) { + actorCtx->targetCtx.forcedTargetActor = NULL; } - if (actor == actorCtx->targetContext.bgmEnemy) { - actorCtx->targetContext.bgmEnemy = NULL; + if (actor == actorCtx->targetCtx.bgmEnemy) { + actorCtx->targetCtx.bgmEnemy = NULL; } AudioSfx_StopByPos(&actor->projectedPos); @@ -3427,7 +3474,7 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) { return newHead; } -s32 func_800BB59C(PlayState* play, Actor* actor) { +s32 Target_InTargetableScreenRegion(PlayState* play, Actor* actor) { s16 x; s16 y; @@ -3436,110 +3483,156 @@ s32 func_800BB59C(PlayState* play, Actor* actor) { return (x > -20) && (x < gScreenWidth + 20) && (y > -160) && (y < gScreenHeight + 160); } -void func_800BB604(GameState* gameState, ActorContext* actorCtx, Player* player, s32 actorCategory) { - PlayState* play = (PlayState*)gameState; - f32 temp_f0_2; - Actor* targetedActor; - Actor* actor; - s32 phi_s2; - CollisionPoly* sp80; - s32 sp7C; - Vec3f sp70; +/** + * Search for targetable actors of the `actorCategory` category. + * + * Looks for the actor of said category with higher targetPriority and the one that is nearest to player. This actor + * must be within the range (relative to player) speicified by its targetMode. + * + * The actor must be on-screen + * + * The highest priority actor is stored in `sTargetablePrioritizedActor`, while the nearest actor is stored in + * `sTargetableNearestActor`. The higher priority / smaller distance of those actors are stored in + * `sTargetablePrioritizedPriority` and `sTargetableNearestActorDistSq`. + * + * There is not much info to infer anything about ACTOR_FLAG_40000000, D_801ED8C4/D_801ED8C0, D_801ED8D8/D_801ED8D0. + * All appear unused in any meaningful way. + * + * For an actor to be taken in consideration by this function it needs: + * - Non-NULL update function (maybe obvious?) + * - Not be Player itself. + * - It must be targetable or ACTOR_FLAG_40000000 + * - Not be the already targeted actor, unless it has the ACTOR_FLAG_80000 flag + * - Be withing the range specified by its targetMode. + * - It must be on-screen (within a margin) + * - Must not be blocked by a surface (?) + * + * This function also checks for the nearest enemy actor, which allows determining if enemy background music should be + * played. This actor is stored in `targetContext.bgmEnemy` and its distance is stored in `sBgmEnemyDistSq` + * + * This function is expected to be called with almost every actor category in each cycle. On a new cycle its global + * variables must be reset by the caller, otherwise the information of the previous cycle will be retained on this one. + */ +void Target_FindTargetableActorForCategory(PlayState* play, ActorContext* actorCtx, Player* player, + ActorType actorCategory) { + f32 distSq; + Actor* actor = actorCtx->actorLists[actorCategory].first; + Actor* lockOnActor = player->lockOnActor; + s32 isNearestTargetableActor; s32 phi_s2_2; - actor = actorCtx->actorLists[actorCategory].first; - targetedActor = player->targetedActor; - while (actor != NULL) { - if ((actor->update != NULL) && ((Player*)actor != player)) { - if (actor->flags & (ACTOR_FLAG_40000000 | ACTOR_FLAG_1)) { - if ((actorCategory == ACTORCAT_ENEMY) && CHECK_FLAG_ALL(actor->flags, ACTOR_FLAG_4 | ACTOR_FLAG_1)) { - if ((actor->xyzDistToPlayerSq < SQ(500.0f)) && (actor->xyzDistToPlayerSq < sBgmEnemyDistSq)) { - actorCtx->targetContext.bgmEnemy = actor; - sBgmEnemyDistSq = actor->xyzDistToPlayerSq; - } - } + for (; actor != NULL; actor = actor->next) { + if ((actor->update == NULL) || ((Player*)actor == player)) { + continue; + } - if ((actor != targetedActor) || (actor->flags & ACTOR_FLAG_80000)) { - temp_f0_2 = func_800B82EC(actor, player, D_801ED8DC); - phi_s2_2 = (actor->flags & ACTOR_FLAG_1) != 0; - if (phi_s2_2) { - phi_s2_2 = temp_f0_2 < D_801ED8C8; - } - phi_s2 = phi_s2_2; - phi_s2_2 = (actor->flags & ACTOR_FLAG_40000000) != 0; - if (phi_s2_2) { - phi_s2_2 = temp_f0_2 < D_801ED8D0; - } + // Actor must be at least either targetable or ACTOR_FLAG_40000000 + if (!(actor->flags & (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_40000000))) { + continue; + } - if (((phi_s2) || (phi_s2_2)) && (func_800B83BC(actor, temp_f0_2))) { - if (func_800BB59C(play, actor)) { - if (((!BgCheck_CameraLineTest1(&play->colCtx, &player->actor.focus.pos, &actor->focus.pos, - &sp70, &sp80, true, true, true, true, &sp7C)) || - (SurfaceType_IsIgnoredByProjectiles(&play->colCtx, sp80, sp7C)))) { - if (actor->targetPriority != 0) { - if ((phi_s2 != 0) && (actor->targetPriority < D_801ED8D4)) { - D_801ED8BC = actor; - D_801ED8D4 = actor->targetPriority; - } - if ((phi_s2_2 != 0) && (actor->targetPriority < D_801ED8D8)) { - D_801ED8C4 = actor; - D_801ED8D8 = actor->targetPriority; - } - } else { - if (phi_s2 != 0) { - D_801ED8B8 = actor; - D_801ED8C8 = temp_f0_2; - } - if (phi_s2_2 != 0) { - D_801ED8C0 = actor; - D_801ED8D0 = temp_f0_2; - } - } - } - } - } - } + // Determine the closest enemy actor to player within a range. Used for playing enemy background music. + if ((actorCategory == ACTORCAT_ENEMY) && + CHECK_FLAG_ALL(actor->flags, ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_UNFRIENDLY)) { + if ((actor->xyzDistToPlayerSq < SQ(500.0f)) && (actor->xyzDistToPlayerSq < sBgmEnemyDistSq)) { + actorCtx->targetCtx.bgmEnemy = actor; + sBgmEnemyDistSq = actor->xyzDistToPlayerSq; } } - actor = actor->next; + // If this actor is the currently targeted one, then ignore it unless it has the ACTOR_FLAG_80000 flag + if ((actor == lockOnActor) && !(actor->flags & ACTOR_FLAG_80000)) { + continue; + } + + distSq = Target_GetAdjustedDistSq(actor, player, sTargetPlayerRotY); + + isNearestTargetableActor = (actor->flags & ACTOR_FLAG_TARGETABLE) && (distSq < sTargetableNearestActorDistSq); + phi_s2_2 = (actor->flags & ACTOR_FLAG_40000000) && (distSq < D_801ED8D0); + + if (!isNearestTargetableActor && !phi_s2_2) { + continue; + } + + if (Target_IsActorInRange(actor, distSq) && Target_InTargetableScreenRegion(play, actor)) { + CollisionPoly* poly; + s32 bgId; + Vec3f posResult; + + if (BgCheck_CameraLineTest1(&play->colCtx, &player->actor.focus.pos, &actor->focus.pos, &posResult, &poly, + true, true, true, true, &bgId)) { + if (!SurfaceType_IsIgnoredByProjectiles(&play->colCtx, poly, bgId)) { + continue; + } + } + + if (actor->targetPriority != 0) { + if (isNearestTargetableActor && (actor->targetPriority < sTargetablePrioritizedPriority)) { + sTargetablePrioritizedActor = actor; + sTargetablePrioritizedPriority = actor->targetPriority; + } + if (phi_s2_2 && (actor->targetPriority < D_801ED8D8)) { + D_801ED8C4 = actor; + D_801ED8D8 = actor->targetPriority; + } + } else { + if (isNearestTargetableActor) { + sTargetableNearestActor = actor; + sTargetableNearestActorDistSq = distSq; + } + if (phi_s2_2) { + D_801ED8C0 = actor; + D_801ED8D0 = distSq; + } + } + } } } -u8 D_801AED8C[] = { +u8 sTargetableActorCategories[] = { ACTORCAT_BOSS, ACTORCAT_ENEMY, ACTORCAT_BG, ACTORCAT_EXPLOSIVES, ACTORCAT_NPC, ACTORCAT_ITEMACTION, ACTORCAT_CHEST, ACTORCAT_SWITCH, ACTORCAT_PROP, ACTORCAT_MISC, ACTORCAT_DOOR, ACTORCAT_SWITCH, }; -void func_800BB8EC(GameState* gameState, ActorContext* actorCtx, Actor** arg2, Actor** arg3, Player* player) { +/** + * Search for the nearest targetable actor. + * + * The specific criteria is specified in Target_FindTargetableActorForCategory. + * + * The actor found is stored in the targetableP parameter. It may be NULL if no actor that fulfills the criteria is + * found. + */ +void Target_GetTargetActor(PlayState* play, ActorContext* actorCtx, Actor** targetableP, Actor** arg3, Player* player) { u8* actorCategories; s32 i; - D_801ED8B8 = D_801ED8BC = D_801ED8C0 = D_801ED8C4 = NULL; - D_801ED8C8 = D_801ED8D0 = sBgmEnemyDistSq = FLT_MAX; - D_801ED8D4 = D_801ED8D8 = INT32_MAX; + sTargetableNearestActor = sTargetablePrioritizedActor = D_801ED8C0 = D_801ED8C4 = NULL; + sTargetableNearestActorDistSq = D_801ED8D0 = sBgmEnemyDistSq = FLT_MAX; + sTargetablePrioritizedPriority = D_801ED8D8 = INT32_MAX; - actorCtx->targetContext.bgmEnemy = NULL; - D_801ED8DC = player->actor.shape.rot.y; + actorCtx->targetCtx.bgmEnemy = NULL; + sTargetPlayerRotY = player->actor.shape.rot.y; - actorCategories = D_801AED8C; + actorCategories = sTargetableActorCategories; + // Try to search for a targetable actor that's a Boss, Enemy or Bg first for (i = 0; i < 3; i++) { - func_800BB604(gameState, actorCtx, player, *actorCategories); + Target_FindTargetableActorForCategory(play, actorCtx, player, *actorCategories); actorCategories++; } - if (D_801ED8B8 == NULL) { - for (; i < ARRAY_COUNT(D_801AED8C); i++) { - func_800BB604(gameState, actorCtx, player, *actorCategories); + // If no actor in the above categories was found then try to search for one in every other category + if (sTargetableNearestActor == NULL) { + for (; i < ARRAY_COUNT(sTargetableActorCategories); i++) { + Target_FindTargetableActorForCategory(play, actorCtx, player, *actorCategories); actorCategories++; } } - if (D_801ED8B8 == NULL) { - *arg2 = D_801ED8BC; + if (sTargetableNearestActor == NULL) { + *targetableP = sTargetablePrioritizedActor; } else { - *arg2 = D_801ED8B8; + *targetableP = sTargetableNearestActor; } if (D_801ED8C0 == NULL) { @@ -3810,7 +3903,7 @@ s16 Actor_TestFloorInDirection(Actor* actor, PlayState* play, f32 distance, s16 s32 Actor_IsTargeted(PlayState* play, Actor* actor) { Player* player = GET_PLAYER(play); - if ((player->stateFlags3 & PLAYER_STATE3_80000000) && actor->isTargeted) { + if ((player->stateFlags3 & PLAYER_STATE3_80000000) && actor->isLockedOn) { return true; } @@ -3823,7 +3916,7 @@ s32 Actor_IsTargeted(PlayState* play, Actor* actor) { s32 Actor_OtherIsTargeted(PlayState* play, Actor* actor) { Player* player = GET_PLAYER(play); - if ((player->stateFlags3 & PLAYER_STATE3_80000000) && !actor->isTargeted) { + if ((player->stateFlags3 & PLAYER_STATE3_80000000) && !actor->isLockedOn) { return true; } @@ -4481,10 +4574,10 @@ s16 func_800BDB6C(Actor* actor, PlayState* play, s16 arg2, f32 arg3) { } if (arg3 < phi_f2) { - actor->flags &= ~ACTOR_FLAG_1; + actor->flags &= ~ACTOR_FLAG_TARGETABLE; Math_SmoothStepToS(&arg2, 0, 6, 0x14, 1); } else { - actor->flags |= ACTOR_FLAG_1; + actor->flags |= ACTOR_FLAG_TARGETABLE; Math_SmoothStepToS(&arg2, 0xFF, 6, 0x14, 1); } |
