PARALLAX (#16): the pick/fire ray was anchored at mech.y+5.0 (a port improvisation) while the sight line ran from the eyepoint (y=6.23) -- two parallel rays whose constant offset grew into the reported low-miss as range closed (measured ry +0.072 @50u -> +1.54 @2.7u). The decomp's sight and pick share the eye origin (HudSimulation @4b7830 chain). Fix: the viewpoint mech's cockpit eye owns the aim-camera publish in BOTH views, origin = its own eye translation; leveling + deliberate elevation untouched; chase view now converges to cockpit ballistics (V cannot change where shots land). After: pick pinned to the crosshair (ry <= 5e-6) from 50u to point-blank; 26 laser + 8 missile center-mass hits at 3/4-screen. Awaiting the reporters' approach-test. VERDICT INSTRUMENTATION (#4 closed authentic, #5 verdict posted): BT_RANGE_LOG per-frame pick tracing + BTGroundRayHitExact analytic cross-check (0/8000 arena fall-throughs; cavern 6/8400 single-frame grazes -- the 'crazy sliding' is the authentic world-pick + 500 m/s slide over depth discontinuities); BT_AUD_TAIL StopNote/fade timing + BT_FIRE_PULSE single-shot driver (the energy 'buzz' is the AUTHORED charging loop: crescendo through recharge, 1.309s authored release, measured within one frame). CAVERN.EGG: solo cavern test egg. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d7158f1f82
commit
70eea6c1a4
@@ -79,11 +79,39 @@ jointtorso — NO explicit eye-side compose exists, one briefly added on false "
|
||||
probe readings double-rotated the view and is retired, see [[cockpit-view]]); the crosshair sits
|
||||
at screen center (`gBTAimX = 0` — the old `BTTwistToReticleX` slew was THE bug: the camera
|
||||
already yawed, so the crosshair counter-slid to HULL-forward, "twisting leaves the crosshairs
|
||||
behind"; `BT_AIM="x y"` still pins it for headless tests) → `BTGetAimRay` (the ACTIVE eye
|
||||
behind"; `BT_AIM="x y"` still pins it for headless tests) → `BTGetAimRay` (the BORESIGHT eye
|
||||
publishes pos+basis via `BTSetAimCamera`, leveled in pitch, the twist yaw riding in the basis) →
|
||||
`Mech::PickRayHit` (world ray → local frame → `BoundingBox::HitBy` slab test vs the collision
|
||||
template's ExtentBox → world hit point).
|
||||
|
||||
**PICK-RAY ORIGIN = the TRUE EYEPOINT (Gitea #16 "shots land LOW, worse up close" — FIXED
|
||||
2026-07-20) [T1 evidence / T2 fix].** The task-#48 publish anchored the pick ray at
|
||||
`mech.y + 5.0` (a port improvisation) while the crosshair's sight line runs from the eyepoint
|
||||
(~y 6.2 on the DEV mech) — two parallel rays with a constant vertical offset, so the pick point
|
||||
slid DOWN the reticle as range closed (measured pre-fix via `BT_PARALLAX_LOG`, the pick point
|
||||
back-projected through the RENDER view: ry +0.07 @ 50u → +0.17 @ 16u → +0.32 @ 10u → +1.5 @
|
||||
2.7u; lasers AND missiles consume the pick, so both landed low). The binary's sight math is
|
||||
EYE-ORIGINATED [T1]: HudSimulation's designator HotBoxVector = target position transformed by
|
||||
`inverse(eyeSegToWorld)` ∘ `inverse(R(EyepointRotation))` where eyeSegToWorld = the HUD's mount
|
||||
SEGMENT frame × mech localToWorld (`@004b7830` part_013.c:5688-5702 — Ghidra drops the segment
|
||||
arg, disasm shows `hud+0xdc`; the seg→world composer is `FUN_00424da8` @00424da8); the VIEW is
|
||||
`inverse(jointtorso→jointeye→siteeyepoint)` (`FUN_004c22c4` part_013.c:11742); and the fired
|
||||
beam CONVERGES from the muzzle segment to the picked point `mech+0x37c` (`@004bace8`
|
||||
part_013.c:7742-7752) — so pick ray and sight line share the eye origin (the pod's division
|
||||
card cast from the view per Auric; the 0x37c/0x388 writer itself is in the un-exported gap).
|
||||
**The fix:** the viewpoint mech's cockpit `siteeyepoint` eye is marked the **BORESIGHT eye**
|
||||
(`DPLEyeRenderable::SetBoresightEye`, set in btl4vid.cpp) and owns the `BTSetAimCamera`
|
||||
publish in BOTH views (it executes in the mech's draw traversal every frame), origin = its own
|
||||
eye translation (eyeW row 4 — the exact frame the crosshair projects from); the leveling +
|
||||
`gBTEyeElev` re-application are unchanged. Chase ballistics are therefore IDENTICAL to cockpit
|
||||
(verified: chase-view pick lands at y=6.23076 = the cockpit eye height while the chase camera
|
||||
sits at y=11); the legacy `+5` anchor survives only as the no-boresight-eye fallback
|
||||
(spectator). Verified after: ry ≤ 5e-6 from 50u to point-blank 2.2u in cockpit AND glass
|
||||
builds; 26 laser `[dmghit]`s + 8 missile hits at range 1.7-2.2 on center-mass/upper zones with
|
||||
the lock ring on the target chest (`scratchpad/i16_laser.png`/`i16_missile.png`). Diags:
|
||||
`BT_PARALLAX_LOG` (pick→render-view back-projection via `BTProjectToRenderView`),
|
||||
`BT_GOTO_STOP`/`BT_GOTO_THR` (approach-test stop radius / walk throttle).
|
||||
|
||||
**THE WORLD-PICK TARGET MODEL (task #41, the reconciliation — binary + pod-video evidence).**
|
||||
The target slot `mech+0x388` holds **whatever entity is downrange of the torso boresight** — a
|
||||
mech OR a WORLD entity (terrain/mesa/building). Evidence: (a) the weapon fire path is DOUBLY
|
||||
@@ -387,6 +415,18 @@ thing: an EXPLICIT `JointedMover::~JointedMover()` in the reconstructed `~Mech`
|
||||
chain TWICE (the dtor-epilogue rule, [[reconstruction-gotchas]] §7) → a double-free of `collisionLists`
|
||||
+ the segment table. Removing it fixed BOTH the death-row crash AND app-exit crashes. [T2]
|
||||
|
||||
**⚠ The SILENT death-crash (Gitea #12, FIXED 2026-07-20) was NOT a mech-teardown bug at all — it
|
||||
was the DEATH-EXPLOSION AUDIO.** A silent hard crash (no WER/markers) a few seconds after ANY mech
|
||||
death — solo dummy, MP self-death, MP peer PEER_DOWN — deterministic on the first kill. Root cause:
|
||||
the death boom is the **AllExplosion preset (25 layered zones)**, but the port's OpenAL
|
||||
`SourceSet.sources[]` array was only **5** wide, so acquiring channels for it overwrote adjacent
|
||||
heap; the corruption turned fatal seconds later at the death Explosion's own audio-entity teardown
|
||||
(`FryDeathRow → Explosion::~Explosion → …DestroyEntityAudioObjects → ~Dynamic3DPatchSource →
|
||||
operator delete`) or the next sequenced virtual dispatch (`AudioControlSequence::RunSequence →
|
||||
Send`, garbage vtable). Fixed by sizing `sources[]` to the real max — see [[reconstruction-gotchas]]
|
||||
§21 (Gitea #12). NOT the held #16 boresight-eye dtor (exonerated), NOT the `rev=-64` mppr value
|
||||
(a `ControlsButton` negative = release, benign). [T2]
|
||||
|
||||
## Death SEQUENCE reconstruction — the map (2026-07-08)
|
||||
Full decomp map of the death path. Two tiers:
|
||||
**EXPORTED (reconstructable) [T1 read]:**
|
||||
|
||||
@@ -131,7 +131,10 @@ valid for reading the decomp, NOT for our compiled layout (see [[reconstruction-
|
||||
### BTPlayer (0x294) experience/game-mode flag block (ctor @4c0bc8; see [[experience-levels]]) [T1]
|
||||
|
||||
Seeded on the master branch from `btMission(+0x1f8)->experienceLevel(+0xe4)` (egg `experience`,
|
||||
parse @4d2f3e → `BTMission+0xe4`) and `advancedDamageOn(+0xf0)`:
|
||||
parse @4d2f3e → `BTMission+0xe4`) and `advancedDamageOn(+0xf0)`. The +0x1f8 mission pointer is
|
||||
the inherited `Player::playerMission`. Port members (issue #2): `simLive`/`heatModelOn`/
|
||||
`advancedDamageOn`(+2)/`levelFlag26c`/`levelFlag270`/`experienceLevel`; bridges
|
||||
`BTPlayerExperienceSimLive`/`…HeatModelOn`/`BTPlayerRoleLocksAdvanced` (btplayer.cpp):
|
||||
|
||||
| Offset | Value by level (nov/std/vet/exp) | Verified readers |
|
||||
|---|---|---|
|
||||
@@ -321,6 +324,8 @@ default-ON (`'0'` disables).
|
||||
| `BT_CRIT_PROBE=<zone>` | hammer one own-mech zone every 4s (crit-propagation diag, task #2; mech4.cpp) |
|
||||
| `BT_REPL_LOG` | replicant/MP replication log (mech4.cpp) |
|
||||
| `BT_GOTO="enemy"\|"x z"` / `BT_GOTO_LOG` | self-driving beeline (to the enemy or a map coordinate) + its log |
|
||||
| `BT_GOTO_STOP=<u>` / `BT_GOTO_THR=<0..1>` | beeline stop-radius / throttle overrides (Gitea #16 approach test: walk all the way in) |
|
||||
| `BT_PARALLAX_LOG` | 2 Hz `[parallax]`: the pick point back-projected through the RENDER view (`BTProjectToRenderView`, L4VIDEO.cpp) — a healthy boresight holds (rx,ry)≈(0,0) at every range (Gitea #16; [[combat-damage]] Targeting) |
|
||||
| `BT_MP_LOG` / `BT_MP_NET` / `BT_MP_FORCE_DMG` | MP diagnostics / forced cross-pod damage |
|
||||
| `BT_AUTODRIVE=<0..1>` | headless throttle |
|
||||
| `BT_KEY_NOFOCUS=1` | accept key input without window focus |
|
||||
|
||||
+21
-1
@@ -337,7 +337,27 @@ and every instrument is now live [T2]:**
|
||||
**GREEN width-1 caret triangle** (ctor @4550-4551 sets green/1 AFTER the yellow bar call —
|
||||
transcription color bug caught by a period reference screenshot, 2026-07-09; same for the
|
||||
bottom bowtie carets @4569-4570); pegs at 1200 with no target; the DISPLAYED range slides at
|
||||
**500 m/s** toward the true pick range (HudSimulation :5652 [T1]). ⚠ A period pod screenshot
|
||||
**500 m/s** toward the true pick range (HudSimulation :5652 [T1]).
|
||||
**VERDICT (Gitea #4, 2026-07-20): the "range slides in/out crazily while walking" report is
|
||||
AUTHENTIC behavior, not a bug [T2 measured].** Per-frame `BT_RANGE_LOG` traces (mech4.cpp, with
|
||||
an independent Möller-Trumbore cross-check `BTGroundRayHitExact` in btvisgnd.cpp) on scripted
|
||||
walks: ARENA1 garage cluster — every frame a real structure-face pick, true range legitimately
|
||||
hopping 40↔600 m at silhouette edges, the caret in motion 74% of frames / ~24 direction
|
||||
reversals per 10 s; CAVERN butte field — 806 instant >50 m jumps, 776 butte↔1200-default
|
||||
boundary crossings, 106/139 s windows swinging >300 m (max 1143 m), caret reversing ~54×/10 s.
|
||||
Every value tracks real geometry; the 500 m/s slide (authentic) then never rests. Elevation was
|
||||
NOT the driver (arena floor is flat y=0) — depth discontinuities are. Cyd's "ray falls through
|
||||
geometry" was checked: 0 fall-through frames on arena, 6/8400 (0.07%, single-frame silhouette
|
||||
grazes) on cavern. Bounded infidelities noted for follow-up, NOT the reported symptom: (a) butte
|
||||
collision (stepped YCyl tiers + cone, buttee_c.sld) is NARROWER than the sculpted buttee.bgf
|
||||
rock — measured a 0.27 m graze past the r=14.6 tier while visibly inside rock (terrain-march
|
||||
tier backstops it, error a few meters at point-blank); (b) the cavern's `butteeu` upper butte
|
||||
sections (buttee.bgf re-instanced at y=50, VideoModel-only, NO solid stream) are
|
||||
pick-transparent — aiming steeply up at a rock tower's top half reads through it; (c) boot
|
||||
transient: before the aim camera is valid, the max-range fallback designates from uninitialized
|
||||
ray floats → `shown` overshoots (~3400) and slides down for the first ~7 s (cosmetically hidden
|
||||
by the 1200 caret peg). Traces: scratchpad i4_*_walk*.log; issue #4 comment has the summary.
|
||||
⚠ A period pod screenshot
|
||||
(`C:\git\image.webp`, likely a DIFFERENT pod revision — its crosshair is ~2.5× taller with
|
||||
arrowhead arms, NOT our binary's ±0.04..0.16 program) structurally CONFIRMS our layout: yellow
|
||||
bar + green caret + colored pip dots on the right ladder, bottom tape + green bowtie, rotating
|
||||
|
||||
@@ -141,7 +141,12 @@ and the boresight pointed that far DOWN, hitting terrain ~50-100 m short of the
|
||||
started over the mech's shoulder. Fix (L4VIDRND `DPLEyeRenderable::Execute`, the `BTSetAimCamera` publish):
|
||||
LEVEL the boresight (drop the view-dir pitch, rebuild an upright basis with world +Y) AND anchor its ORIGIN
|
||||
at the mech's torso (`myEntity->localToWorld` translation + ~5) instead of the render eye. The guns now fire
|
||||
along the mech's horizontal heading from the torso, independent of view mode and terrain tilt. The reticle X
|
||||
along the mech's horizontal heading from the torso, independent of view mode and terrain tilt.
|
||||
**⚠ ORIGIN part SUPERSEDED (2026-07-20, Gitea #16):** the `+5` torso anchor sat BELOW the sight line →
|
||||
shots landed LOW, worse at close range (boresight parallax). The pick ray origin is now the TRUE
|
||||
EYEPOINT: the viewpoint mech's cockpit `siteeyepoint` eye (the BORESIGHT eye) publishes the aim camera
|
||||
in BOTH views from its own eye translation — see [[combat-damage]] Targeting §parallax. The LEVELING +
|
||||
`gBTEyeElev` re-application stand unchanged. The reticle X
|
||||
still carries the torso twist (`BTTwistToReticleX`); reticle Y any elevation. VERIFIED end-to-end: solo,
|
||||
enemy 120 m ahead, **both chase AND cockpit** view → `[target] MECH under boresight ... mechPicks=59
|
||||
groundPicks=0` → beam → `*** DESTROYED`. Also proved `PickRayHit` resolves a REPLICANT when aimed at it
|
||||
|
||||
@@ -127,6 +127,23 @@ on top of it. Full detail: `docs/PROGRESS_LOG.md §5b, §8`.
|
||||
saturate early and fake "per-stride" rates — always timestamp before inferring cadence.
|
||||
- Still deferred: F21 attack velocity/time (all captured events were default 1), F22 HRTF
|
||||
(user has 2 speakers; enable via alsoft.ini `hrtf=true` for headphones).
|
||||
- **Energy-weapon post-beam buzz = AUTHENTIC (Gitea #5 verdict, 2026-07-20)** [T2, measured]:
|
||||
the reported "buzz/electrical sustaining 1–2 s past the beam" is the AUTHORED charge loop
|
||||
(`LaserACharge01-04`, looped, release 1.309 s), started by the WeaponState==3 (Loading) watcher
|
||||
at beam-off, volume authored to track PercentDone (crescendo to ready), stopped on 3→2 with the
|
||||
authored 1.309 s release fade. Measured live (BT_AUD_TAIL=1 + BT_FIRE_PULSE single shots):
|
||||
beam 203–207 ms (authored DischargeTime 0.2 s); sustain loops cut ≤2 ms after leave-Firing
|
||||
(authored release 0); charge StopNote ≤2 ms after Loading→Loaded; fades 1.311–1.326 s vs
|
||||
authored 1.309 s (≤ 1 frame over); laser recharge 2.3–3.8 s, PPC 8.8–16.3 s under multi-weapon
|
||||
generator load (authentic electrical model). NOT the #12 source overflow — no energy preset
|
||||
exceeds 5 zones (max 3; >5 is only the death/UI families: AllExplosion 25, MechExplosion01/
|
||||
Death01 16, AllButtons 14, AllCoolant/AllProjectile 9, Warnings01/AuxExplosion01/AllHits 8,
|
||||
AllWarning 7). Caveat: the reporter's 2026-07-18 build predated 2edde29 (Emitter::SetDirty
|
||||
DelayWatchersFlag poison retirement — PerformAndWatch skips ExecuteWatchers while set,
|
||||
SIMULATE.cpp:461; cleared only by the encore path, UPDATE.cpp:215), which made emitter audio
|
||||
watcher timing encore-erratic that session. Harness kept (env-gated, additive): `[aud-tail]`
|
||||
logging in `L4AUDLVL.cpp` (PLAY/STOP/fade) + `emitter.cpp` (state transitions), and
|
||||
`BT_FIRE_PULSE="on,off"` single-shot trigger pulsing in `mech4.cpp`.
|
||||
- **L4 HAL on Windows + the VS build system: DONE.** [T1]
|
||||
- **Red Planet game logic: COMPLETE & buildable** — `VTV/VTVMPPR/WEAPSYS/...`. RP is at/near playable. [T1]
|
||||
- **Multiplayer: the DOS `NETNUB` driver is already replaced by a ~3.5k-line WinSock2 TCP
|
||||
|
||||
Reference in New Issue
Block a user