Lock-on targeting
A held or toggled button that fixes the player's character and camera on one enemy or object, so movement circles and strafes around it.
On this page
Lock-on targeting fixes the character’s attention on one thing. In The Legend of Zelda: Ocarina of Time, Z locks onto the actor Navi hovers over1, the camera frames it2, and Link keeps facing it while the stick moves him3.
- Lock and faceThe Legend of Zelda: Ocarina of Time (1998). Z locks onto the actor Navi hovers over; the camera takes it as its view target and Link's model turns to face it.1,2,3,4
Games
| Game | Year | How | Note |
|---|---|---|---|
| The Legend of Zelda: Ocarina of Time | 1998 | Lock and face | Z locks onto the actor Navi hovers over; the camera takes it as its view target and Link's model turns to face it |
Every claim about this mechanic, by game (4)
References
- ^ abIn the N64 NTSC 1.0 code, pressing Z locks Link onto the actor Navi hovers over, unless that actor has lock-on disabled; with nothing to lock onto, Z starts "parallel" mode instead. Under the Hold setting the lock lasts while Z is held; under Switch, a flag keeps it after Z is let go.Codezeldaret/oot
How we know
3934 CHECK_BTN_ALL(sControlInput->press.button, BTN_Z)) { ⋮ 3938 nextLockOnActor = play->actorCtx.attention.naviHoverActor; ⋮ 3946 usingHoldTargeting = (gSaveContext.zTargetSetting != 0) || (this->actor.category != ACTORCAT_PLAYER); ⋮ 3950 if ((nextLockOnActor != NULL) && !(nextLockOnActor->flags & ACTOR_FLAG_LOCK_ON_DISABLED)) {
src/overlays/actors/ovl_player_actor/z_player.c lines 3932–3950 at 14759ab · upstream ↗ 3962 if (!usingHoldTargeting) { 3963 this->stateFlags2 |= PLAYER_STATE2_LOCK_ON_WITH_SWITCH; ⋮ 3966 this->focusActor = nextLockOnActor;
src/overlays/actors/ovl_player_actor/z_player.c lines 3962–3966 at 14759ab · upstream ↗ 3976 } else { 3977 // Lock-on was not started above. Set Parallel Mode. ⋮ 3979 Player_SetParallel(this);
src/overlays/actors/ovl_player_actor/z_player.c lines 3976–3979 at 14759ab · upstream ↗ 3898 } else if (zButtonHeld || (this->stateFlags2 & PLAYER_STATE2_LOCK_ON_WITH_SWITCH) || 3899 (this->autoLockOnActor != NULL)) {
src/overlays/actors/ovl_player_actor/z_player.c lines 3898–3899 at 14759ab · upstream ↗ 9typedef enum ZTargetSetting { ⋮ 12} ZTargetSetting;
include/save.h lines 9–12 at 14759ab · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^ abIn the N64 NTSC 1.0 code, unless an earlier branch applies (hookshot flight, pushing or pulling, and a few others), while Link has a focus actor his update makes that actor the main camera's view target and picks a mode for it: talk mode if Link's actor has the talk flag set, else, with the friendly-focus flag set, boomerang-follow mode if a boomerang is out or the friendly Z-target mode, and otherwise the unfriendly Z-target mode. In parallel mode it picks Z-aim mode when either of two checks the decomp leaves unnamed (func_8002DD78, func_808334B4) passes, else Z-wall-climb mode with an unnamed state flag (stateFlags1 bit 21) set, else the Z-parallel mode.Codezeldaret/ootrevised
How we know
11379 } else if ((focusActor = this->focusActor) != NULL) { 11380 if (ACTOR_FLAGS_CHECK_ALL(&this->actor, ACTOR_FLAG_TALK)) { 11381 camMode = CAM_MODE_TALK; 11382 } else if (this->stateFlags1 & PLAYER_STATE1_FRIENDLY_ACTOR_FOCUS) { 11383 if (this->stateFlags1 & PLAYER_STATE1_BOOMERANG_THROWN) { 11384 camMode = CAM_MODE_FOLLOW_BOOMERANG; 11385 } else { 11386 camMode = CAM_MODE_Z_TARGET_FRIENDLY; ⋮ 11388 } else { 11389 camMode = CAM_MODE_Z_TARGET_UNFRIENDLY; ⋮ 11391 Camera_SetViewParam(Play_GetCamera(play, CAM_ID_MAIN), CAM_VIEW_TARGET, focusActor);
src/overlays/actors/ovl_player_actor/z_player.c lines 11379–11391 at 14759ab · upstream ↗ 11403 } else if (this->stateFlags1 & (PLAYER_STATE1_PARALLEL | PLAYER_STATE1_LOCK_ON_FORCED_TO_RELEASE)) { 11404 if (func_8002DD78(this) || func_808334B4(this)) { 11405 camMode = CAM_MODE_Z_AIM; 11406 } else if (this->stateFlags1 & PLAYER_STATE1_21) { 11407 camMode = CAM_MODE_Z_WALL_CLIMB; 11408 } else { 11409 camMode = CAM_MODE_Z_PARALLEL;
src/overlays/actors/ovl_player_actor/z_player.c lines 11403–11409 at 14759ab · upstream ↗ 11431 Camera_RequestMode(Play_GetCamera(play, CAM_ID_MAIN), camMode);src/overlays/actors/ovl_player_actor/z_player.c line 11431 at 14759ab · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^ abIn the N64 NTSC 1.0 code, while Link has a lock-on target and the reticle counter (
reticleSpinCounter, which the decompilers' comment says counts up while a reticle is active) isn't 0, Link's model turns each update toward the locked-on actor's focus point, and in parallel mode toward the parallel angle; the direction he moves in is a separate yaw, which the stick sets relative to the camera. Two state flags the decomp leaves unnamed skip the turn, and the Z-target run and the roll set one of them.Codezeldaret/ootHow we know
3765 * Updates Shape Yaw (`shape.rot.y`). In other words, the Y rotation of Player's model. 3766 * This does not affect the direction Player will move in. ⋮ 3776 if (!(this->stateFlags2 & (PLAYER_STATE2_5 | PLAYER_STATE2_6))) { ⋮ 3780 ((play->actorCtx.attention.reticleSpinCounter != 0) || (this->actor.category != ACTORCAT_PLAYER))) { 3781 Math_ScaledStepToS(&this->actor.shape.rot.y, Math_Vec3f_Yaw(&this->actor.world.pos, &focusActor->focus.pos), 3782 4000); ⋮ 3784 !(this->stateFlags2 & (PLAYER_STATE2_5 | PLAYER_STATE2_6))) { 3785 Math_ScaledStepToS(&this->actor.shape.rot.y, this->parallelYaw, 4000);
src/overlays/actors/ovl_player_actor/z_player.c lines 3765–3785 at 14759ab · upstream ↗ 430 /* 0x4B */ u8 reticleSpinCounter; // Counts up when a reticle is active, used for the spinning animationinclude/actor.h line 430 at 14759ab · upstream ↗ 4146 } else { 4147 *outYawTarget += Camera_GetInputDirYaw(GET_ACTIVE_CAM(play)); 4148 return true;
src/overlays/actors/ovl_player_actor/z_player.c lines 4146–4148 at 14759ab · upstream ↗ 8832 this->stateFlags2 |= PLAYER_STATE2_5;src/overlays/actors/ovl_player_actor/z_player.c line 8832 at 14759ab · upstream ↗ 9695 this->stateFlags2 |= PLAYER_STATE2_5;src/overlays/actors/ovl_player_actor/z_player.c line 9695 at 14759ab · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^In the N64 NTSC 1.0 code, the jump slash started from the Z-targeting A press (stick forward or neutral, holding a melee weapon) sends Link forward along his facing at a speed of 5.0 with a vertical velocity of 5.0.Codezeldaret/oot
How we know
6403 func_8083BA90(play, this, PLAYER_MWA_JUMPSLASH_START, 5.0f, 5.0f);src/overlays/actors/ovl_player_actor/z_player.c line 6403 at 14759ab · upstream ↗ 6313void func_8083BA90(PlayState* play, Player* this, s32 arg2, f32 xzSpeed, f32 yVelocity) { ⋮ 6319 this->yaw = this->actor.shape.rot.y; 6320 this->speedXZ = xzSpeed; 6321 this->actor.velocity.y = yVelocity;
src/overlays/actors/ovl_player_actor/z_player.c lines 6313–6321 at 14759ab · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
Sources
Code
- zeldaret. 2026. “oot: a decompilation of The Legend of Zelda: Ocarina of Time (zeldaret/oot).” Commit 14759ab. zeldaret/oot @ 14759ab · licence, all uses