RIM-116 & Phalanx
Target acquisition
A world query rather than a hook on the projectile – because the projectile classes cannot be extended at all. Classification then has to separate a helicopter from its own bench seat.
Why a world query and not a hook
Projectile and ProjectileMoveComponent live in scripts/Game/generated/ and
cannot be extended with modded class – attempting it aborts the entire script module, not
just that class. Their proto external methods are still callable, though, so the velocity can be read
straight off a found projectile instead of being estimated from two samples.
modded class but open to calls. Anything that would have been an override becomes a query plus a call.void MyAD_Tracker_Scan()
{
m_aFound.Clear();
GetGame().GetWorld().QueryEntitiesBySphere(m_vOrigin, m_fRadius, OnCandidate, null, EQueryEntitiesFlags.DYNAMIC);
}
vector MyAD_Tracker_VelocityOf(IEntity ent)
{
ProjectileMoveComponent move = ProjectileMoveComponent.Cast(ent.FindComponent(ProjectileMoveComponent));
if (move)
return move.GetVelocity(); // callable even where modded class is not
Physics phys = ent.GetPhysics();
if (phys && phys.IsDynamic())
return phys.GetVelocity();
return vector.Zero;
}
An attachment is not an aircraft
A helicopter was tracked as four targets, and the mount shot at the bench seat. Seats and turrets satisfy “enterable and above ground”, so they classified as aircraft in their own right. The fix is one check at the top of classification – the same hierarchy test that fixes countermeasure detection on the chaff page.
MyAD_ETargetKind MyAD_Tracker_Classify(IEntity ent)
{
// an entity with a parent is part of something else: a seat, a turret, a loaded flare
if (ent.GetParent())
{
m_iRejectedAttachments++;
return MyAD_ETargetKind.NONE;
}
...
}
What gets engaged with what
| Kind | Engaged with | Notes |
|---|---|---|
| Aircraft | Missile salvo | a short delay before the first shot, longer at long range |
| Incoming ordnance (rockets, shells) | Gun burst | no delay – there is no time |
| Everything else | Not engaged | – |
Add a dead zone around the mount and a minimum altitude: targets inside either are tracked but not fired at. Both should be per-weapon values rather than shared constants, because a gun and a launcher disagree about what “too close” means.