pilot: target commitment takes kills from 2 to 9; and the target pointer does not exist

The loop re-scored every contact every tick, so the nose chased whichever
fighter scored best that instant and aim error wandered 10-40 deg through a
pass. A missile lock is time-on-target, so constant switching is the one thing
guaranteed to prevent a kill. Commit to a contact until it dies, passes 6000,
sits >90 deg off the nose for 2.5 s, or 14 s elapse.

Same guns, same ballistics, same escort weighting, same missile cadence:
kills 0000 (five gun-only runs) -> 0002 (missiles) -> 0009 (commitment), with
101 missiles vs 98, and the largest hostile-population fall of any run
(134->97). Own hull untouched. The ACROPOLIS still ended at 76.6%, so this is
lethality, not the mission outcome.

Also records a negative result so it is not re-attempted: the selected target is
NOT a raw entity pointer. Three searches came up empty — a +-0x1400 window of
the player object, a full-RAM sweep of every entity-pointer word tapped through
each button (only thread-stack slots churn, which is frame noise), and a delta
tally over all 150 entities of the kind that found the definition pointer at
+0x130. The selection must be a handle, an index, or in a subsystem outside the
entity object.
This commit is contained in:
claude-re
2026-07-30 19:19:23 +00:00
parent 95ac545b2b
commit 9f41fe08e9
4 changed files with 251 additions and 1 deletions

View File

@@ -119,6 +119,16 @@ class Pilot:
HULL_CLEARANCE = 800.0 # clearance ON TOP of a capital ship's own radius
CLOSING_WEIGHT = 4.0 # s of closing-rate credit when ranking attackers
MY_RANGE_WEIGHT = 0.35 # how much our own distance discounts a target
# --- target commitment ---
# The loop re-scored every contact every tick, so the nose chased whichever
# fighter was momentarily best and the aim error wandered 10-40 deg through
# a pass. A missile lock is time-on-target (the OPTIONS screen calls it
# Padlock), so switching targets constantly is the one thing guaranteed to
# prevent a kill. Stay on the chosen contact until it dies, leaves range, or
# sits behind us long enough that chasing it is pointless.
COMMIT_MAX = 14.0 # s before we are allowed to reconsider anyway
COMMIT_DROP = 6000.0 # ...or it gets this far away
COMMIT_BEHIND = 2.5 # ...or stays >90 deg off the nose this long
def __init__(self, W, pad, dry=False, log=sys.stdout):
self.W = W
@@ -145,6 +155,9 @@ class Pilot:
self.missile_down = False
self.missile_t = -1e9
self.missiles = 0
self.commit_off = None # entity we are committed to
self.commit_t = -1e9
self.behind_since = None
def f32(self, off):
b = os.pread(self.W.fd, 4, off)
@@ -226,6 +239,33 @@ class Pilot:
return self.CONE_MAX
return min(self.CONE_MAX, max(self.FIRE_CONE, math.atan2(r + SHELL_RADIUS, d)))
def pick_committed(self, t, me_p, me_v, fwd, hos):
"""pick(), but stay on the same contact long enough to actually kill it."""
cur = None
for off, nm, p, v, r, hard in hos:
if off == self.commit_off and not hard:
cur = (off, nm, p, v, r)
break
if cur is not None:
off, nm, p, v, r = cur
rel = p - me_p
d = float(np.linalg.norm(rel))
behind = ang(rel, fwd) > math.pi / 2
self.behind_since = (self.behind_since if behind else None) or (t if behind else None)
stale = (t - self.commit_t > self.COMMIT_MAX
or d > self.COMMIT_DROP
or (self.behind_since is not None
and t - self.behind_since > self.COMMIT_BEHIND))
if not stale:
lead = self.lead_point(p, v, d)
return (off, nm, lead, lead - me_p, d, r)
# commit to a fresh one
tgt = self.pick(me_p, me_v, fwd, hos)
self.commit_off = tgt[0] if tgt else None
self.commit_t = t
self.behind_since = None
return tgt
def pick(self, me_p, me_v, fwd, hos):
"""Nearest *fighter*, weighted by how far off the nose it is."""
best, bestscore = None, 1e18
@@ -343,7 +383,7 @@ class Pilot:
else:
self.mode = "ENGAGE"
tgt = self.pick(me_p, me_v, fwd, hos)
tgt = self.pick_committed(t, me_p, me_v, fwd, hos)
push, worst = self.av.avoidance(me_p, me_v, me_r, ents, me_off)
if self.mode == "EVADE":