Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b59e2ac040 |
@@ -82,7 +82,6 @@ precise than anything you can infer.
|
|||||||
| Multiplayer, replication, netcode | `context/multiplayer.md` |
|
| Multiplayer, replication, netcode | `context/multiplayer.md` |
|
||||||
| **The OPERATOR CONSOLE + RELAY** — how to launch it, ports, seats, the round/launch lifecycle, re-arm | `context/operator-console.md` |
|
| **The OPERATOR CONSOLE + RELAY** — how to launch it, ports, seats, the round/launch lifecycle, re-arm | `context/operator-console.md` |
|
||||||
| Running a session as sysop (operator-facing how-to) | `docs/OPERATOR_GUIDE.md` |
|
| Running a session as sysop (operator-facing how-to) | `docs/OPERATOR_GUIDE.md` |
|
||||||
| The tester-facing OPEN-ISSUES handout (for Discord) | `docs/OPEN_ISSUES_FOR_TESTERS.txt` — regenerate from the tracker + update the header date before each playtest |
|
|
||||||
| Pod hardware, monitors, RIO, MFD surfaces, input remap (CONTROLS.MAP/XInput) | `context/pod-hardware.md` |
|
| Pod hardware, monitors, RIO, MFD surfaces, input remap (CONTROLS.MAP/XInput) | `context/pod-hardware.md` |
|
||||||
| Glass cockpit desktop dev layer (BT_GLASS/BT_STEAM gates, PadRIO, miniconsole, Steam) | `context/glass-cockpit.md` |
|
| Glass cockpit desktop dev layer (BT_GLASS/BT_STEAM gates, PadRIO, miniconsole, Steam) | `context/glass-cockpit.md` |
|
||||||
| Steam internet MP (the wire seam, identity tokens, lobby) | `context/steam-networking.md` |
|
| Steam internet MP (the wire seam, identity tokens, lobby) | `context/steam-networking.md` |
|
||||||
|
|||||||
@@ -1384,7 +1384,7 @@ cmHeat(K,ModeSecondaryHeat,58,heatpal.pcc,heatpal2.pcc,Myomers);
|
|||||||
}
|
}
|
||||||
|
|
||||||
#=======================================================================
|
#=======================================================================
|
||||||
# Denkou (was: Sunder V1)
|
# Sunder V1
|
||||||
#=======================================================================
|
#=======================================================================
|
||||||
Snd1Init
|
Snd1Init
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -69,23 +69,6 @@ run\run.cmd [EGG] # default DEV.EGG; cd's to content\ and runs btl4.exe -eg
|
|||||||
⚠ **Keep the `if /I "%%P"=="btl4.exe"` guard** — parsing tasklist with `tokens=2` alone reads its
|
⚠ **Keep the `if /I "%%P"=="btl4.exe"` guard** — parsing tasklist with `tokens=2` alone reads its
|
||||||
*"INFO: No tasks are running"* line as a PID and spins forever with nothing running. Full
|
*"INFO: No tasks are running"* line as a PID and spins forever with nothing running. Full
|
||||||
investigation, including which windows exit vs merely hide: `phases/phase-12-orphan-processes.md`.
|
investigation, including which windows exit vs merely hide: `phases/phase-12-orphan-processes.md`.
|
||||||
- **Field-log anatomy — reading a steam night (#157 forensics, 2026-08-10) [T2].** A night's log is
|
|
||||||
a CHAIN of `===== BT411 SESSION` blocks: menu stubs (`args=''`, "first process") alternating with
|
|
||||||
glass generations (`-net 1501 -platform glass`, "relaunched generation"); one glass block = one
|
|
||||||
drop, and boundaries are synchronized across every machine to ±2 s (mission-clock expiry relaunches
|
|
||||||
all peers' menus in the same second). **Stub anatomy:** the steam lobby is CLICK-driven
|
|
||||||
(`steamAction`, btl4fe.cpp), so a menu closed without a click logs exactly **4 boot lines** and
|
|
||||||
exits 0 — a 4-line stub at end-of-night is a player going to bed, NOT a crash (all four machines
|
|
||||||
ended night-14 with identical 4-line stubs at 00:31:2x). 7–8-line stubs = a lobby cycle
|
|
||||||
(`[steamnet] up` + `[lobby] join` + map). `BTCrashFilter` is armed before the first log line and
|
|
||||||
writes a `[crash]` block + module-relative stack on ANY unhandled exception — a silent log end
|
|
||||||
means quit/kill/hang, never an unlogged AV. **`lastrun_<stem>.txt` caveats:** appends stop silently
|
|
||||||
if the file gets locked (the `is_open` guard skips) — a lastrun ending mid-night while the log
|
|
||||||
continues means the file was captured/locked during live troubleshooting, not that the chain died.
|
|
||||||
And the bat sign-off ("The game has exited. If it closed unexpectedly, send…") prints after ANY
|
|
||||||
chain end including a normal quit — it primes players to report quits as crashes; #157 ("did not
|
|
||||||
exit cleanly") was exactly this echo. The arcade-authentic round-end (mission process exits →
|
|
||||||
menu relaunch) itself reads as a crash to first-night players.
|
|
||||||
- **Why this is a BT411-only hazard [T1].** The 1995 pod shipped ONE folder — `BTL4OPT.EXE` sits
|
- **Why this is a BT411-only hazard [T1].** The 1995 pod shipped ONE folder — `BTL4OPT.EXE` sits
|
||||||
next to `BTL4.RES`/`VIDEO\`/`GAUGE\`/`AUDIO\` (it is still there in `content\`) — and RP411/RP412
|
next to `BTL4.RES`/`VIDEO\`/`GAUGE\`/`AUDIO\` (it is still there in `content\`) — and RP411/RP412
|
||||||
keep that shape (`pack-dist.ps1` copies the exe and every asset dir into one dist root). BT411's
|
keep that shape (`pack-dist.ps1` copies the exe and every asset dir into one dist root). BT411's
|
||||||
|
|||||||
+16
-40
@@ -414,14 +414,6 @@ Verified live: bay fire → lamp 0xD (the LRM's select button) flashes 0x37 + en
|
|||||||
on detonation/purge. Diagnostics: `BT_LAMP_LOG` → `[techstat]`/`[galarm]`/`[lamp]`. Details +
|
on detonation/purge. Diagnostics: `BT_LAMP_LOG` → `[techstat]`/`[galarm]`/`[lamp]`. Details +
|
||||||
the four load-bearing fixes en route: [[open-questions]] + [[decomp-reference]] §GaugeAlarm.
|
the four load-bearing fixes en route: [[open-questions]] + [[decomp-reference]] §GaugeAlarm.
|
||||||
|
|
||||||
**These conditions are ROUTINE and SELF-CLEARING [T2, field-verified 2026-08-08].** A `SET` is an
|
|
||||||
operating state, not a fault: every laser volley trips Overheating (cond 3) and clears it on
|
|
||||||
cooldown (33× on one LLaser in a single match), and BadPower (cond 6) flickers whenever
|
|
||||||
simultaneous draw browns the bus. Across a full match every subsystem's SET/CLEARED counts are
|
|
||||||
balanced — nothing latches. So a lamp flashing after a respawn is the mech *operating*, not a
|
|
||||||
failed reset; diagnose from the SET/CLEARED balance, never from a lone SET. Full census + the
|
|
||||||
#137 post-mortem it settled: [[decomp-reference]] §TechStatus.
|
|
||||||
|
|
||||||
## ConfigMapGauge (the weapon panel's trigger-config joystick) — LIVE via LinkToEntity (2026-07-21)
|
## ConfigMapGauge (the weapon panel's trigger-config joystick) — LIVE via LinkToEntity (2026-07-21)
|
||||||
The per-weapon btjoy.pcc joystick image + 4 cm_* state lamps (off/other/only/both) showing,
|
The per-weapon btjoy.pcc joystick image + 4 cm_* state lamps (off/other/only/both) showing,
|
||||||
for each mappable fire button (Pinky/ThumbLow/Trigger/ThumbHigh), whether THIS panel's weapon
|
for each mappable fire button (Pinky/ThumbLow/Trigger/ThumbHigh), whether THIS panel's weapon
|
||||||
@@ -557,38 +549,6 @@ and every instrument is now live [T2]:**
|
|||||||
transcription color bug caught by a period reference screenshot, 2026-07-09; same for the
|
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
|
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]).
|
**500 m/s** toward the true pick range (HudSimulation :5652 [T1]).
|
||||||
**The HudSimulation tuning constants, read off .rdata 2026-08-08 [T1]** (`section_dump.txt`
|
|
||||||
rows ` 4b7ec0 8be55dc3 0000403f 0000803f 0000c842` / ` 4b7ed0 00000000`) —
|
|
||||||
`_DAT_004b7ec4` = **0.75f**, `_DAT_004b7ec8` = **1.0f**, `_DAT_004b7ecc` = **100.0f**,
|
|
||||||
`_DAT_004b7ed0` = **0.0f**, `_DAT_004b7f90` = **0.0f**. ec4/ec8 are the fire-control **LOCK**
|
|
||||||
limits (own HUD host zone < 0.75 damage, targeted zone < 1.0 — so a shot-up cockpit drops to
|
|
||||||
"target held, no lock", and a dead zone can't be re-locked); ed0 is the shared **zero** in the
|
|
||||||
range-slide `Abs()` idiom (the 500 is an immediate `0x43fa0000`, NOT a global). `hud.cpp` had
|
|
||||||
carried all five as 0.0f/500.0f stand-ins under guessed names ("SegmentTempLimit … heat
|
|
||||||
threshold for HUD page visibility" was neither heat nor page visibility) — corrected in place,
|
|
||||||
with the live lock/slide implementation staying in mech4.cpp's targeting step, which had both
|
|
||||||
thresholds right all along.
|
|
||||||
**THE CARET CAN DIE FOR THE WHOLE SESSION — #147, fixed 2026-08-08 [T2 code, T3 field link]:**
|
|
||||||
`sShownRange` (mech4's targeting step) is a **function-level static** — one cell per process,
|
|
||||||
shared by every mech, carried across drops. **NaN is absorbing** in `step = trueRange −
|
|
||||||
sShownRange; sShownRange += step`, and neither the producer's clamps nor
|
|
||||||
`BTReticleRenderable::Draw`'s (`range < minRange` / `range > maxRange`) catch it — both
|
|
||||||
comparisons are **false for NaN**. A poisoned value therefore reaches `AddPoint`/`ConcatMatrix`,
|
|
||||||
and the caret + its bar become **degenerate geometry that stops rendering while the static tick
|
|
||||||
marks keep drawing** — the exact reported symptom ("no range finder on this drop", ticks there,
|
|
||||||
caret gone), sticky until relaunch. Fixed four ways: re-seed on mech change (not on respawn —
|
|
||||||
that reuses the entity, and the binary doesn't reset the readout either), a producer NaN trap, a
|
|
||||||
NaN-safe consumer clamp falling back to the 1200 peg, and — the reason no log could settle it —
|
|
||||||
**`BT_RANGE_LOG` now prints the caret's actual input** (`[range] caret input shown=`). It never
|
|
||||||
did before: `BT_RANGE_LOG` instrumented the PICK (#4) and `[target]`'s `range=` is a *separate*
|
|
||||||
locally-recomputed Sqrt in the weapon-range check, so grepping field logs for NaN found nothing
|
|
||||||
because the poisoned variable was never printed. Causal link to the field report is INFERENCE.
|
|
||||||
**GAP — the 100 m RANGE BIAS is NOT reconstructed [T1 read, unimplemented]:** HudSimulation
|
|
||||||
subtracts `_DAT_004b7ecc` (100.0f) from `RangeToTarget@0x1EC` **every frame while the timed
|
|
||||||
flag @0x22C is set**, accumulating @0x21C by `time_slice` until it reaches @0x1D8, then clearing
|
|
||||||
both. The port's targeting step (mech4.cpp) does the slide but never the bias, so whatever
|
|
||||||
in-game state sets @0x22C currently produces no range offset. Trigger for @0x22C not yet
|
|
||||||
identified — see [[open-questions]].
|
|
||||||
**VERDICT (Gitea #4, 2026-07-20): the "range slides in/out crazily while walking" report is
|
**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
|
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
|
an independent Möller-Trumbore cross-check `BTGroundRayHitExact` in btvisgnd.cpp) on scripted
|
||||||
@@ -823,6 +783,22 @@ pattern across entries [2^bits..255] (high-index art degrades to its
|
|||||||
index-mod-2^bits colour IN-PLANE, can never leak). The 1995 binary ships the
|
index-mod-2^bits colour IN-PLANE, can never leak). The 1995 binary ships the
|
||||||
SAME 64-entry fill and relied on 6-bit art discipline -- garbage is not a
|
SAME 64-entry fill and relied on 6-bit art discipline -- garbage is not a
|
||||||
preservable behaviour, so the cycle-fill is a guarded PORT deviation.
|
preservable behaviour, so the cycle-fill is a guarded PORT deviation.
|
||||||
|
|
||||||
|
**REFINED 2026-08-10 [T1] -- the cycle-fill itself made phantoms.** The
|
||||||
|
in-plane wrap mapped art index 254 onto plane slot 62 = the LIVE
|
||||||
|
`colorMapperMultiArmor` right-armor damage slot, and idx-254 art EXISTS:
|
||||||
|
every SMODE.PCC frame fills the INACTIVE control-mode box interiors with 254
|
||||||
|
(active border/text idx 9 yellow, inactive borders idx 5 orange-red), and
|
||||||
|
BTSEC1.PCX carries a stray 52x13 idx-254 bar at port (199-250, 101-113) --
|
||||||
|
between the heading dial and the armor rosette, geometrically a scratch
|
||||||
|
duplicate of the rosette quadrant bars. Both lit up in the current
|
||||||
|
right-armor colour (adpal ramp green/orange/red) on EVERY render path --
|
||||||
|
playtester-reported as "red boxes around MID/ADV" + "a block between Armor
|
||||||
|
and Heading". On the shipped machine those regions rendered BLACK (the
|
||||||
|
garbage entry's low plane bits were 0 -> in-plane index 0), so the fill now
|
||||||
|
maps [2^bits..255] to `translationTable[0]` (plane BACKGROUND) -- authentic
|
||||||
|
on-screen result, same no-leak guarantee. NB the 2026-07-19 audit verified
|
||||||
|
smode BEFORE the 07-25 cycle-fill landed, which is why the row said CORRECT.
|
||||||
Post-fix: **0 leaks over 60s** on the same probe; sim3 3-pod regression clean.
|
Post-fix: **0 leaks over 60s** on the same probe; sim3 3-pod regression clean.
|
||||||
**The tripwires are DEFAULT-ON in every build** (BT_PLANE_AUDIT=0 opts out): the
|
**The tripwires are DEFAULT-ON in every build** (BT_PLANE_AUDIT=0 opts out): the
|
||||||
plane-leak trap, plus an out-of-bounds draw-start trap in `buildDestPointer`
|
plane-leak trap, plus an out-of-bounds draw-start trap in `buildDestPointer`
|
||||||
|
|||||||
+3
-77
@@ -254,22 +254,7 @@ desktops. Two pieces were added for the cab:
|
|||||||
once, and over CRD you cannot see the panels at all: the log IS the confirmation that a picture
|
once, and over CRD you cannot see the panels at all: the log IS the confirmation that a picture
|
||||||
landed on the right glass.
|
landed on the right glass.
|
||||||
|
|
||||||
### Boot-STABLE panel binding — `monitor:id:` (DEPLOYED + POD-VERIFIED 2026-08-10)
|
### Boot-STABLE panel binding — `monitor:id:` (2026-08-08, staged, pod-untested)
|
||||||
**Live on ALPHA-MR since 2026-08-10** — mapping eye-verified over livestream, then the master
|
|
||||||
`C:\bt411\glass_layout.cfg` flipped to the id form (old cfg saved as
|
|
||||||
`glass_layout.cfg.displaynbak`) and the relaunch bound all three windows to the SAME rects with
|
|
||||||
zero mismatch shouts [T2]. The shipped binding:
|
|
||||||
```
|
|
||||||
Secondary / Radar=monitor:id:Default_Monitor,bare # colour radar LCD, USB adapter
|
|
||||||
VGA Port A=monitor:id:UID224795,bare # RAR0005: Heat + Comm + Mfd2 CRTs
|
|
||||||
VGA Port B=monitor:id:UID200195,bare # RAR0005: Mfd1 + Mfd3 CRTs
|
|
||||||
```
|
|
||||||
⚠ **The radar LCD's USB display adapter presents NO EDID** — its only stable identity is the
|
|
||||||
`Default_Monitor` placeholder (`…#Default_Monitor#…&UID256#`). Unique today; a second EDID-less
|
|
||||||
panel would collide, and the per-boot `[glassid]` dump (BT_GLASS_IDS=1, now PERMANENT in
|
|
||||||
`podprofile.ini`) plus the mismatch shout are the diagnosis tools. The Dell (`DEL4025`) is the
|
|
||||||
PRIMARY main-view panel (BT_FIT owns it; not in the layout cfg) — the 08-08 note calling it a
|
|
||||||
"1908FP" service monitor mis-guessed its role.
|
|
||||||
**Windows renumbers displays.** Nick, after re-cabling + a reboot: *"the order changed … sometimes
|
**Windows renumbers displays.** Nick, after re-cabling + a reboot: *"the order changed … sometimes
|
||||||
they change when one gets turned off and back on, at least how windows SEEs them, even if the
|
they change when one gets turned off and back on, at least how windows SEEs them, even if the
|
||||||
visual desktop tool looks the same."* So the two original binding forms are both boot-fragile —
|
visual desktop tool looks the same."* So the two original binding forms are both boot-fragile —
|
||||||
@@ -495,67 +480,8 @@ instantly and did nothing" actually means "it is still hung". Recover with
|
|||||||
without a GUI):** `DISPLAY\RAR0005\…UID224795`, `DISPLAY\DEL4025\…UID249395` (DELL 1908FP),
|
without a GUI):** `DISPLAY\RAR0005\…UID224795`, `DISPLAY\DEL4025\…UID249395` (DELL 1908FP),
|
||||||
`DISPLAY\RAR0005\…UID200195`. **The two RAR panels share one EDID code and have blank serials**, so
|
`DISPLAY\RAR0005\…UID200195`. **The two RAR panels share one EDID code and have blank serials**, so
|
||||||
`monitor:id:RAR0005` is ambiguous — they must be bound by the per-connector form
|
`monitor:id:RAR0005` is ambiguous — they must be bound by the per-connector form
|
||||||
(`monitor:id:UID224795` / `monitor:id:UID200195`). **RESOLVED 2026-08-10:** the full map is
|
(`monitor:id:UID224795` / `monitor:id:UID200195`). The Dell's code is unique. The cab's shipped
|
||||||
UID224795 = VGA Port A (Heat+Comm+Mfd2), UID200195 = VGA Port B (Mfd1+Mfd3), `Default_Monitor`
|
`glass_layout.cfg` still uses the fragile `monitor:DISPLAY4` device-name form.
|
||||||
(EDID-less USB adapter, UID256) = the colour radar LCD, DEL4025 = the PRIMARY main-view panel
|
|
||||||
(not a service monitor). The master cfg now ships the id form (see the binding section above);
|
|
||||||
`glass_layout.cfg.displaynbak` preserves the old DISPLAYn cfg.
|
|
||||||
|
|
||||||
**7. ⚠ cmd redirect trap when scripting over SSH:** `echo VAR=1>> file` appends `VAR=` — cmd
|
|
||||||
parses the digit-adjacent `1>>` as a stream-handle redirect and eats the value (and MSVC putenv
|
|
||||||
treats an EMPTY value as UNSET, so the flag silently never arms). Space it (`echo VAR=1 >>file`,
|
|
||||||
trailing-space payload) or use PowerShell `Add-Content`. Bit us arming BT_GLASS_IDS 2026-08-10.
|
|
||||||
|
|
||||||
**8. Tester-procedure deploy VERIFIED end-to-end (2026-08-10, build 876):** scp zip →
|
|
||||||
`Expand-Archive` → podkit → `schtasks /run` came up clean on the first try — rig config survived,
|
|
||||||
newest-install auto-resolve worked, no hand-edits. The cab genuinely upgrades like a tester box.
|
|
||||||
|
|
||||||
**9a. ⚠ THE RIO's "COM1" IS A USB-SERIAL ADAPTER — the axis-dropout / frozen-boot fault
|
|
||||||
(2026-08-10, minidump-proven) [T1].** `\Device\VCP0` = an FTDI adapter (FTE7PGA5A); COM2 is a
|
|
||||||
second FTDI (A995JTOYA); **two ghost Prolific PL2303 entries also claim "COM1"** from earlier
|
|
||||||
plug-ins (clean them in Device Manager). When the adapter's **USB side** drops mid-operation:
|
|
||||||
brief drop = analog polls go mute (the field "encoder dropouts", revived by hand-jostle /
|
|
||||||
re-enumeration — NOT by button protocol); drop with a write in flight = the 1995 code's
|
|
||||||
**unbounded `GetOverlappedResult` wait in `PCSerialPacket::SendPacket` parked the whole game at
|
|
||||||
0 CPU forever** (three boots on 2026-08-10; stack: NtWaitForSingleObject ← GetOverlappedResult ←
|
|
||||||
SendPacket ← RIO ctor). **Hardened in 4.11.881**: 500 ms bounded write + CancelIo + 3 s sick
|
|
||||||
window (fast-drop, game keeps frame rate, keyboard fallback lives); `txTO=` in the `[rio]` health
|
|
||||||
line counts the events — proven the same evening (`txTO=1 rRetry=4` on a boot that SURVIVED).
|
|
||||||
USB **selective suspend disabled** system-wide on the cab the same day (powercfg) — prime suspect
|
|
||||||
for the random-period idle dropouts. Hardware to-do: FTDI adapter into a REAR motherboard USB
|
|
||||||
port, reseat its USB end. ⚠ A first "print-deadlock" diagnosis of the boot wedge was WRONG
|
|
||||||
(confounded A/B) and is retracted — the dump is the authority.
|
|
||||||
**Day-end state (2026-08-10 evening) + the pick-up plan.** The 881 soak measured the fault
|
|
||||||
precisely: the board answers for **~13 s after each fresh game start** (254 replies at 20 Hz),
|
|
||||||
then goes MUTE on analog for minutes while host→board writes keep completing (`req=3846 rep=254
|
|
||||||
age=240s`, txTO frozen at 1, abandon=0). Direct hand-poll (`tools/probe_rio.ps1`, also at
|
|
||||||
`C:\bt411\probe_rio.ps1` — raw COM1 CHECK/VERSION/ANALOG with correct [cmd][sum&0x7F] framing,
|
|
||||||
DTR/RTS raised): **zero bytes**. USB re-enumeration of BOTH FTDI converters + immediate re-poll:
|
|
||||||
**still zero** — which argues AGAINST the adapter (a wedged adapter RX clears on re-enum) and AT
|
|
||||||
the board. ⚠ [T4 hypothesis for tomorrow]: 13 s ≈ when the mission render load lights up — a
|
|
||||||
**power rail sagging under the cab's full load** would also explain the original mid-combat
|
|
||||||
dropouts (explosion/load transients) and the button "revival" (load dips + harness jostle).
|
|
||||||
Tomorrow, with hands: (1) loopback plug on the FTDI (TX→RX jumper, probe echoes = adapter fully
|
|
||||||
exonerated); (2) 5 V/12 V at the RIO board while a mission loads (the 13 s correlation is the
|
|
||||||
test); (3) swap in one of the spare Prolific adapters as cheap elimination; (4) rear-mobo USB
|
|
||||||
port + ghost-COM cleanup regardless. ⚠ My STALL/RECOVER edge detector in 881 keys on
|
|
||||||
request-age, which the 50 ms poll keeps resetting — it never fires; the `age=` field carries the
|
|
||||||
real signal (fix the keying to reply-age at the next build).
|
|
||||||
**Remote minidump procedure (worked over SSH, no tools install):** 32-bit dump of the wedged pid
|
|
||||||
via `C:\Windows\SysWOW64\rundll32.exe C:\Windows\SysWOW64\comsvcs.dll, MiniDump <pid>
|
|
||||||
C:\bt411\w.dmp full` → scp home → local x86 cdb (`where.exe cdb` resolves the bt411-tools copy)
|
|
||||||
with `-y C:\git\bt411\dist` (the archived per-build PDBs) → `~*k`. A 64-bit comsvcs dump of the
|
|
||||||
WOW64 process shows only 64-bit frames — use the SysWOW64 pair.
|
|
||||||
|
|
||||||
**9. ⚠ `schtasks /end` ORPHANS the game — the dead-RIO trap (2026-08-10):** `/end` kills the
|
|
||||||
batch, but `runpod.bat` `start ""`s the exe DETACHED, so the old btl4.exe survives, keeps COM1
|
|
||||||
open, and the NEXT launch boots with a dead cockpit board: `InitSerialPort() failed
|
|
||||||
[GetLastError() = 5]` (access denied) → `RIO initialization failed!` → buttons dead while the
|
|
||||||
banner still says "hardware RIO" (the banner is the PROFILE, not the init result). Diagnosis:
|
|
||||||
`tasklist /FI "IMAGENAME eq btl4.exe"` showing ≥2 instances. FIXED at the root the same day:
|
|
||||||
`runpod.bat` now `taskkill /F /IM btl4.exe`s FIRST (original saved as `runpod.bat.bak`), making
|
|
||||||
the BT411Run task an idempotent restart — but any hand-rolled launcher on a future cab needs the
|
|
||||||
same line, and a mid-mission `/run` now RESTARTS the game rather than failing quietly.
|
|
||||||
|
|
||||||
## The 1995 player manual — alignment audit (2026-07-18) [T1, primary source]
|
## The 1995 player manual — alignment audit (2026-07-18) [T1, primary source]
|
||||||
`reference/manual/Tesla40_BT_manual.pdf` (34pp, from Nick). CONFIRMS the reconstruction on
|
`reference/manual/Tesla40_BT_manual.pdf` (34pp, from Nick). CONFIRMS the reconstruction on
|
||||||
|
|||||||
@@ -696,7 +696,7 @@ reconfigure/externalConfigure); parse-skip list EMPTY ([gskip]=0), all 50 attr b
|
|||||||
| 30 | sec: schematic CRITICAL view (cmCrit) | subsystem simulationState/damage | LIVE this audit: N-cycle shows the full subsystem list (GEN A-D, LOOP 1-6, HUD, SENSORS, GYRO, TORSO, weapons) | T2 | CORRECT |
|
| 30 | sec: schematic CRITICAL view (cmCrit) | subsystem simulationState/damage | LIVE this audit: N-cycle shows the full subsystem list (GEN A-D, LOOP 1-6, HUD, SENSORS, GYRO, TORSO, weapons) | T2 | CORRECT |
|
||||||
| 31 | sec: schematic HEAT view (cmHeat) | subsystem currentTemperature tint | #6 pixel-verified; re-cycled this audit (mask 0x450421→0x490421→0x510421) | T2 | CORRECT |
|
| 31 | sec: schematic HEAT view (cmHeat) | subsystem currentTemperature tint | #6 pixel-verified; re-cycled this audit (mask 0x450421→0x490421→0x510421) | T2 | CORRECT |
|
||||||
| 32 | sec: view cycling (N / pod 0x15) | CycleDisplayMode → vtbl+0x4C @4d1ae4 | #6 resolution re-verified live ([mode] display notify 0/1/2) | T2 | CORRECT |
|
| 32 | sec: view cycling (N / pod 0x15) | CycleDisplayMode → vtbl+0x4C @4d1ae4 | #6 resolution re-verified live ([mode] display notify 0/1/2) | T2 | CORRECT |
|
||||||
| 33 | sec: CONTROL MODE lamp (BAS/MID/ADV) | ControlsMapper/DisplayMode oneOfSeveralPixInt | attr wave incr.5; M-cycle verified #6 | T2 | CORRECT |
|
| 33 | sec: CONTROL MODE lamp (BAS/MID/ADV) | ControlsMapper/**ControlMode** oneOfSeveralPixInt (row previously mislabeled DisplayMode — that is the sibling sdspmod) | attr wave incr.5; M-cycle verified #6. **2026-08-10:** this row's verification PREDATED the 07-25 #48 cycle-fill, which then lit the inactive box interiors (art idx 254 → live armor slot 62) — playtester-reported, re-fixed by mapping out-of-range indices to plane background (see context/gauges-hud.md §#48 REFINED); both render paths re-verified against the reference | T2 | CORRECT |
|
||||||
| 34 | sec: duck / searchlight button lamps | duckState (ctor-zeroed only) / Searchlight LightOn | duckState writer missing (P3 leftover) | T3 | DEFERRED-FEED (duck); CORRECT (light attr published) |
|
| 34 | sec: duck / searchlight button lamps | duckState (ctor-zeroed only) / Searchlight LightOn | duckState writer missing (P3 leftover) | T3 | DEFERRED-FEED (duck); CORRECT (light attr published) |
|
||||||
| 35 | sec: messageBoard ticker | StatusMessagePool (NULL stub) + kill ticker strip 0 | 7fc4acb; kill ticker live 2026-07-12, other strips unsurveyed | T2/T3 | DEFERRED-FEED (partial) |
|
| 35 | sec: messageBoard ticker | StatusMessagePool (NULL stub) + kill ticker strip 0 | 7fc4acb; kill ticker live 2026-07-12, other strips unsurveyed | T2/T3 | DEFERRED-FEED (partial) |
|
||||||
| 36 | MFD preset paging (J/K/L, pod RIO banks) | SetPresetMode table @0051dbf0 (little-endian re-decode) | #9; re-verified live this audit: cycles visit EXACTLY the populated set (MFD1: 1,2,4; MFD2: 1-4; MFD3: 1,2) | T2 | CORRECT |
|
| 36 | MFD preset paging (J/K/L, pod RIO banks) | SetPresetMode table @0051dbf0 (little-endian re-decode) | #9; re-verified live this audit: cycles visit EXACTLY the populated set (MFD1: 1,2,4; MFD2: 1-4; MFD3: 1,2) | T2 | CORRECT |
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ cavern.egg`. This is every option the original console exposed for a BattleTech
|
|||||||
- experience (4 [T1 game decode]): novice, standard, veteran, expert ← was hardcoded `expert`
|
- experience (4 [T1 game decode]): novice, standard, veteran, expert ← was hardcoded `expert`
|
||||||
- vehicle (18, friendly→tag): Black Hawk=blkhawk, Loki=loki, Nova=bhk1, Mad Cat=madcat, Thor=thor,
|
- vehicle (18, friendly→tag): Black Hawk=blkhawk, Loki=loki, Nova=bhk1, Mad Cat=madcat, Thor=thor,
|
||||||
Owens=owens, Kotori=own1, Summoner=thr1, Hellbringer=lok1, Timber Wolf=mad1, Avatar=avatar,
|
Owens=owens, Kotori=own1, Summoner=thr1, Hellbringer=lok1, Timber Wolf=mad1, Avatar=avatar,
|
||||||
Satyr=ava1, Sunder=sunder, Denkou=snd1 (#69), Vulture=vulture, Mad Dog=vul1, Mischief=lok2,
|
Satyr=ava1, Sunder=sunder, Sunder V1=snd1, Vulture=vulture, Mad Dog=vul1, Mischief=lok2,
|
||||||
Zanin Neko=mad2 (the 18 ModelList names; matches the 2026-07-18 vehicle sweep)
|
Zanin Neko=mad2 (the 18 ModelList names; matches the 2026-07-18 vehicle sweep)
|
||||||
- color/camo (7, display→tag): White=White, Black=Black, Brown=Brown, Red=**Crimson**, Green=Green,
|
- color/camo (7, display→tag): White=White, Black=Black, Brown=Brown, Red=**Crimson**, Green=Green,
|
||||||
Gray=**Grey**, Tan=Tan ← was White/Black/Crimson only
|
Gray=**Grey**, Tan=Tan ← was White/Black/Crimson only
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
=============================================================================
|
|
||||||
BT411 -- ALL OPEN TRACKER ISSUES (59), SORTED FOR PLAYTESTERS
|
|
||||||
Updated 2026-08-10 (evening) -- after Oracle's full annotated sweep, which
|
|
||||||
closed 35 issues. Thank you Oracle: that is what this list is for.
|
|
||||||
=============================================================================
|
|
||||||
HOW TO REPORT: drop a line in Discord with the issue number and PASS /
|
|
||||||
FAIL / what you saw. Screenshots and rough times help; logs get collected
|
|
||||||
as usual.
|
|
||||||
=============================================================================
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
A. FIXED -- PLEASE VERIFY (headliners first: new fixes fielded THIS build)
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
#149 Glass cockpit stutter / hitching ** HEADLINER **
|
|
||||||
First fielded build with the fix. Glass users -- especially Oracle:
|
|
||||||
mission load and play should feel smooth again (repaints now skip
|
|
||||||
windows whose gauges did not change).
|
|
||||||
#150 Double kill credit (one kill counted twice) ** HEADLINER **
|
|
||||||
First fielded build with the fix (868's double-kills were pre-fix).
|
|
||||||
TEST: kill someone with a missile volley -- scoreboard +1, not +2.
|
|
||||||
#69 "Sunder V1" renamed to DENKOU
|
|
||||||
TEST: vehicle picker shows Denkou -- era witnesses, confirm spelling.
|
|
||||||
#71 Closing the Plasma window lost it until restart
|
|
||||||
TEST: X the plasma window -- it minimizes to the taskbar; click restores.
|
|
||||||
#25 Gamepad turn profile (stick X could not turn the mech)
|
|
||||||
TEST: RajelAran -- bind an axis to "Turn" in content\bindings.txt.
|
|
||||||
#27 Autocannon/Gauss dealt the wrong damage type
|
|
||||||
Oracle asked for a RETEST before closing: ballistics should feel/score
|
|
||||||
like solid shot (no blast splash).
|
|
||||||
#38 Mech colors reverted on respawn
|
|
||||||
TEST: custom paint, die, respawn -- colors stay.
|
|
||||||
#39 Controls were live before the game screen appeared
|
|
||||||
TEST: mash fire during load -- nothing happens until the scene shows.
|
|
||||||
#41 (David/Auric) launcher killed before it could run -- forensics armed
|
|
||||||
TEST: if join.bat ever fails again, send content\lastrun_join.txt.
|
|
||||||
#56 MFD buttons drift away from where they are drawn
|
|
||||||
TEST: alt-tab / focus changes mid-round -- buttons stay aligned.
|
|
||||||
#147 Range caret vanished for the session (ticks stayed)
|
|
||||||
Monitoring: if it happens, the log traps the culprit -- just report it.
|
|
||||||
#158 (Sauron) could not move after respawn until throttle cycled
|
|
||||||
TEST when it happens: does cycling the throttle free you?
|
|
||||||
YES -> the #146 release mechanic (expected). NO -> map + spawn spot.
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
B. OPEN -- HELP US REPRODUCE / NARROW (what to note when it happens)
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
#24 Controller hat/look view sticks (recovers after wiggling)
|
|
||||||
#37 Mech torso appears BACKWARDS to other players (transient)
|
|
||||||
#74 8BitDo gamepad works solo, dead in Steam MP (VexUbiquity)
|
|
||||||
#102 Owens: full-throttle run -> hold reverse = animation/audio hang
|
|
||||||
REPRO known (exterior cam, savannah); self-clears on a torso twist.
|
|
||||||
#125 Peers do not see the FIRST destroyed-zone graphic (2nd hit shows it)
|
|
||||||
#126 Peer weapon fire invisible AND silent from some positions
|
|
||||||
#128 Ramming terrain = INSTANT coolant leak -- Oracle re-confirms STILL LIVE
|
|
||||||
#130 Vulture "skating" (gliding without walk animation)
|
|
||||||
#132 (Conn Man) persistent yellow line on the HUD in every mech
|
|
||||||
#135 Coolant leak with NO flashing annunciators -- Oracle re-confirms LIVE
|
|
||||||
#136 A SHUT leaking loop starts/stops leaking with COMPONENT toggles
|
|
||||||
(Oracle marked "Clarify" -- one more description pass requested.)
|
|
||||||
#143 One panel hit -> smoke erupts from MULTIPLE places at once
|
|
||||||
#153 Basic-mode elevation limit only applies after cycling modes (fix pending)
|
|
||||||
#154 Generator Out warning fires on the WRONG EDGE (at recovery, not trip)
|
|
||||||
Refined by Oracle: the stuck-forever gen did NOT reproduce; era rule =
|
|
||||||
gens return at HALF-cooled (red bar portion gone). Threshold audit due.
|
|
||||||
#155 PANIC lit: Eng + Weapon MFD banks dead; Score/Radar/Coolant stay live
|
|
||||||
(Oracle mapped the exact bank split; #50 closed into this ticket.
|
|
||||||
Flicker half = authentic. Next: is the bank capture authentic too?)
|
|
||||||
#159 (Conn Man) lag during drops -- missiles / fire exploding in empty space
|
|
||||||
NOTE: shooter + target + rough time; match receipts measure the rest.
|
|
||||||
#160 Pod cab: RIO axis dropouts + boot wedges (hardware investigation)
|
|
||||||
Cab-side only. Bounded-write hardening is in this build; the cage
|
|
||||||
hardware work continues with Nick.
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
C. STILL-OPEN ERA QUESTIONS
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
#103 Mech-to-mech RAM: armor damage or internals only? (Oracle: don't know;
|
|
||||||
Lynx / Ronin / Draco -- your call. Binary does internals-only.)
|
|
||||||
#133 Generator X-out on the MFD: Oracle recalls an X "under certain
|
|
||||||
circumstances" -- WHICH circumstances? (shutdown / overheat / destroyed)
|
|
||||||
ALSO (#152 rider): did Mid/Adv auto-recentre the torso in the pod, or only
|
|
||||||
Basic? (Oracle: don't know. Binary says: no auto-recentre.)
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
D. DESIGN CALLS -- group opinions wanted
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
#151 Panic eject costs -499: verified REAL 1995 scoring (your death scored
|
|
||||||
as suicide + death penalty). Keep authentic, or house-rule a flat cost?
|
|
||||||
#23 Non-glass screen layout: Oracle proposes widescreen-aware sizing --
|
|
||||||
world view wider + taller, moved up, allowed to overlap the radar.
|
|
||||||
Opinions welcome before anyone prototypes it.
|
|
||||||
#77 Resizable Secondary/Radar window (touch-panel cockpits). Want it?
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
E. KNOWN GAPS -- confirmed and on the list, no need to re-report
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
#49 Radar/map does not draw the arena WALL geometry
|
|
||||||
#76 Glass layout save/restore rework (some windows not saved)
|
|
||||||
#83 INCOMING MISSILE alarm not implemented yet
|
|
||||||
#90 Flames/smoke from serious damage: less than the original (tuning)
|
|
||||||
#104 Mad Dog "NARC 15" label: NARC postdates our 4.10 binary (Oracle: added
|
|
||||||
in a late 4.x release; zero NARC in our decomp) -- content rename due.
|
|
||||||
#105 Sensor damage effects: Oracle's era spec captured (HUD flicker/loss,
|
|
||||||
radar loss) -- implementation pending.
|
|
||||||
#111 Peers see a dying mech's blue warp bubble (should see explosion only)
|
|
||||||
#112 AFC rounds shotgun across zones (should land as one projectile)
|
|
||||||
#113 LRM burn/hit state lasts too long
|
|
||||||
#115 Hot box / target select not connected (Oracle era note: hotbox was a
|
|
||||||
STANDARD-mode feature; absent in Expert -- gating to reconcile)
|
|
||||||
#121 Sensor HEAT has no consequences yet
|
|
||||||
#123 Searchlight: the visible LIGHT + night-fog swap still to come
|
|
||||||
#145 IR "predator vision": decode done, display not implemented
|
|
||||||
#156 Fade-to-black at mission end not happening
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
F. INTERNAL ENGINEERING BACKLOG (nothing to test)
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
#14 Glass panel unreconstructed button handler backlog (census)
|
|
||||||
#17 Cavern upper-butte halves lack a collision stream (authenticity TBD)
|
|
||||||
#21 Weapon recharge arc dark after eng-page use (symptom trail -> #62)
|
|
||||||
#28 Confirm the vital-subsystem-crit death path can fire (machinery in)
|
|
||||||
#30 Weapon "unavailable" (level-7) display verification + accessor cleanup
|
|
||||||
#63 PlayerStatus reads raw 1995 offsets (databinding trap, dormant)
|
|
||||||
#64 damageZone shadow field (half-fixed; consequences disarmed)
|
|
||||||
#65 HandleMessage non-virtual across 10 classes (latent dispatch trap)
|
|
||||||
#72 BTLoadPump swallows WM_QUIT during load (latent)
|
|
||||||
#107 Destroyed HeatSink annunciates nothing (no lamp for condition 0)
|
|
||||||
#117 KB note: per-chassis cockpit bounce was deliberate (Ronin) -- FYI
|
|
||||||
|
|
||||||
=============================================================================
|
|
||||||
End of list. 59 open issues total:
|
|
||||||
12 verify (2 headliners), 17 reproduce, 3 era questions, 3 design calls,
|
|
||||||
14 known gaps, 11 internal.
|
|
||||||
35 issues closed 2026-08-10 on Oracle's annotated sweep.
|
|
||||||
=============================================================================
|
|
||||||
@@ -2121,21 +2121,12 @@ static unsigned long
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
// [rio] health printer (L4RIO.cpp): the serial poll path only COUNTS (kept
|
|
||||||
// I/O-free by design; the 2026-08-10 wedges once blamed on prints there were
|
|
||||||
// really the USB-serial adapter hanging an unbounded overlapped write --
|
|
||||||
// see PCSerialPacket::SendPacket); the report rides this tick, which
|
|
||||||
// already streams [glassperf] every second.
|
|
||||||
extern "C" void BTRioHealthReport();
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BTGlassPanels_Tick()
|
BTGlassPanels_Tick()
|
||||||
{
|
{
|
||||||
if (gWinCount == 0)
|
if (gWinCount == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BTRioHealthReport();
|
|
||||||
|
|
||||||
static unsigned long sLastPaint = 0;
|
static unsigned long sLastPaint = 0;
|
||||||
unsigned long now = GetTickCount();
|
unsigned long now = GetTickCount();
|
||||||
if (now - sLastPaint < (unsigned long)RepaintMilliseconds)
|
if (now - sLastPaint < (unsigned long)RepaintMilliseconds)
|
||||||
|
|||||||
@@ -410,20 +410,6 @@ int PCSerialPacket::ReceivePacket(BYTE *destPtr) // returns len (zero if none)
|
|||||||
// Returns:
|
// Returns:
|
||||||
// void
|
// void
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
//
|
|
||||||
// Serial-write health (see the bounded wait below): after a write timeout
|
|
||||||
// the link is SICK for 3 s and writes fast-drop -- one stall, not one per
|
|
||||||
// poll. BTPcspakTxTimeouts feeds the [rio] telemetry.
|
|
||||||
//
|
|
||||||
static unsigned gPcspakTxTimeout = 0;
|
|
||||||
static DWORD gPcspakTxSickUntil = 0;
|
|
||||||
|
|
||||||
extern "C" unsigned
|
|
||||||
BTPcspakTxTimeouts()
|
|
||||||
{
|
|
||||||
return gPcspakTxTimeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PCSerialPacket::SendPacket(BYTE *srcPtr) //sends packet
|
void PCSerialPacket::SendPacket(BYTE *srcPtr) //sends packet
|
||||||
{
|
{
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
@@ -432,11 +418,6 @@ void PCSerialPacket::SendPacket(BYTE *srcPtr) //sends packet
|
|||||||
if(!enabled) //if disabled, don't even try
|
if(!enabled) //if disabled, don't even try
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (gPcspakTxSickUntil != 0 && GetTickCount() < gPcspakTxSickUntil)
|
|
||||||
{
|
|
||||||
return; // adapter sick: drop, don't stall
|
|
||||||
}
|
|
||||||
|
|
||||||
BYTE cmd = *srcPtr; //get the command byte
|
BYTE cmd = *srcPtr; //get the command byte
|
||||||
cmd &= 0x7F; //remove MSB
|
cmd &= 0x7F; //remove MSB
|
||||||
int length = txLengthPtr[cmd]; //get the length in al
|
int length = txLengthPtr[cmd]; //get the length in al
|
||||||
@@ -478,37 +459,11 @@ void PCSerialPacket::SendPacket(BYTE *srcPtr) //sends packet
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
DWORD bytesWritten;
|
||||||
// BOUNDED completion wait (2026-08-10, ALPHA-MR field minidump). The
|
GetOverlappedResult(hComm, &overlapSend, &bytesWritten, TRUE);
|
||||||
// RIO's "COM1" is a USB-serial adapter; when its USB link drops with a
|
if(bytesWritten != length + 1)
|
||||||
// write in flight the overlapped write NEVER completes, and the original
|
|
||||||
// GetOverlappedResult(..., TRUE) parked the whole game at 0 CPU forever
|
|
||||||
// (cdb-proven: NtWaitForSingleObject <- GetOverlappedResult <-
|
|
||||||
// SendPacket <- RIO ctor). Now: 500 ms bound (9600 baud needs ~21 ms),
|
|
||||||
// CancelIo on expiry, and a 3 s SICK window that fast-drops writes so a
|
|
||||||
// dead adapter costs one stall, not one per 50 ms poll -- the game stays
|
|
||||||
// at frame rate with a degraded RIO and the keyboard fallback alive.
|
|
||||||
// gPcspakTxTimeout feeds the [rio] health line (txTO=).
|
|
||||||
//
|
|
||||||
DWORD bytesWritten = 0;
|
|
||||||
DWORD wait_result = WaitForSingleObject(overlapSend.hEvent, 500);
|
|
||||||
if (wait_result == WAIT_OBJECT_0)
|
|
||||||
{
|
{
|
||||||
GetOverlappedResult(hComm, &overlapSend, &bytesWritten, FALSE);
|
DEBUG_STREAM << "Not all data was written to serial port!\n" << std::flush;
|
||||||
gPcspakTxSickUntil = 0;
|
|
||||||
if (bytesWritten != (DWORD)(length + 1))
|
|
||||||
{
|
|
||||||
DEBUG_STREAM << "Not all data was written to serial port!\n"
|
|
||||||
<< std::flush;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No print here -- serial-path discipline; the counter surfaces in
|
|
||||||
// the [rio] health line (txTO=) from the glass-tick printer.
|
|
||||||
CancelIo(hComm);
|
|
||||||
++gPcspakTxTimeout;
|
|
||||||
gPcspakTxSickUntil = GetTickCount() + 3000;
|
|
||||||
}
|
}
|
||||||
delete buffer;
|
delete buffer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,11 +25,7 @@ static LRESULT CALLBACK
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
// Minimize, never hide (#71): SW_HIDE left no way back short of a
|
ShowWindow(window, SW_HIDE); // hide only; the renderer owns it
|
||||||
// restart. A minimized window keeps its taskbar button (both framed
|
|
||||||
// and ,noframe styles), so the player can recover the display. The
|
|
||||||
// renderer still owns the window either way.
|
|
||||||
ShowWindow(window, SW_MINIMIZE);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return DefWindowProcW(window, message, wparam, lparam);
|
return DefWindowProcW(window, message, wparam, lparam);
|
||||||
|
|||||||
@@ -1240,105 +1240,6 @@ RIO::~RIO()
|
|||||||
Check_Fpu();
|
Check_Fpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// [rio] telemetry state (see the tracking block in GetNextEvent). File-scope
|
|
||||||
// statics on purpose: one hardware RIO per process, no header/layout churn --
|
|
||||||
// and the PRINTER (BTRioHealthReport, called from the glass tick) reads ONLY
|
|
||||||
// these statics, never RIO members, so it needs no instance and touches
|
|
||||||
// nothing the serial layer locks.
|
|
||||||
//
|
|
||||||
static int gRioPresent = 0;
|
|
||||||
static unsigned gRioReqCount = 0;
|
|
||||||
static unsigned gRioRepCount = 0;
|
|
||||||
static unsigned gRioBtnCount = 0;
|
|
||||||
static int gRioReqPending = 0;
|
|
||||||
static DWORD gRioLastReqTick = 0;
|
|
||||||
static DWORD gRioLastReplyTick = 0;
|
|
||||||
static int gRioStallActive = 0;
|
|
||||||
static DWORD gRioStallStart = 0;
|
|
||||||
static unsigned gRioStallBtnBase = 0;
|
|
||||||
static unsigned gRioStallCount = 0;
|
|
||||||
static DWORD gRioLastStallMs = 0;
|
|
||||||
static unsigned gRioLastStallBtns = 0;
|
|
||||||
static unsigned gRioLineErrMirror = 0;
|
|
||||||
static unsigned gRioOverrunMirror = 0;
|
|
||||||
static unsigned gRioAbandonMirror = 0;
|
|
||||||
static unsigned gRioRRetryMirror = 0;
|
|
||||||
static unsigned gRioRAbandonMirror = 0;
|
|
||||||
static unsigned gRioRFullMirror = 0;
|
|
||||||
|
|
||||||
extern "C" unsigned BTPcspakTxTimeouts(); // L4PCSPAK.cpp: bounded-write stat
|
|
||||||
|
|
||||||
//
|
|
||||||
// The printer half -- called from BTGlassPanels_Tick beside the [glassperf]
|
|
||||||
// report (a stream site that prints every second without incident), NEVER
|
|
||||||
// from the serial path. Edge lines land at the tick's ~1 s granularity,
|
|
||||||
// ample for the multi-second field dropouts this exists to catch.
|
|
||||||
// BT_RIO_LOG=0 opts out; silent when no hardware RIO ever came up.
|
|
||||||
//
|
|
||||||
extern "C" void
|
|
||||||
BTRioHealthReport()
|
|
||||||
{
|
|
||||||
static int sLog = -1;
|
|
||||||
static DWORD sLastLine = 0;
|
|
||||||
static unsigned sSeenStalls = 0;
|
|
||||||
static int sSawActive = 0;
|
|
||||||
|
|
||||||
if (!gRioPresent)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (sLog < 0)
|
|
||||||
{
|
|
||||||
const char *e = getenv("BT_RIO_LOG");
|
|
||||||
sLog = (e != 0 && *e == '0') ? 0 : 1;
|
|
||||||
}
|
|
||||||
if (!sLog)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD now = GetTickCount();
|
|
||||||
if (gRioStallActive && !sSawActive)
|
|
||||||
{
|
|
||||||
sSawActive = 1;
|
|
||||||
DEBUG_STREAM << "[rio] STALL analog silent "
|
|
||||||
<< (now - gRioStallStart) << "ms and counting req="
|
|
||||||
<< gRioReqCount << " rep=" << gRioRepCount
|
|
||||||
<< "\n" << std::flush;
|
|
||||||
}
|
|
||||||
else if (!gRioStallActive && sSawActive)
|
|
||||||
{
|
|
||||||
sSawActive = 0;
|
|
||||||
}
|
|
||||||
if (sSeenStalls != gRioStallCount)
|
|
||||||
{
|
|
||||||
sSeenStalls = gRioStallCount;
|
|
||||||
DEBUG_STREAM << "[rio] RECOVER stall#" << gRioStallCount
|
|
||||||
<< " lasted " << gRioLastStallMs
|
|
||||||
<< "ms btnDuring=" << gRioLastStallBtns
|
|
||||||
<< "\n" << std::flush;
|
|
||||||
}
|
|
||||||
if (now - sLastLine >= 5000)
|
|
||||||
{
|
|
||||||
sLastLine = now;
|
|
||||||
DEBUG_STREAM << "[rio] req=" << gRioReqCount
|
|
||||||
<< " rep=" << gRioRepCount
|
|
||||||
<< " btn=" << gRioBtnCount
|
|
||||||
<< " age=" << (gRioLastReplyTick != 0
|
|
||||||
? (now - gRioLastReplyTick) : 0)
|
|
||||||
<< "ms stalls=" << gRioStallCount
|
|
||||||
<< " txTO=" << BTPcspakTxTimeouts()
|
|
||||||
<< " lineErr=" << gRioLineErrMirror
|
|
||||||
<< " overrun=" << gRioOverrunMirror
|
|
||||||
<< " abandon=" << gRioAbandonMirror
|
|
||||||
<< " rRetry=" << gRioRRetryMirror
|
|
||||||
<< " rAbandon=" << gRioRAbandonMirror
|
|
||||||
<< " rFull=" << gRioRFullMirror
|
|
||||||
<< "\n" << std::flush;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Logical
|
Logical
|
||||||
RIO::TestInstance() const
|
RIO::TestInstance() const
|
||||||
{
|
{
|
||||||
@@ -1363,36 +1264,6 @@ Logical
|
|||||||
Logical reply, looping;
|
Logical reply, looping;
|
||||||
Word errors;
|
Word errors;
|
||||||
|
|
||||||
//
|
|
||||||
// [rio] link-health TRACKING -- pure arithmetic, no I/O here by design.
|
|
||||||
// CORRECTED HISTORY (2026-08-10): the boot wedges first blamed on prints
|
|
||||||
// from this path were actually the USB-serial adapter dropping its link
|
|
||||||
// with a write in flight -- the unbounded GetOverlappedResult in
|
|
||||||
// PCSerialPacket::SendPacket parked the game (minidump-proven; the
|
|
||||||
// print-deadlock A/B was confounded by the adapter behaving that boot).
|
|
||||||
// The count-here / print-from-the-glass-tick split stays anyway: it
|
|
||||||
// keeps this hot polled path I/O-free and the printer at one known
|
|
||||||
// stream site (BTRioHealthReport below, beside [glassperf]).
|
|
||||||
//
|
|
||||||
if (operational)
|
|
||||||
{
|
|
||||||
DWORD now = GetTickCount();
|
|
||||||
if (!gRioStallActive && gRioReqPending
|
|
||||||
&& now - gRioLastReqTick > 500)
|
|
||||||
{
|
|
||||||
gRioStallActive = 1;
|
|
||||||
gRioStallStart = gRioLastReqTick;
|
|
||||||
gRioStallBtnBase = gRioBtnCount;
|
|
||||||
}
|
|
||||||
gRioPresent = 1;
|
|
||||||
gRioLineErrMirror = (unsigned) lineErrorCount;
|
|
||||||
gRioOverrunMirror = (unsigned) overrunCount;
|
|
||||||
gRioAbandonMirror = (unsigned) abandonCount;
|
|
||||||
gRioRRetryMirror = (unsigned) remoteRetryCount;
|
|
||||||
gRioRAbandonMirror = (unsigned) remoteAbandonCount;
|
|
||||||
gRioRFullMirror = (unsigned) remoteFullBufferCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
//PCSPAKState(this);
|
//PCSPAKState(this);
|
||||||
//
|
//
|
||||||
//cout << flush;
|
//cout << flush;
|
||||||
@@ -1506,20 +1377,6 @@ Logical
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case AnalogReply:
|
case AnalogReply:
|
||||||
++gRioRepCount;
|
|
||||||
gRioReqPending = 0;
|
|
||||||
gRioLastReplyTick = GetTickCount();
|
|
||||||
if (gRioStallActive)
|
|
||||||
{
|
|
||||||
// The reply that ended the drought -- record only; the
|
|
||||||
// glass-tick printer emits the RECOVER line. btnDuring
|
|
||||||
// is the field theory's verdict: >0 on every recover =
|
|
||||||
// button traffic resyncs the link; 0 = it self-heals.
|
|
||||||
gRioStallActive = 0;
|
|
||||||
++gRioStallCount;
|
|
||||||
gRioLastStallMs = gRioLastReplyTick - gRioStallStart;
|
|
||||||
gRioLastStallBtns = gRioBtnCount - gRioStallBtnBase;
|
|
||||||
}
|
|
||||||
destination->Type = RIO::AnalogEvent;
|
destination->Type = RIO::AnalogEvent;
|
||||||
//
|
//
|
||||||
// NOTE: no data is sent in this packet.
|
// NOTE: no data is sent in this packet.
|
||||||
@@ -1566,13 +1423,11 @@ Logical
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ButtonPressed:
|
case ButtonPressed:
|
||||||
++gRioBtnCount;
|
|
||||||
destination->Type = RIO::ButtonPressedEvent;
|
destination->Type = RIO::ButtonPressedEvent;
|
||||||
destination->Data.Unit = receive_buffer[1];
|
destination->Data.Unit = receive_buffer[1];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ButtonReleased:
|
case ButtonReleased:
|
||||||
++gRioBtnCount;
|
|
||||||
destination->Type = RIO::ButtonReleasedEvent;
|
destination->Type = RIO::ButtonReleasedEvent;
|
||||||
destination->Data.Unit = receive_buffer[1];
|
destination->Data.Unit = receive_buffer[1];
|
||||||
break;
|
break;
|
||||||
@@ -1713,9 +1568,6 @@ void
|
|||||||
if (operational && !TestModeActive)
|
if (operational && !TestModeActive)
|
||||||
{
|
{
|
||||||
SendPacket((Byte *) request_analog_string);
|
SendPacket((Byte *) request_analog_string);
|
||||||
++gRioReqCount;
|
|
||||||
gRioReqPending = 1;
|
|
||||||
gRioLastReqTick = GetTickCount();
|
|
||||||
}
|
}
|
||||||
Check_Fpu();
|
Check_Fpu();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7557,17 +7557,28 @@ void
|
|||||||
// LEFT AS HEAP GARBAGE and any pixmap pixel >= that count wrote the
|
// LEFT AS HEAP GARBAGE and any pixmap pixel >= that count wrote the
|
||||||
// garbage's high bits into other displays' planes (the #48 stray
|
// garbage's high bits into other displays' planes (the #48 stray
|
||||||
// blocks; convicted live by BT_PLANE_AUDIT -- the 480x640 radar
|
// blocks; convicted live by BT_PLANE_AUDIT -- the 480x640 radar
|
||||||
// background carries index 217). Cycle the in-plane pattern across
|
// background carries index 217). Map the remainder to the plane
|
||||||
// the remainder: high-index art degrades to its (index mod 2^bits)
|
// BACKGROUND (translationTable[0]): high-index art renders as the
|
||||||
// colour IN-PLANE, and can never leak. (The 1995 binary shipped the
|
// port's background colour in-plane, and can never leak.
|
||||||
// same 64-entry fill and relied on art discipline; garbage is not a
|
//
|
||||||
// preservable behaviour, so this is a guarded PORT deviation.)
|
// REFINED 2026-08-10 (the sec-surface phantoms): the first #48 fill
|
||||||
|
// cycled the remainder IN-PLANE (index mod 2^bits), which mapped art
|
||||||
|
// index 254 onto plane slot 62 -- a LIVE colorMapperMultiArmor damage
|
||||||
|
// slot. SMODE.PCC's inactive control-mode box interiors and a stray
|
||||||
|
// 52x13 idx-254 bar baked into BTSEC1.PCX (between the heading dial
|
||||||
|
// and the armor rosette) lit up in the current right-armor damage
|
||||||
|
// colour on every render path. On the shipped machine those regions
|
||||||
|
// rendered BLACK (the heap garbage's low plane bits were 0 ->
|
||||||
|
// in-plane index 0), so background IS the authentic on-screen result.
|
||||||
|
// (The 1995 binary shipped the same 64-entry fill and relied on art
|
||||||
|
// discipline; garbage is not a preservable behaviour, so this stays a
|
||||||
|
// guarded PORT deviation.)
|
||||||
{
|
{
|
||||||
int filled = 1;
|
int filled = 1;
|
||||||
for (int b = bitMask & 0xFF; b != 0; b &= (b - 1))
|
for (int b = bitMask & 0xFF; b != 0; b &= (b - 1))
|
||||||
filled <<= 1;
|
filled <<= 1;
|
||||||
for (int i = filled; i < 256; ++i)
|
for (int i = filled; i < 256; ++i)
|
||||||
translationTable[i] = translationTable[i & (filled - 1)];
|
translationTable[i] = translationTable[0];
|
||||||
}
|
}
|
||||||
Check_Fpu();
|
Check_Fpu();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,36 +234,6 @@ static LONG WINAPI
|
|||||||
return EXCEPTION_EXECUTE_HANDLER; // die (after the evidence is out)
|
return EXCEPTION_EXECUTE_HANDLER; // die (after the evidence is out)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// lastrun_<stem>.txt clean-exit markers (#157, 2026-08-10): the launch record
|
|
||||||
// only ever said "exe reached WinMain", so a night that ended with the player
|
|
||||||
// closing the menu was indistinguishable from a silent death -- and the bat's
|
|
||||||
// sign-off taught players to report normal quits as crashes. The deliberate
|
|
||||||
// exit paths stamp the record themselves now, so the file answers "crash or
|
|
||||||
// quit?" on its own. Name captured at breadcrumb time (cwd is content\ by
|
|
||||||
// then -- the same file the bats bracket).
|
|
||||||
//
|
|
||||||
static char gBTLastrunName[MAX_PATH] = "";
|
|
||||||
|
|
||||||
void
|
|
||||||
BTLastrunNote(const char *note)
|
|
||||||
{
|
|
||||||
if (gBTLastrunName[0] == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SYSTEMTIME lt;
|
|
||||||
GetLocalTime(<);
|
|
||||||
std::ofstream f(gBTLastrunName, std::ios::out | std::ios::app);
|
|
||||||
if (f.is_open())
|
|
||||||
{
|
|
||||||
char stamp[64];
|
|
||||||
wsprintfA(stamp, "[%04d-%02d-%02d %02d:%02d:%02d] ",
|
|
||||||
lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond);
|
|
||||||
f << stamp << note << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================================================================//
|
//===========================================================================//
|
||||||
// environ.ini -- the player's settings file (cwd = content\). One KEY=VALUE
|
// environ.ini -- the player's settings file (cwd = content\). One KEY=VALUE
|
||||||
// per line; the real environment always WINS, so a launcher .bat or a shell
|
// per line; the real environment always WINS, so a launcher .bat or a shell
|
||||||
@@ -863,7 +833,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
GetComputerNameA(machine, &machine_len);
|
GetComputerNameA(machine, &machine_len);
|
||||||
char lastrun_name[MAX_PATH];
|
char lastrun_name[MAX_PATH];
|
||||||
wsprintfA(lastrun_name, "lastrun_%s.txt", logStem);
|
wsprintfA(lastrun_name, "lastrun_%s.txt", logStem);
|
||||||
lstrcpynA(gBTLastrunName, lastrun_name, MAX_PATH);
|
|
||||||
std::ofstream breadcrumb(lastrun_name, std::ios::out | std::ios::app);
|
std::ofstream breadcrumb(lastrun_name, std::ios::out | std::ios::app);
|
||||||
if (breadcrumb.is_open())
|
if (breadcrumb.is_open())
|
||||||
{
|
{
|
||||||
@@ -1240,7 +1209,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
BTFeLaunchSpec fe_spec;
|
BTFeLaunchSpec fe_spec;
|
||||||
if (BTFrontEnd_Run(&fe_spec) != 0 || fe_spec.mode == BTFeLaunchNone)
|
if (BTFrontEnd_Run(&fe_spec) != 0 || fe_spec.mode == BTFeLaunchNone)
|
||||||
{
|
{
|
||||||
BTLastrunNote("clean exit: player quit from the menu");
|
|
||||||
return 0; // quit from the menu
|
return 0; // quit from the menu
|
||||||
}
|
}
|
||||||
char fe_arguments[192];
|
char fe_arguments[192];
|
||||||
|
|||||||
@@ -174,8 +174,6 @@ void
|
|||||||
{
|
{
|
||||||
MarshalLog("window closed by the user -- exiting for real "
|
MarshalLog("window closed by the user -- exiting for real "
|
||||||
"(no relaunch)");
|
"(no relaunch)");
|
||||||
extern void BTLastrunNote(const char *);
|
|
||||||
BTLastrunNote("clean exit: player closed the game window");
|
|
||||||
ExitProcess(0);
|
ExitProcess(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,16 +257,6 @@ void
|
|||||||
if (CreateProcessW(exe_path, command_line, NULL, NULL, FALSE,
|
if (CreateProcessW(exe_path, command_line, NULL, NULL, FALSE,
|
||||||
0, NULL, NULL, &startup, &process))
|
0, NULL, NULL, &startup, &process))
|
||||||
{
|
{
|
||||||
// Hand the child our foreground right BEFORE we die (#157): Windows
|
|
||||||
// refuses SetForegroundWindow to a process spawned by an exiting
|
|
||||||
// background parent, so the round-end menu could open BEHIND the
|
|
||||||
// desktop clutter -- which is how a normal between-rounds relaunch
|
|
||||||
// read as "the game crashed" from the cockpit seat.
|
|
||||||
if (!AllowSetForegroundWindow(process.dwProcessId))
|
|
||||||
{
|
|
||||||
MarshalLog("foreground handoff denied -- the next window may "
|
|
||||||
"open behind");
|
|
||||||
}
|
|
||||||
CloseHandle(process.hThread);
|
CloseHandle(process.hThread);
|
||||||
CloseHandle(process.hProcess);
|
CloseHandle(process.hProcess);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -412,7 +412,7 @@ static const CatalogEntry kVehicles[] =
|
|||||||
{ "avatar", "Avatar" },
|
{ "avatar", "Avatar" },
|
||||||
{ "ava1", "Satyr" },
|
{ "ava1", "Satyr" },
|
||||||
{ "sunder", "Sunder" },
|
{ "sunder", "Sunder" },
|
||||||
{ "snd1", "Denkou" }, // #69: the 4.x-era name (two era witnesses)
|
{ "snd1", "Sunder V1" },
|
||||||
{ "vulture", "Vulture" },
|
{ "vulture", "Vulture" },
|
||||||
{ "vul1", "Mad Dog" },
|
{ "vul1", "Mad Dog" },
|
||||||
{ "lok2", "Mischief" },
|
{ "lok2", "Mischief" },
|
||||||
|
|||||||
@@ -1032,12 +1032,6 @@ void
|
|||||||
{
|
{
|
||||||
Check(message);
|
Check(message);
|
||||||
|
|
||||||
// #150 -- the binary's ONCE-PER-DEATH latch (local_14 @0x4a0230 body,
|
|
||||||
// part_012.c:14625-14629): IsMechDestroyed() sampled AT ENTRY. The kill
|
|
||||||
// report posts only on the 0->1 edge (!destroyedAtEntry && destroyed-now);
|
|
||||||
// a later salvo of the killing volley takes the inflicted-only path.
|
|
||||||
const int destroyedAtEntry = IsMechDestroyed();
|
|
||||||
|
|
||||||
// MP DIAGNOSTIC (task #47): confirm the handler runs on the OWNING MASTER
|
// MP DIAGNOSTIC (task #47): confirm the handler runs on the OWNING MASTER
|
||||||
// for a cross-pod (network-delivered) TakeDamage + what state it carries.
|
// for a cross-pod (network-delivered) TakeDamage + what state it carries.
|
||||||
if (getenv("BT_MP_NET"))
|
if (getenv("BT_MP_NET"))
|
||||||
@@ -1248,31 +1242,11 @@ void
|
|||||||
// vital-wreck flag, and the loop-ENTRY zone. This retires
|
// vital-wreck flag, and the loop-ENTRY zone. This retires
|
||||||
// BTPostDamageScore/BTPostKillScore -- see the btplayer.cpp tombstone.
|
// BTPostDamageScore/BTPostKillScore -- see the btplayer.cpp tombstone.
|
||||||
//
|
//
|
||||||
// #150 DOUBLE-KILL FIX, two binary-grounded gates (2026-08-10):
|
|
||||||
//
|
|
||||||
// (1) MASTER ONLY. The binary OPENS this handler with the assertion
|
|
||||||
// `if ((flags & 0xc) == 4) Fail("Replicant Mech recieving takedam...",
|
|
||||||
// MECH.CPP, 0x3da)` (part_012.c:14613-14616) -- in 1995 a replicant
|
|
||||||
// executing TakeDamage was a BUG, so the report tail could only ever
|
|
||||||
// run on the victim's master, once. This port deliberately applies
|
|
||||||
// damage on replicants too (local visual responsiveness), so the tail
|
|
||||||
// ALSO ran there -- and the replicant's movement mode can't flip to
|
|
||||||
// wreck until the death record round-trips, so a multi-round killing
|
|
||||||
// volley posted a kill report PER ROUND inside that window. Measured:
|
|
||||||
// one death -> two type-2 arms 1ms apart, kills 0->2 (the field's
|
|
||||||
// "one kill counted twice", #150). Gate the REPORTS to the master;
|
|
||||||
// the local damage application stays.
|
|
||||||
//
|
|
||||||
// (2) ENTRY LATCH. The binary's newly-destroyed test is the 0->1 edge of
|
|
||||||
// IsMechDestroyed() across THIS handler call (local_14), not the
|
|
||||||
// movement-mode-derived deathBlastArmed -- on the master both agree,
|
|
||||||
// but the binary's form is the spec.
|
|
||||||
if (GetInstance() != ReplicantInstance)
|
|
||||||
{
|
{
|
||||||
extern void BTMechPostCombatReports(void *, void *, float, int, int, int);
|
extern void BTMechPostCombatReports(void *, void *, float, int, int, int);
|
||||||
BTMechPostCombatReports((void *)this, (void *)message,
|
BTMechPostCombatReports((void *)this, (void *)message,
|
||||||
(float)damageTally, zoneDestroyed, reportZone,
|
(float)damageTally, zoneDestroyed, reportZone,
|
||||||
!destroyedAtEntry && IsMechDestroyed());
|
deathBlastArmed && IsMechDestroyed());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,9 +93,8 @@ if defined BT_STILL_RUNNING (
|
|||||||
goto btwait
|
goto btwait
|
||||||
)
|
)
|
||||||
echo.
|
echo.
|
||||||
echo The game has exited. (Quitting from the menu lands here -- normal.)
|
echo The game has exited. If it closed unexpectedly, send the operator
|
||||||
echo If it CRASHED or would not start, send the operator BOTH of these
|
echo BOTH of these from the content folder:
|
||||||
echo from the content folder:
|
|
||||||
echo content\lastrun_solo.txt (tiny -- send it EVEN IF there is
|
echo content\lastrun_solo.txt (tiny -- send it EVEN IF there is
|
||||||
echo no solo_*.log at all: that combination
|
echo no solo_*.log at all: that combination
|
||||||
echo is how we spot a blocked launch)
|
echo is how we spot a blocked launch)
|
||||||
|
|||||||
@@ -97,10 +97,7 @@ if defined BT_STILL_RUNNING (
|
|||||||
goto btwait
|
goto btwait
|
||||||
)
|
)
|
||||||
echo.
|
echo.
|
||||||
echo The game has exited.
|
echo The game has exited. If it closed unexpectedly, send the operator BOTH
|
||||||
echo (Normal exits land here too: round ends return everyone to the menu,
|
|
||||||
echo and closing the menu window quits -- neither is a crash.)
|
|
||||||
echo If it CRASHED or would not start, send the operator BOTH:
|
|
||||||
echo content\lastrun_steam.txt (tiny -- send it EVEN IF there is no
|
echo content\lastrun_steam.txt (tiny -- send it EVEN IF there is no
|
||||||
echo steam_*.log at all: that is how we spot
|
echo steam_*.log at all: that is how we spot
|
||||||
echo a launch blocked before it ran)
|
echo a launch blocked before it ran)
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# #150/#151: count type-2 arm executions per kill + measure the eject score arithmetic
|
|
||||||
. /c/git/bt411/scratchpad/night6/bench_common.sh
|
|
||||||
cd /c/git/bt411/content || exit 1
|
|
||||||
taskkill //F //IM btl4.exe >/dev/null 2>&1; sleep 3
|
|
||||||
rm -f sc_a.log sc_b.log sc_r.log
|
|
||||||
mkdir -p /c/git/bt411/scratchpad/night14/mlbak && mv matchlog_*.txt /c/git/bt411/scratchpad/night14/mlbak/ 2>/dev/null
|
|
||||||
bt_expert_egg MP.EGG SC.EGG
|
|
||||||
sed -i "s/^map=.*/map=grass/; s/^time=.*/time=day/; s/^vehicle=.*/vehicle=madcat/" SC.EGG
|
|
||||||
# B: unarmed slow target, respawns on death
|
|
||||||
( export BT_GOTO=enemy BT_GOTO_STOP=80 BT_SCORE_LOG=1 BT_DEATH_LOG=1 BT_MATCHLOG=1 BT_MP_LOG=1
|
|
||||||
bt_launch sc_b.log SC.EGG 0x0C -net 1601 )
|
|
||||||
sleep 2
|
|
||||||
# A: kills B with autofire, then panic-ejects late
|
|
||||||
( export BT_GOTO=enemy BT_GOTO_STOP=100 BT_AUTOFIRE=1 BT_AF_MISSILE=1 BT_AF_PERIOD=4
|
|
||||||
export BT_EJECT_AT=9000
|
|
||||||
export BT_SCORE_LOG=1 BT_DEATH_LOG=1 BT_MATCHLOG=1 BT_MP_LOG=1
|
|
||||||
bt_launch sc_a.log SC.EGG 0x03 -net 1501 )
|
|
||||||
sleep 5
|
|
||||||
python ../tools/btconsole.py SC.EGG 127.0.0.1:1501 127.0.0.1:1601 > sc_r.log 2>&1 &
|
|
||||||
R=$!; sleep 300; kill $R 2>/dev/null; sleep 2
|
|
||||||
bt_kill_ours; sleep 2; taskkill //F //IM btl4.exe >/dev/null 2>&1
|
|
||||||
echo RESULT
|
|
||||||
echo "--- B deaths (kills A should have earned) ---"
|
|
||||||
grep -ac "Mech::Reset" sc_b.log
|
|
||||||
echo "--- A: kill-arm executions + score sequence (matchlog) ---"
|
|
||||||
grep -ah "SCORE\|KILL\|EJECT\|DEATH" matchlog_*.txt 2>/dev/null | head -25
|
|
||||||
echo "--- A: scorepost receipts (producer side) ---"
|
|
||||||
grep -a "scorepost" sc_a.log | head -10
|
|
||||||
grep -a "scorepost" sc_b.log | head -10
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# Hand-poll the RIO board over COM1 -- no game involved. Wire format per
|
|
||||||
# PCSerialPacket::SendPacket: [cmd][checksum = sum & 0x7F].
|
|
||||||
$p = New-Object System.IO.Ports.SerialPort COM1,9600,None,8,One
|
|
||||||
$p.DtrEnable = $true
|
|
||||||
$p.RtsEnable = $true
|
|
||||||
$p.ReadTimeout = 200
|
|
||||||
$p.Open()
|
|
||||||
'PORT OPEN CTS=' + $p.CtsHolding + ' DSR=' + $p.DsrHolding
|
|
||||||
|
|
||||||
function Send-Cmd([byte[]]$bytes, [string]$name) {
|
|
||||||
$p.DiscardInBuffer()
|
|
||||||
$p.Write($bytes, 0, $bytes.Length)
|
|
||||||
Start-Sleep -Milliseconds 700
|
|
||||||
$got = @()
|
|
||||||
while ($p.BytesToRead -gt 0) { $got += [byte]$p.ReadByte() }
|
|
||||||
$hex = ($got | ForEach-Object { $_.ToString('X2') }) -join ' '
|
|
||||||
"$name -> $($got.Count) byte(s): $hex"
|
|
||||||
}
|
|
||||||
|
|
||||||
Send-Cmd @([byte]0x80, [byte]0x00) 'CHECK 0x80'
|
|
||||||
Send-Cmd @([byte]0x81, [byte]0x01) 'VERSION 0x81'
|
|
||||||
Send-Cmd @([byte]0x82, [byte]0x02) 'ANALOG 0x82'
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
Send-Cmd @([byte]0x82, [byte]0x02) 'ANALOG again'
|
|
||||||
$p.Close()
|
|
||||||
'DONE'
|
|
||||||
Reference in New Issue
Block a user