docs/re: in-flight control mapping, and why lethality is an aim-dwell problem
Probed rather than assumed: hold each pad input and photograph the HUD ammo counters. RB = nose gun (NOSE BM 6000->5956 in 4 s, ~11 rounds/s, HEAT rises), Y = main mount (MAIN MPM 300->299), d-pad = tactical map overlay, and LB/X/B/A/LS/RS move neither counter. No target-cycle input exists. The green TARGET marker is already up with nothing pressed, so the game selects for us and a guided missile's lock is a time-on-target mechanic, not a button. That closes the lethality question: it is not target choice (escort weighting), not ballistics (now from the confirmed Shell records), and not the mapping — the steering loop simply never holds the nose on one contact long enough to lock. Aim dwell is the next lever. Also records two things the reimplementation needs: two weapons with separate ammo pools and HUD counters, and a HEAT bar that fills while the gun fires (cap and cool-down not yet measured).
This commit is contained in:
@@ -33,6 +33,7 @@ Promote to a prose `structures/…md` file when a format needs behavioural notes
|
||||
| IDXD object layout solver | ✅ | [`tools/re-capture/weapon_runtime.py`](../../tools/re-capture/weapon_runtime.py) | Scan RAM for a class's vtable → enumerate its objects → brute-force `(field, offset, encoding)` against the disc records. Accepts a binding only on **zero** contradictions. Generalizes to any IDXD-backed definition |
|
||||
| Live entity state, anchored on the definition | ✅ | [`tools/re-capture/own_state.py`](../../tools/re-capture/own_state.py) · [autopilot](autopilot-memory-driven.md) | An undamaged craft holds its definition's own numbers, so a *solved definition field* locates the matching live field without a value scan: definition `HP` (1500) → **hull at `position+0x154`**, confirmed by a trace across a death (30/60/90 per hit, negative at 0). Reusable for any live counter whose maximum the definition carries |
|
||||
| Mission / escort state, every entity's hull | ✅ | [`tools/re-capture/mission_state.py`](../../tools/re-capture/mission_state.py) · [escort state](mission-escort-state.md) | `hull = position + 0x154` is a property of the **entity class**, not of the player object: at t=0 it equals each entity's own definition `HP` across 7 classes and 5 distinct HP values (turret 100, fighter 500, destroyer 10000, cruiser 30000, **ACROPOLIS 25000**), falls under fire (780 damage events in 240 s), goes negative at death, and the object then leaves the heap. So an escort objective is scoreable live — `UN_f101_TCAF_Acropolis` measured at 25000 → 23038 over 240 s, attack starting only at t≈170 s. `REMAINING OB` counts objectives, not hostiles (012 on the HUD vs 118 live ADAN); its address is still ❔ |
|
||||
| In-flight control mapping | ✅/🟡 | [`tools/re-capture/fire_probe.sh`](../../tools/re-capture/fire_probe.sh) · [controls](flight-controls-runtime.md) | Measured by holding each pad input and photographing the HUD ammo counters: **`RB` = nose gun** (6000→5956 in 4 s, ~11 rounds/s, HEAT rises), **`Y` = main mount** (missiles, 300→299), d-pad = **tactical map** overlay, nothing else moves a counter. No target-cycle input exists — the `TARGET` marker is present with nothing pressed, so targeting is automatic and a missile lock is **time-on-target**. That, not target choice or ballistics, is what caps lethality at 2 kills per 98 missiles |
|
||||
| Input → dynamics calibration | ✅ | [`tools/re-capture/ctrl_probe.py`](../../tools/re-capture/ctrl_probe.py) · [`binq.py`](../../tools/re-capture/binq.py) | Hold each pad input in turn and measure the craft's speed as displacement/s of its own position triple — no speed field needed first. Settled the throttle: **`RT` accelerates, `LT` brakes, and the setting persists** (488 → 1510 → 174 units/s), overturning an earlier field-scan conclusion |
|
||||
|
||||
## Functions / code paths
|
||||
|
||||
BIN
docs/re/captures/dpad-tactical-map.png
Normal file
BIN
docs/re/captures/dpad-tactical-map.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 MiB |
46
docs/re/flight-controls-runtime.md
Normal file
46
docs/re/flight-controls-runtime.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# In-flight control mapping — measured, not assumed
|
||||
|
||||
**Status:** ✅ for the weapon bindings (ammo counters move), 🟡 for the rest (HUD
|
||||
observation only). Probes: `tools/re-capture/fire_probe.sh` (hold each input, photograph
|
||||
the ammo counters) and `lock_probe.sh` (tap each, watch the reticle). Stage 02, in flight.
|
||||
Evidence: [`captures/fire-probe-ammo-counters.png`](captures/fire-probe-ammo-counters.png).
|
||||
|
||||
| input | effect | confidence |
|
||||
|---|---|---|
|
||||
| **`RB`** | **Nose gun.** `NOSE BM` 06000 → 05956 in a 4 s hold ≈ **11 rounds/s**; `HEAT` bar rises | ✅ |
|
||||
| **`Y`** | **Main mount** (missiles). `MAIN MPM` 00300 → 00299 per tap | ✅ |
|
||||
| **`RT` / `LT`** | Throttle up / brake, a *persistent* setting (488 → 1510 → 174 u/s) | ✅ (earlier session) |
|
||||
| **d-pad** | **Tactical map** overlay (grid with contact blips) — not target cycling | 🟡 |
|
||||
| `LB`, `X`, `B`, `A`, `LS`, `RS` | No change to either ammo counter | ✅ (as "not a weapon") |
|
||||
|
||||
## Targeting appears to be automatic, and that is the lethality problem
|
||||
|
||||
No input was found that cycles a target. The green `TARGET` marker is already present in
|
||||
idle frames with nothing pressed, so the game selects for us — most likely whatever sits
|
||||
nearest the reticle — and a guided missile's lock is then a **time-on-target** mechanic
|
||||
rather than a button.
|
||||
|
||||
That fits the measurements end to end:
|
||||
|
||||
- the guns fire fine (11 rounds/s) but the kill counters read `0000` after five gun-only
|
||||
runs → **we shoot and miss**;
|
||||
- guided missiles (`Missile_P`, Power 200, `GuidanceType` 5) got the first kills,
|
||||
`WARPLANES 0002`, but only **2 per 98 launches**;
|
||||
- the pilot's own log shows aim error wandering between ~10° and ~40° for most of a
|
||||
pass.
|
||||
|
||||
So the remaining bottleneck is **not** the target choice (escort weighting), **not** the
|
||||
ballistics (now taken from the confirmed `Shell` records), and **not** the input mapping
|
||||
(measured above). It is that the steering loop never holds the nose on one contact long
|
||||
enough to complete a lock. The next thing worth doing is making aim *dwell* — and the
|
||||
cheapest oracle for whether a lock ever completes is the reticle itself, or finding the
|
||||
lock timer in the player object with the same anchoring trick used for hull.
|
||||
|
||||
## Notes for the reimplementation
|
||||
|
||||
- Two independent weapons with separate ammo pools and separate HUD counters:
|
||||
`NOSE BM` (gun, 6000) and `MAIN MPM` (missiles, 300).
|
||||
- The gun has a **HEAT** bar that fills while firing — a sustained-fire limit the
|
||||
reimplementation needs; its cap and cool-down rate are not measured yet.
|
||||
- The tactical map is a full-screen overlay bound to the d-pad and does not pause flight
|
||||
(the craft kept taking fire with it open).
|
||||
34
tools/re-capture/lock_probe.sh
Executable file
34
tools/re-capture/lock_probe.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
# Which input SELECTS a target, and does a lock then build?
|
||||
#
|
||||
# 98 guided missiles produced 2 kills. A guided missile with nothing to guide to
|
||||
# flies straight, so the suspicion is that the loop has never selected a target
|
||||
# at all: the HUD carries a `TARGET` marker and a lock reticle, and no button in
|
||||
# pilot.py has ever touched them. fire_probe.sh already showed LB/X/B/A/LS/RS do
|
||||
# not discharge a weapon — but "does not fire" says nothing about "does not
|
||||
# select", so sweep them again watching the RETICLE instead of the ammo.
|
||||
#
|
||||
# Captures the centre of the screen (reticle + lock brackets) and the right-hand
|
||||
# target panel, so a selection or a building lock is visible either way.
|
||||
set -u
|
||||
export HOME=/sylph-home/re SDL_AUDIODRIVER=dummy DISPLAY=:98
|
||||
SD="$(cd "$(dirname "$0")" && pwd)"
|
||||
SHOTS=/sylph-home/re/shots
|
||||
HOLD="${1:-3}"
|
||||
|
||||
shot(){ screenshot "$SHOTS/lock-$1.png" >/dev/null 2>&1; echo " shot $1"; }
|
||||
|
||||
"$SD/launch_mission.sh" fly || { echo "BOOT FAILED"; exit 1; }
|
||||
sleep 3
|
||||
shot "00-idle"
|
||||
|
||||
# tap, not hold: a select is an edge, and holding a cycle button would just spin
|
||||
# through every contact. Two taps each, so a cycle that lands on nothing the
|
||||
# first time still shows on the second.
|
||||
for b in RS LS LB B X A Y; do
|
||||
vgamepad tap "$b" 200; sleep 0.4; vgamepad tap "$b" 200; sleep "$HOLD"
|
||||
shot "tap-$b"
|
||||
done
|
||||
vgamepad reset
|
||||
shot "99-final"
|
||||
echo "PROBE DONE"
|
||||
Reference in New Issue
Block a user