pilot: target select is A pressed TWICE — from the HUD tutorial, not from probing
HEADS-UP DISPLAY tutorial, verbatim: 'Press A twice to target the enemy closest to the center of the screen.' A double tap, which is exactly why every button sweep in flight-controls-runtime.md found nothing and why I concluded targeting was automatic — each sweep tapped once. It also explains the missiles: GuidanceType 5 guides to the GAME's selection and the loop had never made one, so 98 launches guided to nothing. Wired in: double-tap A when the committed contact is already within 14 deg of the nose, so the game's choice and ours are the same object. One run: 8 kills from 66 missiles (12% per missile) against the previous 9 from 101 (8.9%). The absolute count is inside run variance and the efficiency gain is one sample, so neither is claimed as decisive — it needs repeat runs. Also documents that expository tutorials self-advance while interactive ones stall (BASIC CONTROLS waits forever on 'Go to the box'), and that captions need cropping across many frames because they type out.
This commit is contained in:
BIN
docs/re/captures/tutorial-hud-target-select.png
Normal file
BIN
docs/re/captures/tutorial-hud-target-select.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 884 KiB |
@@ -72,9 +72,26 @@ the craft's response to a given stick deflection is configurable. Any calibratio
|
|||||||
against one profile (e.g. the `ctrl_probe.py` throttle numbers) is only valid for the
|
against one profile (e.g. the `ctrl_probe.py` throttle numbers) is only valid for the
|
||||||
save's current settings.
|
save's current settings.
|
||||||
|
|
||||||
**Next:** bind physical buttons to actions 9–14 by watching the *reticle and target
|
## What the tutorials state outright
|
||||||
panel* (not the ammo counters) — and once `Change Target` and `Padlock` are identified,
|
|
||||||
re-run the missile test with a locked target.
|
`tutorial_capture.sh <index> <secs> <tag>` plays one lesson and photographs it. Captions
|
||||||
|
use a typewriter effect, so crop `900x125+160+40` from many frames to read a full
|
||||||
|
sentence. Lessons that require the player to *do* something stall (BASIC CONTROLS sits
|
||||||
|
on "Go to the box on your screen" forever with nobody flying); the expository ones run
|
||||||
|
on their own.
|
||||||
|
|
||||||
|
- **HEADS-UP DISPLAY (index 1):** *"Enemies are displayed with **red markers** and allies
|
||||||
|
with **blue markers**." · "Targeting an enemy displays an Armor Gauge…" ·* **"Press Ⓐ
|
||||||
|
twice to target the enemy closest to the center of the screen."**
|
||||||
|
- **ADVANCED CONTROLS (index 5):** `B`+`LS` = Side Roll / 180 Degree Turn / Level Off ·
|
||||||
|
`B`+`A` together = face the target · `LT`+`RT` together = *"sets your fighter's speed
|
||||||
|
to that of the target… works well when you are trying to get behind an enemy. Once
|
||||||
|
behind an enemy, this also helps you attack them."*
|
||||||
|
|
||||||
|
**`Change Target` is Ⓐ pressed TWICE** — a double tap. That is why every button sweep in
|
||||||
|
this document found nothing and why I wrongly concluded targeting was automatic: each
|
||||||
|
sweep tapped once. It also explains the missiles — `GuidanceType 5` needs the *game's*
|
||||||
|
selection, and the loop had never made one, so 98 launches guided to nothing.
|
||||||
|
|
||||||
## Notes for the reimplementation
|
## Notes for the reimplementation
|
||||||
|
|
||||||
|
|||||||
@@ -159,6 +159,15 @@ class Pilot:
|
|||||||
# "Press B and A together to face [the target]" — a snap turn, far quicker
|
# "Press B and A together to face [the target]" — a snap turn, far quicker
|
||||||
# than winding the PD controller around for a contact behind us.
|
# than winding the PD controller around for a contact behind us.
|
||||||
FACE_MIN = math.radians(999) # 50 deg to re-enable the B+A snap turn
|
FACE_MIN = math.radians(999) # 50 deg to re-enable the B+A snap turn
|
||||||
|
# HEADS-UP DISPLAY tutorial, verbatim: "Press A twice to target the enemy
|
||||||
|
# closest to the center of the screen." A DOUBLE tap — which is why every
|
||||||
|
# single-tap button sweep found nothing and concluded targeting was
|
||||||
|
# automatic. It also explains the missiles: GuidanceType 5 needs the GAME's
|
||||||
|
# selection, and we had never made one, so 98 launches guided to nothing.
|
||||||
|
# Select only when our committed contact is already near screen centre, so
|
||||||
|
# the game's choice and ours are the same object.
|
||||||
|
SELECT_CONE = math.radians(14)
|
||||||
|
SELECT_PERIOD = 3.0
|
||||||
FACE_PERIOD = 4.0
|
FACE_PERIOD = 4.0
|
||||||
|
|
||||||
def __init__(self, W, pad, dry=False, log=sys.stdout):
|
def __init__(self, W, pad, dry=False, log=sys.stdout):
|
||||||
@@ -193,6 +202,8 @@ class Pilot:
|
|||||||
self.face_t = -1e9
|
self.face_t = -1e9
|
||||||
self.face_down = None
|
self.face_down = None
|
||||||
self.faces = 0
|
self.faces = 0
|
||||||
|
self.select_t = -1e9
|
||||||
|
self.selects = 0
|
||||||
|
|
||||||
def f32(self, off):
|
def f32(self, off):
|
||||||
b = os.pread(self.W.fd, 4, off)
|
b = os.pread(self.W.fd, 4, off)
|
||||||
@@ -254,6 +265,15 @@ class Pilot:
|
|||||||
self.pad.trig("LT", 1.0 if want < 0 else 0.0)
|
self.pad.trig("LT", 1.0 if want < 0 else 0.0)
|
||||||
self.throttle = want
|
self.throttle = want
|
||||||
|
|
||||||
|
def select_target(self, t):
|
||||||
|
"""A, twice: make the GAME target what we are already pointing at."""
|
||||||
|
if self.dry or t - self.select_t < self.SELECT_PERIOD:
|
||||||
|
return
|
||||||
|
self.pad.f.write("tap A 90\n")
|
||||||
|
self.pad.f.write("tap A 90\n")
|
||||||
|
self.select_t = t
|
||||||
|
self.selects += 1
|
||||||
|
|
||||||
def face_target(self, t):
|
def face_target(self, t):
|
||||||
"""B + A: snap the nose onto the selected target."""
|
"""B + A: snap the nose onto the selected target."""
|
||||||
if self.dry or t - self.face_t < self.FACE_PERIOD:
|
if self.dry or t - self.face_t < self.FACE_PERIOD:
|
||||||
@@ -556,6 +576,11 @@ class Pilot:
|
|||||||
if fire != self.firing:
|
if fire != self.firing:
|
||||||
(self.pad.press if fire else self.pad.release)("RB")
|
(self.pad.press if fire else self.pad.release)("RB")
|
||||||
self.firing = fire
|
self.firing = fire
|
||||||
|
if (tgt and self.mode in ("ENGAGE", "DEFEND")
|
||||||
|
and abs(aim[0]) < self.SELECT_CONE
|
||||||
|
and abs(aim[1]) < self.SELECT_CONE
|
||||||
|
and tgt[4] < MISSILE_RANGE and pn < 1.2):
|
||||||
|
self.select_target(t)
|
||||||
if self.face_down is not None and t - self.face_down > 0.2:
|
if self.face_down is not None and t - self.face_down > 0.2:
|
||||||
self.pad.release("B")
|
self.pad.release("B")
|
||||||
self.pad.release("A")
|
self.pad.release("A")
|
||||||
@@ -577,7 +602,7 @@ class Pilot:
|
|||||||
f"thr={str(self.throttle):>5} yaw={math.degrees(yaw):+6.1f} "
|
f"thr={str(self.throttle):>5} yaw={math.degrees(yaw):+6.1f} "
|
||||||
f"pit={math.degrees(pitch):+6.1f} aim={math.degrees(aim[0]):+6.1f}"
|
f"pit={math.degrees(pitch):+6.1f} aim={math.degrees(aim[0]):+6.1f}"
|
||||||
f"/{math.degrees(aim[1]):+6.1f} fire={int(fire)} msl={self.missiles}"
|
f"/{math.degrees(aim[1]):+6.1f} fire={int(fire)} msl={self.missiles}"
|
||||||
f" fc={self.faces}")
|
f" fc={self.faces} sel={self.selects}")
|
||||||
if ast is not None:
|
if ast is not None:
|
||||||
msg += f" ast={a_frac*100:5.1f}%"
|
msg += f" ast={a_frac*100:5.1f}%"
|
||||||
if a_dmg > self.ASSET_ALERT:
|
if a_dmg > self.ASSET_ALERT:
|
||||||
|
|||||||
Reference in New Issue
Block a user