Files
Syplheed-Reborn/tools/re-capture/throttle_curve.py
Claude (auto-RE) 0cb81b6200 re(flight): the linear discrepancy is a world-unit vs displayed-speed difference
Screenshotting the HUD speed readout at each throttle step, beside the
position-derived measurement of the same moment:

  RT 0.00   HUD 350 (= CruisingVelocity)   position ~447   ratio 1.28
  RT 0.25   HUD 507                        position ~652   ratio 1.29
  RT 0.75   HUD 963                        position ~1141  ratio 1.19

So (a) the HUD speaks the definition's units — exactly CruisingVelocity at neutral,
963 at three-quarters against the 987 the interpolation predicts — confirming the
throttle law in the game's own numbers without any position sampling; and (b) world
displacement runs ~1.2x the displayed speed. Since settled angular rates need no such
factor, this is a unit difference between the position triple and the velocity
fields, not a clock effect: a reimplementation moving entities at MaximumVelocity in
world coordinates will be ~20% slow.

Also fixes speed_law.find_player: a mission holds more than one *_Player object and
at least one never moves, so the finder now samples each candidate twice and keeps
the one that displaces. Locking onto the static one is what produced a run of exact
zeros while the game was visibly flying.

🟡 The ratio is 1.19-1.29 rather than a clean constant and every sample was taken in
a firefight; pinning it wants a quiet map.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NptfmpjdpNCKEez6d2xvA9
2026-08-13 17:06:35 +00:00

60 lines
2.6 KiB
Python

#!/usr/bin/env python3
"""Is the throttle ANALOGUE, and is full deflection the afterburner?
speed_law.py measured a settled speed of ~1 530 under full `RT` against a
`MaximumVelocity` of 1 200 — attributed to the emulated time base because the same
~1.2x appears in the turn rates. But `RT` is an analogue trigger, so there is a
second reading worth excluding: that partial deflection reaches MaximumVelocity and
FULL deflection is the afterburner (which would also explain why no button toggles
it). This walks the trigger 0.00 -> 1.00 and reports the settled speed at each step.
Usage: throttle_curve.py <out.csv> [dwell_s]
"""
import math, os, subprocess, sys, time
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import speed_law
def pad(*a):
subprocess.run(["vgamepad", *a], capture_output=True)
def windowed(seq, lo, hi):
a = [s for s in seq if s[0] >= lo][0]
b = [s for s in seq if s[0] <= hi][-1]
return math.dist(a[1:], b[1:]) / (b[0] - a[0])
def main():
out_csv = sys.argv[1]
dwell = float(sys.argv[2]) if len(sys.argv) > 2 else 6.0
axis = sys.argv[3] if len(sys.argv) > 3 else "RT" # RT ramps up, LT ramps down
w, off, nm = speed_law.find_player()
if not w:
sys.exit("player entity not found after retries")
print(f"# locked on {nm}")
rows = []
for v in (0.0, 0.25, 0.5, 0.75, 1.0):
pad("trig", "RT", "0.0"); pad("trig", "LT", "0.0")
pad("trig", axis, str(v))
time.sleep(6.0) # settle: 5 s+ is what the turn-rate fix showed is needed
# Screenshot the HUD at the settled speed: its readout is in the
# DEFINITION's unit (it shows 350 at neutral = CruisingVelocity), so it is
# the ground truth the position-derived number has to be compared against.
subprocess.run(["screenshot", f"/sylph-home/re/shots/hud_{axis}_{v}.png"],
capture_output=True)
seq, t0 = [], time.time()
while time.time() - t0 < dwell:
seq.append((round(time.time() - t0, 3), *speed_law.pos_at(w.fd, off)))
time.sleep(0.05)
for s in seq:
rows.append((v, *s))
wins = [windowed(seq, t, t + 1.0) for t in range(int(dwell) - 1)]
print(f"# {axis}={v:<4} settled speed per 1 s window: " + " ".join(f"{x:6.0f}" for x in wins))
pad("trig", "RT", "0.0"); pad("reset")
with open(out_csv, "w") as f:
f.write("rt,t,x,y,z\n")
for r in rows:
f.write(",".join(str(x) for x in r) + "\n")
print(f"# wrote {out_csv}")
if __name__ == "__main__":
main()