canRetarget

What this is

canRetarget is a boolean weapon-definition field on WeaponDef (src/starship-survivors/data/weapons/_types.ts) that controls whether a homing projectile is allowed to acquire a new target after its locked target dies, freezes, or enters the dying state. It is read at fire time, stored per-bullet as _canRetarget, and consulted by the homing update loop in bullets.ts. The flag is independent of homing strength — a projectile can have very strong homing (homingStrength: 999) and still be set to canRetarget: false, in which case it tracks its initial target and fizzles when that target is gone.

The field defaults to true. The default is applied at the barrel-build step (canRetarget: def.canRetarget !== false) and again when the barrel is converted to a bullet (_canRetarget: barrel.canRetarget !== false), so any weapon that omits the field gets retargeting enabled.

FieldTypeDefaultStored on bullet as
canRetargetboolean | undefinedtrue_canRetarget

Which weapons set it

Every weapon that explicitly sets canRetarget: false is listed below. No weapon in the codebase sets it to true explicitly — true is always the default.

WeaponFileHoming strength (base)Notes
Riflesrc/starship-survivors/data/weapons/rifle.ts999Strong lock-on, one target per round; round fizzles if target dies mid-flight
Coilgunsrc/starship-survivors/data/weapons/coilgun.ts999Same single-target rail-slug pattern as Rifle
Mega Bullet (legendary)src/starship-survivors/data/weapons/legendaries.ts0Non-homing legendary; flag set so the projectile cannot grab a new target if its launch target dies
Trailblazer (legendary)src/starship-survivors/data/weapons/legendaries.ts0Non-homing legendary; same rationale as Mega Bullet

All other weapons (missile, etc.) inherit the default true.

Runtime behavior

The flag is consulted inside the homing update branch in bullets.ts only when the current locked target is no longer a valid chase target.

A target is considered “lost” if any of the following are true:

Condition on _homingTargetMeaning
!aliveEnemy was killed
_frozenForLagEnemy was frozen due to lag-handling
_dyingEnemy is in its death animation

When a target is lost:

_canRetarget valueOutcome
falseb.l = 0 — bullet lifetime is set to zero and the projectile fizzles on the same frame (the homing update returns immediately)
true (default)_homingTarget is cleared to null; the same frame’s seeking pass finds a new alive enemy via the spatial grid (radius 500) and locks onto it per targetMode

There is no separate retarget cooldown or cadence. Retargeting is purely event-driven by target death — it can happen at most once per frame, only when the current target becomes invalid. While the locked target remains alive, the projectile keeps chasing it regardless of whether closer or lower-HP enemies appear; canRetarget has no effect during normal pursuit.

The flag is also gated by the homing delay phase. During the initial delay (_homingAge < _homingDelaySec) the projectile is accelerating from launch speed toward cruise speed and the seeking branch is not yet running, so a target death in that window is not checked. Seeking — and therefore retargeting — only begins once the delay has elapsed.

Phase_canRetarget checked?
Delay phase (age < delay)No — seeking branch not reached
Seeking phase, target aliveNo — flag is only read when target is lost
Seeking phase, target lostYes — determines fizzle vs. re-lock

Interaction with target modes

canRetarget and targetMode are independent fields that combine at runtime.

FieldControls
targetModeHow a target is picked when a re-lock is needed (e.g. low_hp picks lowest-HP enemy, default picks nearest)
canRetargetWhether a re-lock is allowed at all when the current target is lost

If canRetarget is false, targetMode is effectively only consulted once — at launch, for the initial lock — because no second lock will ever occur. Subsequent target deaths fizzle the projectile.

If canRetarget is true (the default), every re-lock pass re-applies the targetMode logic. A weapon with targetMode: 'low_hp' and canRetarget: true will, on each target death, scan the spatial grid (radius 500), filter to alive non-frozen non-dying enemies, and pick the one with the lowest HP — ties broken by distance. A weapon with default targetMode does the same scan but picks by squared distance only.

The combination matters most for high-homingStrength weapons like Rifle and Coilgun: setting canRetarget: false is what stops two rifle rounds from collapsing onto the same surviving enemy when their original targets die — instead, each round dies with its target, preserving the spread of damage across the field that the initial multi-lock established.