Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0e29a4d97 | ||
|
|
5cde991f56 | ||
|
|
e693b481b3 | ||
|
|
81b0887033 | ||
|
|
8b3d1c8113 | ||
|
|
e614924107 | ||
|
|
fcd592c0f2 | ||
|
|
2fe58b8b89 | ||
|
|
c3258ee2e1 |
@@ -1328,3 +1328,19 @@ record shipped penalty-off for entire steam nights, #162); (3) the bench for ANY
|
||||
here is scratchpad/night15/kd_bench.sh -- five HARD invariants (deaths==increments,
|
||||
cost-per-death, credit-per-kill, zero swallowed, arithmetic witness); its predecessor's
|
||||
assertions were greps that matched nothing, which is how both halves shipped broken.
|
||||
|
||||
|
||||
## Weapon destroyed-state: the ONE-cell contract (#165 root cause, night-16) [T1]
|
||||
Binary: subsystem `+0x40` (statusAlarm level) is THE destroyed cell -- all writers (base
|
||||
TakeDamage @0x4ac0bc zone-saturation tail; cascade descent @0049c9a8; slot-8 pump watchdog),
|
||||
all readers (Emitter gate @004baa88 `==1` strict; small-dial X @004c7844; techstat; the wire
|
||||
header). Four alarm cells exist per weapon and are NOT interchangeable: +0x40 status/health,
|
||||
+0x184 temperature (gate clause `==2`), +0x278 power feed (eng-page X only!), +0x364 weaponAlarm
|
||||
FSM (level 7 "unavailable" = AMMO weapons only, @004bb9b8/@004bbd04 -- the #30 answer). The
|
||||
eng-page energy X (@004c8990) draws on `+0x40==1 OR power!=4`: an X over a LOADED emitter that
|
||||
legally fires its one loaded shot is AUTHENTIC binary behavior (power-fault case). Destroyed
|
||||
emitters park at weaponAlarm=3 (Loading) via the gate's per-frame refusal -- "recharging under
|
||||
the X" is authentic. Replication: weapon statusAlarm NEVER crosses the wire; destroyed-ness
|
||||
reaches peers via ZONE records only; replicant emitters run a gateless Simulate (@004ba8d0) --
|
||||
fire legality is master-only. Port fix + the four-store split it repaired: [[reconstruction-gotchas]] SS30;
|
||||
bench: `scratchpad/night16/weaponx_bench.sh` (crit-path kill + partial-crit freeze regression).
|
||||
|
||||
@@ -826,3 +826,41 @@ classes (PlayerStatus/pilotList/...) with the config interpreter, which let
|
||||
more of the authored page furniture parse + draw than before -- the leaking
|
||||
high-index pixmaps rode in with that. [T3 for this correlation detail; the
|
||||
leak itself and its fix are T2 live-verified.]
|
||||
|
||||
|
||||
## Coolant-leak LAMP ROUTING (#172, night-16 hunt 2026-08-13) [T1 resolver + T2 field]
|
||||
The leak lamp chain is INTACT -- every staged leak all night (35 events, 4 machines, incl. the
|
||||
"fatal" case) asserted its lamp the SAME FRAME as the [techstat] cond-2 SET. The field reports
|
||||
were three different presentation facts:
|
||||
- **Generator leak -> the radar-rail generator button ONLY** (kBTGeneratorLamp @0051d070; both
|
||||
authored item codes 0x80+0x87 collapse to that one lamp, mode 0xffffffff = the ALWAYS-ACTIVE
|
||||
sentinel, never mode-gated). NO MFD carries any generator-leak indicator -- binary-authentic
|
||||
(@004cc2fc). In glass surround that rail cell renders at the minimumStrip floor (~6px,
|
||||
L4RIOBANK.cpp) -- Elengil's fatal lamp FLASHED for 28.4s. ~~"effectively invisible"~~
|
||||
**CORRECTED SAME DAY (user challenge upheld, bench-verified):** the strip PAINTS AND BLINKS
|
||||
correctly -- [lampblink] receipts show the painted shade alternating at a metronomic 125ms,
|
||||
full frame rate, in a loop code-identical to 913's; Elengil's layout receipts show the stock
|
||||
surround with the lamp on screen (~126px wide x ~6px strip @4Hz). The failure is
|
||||
EXPECTATION, not visibility: testers watch the MFDs, and no MFD carries a generator-leak
|
||||
indicator (authentic). Resolution: the handout's WHERE-TO-LOOK entry; the ALERT RING
|
||||
deviation exists but is GATED OFF (BT_ALERT_RING=1) pending Friday evidence that testers
|
||||
miss the lamp even knowing its location. Receipts: [lamppx] alert edges, [lampblink] shade
|
||||
transitions (BT_LAMP_LOG), [seqloop] voice Start/Stop. Era question for Oracle: how
|
||||
prominent was the pod's physical generator button light?
|
||||
- **Condenser (loop) leak -> the per-loop button** (@0051d058, 1-based '2F 2E 2D 2B 2A 29';
|
||||
the 0x2c gap is AUTHENTIC -- 0x2c belongs to the DISTINCT coolingLoop set of the code<0x80
|
||||
path). Also always-active. No gate, immediate flash.
|
||||
- **Weapon leak (AFC50 family) -> PAGE-SCOPED lamps only** (quad-select + its eng-page button):
|
||||
the mode gate (@00444e64 == LAMP.cpp) skips the notify while the page is hidden and the
|
||||
page-entry force-notify delivers it when the player pages there -- "flash appeared at the
|
||||
second voice line" = the player paging to engineering after voice loop #1. AUTHENTIC;
|
||||
documented for testers, not fixed. Coolant-cooled guns leak in PAIRS (weapon bit + serving
|
||||
condenser bit) -- one page-gated lamp, one always-active loop lamp.
|
||||
- **The VOICE is a LOOPING sequence** (0E4ACE50, tempo 160): Start on the coolantActive 0->1
|
||||
edge, self-repeats, Stop on 1->0 (the #136 model REFINED: edge-started, level-looped,
|
||||
edge-stopped; hysteresis flap = restart). Voice repetitions carry NO edge information --
|
||||
the field testers used the voice as a clock and mis-dated the lamp. Receipt: [seqloop]
|
||||
START/STOP, always-on for looped sequences.
|
||||
- Authored no-lamp facts (from the mechalrm item census, [galm-item]): conditions 1 (Damaged)
|
||||
and 3 (Overheating) have NO lamp items for ANY subsystem; cond 0 (Destroyed) resolves lamps
|
||||
only for weapon-slot subsystems. A heat alarm never flashes a cockpit button -- authored.
|
||||
|
||||
@@ -1194,3 +1194,54 @@ DATAPOINT (2026-08-11, the #162 retest wave): the kd4/kd8 benches audit this exp
|
||||
and saw **0 inst=R DMG rows across three 4-node runs and one 8-node melee** (35 deaths total)
|
||||
on build ~900 -- the behavior did not reproduce on the bench rig; whatever produced the
|
||||
night-15 field rows needs field conditions (steam wire seam?) the LAN relay path lacks.
|
||||
|
||||
## Night-16 playtest intelligence (build 4.11.913, 2026-08-12) [T2 player testimony + log receipts]
|
||||
Field-verified CLOSED this night: #162 (K/D exact all night, 3 independent confirms), #156
|
||||
(fade), #154 (gen voice at trip), #135 (leak flashes the right lamp), #169 (lobby layout),
|
||||
#128 (no ram leaks; ram crits land on gyro/torso progressively, myomer crits unobtainable --
|
||||
consistent with internals-only, see #103). Logs: `scratchpad/night16/` + Oracle notes.
|
||||
|
||||
- **#170 -- post-mission menu-relaunch crash (TOP defect).** `[fe] mission over -- relaunching
|
||||
the menu` -> `[crash] UNHANDLED EXCEPTION code=0xc0000005 addr=0x0 access=8 target=0x0`.
|
||||
7 hits / 3 machines / identical module-relative stack, all frames in a Steam-family DLL;
|
||||
a NULL function-pointer call dispatched by a Steam callback across the mission-teardown ->
|
||||
menu-relaunch boundary. Intermittent (10 relaunches -> 3 crashes in one log). [T4 hypothesis:
|
||||
callback left registered across teardown; possibly a #163/#156 teardown-ORDER regression.]
|
||||
Players report it as "crash while joining lobby" -- it is not the join.
|
||||
**ROOT-CAUSED + FIXED same night [T2]:** the first #163 fix's `SteamAPI_Shutdown()` inside
|
||||
`BTSteamNet_ShutdownAll` raced steamclient's service thread (round-end = a burst of peer
|
||||
closes always in flight). ShutdownAll is now a QUIESCE (no Shutdown; linger closes; seam
|
||||
gated first) and every exit path dies via TerminateProcess -- see [[steam-networking]]
|
||||
§THE EXIT CONTRACT. Field verify Friday; the crash filter now names foreign DLL frames.
|
||||
- **#171 -- ballistic/missile hitscan era question (HOLD until group consensus).** Era witnesses
|
||||
(Oracle, Lynx, Sauron; Dplotta softer; Draco DISSENTS) recall AFC/Gauss as instant-hit,
|
||||
no lead, no flight animation, single-panel damage, no splash. 913 field observations: locked
|
||||
AFC50 misses a perpendicular mover unless led; ballistics AND SRM/Streak/Narc hit beyond the
|
||||
rangefinder max without limit; energy weapons DO stop damaging at rangefinder max (=> at least
|
||||
one unmapped range-gating mechanism exists). The projectile flight clocks are [T1] from the
|
||||
decomp (#168) -- reconcile: hit-resolved-at-trigger with cosmetic projectile? speeds/ranges
|
||||
off? undiscovered range gate? Pod-hardware ground truth possible end of month.
|
||||
- **#172 -- leak lamp first-flash delayed/absent.** Elengil: flash only on the SECOND voice line
|
||||
(x2 spawns, AFC50/Zanin Neko); once ABSENT for an entire fatal leak (5-6 voice repetitions,
|
||||
no flash on any MFD, died ~9:38PM CT -- the match's only death, receipt findable in night16).
|
||||
Distinct from the closed #135: this is the SET-edge / first-flash arming path.
|
||||
- **#173 -- chicken-walker seek-4 myomer overheat** (see [[subsystems]] night-16 note).
|
||||
- **#165 ROOT-CAUSED + FIXED + BENCHED (2026-08-13, the 4-agent hunt):** gotcha SS30 -- the
|
||||
binary's ONE destroyed cell was split into four port stores and the crit-lottery kill path
|
||||
(MechWeapon::TakeDamage) wrote none the gate reads. Fixed (chain to MechSubsystem::TakeDamage,
|
||||
FSM tail deleted, phantom simulationState initialized + bridged); weaponx_bench PASS both
|
||||
phases. RESIDUAL UNKNOWNS from the hunt: (i) Elengil's 20:17 ET no-X facet needs ALIA's
|
||||
PRE-ROTATION steam_20260812.log (ask Elengil -- staged file starts 22:20 ET); (ii) cascade
|
||||
re-descend re-entrancy (zone 18 x7 re-rolls, own ticket); (iii) incident-(b) "no damage on
|
||||
target": shooter log computed FULL damage (11.76) -- wire/victim-side loss, needs paired
|
||||
matchlogs (fleet-wide BT_DMG_LOG + matchlog next night would make this attributable).
|
||||
- **#172 RESOLVED (2026-08-13, 4-agent hunt): the lamp chain was NEVER broken** -- all 35
|
||||
staged leak events flashed same-frame. Three presentation facts: generator lamp = the ~6px
|
||||
radar-rail strip in glass (fatal case: flashed 28.4s unseen -> ALERT BLOOM deviation);
|
||||
weapon-leak lamps are page-gated AUTHENTICALLY (the "delayed" flash = the player paging to
|
||||
engineering); the leak voice LOOPS off one edge (testers' clock was wrong). See
|
||||
[[gauges-hud]] SSCoolant-leak LAMP ROUTING. Receipts armed: [seqloop], [lamppx]. Residual:
|
||||
Lynx's loop-6 report unstaged (his machine, no log); Elengil's AFC50 pre-rotation log still
|
||||
wanted for the pair-leak confirmation.
|
||||
- Nanook lost the coolant MFD glass window, recovered only by config edit -> #76 comment
|
||||
(in-game layout-reset recovery path).
|
||||
|
||||
@@ -1014,3 +1014,53 @@ sampled a cell whose write timing differs from the binary's". Fix shape: run the
|
||||
transition inline at the destruction edge (mech.cpp death_tail → `UpdateDeathState(0)`), keep the
|
||||
per-frame caller for maintenance. Verified: kd4_bench 9/9/9/9 + kd8_stress 26/26/26/26, both
|
||||
SWALLOWED=0 (the receiver dedup tripwire now never fires — no duplicate is ever GENERATED).
|
||||
|
||||
|
||||
## 30. ONE binary cell, FOUR port stores: the destroyed-state split that survived three "fixes" (#165, night-16 2026-08-13)
|
||||
The binary keeps ONE destroyed cell per subsystem: `+0x40` = the statusAlarm level -- written by
|
||||
EVERY destruction path (base TakeDamage @0x4ac0bc at private-zone saturation; zone-cascade
|
||||
descent @0049c9a8; the per-frame watchdog in the slot-8 message pump), read by EVERY consumer
|
||||
(the Emitter fire gate @004baa88, the small weapon-dial X @004c7844, the techstat scan, the wire
|
||||
via the Simulation record header). The port split that cell into FOUR stores that never talked:
|
||||
the private DamageZone.damageLevel (drives the X), the ReconAlarm statusAlarm (gate clause 2 --
|
||||
written ONLY by the cascade + bench hook), a phantom `int simulationState` (gate clause 1 --
|
||||
ZERO writers, NEVER ctor-initialized: uninitialized pool memory, MEMBLOCK recycles unzeroed),
|
||||
and the weaponAlarm FSM cell. `MechWeapon::TakeDamage` then bypassed the reconstructed
|
||||
`MechSubsystem::TakeDamage` (which HAS the destroyed tail) for the raw engine base -- so the
|
||||
everyday CRIT-LOTTERY kill saturated the zone (X lit) without ever writing a gate cell: X'd
|
||||
weapons kept firing. Three prior "fixes" all aimed at the GATE, and the bench (BT_KILL_SUBSYS)
|
||||
wrote both cells directly -- 4,213 refusals proving a gate that was never broken.
|
||||
**Sibling defect in the same function:** the port-authored tail drove the weapon FSM from zone
|
||||
state -- saturation -> level 0 (=Firing!), partial damage -> level 1 (NO case in either FSM:
|
||||
silent freeze; with beamFlag armed = the 883 hanging beam, #164's upstream writer).
|
||||
**Rules:** (1) when the binary reads/writes ONE offset, the port must have ONE authority --
|
||||
alias, don't duplicate; if layout forces a twin field, every writer writes BOTH (grep-audit the
|
||||
writer census, not the reader census). (2) Never let an override "simplify away" the
|
||||
reconstructed base -- `MechWeapon::TakeDamage` calling `Subsystem::TakeDamage` instead of
|
||||
`MechSubsystem::TakeDamage` dropped the invariant silently. (3) A bench hook that writes state
|
||||
directly validates READERS only; destruction/state benches must drive the REAL writer path
|
||||
(BT_CRIT_SUBSYS: Damage -> ApplyDamageAndMeasure -> virtual TakeDamage). (4) Every ctor
|
||||
initializes every reconstructed field -- an unwritten int in pooled memory is a time bomb.
|
||||
Verified: weaponx_bench P1 (crit kill: 0 FIRED after, 5,664 refusals, X+gate agree) + P2
|
||||
(partial crit keeps firing -- the freeze is gone). Full mechanism: the night-16 workflow dossier
|
||||
(4 agents, cross-examined) + docs/GEN_WARNING_AUDIT-style lanes in the #165 ticket thread.
|
||||
|
||||
|
||||
## 31. GUARD-SCOPE NARROWING: a binary guard wrapping a whole block, transcribed onto its first statement (#174, 2026-08-13)
|
||||
The binary's burst loop guards the ENTIRE per-burst application on zone-not-destroyed
|
||||
(`if (piVar1[9] != 1) { crit-roll | zone TakeDamage; score tally; destroyed-flag }`,
|
||||
part_012.c:14661-14677 @0x4a0446) -- a burst landing on a dead zone is a structural no-op:
|
||||
no re-application, no cascade re-fire, NO SCORE. The port transcribed that guard onto the
|
||||
crit roll ONLY; the unguarded TakeDamage re-saturated the zone every burst, whose >=1.0 tail
|
||||
re-ran RecurseSegmentTable (night-16 field: zone 18 x7, zone 9 x4 per mission), each pass
|
||||
re-pushing crit allotment into surviving subsystems (the ram "crits worsened with each
|
||||
collision") -- and hits on wreckage kept SCORING (the binary awards zero). Neither
|
||||
RecurseSegmentTable nor SendSubsystemDamage has any internal re-entry protection in the
|
||||
binary (verified @0049cad4/@0049c9a8: no `used` write, no top gate) -- the delivery-layer
|
||||
guard is the ONLY protection, so its scope is load-bearing.
|
||||
**Rule:** when transcribing a decomp `if` whose body spans multiple statements, diff the
|
||||
BRACE SCOPE against the port -- a guard attached to the wrong statement compiles, runs, and
|
||||
passes every reader-side bench. **Bench rule (the #165 lesson, second application in one
|
||||
week):** prove the bench detects the bug BEFORE trusting its pass -- the negative control
|
||||
here (fix stashed) scored 147 cascades where the fixed build scores 1.
|
||||
Bench: BT_ZONE_HAMMER=<zone>[,<amt>] (mech4.cpp) + scratchpad/night16/cascade_bench.sh.
|
||||
|
||||
@@ -60,6 +60,32 @@ reset on death), #69 (Sunder V1 → Denkou naming).
|
||||
token / transport layer. Everything above the seam is the same arcade mesh — the three replication
|
||||
symptoms this night produced would all reproduce on the relay.
|
||||
|
||||
## THE EXIT CONTRACT (#163 -> #170, settled 2026-08-12) [T2 field-proven]
|
||||
Process-exit topology for every glass/steam process: **flush -> quiesce -> TerminateProcess.**
|
||||
`BTSteamNet_ShutdownAll` (L4STEAMNET.cpp) is a QUIESCE: gate `steamActive` FIRST (stops
|
||||
marshal/game-thread seam re-entry), `CloseConnection(..., linger=true)` on every connection
|
||||
("round over", not a peer-side timeout), close listeners, one `sockets->RunCallbacks()` drain,
|
||||
`Sleep(60)` grace. **It deliberately never calls `SteamAPI_Shutdown()`, and no exit path may
|
||||
return through the CRT** (menu-quit included -- it dies via `BTOrderlyDie`, btl4console.cpp).
|
||||
|
||||
The two-failure history, because each fix's reason constrains the other:
|
||||
- **883 (no teardown at all):** bare `ExitProcess` ran DLL_PROCESS_DETACH with live SNS threads
|
||||
-> intermittent loader-lock deadlock -> "frozen view of how the game ended" + the menu child
|
||||
hung in `SteamAPI_Init` against the wedged half-dead sibling (#163, night15).
|
||||
- **913 (full `SteamAPI_Shutdown` before TerminateProcess):** at round end every peer closes
|
||||
simultaneously, so status events are ALWAYS in flight; Shutdown tears client state down while
|
||||
steamclient's own service thread dispatches them -> that thread calls literal NULL
|
||||
(0xc0000005 access=8 target=0x0, BaseThreadInitThunk root, ZERO btl4 frames) in the window
|
||||
before TerminateProcess (#170, night16: 7 hits / 3 machines / one module-relative stack).
|
||||
- **The stable point:** TerminateProcess kills all threads atomically with every pointer still
|
||||
valid (no detach, no dispatch window); the Steam client GCs the session on IPC pipe break --
|
||||
the standard crashed-game path (883 relaunched all night with no Shutdown ever called). The
|
||||
child-hang needed a WEDGED sibling, which TerminateProcess makes structurally impossible.
|
||||
|
||||
Forensics rider: the crash filter (btl4main.cpp `BTCrashFilter`) now prints foreign frames as
|
||||
`<module.dll>+0xOFFSET` (VirtualQuery AllocationBase + GetModuleFileName), so a future
|
||||
foreign-thread crash names its DLL instead of an unresolvable ASLR address.
|
||||
|
||||
## Key Relationships
|
||||
- Rides: [[glass-cockpit]] miniconsole (marshal has a Steam-wire branch) · Extends:
|
||||
[[multiplayer]] (the arcade mesh, unchanged above the seam)
|
||||
|
||||
@@ -338,3 +338,18 @@ forward at the respawn (physical lever / HOTAS — exactly who reported it) had
|
||||
speed in the spike frames. The calibration facts above (constants byte-exact, dt-normalised
|
||||
kinetic term) all STAND; the in-life governor (running hot at sustained top speed derates the
|
||||
myomers) is authentic and remains.
|
||||
|
||||
## Spawn-discharge loop heat + per-chassis generator bias (night-16 field, 2026-08-12) [T3 field-observed, mechanism plausible-authentic]
|
||||
Oracle's explanation for the long-standing "missiles cook off on one side first" reports
|
||||
(Lynx): at spawn ALL weapons start discharged, and the initial CHARGE of the energy weapons
|
||||
dumps heat into their loops; generator assignments are biased per chassis (Avatar: BOTH large
|
||||
lasers on GeneratorA), so that side's loops start hot and a missile launcher sharing the side
|
||||
cooks off first even if the player fires only missiles. Not yet verified against the authored
|
||||
data -- verify via BTL4.RES generator/loop assignments before treating as established. [T3]
|
||||
|
||||
Related open defect/question: **#173** -- Vulture (and per Oracle ALL large chicken walkers)
|
||||
cannot run seek-4 myomers without immediate overheat, loop 5 pegged, heat only sheds near
|
||||
standstill (Elengil; Oracle repro). Investigate myomer heat rate + loop-5 capacity vs authored
|
||||
data for those chassis; authored-balance vs port-artifact undecided. The myomer drive-heat
|
||||
FORMULA is verified faithful (#137, above) -- if the rate is right, the question moves to the
|
||||
authored loop capacity / condenser assignments.
|
||||
|
||||
@@ -226,3 +226,11 @@ wrote); affinity masks 2-cores-each up to 4 nodes, 1-each at 8.
|
||||
- Uses: [[build-and-run]] (parity, env gates, BT_SHOT capture) · [[experience-levels]] (expert vs novice gating)
|
||||
- Informs: [[reconstruction-method]] (step 4 "verify honestly" — this file is the how)
|
||||
- Incident sources: [[reconstruction-gotchas]] §23 (pixels), §25 (same-pass latch timing — caught by the 4-node bench), §26 (silent stubs); [[multiplayer]] (replication layers)
|
||||
|
||||
## weaponx_bench (night16) -- #165 crit-path destruction
|
||||
`scratchpad/night16/weaponx_bench.sh`: single node, vulture, BT_AUTOFIRE; P1 kills ERSLaser_1
|
||||
via BT_CRIT_SUBSYS (the REAL writer path: Damage -> ApplyDamageAndMeasure -> virtual TakeDamage)
|
||||
and asserts [crit] DESTROYED + [techstat] X + zero named FIRED after + REFUSED>0 + survivor
|
||||
fires; P2 partial-crits to 0.5 and asserts the weapon KEEPS firing (freeze regression, the #164
|
||||
upstream writer). LESSON (gotcha SS30): BT_KILL_SUBSYS writes the cells directly and can only
|
||||
validate READERS -- state benches must drive the real writer path.
|
||||
|
||||
@@ -217,7 +217,7 @@ yet reconstructed (parse-skipped). The separate window is now the **live viewer*
|
||||
- **Pod MFD port-name reconcile (pod-only):** a ~5-line positional dual-name fallback in `SVGA16::Update`
|
||||
(`UL = GetGraphicsPort("auxUL2"); if(!UL) UL = GetGraphicsPort("Heat"); …`) so BT MFDs reach the pod's real
|
||||
monitors. NOT a CFG rename (the CFG uses BT names pervasively + `MUNGA_L4` is shared with RP's aux names).
|
||||
- **Polish:** overlay-plane compositing over `sec`; a pod-accurate RGB-packing toggle; texture atlas
|
||||
- **Polish:** ~~overlay-plane compositing over `sec`~~ (DONE 2026-08-13, row 28); a pod-accurate RGB-packing toggle; texture atlas
|
||||
(one lock/upload); device-reset recreate hardening for the additional swap chain.
|
||||
|
||||
## Widget reconstruction — the real fix (in progress; mapped by `bt-gauge-widget-recon-map`)
|
||||
@@ -691,7 +691,7 @@ reconfigure/externalConfigure); parse-skip list EMPTY ([gskip]=0), all 50 attr b
|
||||
| 25 | sec: headingPointer needle + numeric | YawPitchRoll decomposition (engine-convention port of euler[0]) | LIVE: 089→120 while turning under BT_GOTO | T2 | CORRECT |
|
||||
| 26 | sec: numericSpeed | LinearSpeed (abs(adv)/dt) | LIVE: 0 parked → 176-182 walking | T2 | CORRECT (units question stays open) |
|
||||
| 27 | sec: digitalClock MISSION TIME | engine mission clock (format enum arg) | LIVE: 09:19→06:04 counting | T0/T2 | CORRECT |
|
||||
| 28 | sec: sectorDisplay (overlay) | localOrigin → Round(−Z·0.01)+500 / Round(X·0.01)+500 | commit 4a4ec68 [BT_SECTOR_LOG live]; NOTE: overlay plane not composited into the dev sec cell (polish item) — data verified by log | T2 | CORRECT |
|
||||
| 28 | sec: sectorDisplay (overlay) | localOrigin → Round(−Z·0.01)+500 / Round(X·0.01)+500 | commit 4a4ec68 [BT_SECTOR_LOG live]; **overlay plane COMPOSITED 2026-08-13** (branch sec-overlay-composite): every sec expand (BTDrawGaugeSurfaces, BTDrawCockpitPanels, SVGA16::Update case 0, glass BlitSurface) now uses sec\|overlay = 0xFF — clut0 already held the arcade DAC's combined table (BuildSecondaryPalette spreads each port over the other's bit combos), so the fix is mask-only; the glass dirty token gained the overlay port so the numerals repaint. Verified live: SECTOR ticks + SCALE:1000 at spawn (1000 = radarRange init; the DOS shot's 4000 is max zoom) + the btsec1ov graticule now draws | T2 | CORRECT |
|
||||
| 29 | sec: schematic ARMOR view (cmArmor/multiArmor, dama.pcc) | zone damageLevel ×100 → adpal ramp | incr.3/4; all-green pristine LIVE | T2 | CORRECT (AUTH-STATIC all-green solo) |
|
||||
| 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 |
|
||||
|
||||
-290
File diff suppressed because one or more lines are too long
-638
@@ -1,638 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>BattleTech 4.11 — the mech roster</title>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
:root {
|
||||
--ground: #0e0f11; --panel: #16181b; --rule: #2a2e33;
|
||||
--ink: #e8e6e2; --ink-mid: #a3a8ae; --ink-low: #71777e;
|
||||
--hot: #f39313; /* palette 6, the display's own amber */
|
||||
--nrg: #ff5340; /* energy weapons */
|
||||
--bal: #f39313; /* ballistic */
|
||||
--msl: #58c470; /* missiles -- the armor doll's green family */
|
||||
--mono: ui-monospace, "Cascadia Mono", Consolas, Menlo, monospace;
|
||||
--sans: ui-sans-serif, system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--ground: #f4f2ee; --panel: #fbfaf8; --rule: #ddd8d0;
|
||||
--ink: #14161a; --ink-mid: #565c63; --ink-low: #7d838a;
|
||||
--hot: #a35f00; --nrg: #b3260f; --bal: #a35f00; --msl: #1c7a3f;
|
||||
}
|
||||
}
|
||||
body {
|
||||
margin: 0; background: var(--ground); color: var(--ink);
|
||||
font: 400 15px/1.6 var(--sans);
|
||||
}
|
||||
.wrap { max-width: 78rem; margin: 0 auto; padding: 0 clamp(1rem, 4vw, 2.5rem); }
|
||||
.sr-only {
|
||||
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
|
||||
overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
|
||||
}
|
||||
:focus-visible { outline: 2px solid var(--hot); outline-offset: 2px; }
|
||||
|
||||
header.top { border-bottom: 1px solid var(--rule); padding: clamp(2.5rem,6vw,4rem) 0 1.75rem; }
|
||||
.eyebrow {
|
||||
font: 500 12px/1 var(--mono); letter-spacing: .2em; text-transform: uppercase;
|
||||
color: var(--ink-low); margin: 0 0 1rem;
|
||||
}
|
||||
h1 {
|
||||
font: 700 clamp(1.9rem,1.4rem+2.2vw,3rem)/1.05 var(--mono);
|
||||
letter-spacing: -.02em; text-transform: uppercase; margin: 0 0 .9rem;
|
||||
}
|
||||
h1 em { font-style: normal; color: var(--hot); }
|
||||
.lede { max-width: 62ch; color: var(--ink-mid); margin: 0 0 1.4rem; font-size: 1.05rem; }
|
||||
.lede strong { color: var(--ink); font-weight: 600; }
|
||||
.rules { display: flex; flex-wrap: wrap; gap: .6rem 2rem; margin: 0; padding: 0; list-style: none; }
|
||||
.rules li {
|
||||
font: 500 12px/1.5 var(--mono); color: var(--ink-mid);
|
||||
padding-left: 1.1rem; position: relative;
|
||||
}
|
||||
.rules li::before {
|
||||
content: ""; position: absolute; left: 0; top: .45em;
|
||||
width: .45rem; height: .45rem; background: var(--hot);
|
||||
}
|
||||
.rules b { color: var(--ink); font-weight: 700; }
|
||||
|
||||
.bar {
|
||||
position: sticky; top: 0; z-index: 5;
|
||||
background: var(--ground);
|
||||
border-bottom: 1px solid var(--rule); padding: .75rem 0;
|
||||
}
|
||||
.bar__in { display: flex; flex-wrap: wrap; gap: .75rem 1.25rem; align-items: center; }
|
||||
.seg { display: inline-flex; border: 1px solid var(--rule); }
|
||||
.seg button {
|
||||
font: 500 12px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase;
|
||||
background: none; border: 0; color: var(--ink-mid); padding: .55rem .9rem; cursor: pointer;
|
||||
}
|
||||
.seg button[aria-pressed="true"] { background: var(--hot); color: var(--ground); }
|
||||
.search {
|
||||
flex: 1 1 12rem; min-width: 9rem;
|
||||
font: 400 12px var(--mono);
|
||||
background: var(--panel); color: var(--ink);
|
||||
border: 1px solid var(--rule); padding: .55rem .7rem;
|
||||
}
|
||||
.search::placeholder { color: var(--ink-low); }
|
||||
.count { font: 500 12px var(--mono); color: var(--ink-low); letter-spacing: .1em; }
|
||||
|
||||
.key { display: flex; flex-wrap: wrap; gap: .4rem .9rem; padding: 1.25rem 0 0; }
|
||||
.key span { display: inline-flex; align-items: center; gap: .4rem;
|
||||
font: 500 12px var(--mono); letter-spacing: .08em; color: var(--ink-low); }
|
||||
.key i { width: .7rem; height: .7rem; display: inline-block; }
|
||||
|
||||
.roster { display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule);
|
||||
margin: 1.75rem 0 3rem; }
|
||||
.mech { background: var(--panel); display: grid; gap: 0;
|
||||
grid-template-columns: minmax(15rem, 19rem) 1fr; }
|
||||
@media (max-width: 46rem) { .mech { grid-template-columns: 1fr; } }
|
||||
.mech[hidden] { display: none; }
|
||||
|
||||
.mech__id { padding: 1.1rem 1.25rem 1.35rem; border-right: 1px solid var(--rule); }
|
||||
@media (max-width: 46rem) { .mech__id { border-right: 0; border-bottom: 1px solid var(--rule); } }
|
||||
.hull { margin: 0 0 .9rem; display: flex; flex-direction: column; gap: .45rem;
|
||||
align-items: flex-start; }
|
||||
/* The game's own review image on the display's own black, either theme. */
|
||||
.hull__img {
|
||||
display: block; width: 7rem; height: auto;
|
||||
background: #000; border: 1px solid var(--rule); image-rendering: pixelated;
|
||||
}
|
||||
.hull figcaption {
|
||||
font: 500 11px/1.35 var(--mono); letter-spacing: .1em;
|
||||
text-transform: uppercase; color: var(--ink-low);
|
||||
}
|
||||
.mech__id h3 {
|
||||
font: 700 1.5rem/1 var(--mono); letter-spacing: .01em;
|
||||
margin: 0 0 .55rem; text-transform: uppercase;
|
||||
}
|
||||
.mech__key {
|
||||
font: 500 12px/1 var(--mono); letter-spacing: .12em;
|
||||
color: var(--ink-low); margin: -.3rem 0 .7rem;
|
||||
}
|
||||
.mech__load { display: flex; flex-wrap: wrap; gap: .3rem; margin: 0 0 .7rem; }
|
||||
.chip {
|
||||
font: 500 11px/1 var(--mono); letter-spacing: .08em;
|
||||
padding: .3rem .45rem; border: 1px solid currentColor;
|
||||
}
|
||||
.chip--e { color: var(--nrg); }
|
||||
.chip--b { color: var(--bal); }
|
||||
.chip--m { color: var(--msl); }
|
||||
.mech__meta { display: flex; flex-wrap: wrap; gap: .8rem; margin: 0 0 .2rem;
|
||||
font: 400 12px var(--mono); color: var(--ink-low); font-variant-numeric: tabular-nums; }
|
||||
.spec {
|
||||
margin: .75rem 0 0; display: grid; grid-template-columns: 1fr auto;
|
||||
gap: .2rem .8rem; font: 500 12px var(--mono);
|
||||
}
|
||||
.spec div { display: contents; }
|
||||
.spec dt { color: var(--ink-low); letter-spacing: .06em; }
|
||||
.spec dd { margin: 0; text-align: right; color: var(--ink); font-variant-numeric: tabular-nums; }
|
||||
.mech__sheet { margin: .6rem 0 0; font: 400 11px/1.5 var(--mono); color: var(--ink-low); }
|
||||
|
||||
.mech__tables { min-width: 0; }
|
||||
.tablewrap { overflow-x: auto; }
|
||||
table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }
|
||||
thead th {
|
||||
font: 500 12px/1 var(--mono); letter-spacing: .14em;
|
||||
color: var(--ink-low); text-align: left; font-weight: 500;
|
||||
padding: .9rem .9rem .55rem; border-bottom: 1px solid var(--rule); white-space: nowrap;
|
||||
}
|
||||
tbody th {
|
||||
font: 500 13px/1.3 var(--mono); text-align: left; color: var(--ink);
|
||||
padding: .5rem .9rem; border-bottom: 1px solid var(--rule); white-space: nowrap;
|
||||
}
|
||||
tbody td {
|
||||
font: 400 13px/1.3 var(--mono); color: var(--ink-mid);
|
||||
padding: .5rem .9rem; border-bottom: 1px solid var(--rule); white-space: nowrap;
|
||||
}
|
||||
tbody tr:last-child th, tbody tr:last-child td { border-bottom: 0; }
|
||||
th.num, td.num { text-align: right; }
|
||||
|
||||
.empty-state {
|
||||
margin: 2rem 0; font: 500 13px var(--mono); color: var(--ink-low);
|
||||
}
|
||||
.foot {
|
||||
border-top: 1px solid var(--rule); padding: 1.5rem 0 0; max-width: 76ch;
|
||||
color: var(--ink-low); font-size: 13px;
|
||||
}
|
||||
.foot:last-child { padding-bottom: 4rem; }
|
||||
.foot code { font-family: var(--mono); color: var(--ink-mid); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="top">
|
||||
<div class="wrap">
|
||||
<p class="eyebrow">BattleTech 4.11 · from btl4fe.cpp, L4GAUGE.CFG and the player's manual</p>
|
||||
<h1>Every mech,<br><em>and what it carries</em></h1>
|
||||
<p class="lede">All <strong>18 mechs the menu offers</strong> — 8 base chassis
|
||||
and 10 variants — each with its authored weapons roster, ammo bins and the
|
||||
stat sheet from the original player's manual. The portraits are the game's own
|
||||
mission-review images, shown in their undamaged state.</p>
|
||||
<ul class="rules">
|
||||
<li><b>Variants share the chassis</b>, not the loadout</li>
|
||||
<li><b>Blackhawk, Nova, Owens, Kotori</b> have a fixed torso</li>
|
||||
<li>The manual sheets cover the <b>six 4.0 hulls</b> only</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="bar">
|
||||
<div class="wrap bar__in">
|
||||
<div class="seg" role="group" aria-label="Filter">
|
||||
<button type="button" data-filter="all" aria-pressed="true">All 18</button>
|
||||
<button type="button" data-filter="base" aria-pressed="false">Base 8</button>
|
||||
<button type="button" data-filter="variant" aria-pressed="false">Variants 10</button>
|
||||
</div>
|
||||
<input id="search" class="search" type="search" placeholder="Search mech or weapon…"
|
||||
aria-label="Search mech or weapon">
|
||||
<span class="count" id="count">18 / 18 mechs</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="wrap">
|
||||
<div class="key">
|
||||
<span><i style="background:var(--nrg)"></i>Energy</span>
|
||||
<span><i style="background:var(--bal)"></i>Ballistic</span>
|
||||
<span><i style="background:var(--msl)"></i>Missile</span>
|
||||
</div>
|
||||
|
||||
<div class="roster">
|
||||
<article class="mech" data-tags="base" data-search="blkhawk black hawk er large laser er medium laser er small laser srm 6 erllaser ermlaser erslaser srm6">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Black Hawk mission-review portrait" loading="lazy">
|
||||
<figcaption>Black Hawk chassis · with Nova</figcaption>
|
||||
</figure>
|
||||
<h3>Black Hawk</h3>
|
||||
<p class="mech__key">blkhawk · base chassis</p>
|
||||
<p class="mech__load"><span class="chip chip--e">ER LARGE LASER</span><span class="chip chip--e">5× ER MEDIUM LASER</span><span class="chip chip--e">2× ER SMALL LASER</span><span class="chip chip--m">2× SRM 6</span></p>
|
||||
<p class="mech__meta"><span>10 weapons</span><span>2 ammo bins</span><span>torso FIXED</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>50 t</dd></div><div><dt>Armor points</dt><dd>1362</dd></div><div><dt>Reservoir</dt><dd>1600 L</dd></div><div><dt>Heat sinks</dt><dd>16</dd></div><div><dt>Torso</dt><dd>FIXED</dd></div><div><dt>0–100 kph</dt><dd>5.1 s</dd></div><div><dt>Top speed</dt><dd>190 kph</dd></div><div><dt>Super charged</dt><dd>280 kph</dd></div><div><dt>Gimped</dt><dd>60 kph</dd></div></dl>
|
||||
<p class="mech__sheet">manual p. 29</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Black Hawk</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Large Laser</th><td>Energy</td><td class="num">1</td><td class="num">—</td></tr><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">5</td><td class="num">—</td></tr><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">SRM 6</th><td>Missile</td><td class="num">2</td><td class="num">2×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="base" data-search="loki loki er medium laser er small laser afc 50 srm 4 ermlaser erslaser afc50 srm4">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Loki mission-review portrait" loading="lazy">
|
||||
<figcaption>Loki chassis · with Hellbringer, Mischief</figcaption>
|
||||
</figure>
|
||||
<h3>Loki</h3>
|
||||
<p class="mech__key">loki · base chassis</p>
|
||||
<p class="mech__load"><span class="chip chip--e">2× ER MEDIUM LASER</span><span class="chip chip--e">2× ER SMALL LASER</span><span class="chip chip--b">2× AFC 50</span><span class="chip chip--m">SRM 4</span></p>
|
||||
<p class="mech__meta"><span>7 weapons</span><span>3 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>75 t</dd></div><div><dt>Armor points</dt><dd>2110</dd></div><div><dt>Reservoir</dt><dd>3800 L</dd></div><div><dt>Heat sinks</dt><dd>38</dd></div><div><dt>Torso</dt><dd>60°/s · 110°</dd></div><div><dt>0–100 kph</dt><dd>4.5 s</dd></div><div><dt>Top speed</dt><dd>143 kph</dd></div><div><dt>Super charged</dt><dd>182 kph</dd></div><div><dt>Gimped</dt><dd>40 kph</dd></div></dl>
|
||||
<p class="mech__sheet">manual p. 25</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Loki</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">AFC 50</th><td>Ballistic</td><td class="num">2</td><td class="num">2×</td></tr><tr><th scope="row">SRM 4</th><td>Missile</td><td class="num">1</td><td class="num">1×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="variant" data-search="bhk1 nova er medium laser ppc srm 6 ermlaser ppc srm6">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Nova mission-review portrait" loading="lazy">
|
||||
<figcaption>Black Hawk chassis · with Black Hawk</figcaption>
|
||||
</figure>
|
||||
<h3>Nova</h3>
|
||||
<p class="mech__key">bhk1 · variant of Black Hawk</p>
|
||||
<p class="mech__load"><span class="chip chip--e">3× ER MEDIUM LASER</span><span class="chip chip--e">2× PPC</span><span class="chip chip--m">2× SRM 6</span></p>
|
||||
<p class="mech__meta"><span>7 weapons</span><span>2 ammo bins</span><span>torso FIXED</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>FIXED</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">chassis sheet: see Black Hawk</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Nova</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">3</td><td class="num">—</td></tr><tr><th scope="row">PPC</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">SRM 6</th><td>Missile</td><td class="num">2</td><td class="num">2×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="base" data-search="madcat mad cat er large laser er small laser afc 100 lrm 15 erllaser erslaser afc100 lrm15">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Mad Cat mission-review portrait" loading="lazy">
|
||||
<figcaption>Mad Cat chassis · with Timber Wolf, Zanin Neko</figcaption>
|
||||
</figure>
|
||||
<h3>Mad Cat</h3>
|
||||
<p class="mech__key">madcat · base chassis</p>
|
||||
<p class="mech__load"><span class="chip chip--e">ER LARGE LASER</span><span class="chip chip--e">2× ER SMALL LASER</span><span class="chip chip--b">AFC 100</span><span class="chip chip--m">2× LRM 15</span></p>
|
||||
<p class="mech__meta"><span>6 weapons</span><span>3 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>75 t</dd></div><div><dt>Armor points</dt><dd>2195</dd></div><div><dt>Reservoir</dt><dd>2800 L</dd></div><div><dt>Heat sinks</dt><dd>28</dd></div><div><dt>Torso</dt><dd>80°/s · 90°</dd></div><div><dt>0–100 kph</dt><dd>4.2 s</dd></div><div><dt>Top speed</dt><dd>175 kph</dd></div><div><dt>Super charged</dt><dd>220 kph</dd></div><div><dt>Gimped</dt><dd>62 kph</dd></div></dl>
|
||||
<p class="mech__sheet">manual p. 26</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Mad Cat</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Large Laser</th><td>Energy</td><td class="num">1</td><td class="num">—</td></tr><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">AFC 100</th><td>Ballistic</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">LRM 15</th><td>Missile</td><td class="num">2</td><td class="num">2×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="base" data-search="thor thor er medium laser er ppc er small laser large laser lrm 15 ermlaser erppc erslaser llaser lrm15">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="204"
|
||||
alt="Thor mission-review portrait" loading="lazy">
|
||||
<figcaption>Thor chassis · with Summoner</figcaption>
|
||||
</figure>
|
||||
<h3>Thor</h3>
|
||||
<p class="mech__key">thor · base chassis</p>
|
||||
<p class="mech__load"><span class="chip chip--e">ER MEDIUM LASER</span><span class="chip chip--e">2× ER PPC</span><span class="chip chip--e">2× ER SMALL LASER</span><span class="chip chip--e">LARGE LASER</span><span class="chip chip--m">LRM 15</span></p>
|
||||
<p class="mech__meta"><span>7 weapons</span><span>1 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>75 t</dd></div><div><dt>Armor points</dt><dd>2110</dd></div><div><dt>Reservoir</dt><dd>3800 L</dd></div><div><dt>Heat sinks</dt><dd>38</dd></div><div><dt>Torso</dt><dd>60°/s · 110°</dd></div><div><dt>0–100 kph</dt><dd>4.5 s</dd></div><div><dt>Top speed</dt><dd>143 kph</dd></div><div><dt>Super charged</dt><dd>182 kph</dd></div><div><dt>Gimped</dt><dd>40 kph</dd></div></dl>
|
||||
<p class="mech__sheet">manual p. 25</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Thor</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">1</td><td class="num">—</td></tr><tr><th scope="row">ER PPC</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">Large Laser</th><td>Energy</td><td class="num">1</td><td class="num">—</td></tr><tr><th scope="row">LRM 15</th><td>Missile</td><td class="num">1</td><td class="num">1×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="base" data-search="owens owens er medium laser er small laser srm 6 ermlaser erslaser srm6">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJ4AAADLCAMAAACoGNoNAAADAFBMVEUAAAD/AAAP/wdjY2NTU1PDYxOfn58A4wD/AAD/05f///9jY9fzgwCDUwDzwwBTMwAAAAAARwAzMwAAAABbWwB/fwDLywAPRwCDf/8fdxcAAIs7OzsPMwt7ewCHUwCTAAAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwCTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6v///+68zF9AAAEV0lEQVR42u3cgW6bMBAGYEv3BHuESZ0WqVW6bEn7/m+22BiwDx+cyRlo+p/UqWpD+HbmDmNonEMgEAgEAoFAIBAIBAKBQCAQCARi2yAxjq07hI/ojw+iC4/j8Ghj3vIg/btH5HnhAu96j3X7URxQgi74qEvfPO96FXyrDlaijzRI0nmfz17nk0vjepV89JmGyke9LuxCw/Nfl2koeWE3vY80Azvq/PdLvFC5q3lxNz2PanJXzbvdYxVPzN/kkFHw0tJIebdb4uOloeSxw5cXwoeGlzaWkXe7pT5NY+G8T1Ysa3n8rDHPE7dezZuWRrFrqHnlrfPSUPIiizWWNry+sUSjlkeTtkx0GoObZ0sjvPB9jIyX1ISOl1VwFa/cWBS8YYiNef2v5tryHjzWnARe8qpteb99+H87njAlIDqfz/7rbMfjpTGEwCMheyHKPNbtqkrjI9MpePQ4r6axsAnVQCrzgrDIi7Qpb/gmn1CtO2s05a04a7Bz7hLPA0s879LyqBkv6AqFe/Gw/XleeClcCvnRpb15Xe6KPD++/QBb85Sl0R13Eq/zWZcGm1DN8Cj2PWFwQ98jVWNR9z12TpN5FI1jD85Lo8te310kXn5Ws+JRxBV7Stpdgo9NCTbh1cW2PBeTp8remdx34bH51Da8z8r53lJjMePVX6mxs0ZxvufqCsNJ8z2zVYIJL2bv51z0jUW8FDLkUXal1nflZV64HMmSV8MrLVCVs0c5LwCXeZTzaDZ70xUq5QIa50XfIi9es6l4y7dGxMXbCS8K53n9PiRe5eJt4pte55K4iLF4c0jkZa3PuWrfLM+x9P29R5a86SKGxKu4czD573d9r8BzPS+84m+IccglXvquj9536X9ymufF3HX5m+W9l3kP3cbKT2uP8ZLObHWX7avzhkMvHHxH4w2Fm5buwXi6xrItL4sfQrPYkTdzSnN785zMoyPwnOphjP14jhaH9pA8B95X4g3Xk6R5UmnCG1dbmvDGy3HGS1I2kz0qXEva806TzCQ+Kheuk26r2T22lAEVD6KxV7BlAvunqmSe5g3YIkbr5/Q23Lw6e6da3nu77E3Wp3zx1vGysjUWHp7ni8GSR2TYW8IFuC0vXSv4FrwsVvDyuxzWPB61PBbgHYl35GOP7CvX8LwWeVbZi7y2f1ew6Rto3j2fMFe+wfSmlXMt53wbbarfx8sQa2bLr0OABx544IEH3s48suPRLn/6127rZ8geeOCBBx544IEHHnjggQceeOCBBx54WKHaMXtkyWtxN/IliXre62vmo2Yj+zjPfHzBe2oeWfa9Jg9nWmWvQWe2zp47znMYboNnMfLRfWRwwQPv2Urj1xBreG9DgAceeOCB99y87kyU8uqfvM14ts98P/RR7S0/6p3GxK3Yh7DJmEJqcbwx75KNH29Wx2Gqy8ph/MUSb2SUy+StLW+milk5gAceeOB9bZ7itCZ/fIcZT9zBYzybicH+vP8Wh7Z72j2/ewAAAABJRU5ErkJggg==" width="158" height="203"
|
||||
alt="Owens mission-review portrait" loading="lazy">
|
||||
<figcaption>Owens chassis · with Kotori</figcaption>
|
||||
</figure>
|
||||
<h3>Owens</h3>
|
||||
<p class="mech__key">owens · base chassis</p>
|
||||
<p class="mech__load"><span class="chip chip--e">2× ER MEDIUM LASER</span><span class="chip chip--e">4× ER SMALL LASER</span><span class="chip chip--m">2× SRM 6</span></p>
|
||||
<p class="mech__meta"><span>8 weapons</span><span>2 ammo bins</span><span>torso FIXED</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>25 t</dd></div><div><dt>Armor points</dt><dd>760</dd></div><div><dt>Reservoir</dt><dd>1500 L</dd></div><div><dt>Heat sinks</dt><dd>15</dd></div><div><dt>Torso</dt><dd>FIXED</dd></div><div><dt>0–100 kph</dt><dd>4.2 s</dd></div><div><dt>Top speed</dt><dd>154 kph</dd></div><div><dt>Super charged</dt><dd>265 kph</dd></div><div><dt>Gimped</dt><dd>63 kph</dd></div></dl>
|
||||
<p class="mech__sheet">manual p. 29</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Owens</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">4</td><td class="num">—</td></tr><tr><th scope="row">SRM 6</th><td>Missile</td><td class="num">2</td><td class="num">2×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="variant" data-search="own1 kotori er medium laser er small laser afc 25 nrk 5 ermlaser erslaser afc25 nrk5">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Kotori mission-review portrait" loading="lazy">
|
||||
<figcaption>Owens chassis · with Owens</figcaption>
|
||||
</figure>
|
||||
<h3>Kotori</h3>
|
||||
<p class="mech__key">own1 · variant of Owens</p>
|
||||
<p class="mech__load"><span class="chip chip--e">ER MEDIUM LASER</span><span class="chip chip--e">ER SMALL LASER</span><span class="chip chip--b">AFC 25</span><span class="chip chip--b">2× NRK 5</span></p>
|
||||
<p class="mech__meta"><span>5 weapons</span><span>3 ammo bins</span><span>torso FIXED</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>FIXED</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">chassis sheet: see Owens</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Kotori</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">1</td><td class="num">—</td></tr><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">1</td><td class="num">—</td></tr><tr><th scope="row">AFC 25</th><td>Ballistic</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">NRK 5</th><td>Ballistic</td><td class="num">2</td><td class="num">2×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="variant" data-search="thr1 summoner er small laser large laser afc 25 lrm 10 erslaser llaser afc25 lrm10">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="204"
|
||||
alt="Summoner mission-review portrait" loading="lazy">
|
||||
<figcaption>Thor chassis · with Thor</figcaption>
|
||||
</figure>
|
||||
<h3>Summoner</h3>
|
||||
<p class="mech__key">thr1 · variant of Thor</p>
|
||||
<p class="mech__load"><span class="chip chip--e">4× ER SMALL LASER</span><span class="chip chip--e">2× LARGE LASER</span><span class="chip chip--b">2× AFC 25</span><span class="chip chip--m">LRM 10</span></p>
|
||||
<p class="mech__meta"><span>9 weapons</span><span>3 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>twists</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">chassis sheet: see Thor</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Summoner</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">4</td><td class="num">—</td></tr><tr><th scope="row">Large Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">AFC 25</th><td>Ballistic</td><td class="num">2</td><td class="num">2×</td></tr><tr><th scope="row">LRM 10</th><td>Missile</td><td class="num">1</td><td class="num">1×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="variant" data-search="lok1 hellbringer large laser medium laser ppc small laser srm 4 llaser mlaser ppc slaser srm4">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJ4AAADLCAMAAACoGNoNAAADAFBMVEUAAAD/AAAP/wdjY2NTU1PDYxOfn58A4wD/AAD/05f///9jY9fzgwCDUwDzwwBTMwAAAAAARwAzMwAAAABbWwB/fwDLywAPRwCDf/8fdxcAAIs7OzsPMwt7ewCHUwCTAAAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwCTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6v///+68zF9AAAGH0lEQVR42u3cjXqiOhAGYJ7nu4K9hB49p1q2erT1/m9tgfwQYGYSSIJxm9nW2m2prxOSDEFpmho1atSoUaOYAB2l6M50oBgdkbssPmBtSw0OKncZfMBqH3TuzjqJZ5vMHLz/yRB5mqSTaL9W3pxHtHflhfNuTljemeoa5/15mPJgePSoXHlhvLIbt5SuMdHpvlEOD3MeKi+ax5QE5z15DcsDWe5lqffEgmquUz6dsH2qZcnH8vY+1gDe5zE84G3p6+Iyj9xHQSSvwyx5vbAcHma40nhOA/f3n8KDxFM35i7DQ+ZjfoGncgiZlwloBgWaN6bP3OF56YX6rx4ODE8ly/JUVyZ5Hx+phdZ2EHjaeDMynveRVjjaBJ4eh23cRJ4RpuEdxuB5N2LiEHiDsPIK40XGD+MhY+MiybDi47Hh5SFB7vw8Jnk+XnT+1ETmzx6t8/Iifaph57zu05QH6tsbWcwP+173aRpafTvlRfn0bkfxVN4Mb+kzFUvPUnmjeRE+Wwb4eXOfLQm8vM0+22Xdrqs83e3X15e6827m/7lO87rb7+9vdWfCM/c3+twyZVKxdB9fKob7tmKZ6RTv0uP6GO5PKpa44RnTrOn9kOXdZuWUwJvOHtuz5+51B1stw+j69nV47jHuyPs2YXjTmW0Y/bY2Lpazrch7PB4e3nzmxUcE7+Duf2qGE3gPFR7e8GemY9/2rgFHpw/DuX2P5s32Pb3ehsnQF1ELwNWJvIcJL8/4sLYycOsNRYOrM7wBqEZmy/vF8AagGpkvztOEaVp74OY/Oup+/p8OTKpPd41lUjNR2fvl8Kb1lfs8nV6CTx2yT+kwfMFh0ivkJSB23+PXWNz+iwEGj0/rhtxNeE0GXjPhDfmTfb2u/9jMI8a9lTyA9UHREMNbzBrreFBE0DyTOJFHBMsTl73pxh18JM9mbto1kI2HZddQGWR4KnM6f+NU22xs3Iu8OjpOvmPuVPfgeI5vHPeItWV3JdLHc48p58/VGfdG3SffuLA+ehhXJgML4RkYubZsHsTqIDSumz9mkknMG/flT7dvSDy1D7LdOy3PGPWQHMBT/9jBMeG+N/MhKHtC7pIOLET+ZJ7tGtILo96XAZJHjCsXaUL1dg0bUtnwTvkw51ELLOJJIdiiiuMFFYWxy49BfzjLWecu7vf7Vl66czBvZODtruKN+4U9XnS7mbfTS4I5H+4meF7TPM3n4e33cuotvB1f7E2nT9739nwtOj+s3IWhpWme7BPHvabZ0/e2JvYZ8NJE4Txk0p3cwD9D6C9kmF/B1YnKi+Thx/FQeWXwrsjwytZT5ZXBS+7raXPeingGT2dGSB/wxOxF8BL7BlnllcJL6lOwyiuGl9CnXdywLPGYYfln8XTMefrHnG3cel7vpTxgQ+m8E9O49hfohuV416Stm42HlLoF7zQChLZledfieUh5eLuNN9TuJO+ahnfy8ZrSecIylMC75uWd3M5ZME/evmSeOvCpvNfjnUrn4dV515J5qLyX5Xl9lRfBMysClfeKPI+v8mLOHec/7xzDwy68XF0j0ftzpUktYlhGqrcP55lzk12XgC/mI8rRhJdNiDnWwDXvAhq3eHtCzHEuEvIgL2J4B6asa8vMiYPA50/zsAOvieHlPqcW+gggT/nl5zUxvKdesDVk4z1eGBezcTLdkYruvwMmtS5aKpBsypV43neEtgIvyRU7jjzv6K33Wp7XJvBByl7gmyf47CXgHaXsHY8yr5Wy11Ze5VVe5a3lwc9D/KTh4wlv3MvMQxAPETw8i4cwHqKrFS+PeU9j6+e1cbxjAO/IvSW4bF4bwmujLpMVxCN9e/DGok4IieeLv54nEXULS40r02J5R837dxH9RaoDeb8XkYYHczz2yjxxYCmWZ8ZdlhddU6mBz8PjJ7UCeGzFpwEyL0VFpXjTUUHzpIUMlzfd2PJSFHwQeeKFGvy8RKtnPcdtWIfXBPHchh15qVb3eJ53gYrjJVxB43khG3O8JjMvbPkxK089BsMLe3IML+HiN8kL3ZjiNUlPHFRe5VVe5f1E3qKgWsObF1RN9qt17LHxuqrP3mzg/bY3uXiFZu9J8QfLAgmseMAx/wAAAABJRU5ErkJggg==" width="158" height="203"
|
||||
alt="Hellbringer mission-review portrait" loading="lazy">
|
||||
<figcaption>Loki chassis · with Loki, Mischief</figcaption>
|
||||
</figure>
|
||||
<h3>Hellbringer</h3>
|
||||
<p class="mech__key">lok1 · variant of Loki</p>
|
||||
<p class="mech__load"><span class="chip chip--e">2× LARGE LASER</span><span class="chip chip--e">2× MEDIUM LASER</span><span class="chip chip--e">2× PPC</span><span class="chip chip--e">2× SMALL LASER</span><span class="chip chip--m">SRM 4</span></p>
|
||||
<p class="mech__meta"><span>9 weapons</span><span>1 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>twists</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">chassis sheet: see Loki</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Hellbringer</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">Large Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">Medium Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">PPC</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">Small Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">SRM 4</th><td>Missile</td><td class="num">1</td><td class="num">1×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="variant" data-search="mad1 timber wolf medium laser afc 25 lrm 10 mlaser afc25 lrm10">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Timber Wolf mission-review portrait" loading="lazy">
|
||||
<figcaption>Mad Cat chassis · with Mad Cat, Zanin Neko</figcaption>
|
||||
</figure>
|
||||
<h3>Timber Wolf</h3>
|
||||
<p class="mech__key">mad1 · variant of Mad Cat</p>
|
||||
<p class="mech__load"><span class="chip chip--e">4× MEDIUM LASER</span><span class="chip chip--b">2× AFC 25</span><span class="chip chip--m">2× LRM 10</span></p>
|
||||
<p class="mech__meta"><span>8 weapons</span><span>4 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>twists</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">chassis sheet: see Mad Cat</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Timber Wolf</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">Medium Laser</th><td>Energy</td><td class="num">4</td><td class="num">—</td></tr><tr><th scope="row">AFC 25</th><td>Ballistic</td><td class="num">2</td><td class="num">2×</td></tr><tr><th scope="row">LRM 10</th><td>Missile</td><td class="num">2</td><td class="num">2×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="base" data-search="avatar avatar er large laser er medium laser afc 50 lrm 10 erllaser ermlaser afc50 lrm10">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJ4AAADLCAMAAACoGNoNAAADAFBMVEUAAAD/AAAP/wdjY2NTU1PDYxOfn58A4wD/AAD/05f///9jY9fzgwCDUwDzwwBTMwAAAAAARwAzMwAAAABbWwB/fwDLywAPRwCDf/8fdxcAAIs7OzsPMwt7ewCHUwCTAAAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwAAZwCTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6uTh6v///+68zF9AAAGtUlEQVR42u3c23bjKgwAUK+lL0mbTrrSnnR6e+n/f9jYIIHEzYDByWnQQy5unOwKhLFpM00jRowYMWLEiBEjRoy4x4BkDN4a710F3okng5fJcxr15njv7376bovHUnd7PM3CmxvhmX4G75g4fWc75NXHvDTvWkD92acT5/3MwXmXy5WEhBO8nyV7P4J3DaC1ubw5eS5vZyEIXBZvP6Bjy2jc/YS+jXhYsn5p+EDoiSOTc3w1I0pgYNHBiZ102qV44eyRCY9qLHtUxPq2S+q0jXiolTwAyUMP8bSwdQKBVyvycEzmPJM5yVNNCyaFl7YzaXyzx8cQjzWumLHwxvV553MrIdkeXd6JygQC0z3Z93jjIu+Mwga8RwzBcyvXi1DlCp4WbuY9+rzPObzKjWdvjq85fN65C+/zk/s473uOEO9LxT68z0/hY7zvb+MTvC+M6/K+v61vHx4Ing7Lc858fB4WheFhnBvVBggepot4dHwzE3rBs+UKQDw6wHEebMudz3NLA0LZ08cRpzR83pb86WOFz3MGFhCFy0oX3IElwKv36YZlw7IVifneAcywZ3XL/PTA53t89mLbtr7/2WMZZPPEuLzCMzVS5+NHM5wShONwKNtOU4Jt5ctqloynQCjGIRCKdwmEHFtUeWwc8lAX8M0bD0Gf2nwJ+PR0VFZHXfacIfnk+5Zth3ArKp7vA5k+ONfzjG/pHnpy7MYpnb2Lv8eybTJlUXtow2HF6KZk9uK8YPYm9FWXLk2SgXTEozMgfZPDM6dDNG3Gt4Nz+bTZNgLZUIc8OmOjm3Ue0MmZOemg9wPW+/LWGkDy+B6teRObv2Suhcw//INheh69vnHjqnc02fvPRMK36Bafuo/wIqXhDCmrpRHlxX1aB2leJHsAf/8yWH32Fl+Mp3MneCB5sb4362bfMkC7vGjfY4NL1koc8vBG86AvD8qyZ32mcu1Pk42LvJLGtYNfNs/4vESvlEacFy0NNrhgTcAqj3xeL8jKHviNm8qe8S0oTUuXBisP76cZfQ9K+h576xmls7fOU4ML7MzTOnyQ5gV1XUqjlEdHtMBL1o4a0WE5VRplvNTIyFcNQkeN6EHNZi+2dlDMS1yZx+sWtu8lQvY9e32+qjRyLs7rq921EyrM3xTirQ4smT5VvxUTKrM+OYV468NyfgLd0jjg6drB3OmHvDRiqTO8tYNa/sKVXbyyPH5lwOfRAgfk/CXR1uUhA8zkQSJ1LbPntnAWbwXXmMcTmNP34iXRoXElkHhu7eJGtggJ6bdrmD1ZIijxr7AgL2cNF/JO1Wp6YPDqGebwkpE6N32NlioBDxspHlwyF28tr91aLx7bkrzMnm7T13Il2nYzHR9zCF52LrrwnCHhQ0XVIEG81n9oAPCgYr77wFBP9EYo/01bpayAl/PJLXh+s5Xwuv+VjY7nOQp5b3P0NDLZs+ZRGN4D6RiP4o2ik4/JBM4r3dh5xxuLXjzbvJQgk6lQ2BfZpu3FE21bzpOt27dxN/B6Nu7gDd41eWw0hpxgL9yFh9kzB4yVWF6nYXvyMnEI3J/38FDgG7zb5oHb90pC8Pocc/lstI5HT/Zo3KKdd2hcmsZv4/WdzdvGreB1Ph9qwpumvv+0sYE3Tf3/36WYB4M3eIN3PV71sOwec++UVzklkBOqu+TZZt3M6zph2d732vvAn8zXZq9D/hZcQ17jsw19PbQhr61PNWxT3tvgDd7gDd7g/WIeNJ6xjIPa4P2KCdW07evX+n97m1wMr+L1XQ6Xq34VO/e77j14DdeFnsv7jux7+3yF4h47b/x6x477FuiOx6O6wcANmbyXlxd1g4EbGvmQBUfOwycZPC164Tx80o6nEih5oLdn8FQCJQ/09oaN62evoHH97N1T4w7e4A3e4A3e4A3enjwW5TwW95U9kTAnlZk7+9PRMd8bvMG7b97/YGDxr5AUZM/fuUPjMuOxuHFfuKxL3zua5q3imaa9Mx4VBgheQWkIHtjimNqWruHlX0GU1aB5PRb9TLUaXuHOhtfv2q2XvYKLt5LXyLj+vw69ds7FPamwj+bHT3wrpHZ+VTHf46Plsd269RuDLUOpDE/BkkCL0/eWp7lbgRZn7jmPzGEgx1kVe8DslV/saT7dUfEH+of+96Xhp5t29HgWXgEM4UI88wL+GQz3asPnVQPBZuXpaYXnAsO4MM+kt3QcdROX4tGvAfq7Z3UhOLgYz/wa5cO8i4jzMHfEAx+X4L0Wj4GQNvhwfLXiBQkWEZM34D0l0rfCg9do9n4drzo27PpreDcU/wDwAOAHKra7nQAAAABJRU5ErkJggg==" width="158" height="203"
|
||||
alt="Avatar mission-review portrait" loading="lazy">
|
||||
<figcaption>Avatar chassis · with Satyr</figcaption>
|
||||
</figure>
|
||||
<h3>Avatar</h3>
|
||||
<p class="mech__key">avatar · base chassis</p>
|
||||
<p class="mech__load"><span class="chip chip--e">2× ER LARGE LASER</span><span class="chip chip--e">4× ER MEDIUM LASER</span><span class="chip chip--b">AFC 50</span><span class="chip chip--m">2× LRM 10</span></p>
|
||||
<p class="mech__meta"><span>9 weapons</span><span>3 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>twists</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">no manual sheet (4.10 addition)</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Avatar</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Large Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">4</td><td class="num">—</td></tr><tr><th scope="row">AFC 50</th><td>Ballistic</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">LRM 10</th><td>Missile</td><td class="num">2</td><td class="num">2×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="variant" data-search="ava1 satyr er medium laser ppc afc 100 lrm 5 srm 2 ermlaser ppc afc100 lrm5 srm2">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Satyr mission-review portrait" loading="lazy">
|
||||
<figcaption>Avatar chassis · with Avatar</figcaption>
|
||||
</figure>
|
||||
<h3>Satyr</h3>
|
||||
<p class="mech__key">ava1 · variant of Avatar</p>
|
||||
<p class="mech__load"><span class="chip chip--e">2× ER MEDIUM LASER</span><span class="chip chip--e">PPC</span><span class="chip chip--b">AFC 100</span><span class="chip chip--m">LRM 5</span><span class="chip chip--m">SRM 2</span></p>
|
||||
<p class="mech__meta"><span>6 weapons</span><span>3 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>twists</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">no manual sheet (4.10 addition)</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Satyr</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">PPC</th><td>Energy</td><td class="num">1</td><td class="num">—</td></tr><tr><th scope="row">AFC 100</th><td>Ballistic</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">LRM 5</th><td>Missile</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">SRM 2</th><td>Missile</td><td class="num">1</td><td class="num">1×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="base" data-search="sunder sunder er medium laser er small laser medium laser afc 100 afc 25 lrm 10 ermlaser erslaser mlaser afc100 afc25 lrm10">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Sunder mission-review portrait" loading="lazy">
|
||||
<figcaption>Sunder chassis · with Denkou</figcaption>
|
||||
</figure>
|
||||
<h3>Sunder</h3>
|
||||
<p class="mech__key">sunder · base chassis</p>
|
||||
<p class="mech__load"><span class="chip chip--e">2× ER MEDIUM LASER</span><span class="chip chip--e">2× ER SMALL LASER</span><span class="chip chip--e">2× MEDIUM LASER</span><span class="chip chip--b">AFC 100</span><span class="chip chip--b">AFC 25</span><span class="chip chip--m">LRM 10</span></p>
|
||||
<p class="mech__meta"><span>9 weapons</span><span>3 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>twists</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">no manual sheet (4.10 addition)</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Sunder</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">Medium Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">AFC 100</th><td>Ballistic</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">AFC 25</th><td>Ballistic</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">LRM 10</th><td>Missile</td><td class="num">1</td><td class="num">1×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="variant" data-search="snd1 denkou er small laser ppc afc 25 lrm 5 erslaser ppc afc25 lrm5">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Denkou mission-review portrait" loading="lazy">
|
||||
<figcaption>Sunder chassis · with Sunder</figcaption>
|
||||
</figure>
|
||||
<h3>Denkou</h3>
|
||||
<p class="mech__key">snd1 · variant of Sunder</p>
|
||||
<p class="mech__load"><span class="chip chip--e">ER SMALL LASER</span><span class="chip chip--e">3× PPC</span><span class="chip chip--b">AFC 25</span><span class="chip chip--m">LRM 5</span></p>
|
||||
<p class="mech__meta"><span>6 weapons</span><span>2 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>twists</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">no manual sheet (4.10 addition)</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Denkou</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">1</td><td class="num">—</td></tr><tr><th scope="row">PPC</th><td>Energy</td><td class="num">3</td><td class="num">—</td></tr><tr><th scope="row">AFC 25</th><td>Ballistic</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">LRM 5</th><td>Missile</td><td class="num">1</td><td class="num">1×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="base" data-search="vulture vulture er medium laser er small laser large laser lrm 20 ermlaser erslaser llaser lrm20">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Vulture mission-review portrait" loading="lazy">
|
||||
<figcaption>Vulture chassis · with Mad Dog</figcaption>
|
||||
</figure>
|
||||
<h3>Vulture</h3>
|
||||
<p class="mech__key">vulture · base chassis</p>
|
||||
<p class="mech__load"><span class="chip chip--e">2× ER MEDIUM LASER</span><span class="chip chip--e">2× ER SMALL LASER</span><span class="chip chip--e">2× LARGE LASER</span><span class="chip chip--m">2× LRM 20</span></p>
|
||||
<p class="mech__meta"><span>8 weapons</span><span>2 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>75 t</dd></div><div><dt>Armor points</dt><dd>2025</dd></div><div><dt>Reservoir</dt><dd>2400 L</dd></div><div><dt>Heat sinks</dt><dd>24</dd></div><div><dt>Torso</dt><dd>50°/s · 130°</dd></div><div><dt>0–100 kph</dt><dd>4.7 s</dd></div><div><dt>Top speed</dt><dd>175 kph</dd></div><div><dt>Super charged</dt><dd>235 kph</dd></div><div><dt>Gimped</dt><dd>62 kph</dd></div></dl>
|
||||
<p class="mech__sheet">manual p. 26</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Vulture</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">Large Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">LRM 20</th><td>Missile</td><td class="num">2</td><td class="num">2×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="variant" data-search="vul1 mad dog er small laser ppc lrm 15 erslaser ppc lrm15">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Mad Dog mission-review portrait" loading="lazy">
|
||||
<figcaption>Vulture chassis · with Vulture</figcaption>
|
||||
</figure>
|
||||
<h3>Mad Dog</h3>
|
||||
<p class="mech__key">vul1 · variant of Vulture</p>
|
||||
<p class="mech__load"><span class="chip chip--e">4× ER SMALL LASER</span><span class="chip chip--e">2× PPC</span><span class="chip chip--m">2× LRM 15</span></p>
|
||||
<p class="mech__meta"><span>8 weapons</span><span>2 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>twists</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">chassis sheet: see Vulture</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Mad Dog</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Small Laser</th><td>Energy</td><td class="num">4</td><td class="num">—</td></tr><tr><th scope="row">PPC</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">LRM 15</th><td>Missile</td><td class="num">2</td><td class="num">2×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="variant" data-search="lok2 mischief medium laser ppc small laser afc 25 gauss srm 4 mlaser ppc slaser afc25 gauss srm4">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Mischief mission-review portrait" loading="lazy">
|
||||
<figcaption>Loki chassis · with Loki, Hellbringer</figcaption>
|
||||
</figure>
|
||||
<h3>Mischief</h3>
|
||||
<p class="mech__key">lok2 · variant of Loki</p>
|
||||
<p class="mech__load"><span class="chip chip--e">3× MEDIUM LASER</span><span class="chip chip--e">PPC</span><span class="chip chip--e">2× SMALL LASER</span><span class="chip chip--b">AFC 25</span><span class="chip chip--b">GAUSS</span><span class="chip chip--m">SRM 4</span></p>
|
||||
<p class="mech__meta"><span>9 weapons</span><span>3 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>twists</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">chassis sheet: see Loki</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Mischief</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">Medium Laser</th><td>Energy</td><td class="num">3</td><td class="num">—</td></tr><tr><th scope="row">PPC</th><td>Energy</td><td class="num">1</td><td class="num">—</td></tr><tr><th scope="row">Small Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">AFC 25</th><td>Ballistic</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">Gauss</th><td>Ballistic</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">SRM 4</th><td>Missile</td><td class="num">1</td><td class="num">1×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article>
|
||||
<article class="mech" data-tags="variant" data-search="mad2 zanin neko er medium laser er ppc afc 50 lrm 15 srm 6 ermlaser erppc afc50 lrm15 srm6">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="data:image/png;base64,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" width="158" height="203"
|
||||
alt="Zanin Neko mission-review portrait" loading="lazy">
|
||||
<figcaption>Mad Cat chassis · with Mad Cat, Timber Wolf</figcaption>
|
||||
</figure>
|
||||
<h3>Zanin Neko</h3>
|
||||
<p class="mech__key">mad2 · variant of Mad Cat</p>
|
||||
<p class="mech__load"><span class="chip chip--e">2× ER MEDIUM LASER</span><span class="chip chip--e">ER PPC</span><span class="chip chip--b">AFC 50</span><span class="chip chip--m">LRM 15</span><span class="chip chip--m">2× SRM 6</span></p>
|
||||
<p class="mech__meta"><span>7 weapons</span><span>4 ammo bins</span><span>torso TWISTS</span></p>
|
||||
<dl class="spec"><div><dt>Tonnage</dt><dd>—</dd></div><div><dt>Armor points</dt><dd>—</dd></div><div><dt>Reservoir</dt><dd>—</dd></div><div><dt>Heat sinks</dt><dd>—</dd></div><div><dt>Torso</dt><dd>twists</dd></div><div><dt>0–100 kph</dt><dd>—</dd></div><div><dt>Top speed</dt><dd>—</dd></div><div><dt>Super charged</dt><dd>—</dd></div><div><dt>Gimped</dt><dd>—</dd></div></dl>
|
||||
<p class="mech__sheet">chassis sheet: see Mad Cat</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the Zanin Neko</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody><tr><th scope="row">ER Medium Laser</th><td>Energy</td><td class="num">2</td><td class="num">—</td></tr><tr><th scope="row">ER PPC</th><td>Energy</td><td class="num">1</td><td class="num">—</td></tr><tr><th scope="row">AFC 50</th><td>Ballistic</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">LRM 15</th><td>Missile</td><td class="num">1</td><td class="num">1×</td></tr><tr><th scope="row">SRM 6</th><td>Missile</td><td class="num">2</td><td class="num">2×</td></tr></tbody>
|
||||
</table></div></div>
|
||||
</article></div>
|
||||
<p class="empty-state" id="nomatch" hidden>No mech matches that.</p>
|
||||
|
||||
<p class="foot">The roster is <code>kVehicles[]</code> in <code>game/glass/btl4fe.cpp</code>
|
||||
— the exact catalog the in-game menu offers, in menu order. Each mech's weapons and
|
||||
ammo bins are its <code>cmCrit(...)</code> lines in <code>content/GAUGE/L4GAUGE.CFG</code>,
|
||||
the critical-damage schematic's authored subsystem roster (independently confirmed against
|
||||
the subsystem records in <code>BTL4.RES</code>). Nothing is transcribed by hand.</p>
|
||||
<p class="foot">The portraits are each mech's mission-review image
|
||||
(<code>GAUGE/<stem>_MR.PCC</code>) resolved through the review screen's own palette.
|
||||
In play, its zone indexes are live damage slots painted green→orange→red by the
|
||||
ColorMapper gauges; this page shows every zone at the undamaged ramp entry — the
|
||||
same green the armor doll idles at. Variants without their own portrait share the base's,
|
||||
exactly as the resource file does.</p>
|
||||
<p class="foot">Mech stats are the original player's manual stat sheets (pp. 25, 26, 29).
|
||||
The manual documents the six 4.0 hulls; Avatar and Sunder arrived with 4.10 and have no
|
||||
sheet, so their rows show a dash rather than an invented number. FIXED vs twisting torso
|
||||
is read from the shipped resource file: a mech twists only if its subsystem record carries
|
||||
the <code>jointtorso</code>/<code>jointtshadow</code> joints — the four fixed mechs
|
||||
match the manual's Torso 0/0 rows exactly.</p>
|
||||
<p class="foot">Weapon notes: ER lasers fire red beams, PPCs blue, standard lasers yellow.
|
||||
Authored ranges where the game states them: PPCs 900 m, missiles 800 m, the
|
||||
Blackhawk's lasers 500 m, the AFC 50 750 m. The Blackhawk's SRM 6
|
||||
racks fire Streak ammunition. LRM tube counts are the salvo size; each launcher's ammo
|
||||
bin is listed beside it.</p>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const cards = [...document.querySelectorAll('.mech')];
|
||||
const count = document.getElementById('count');
|
||||
const search = document.getElementById('search');
|
||||
let filter = 'all';
|
||||
|
||||
function apply() {
|
||||
const q = search.value.trim().toLowerCase();
|
||||
let shown = 0;
|
||||
for (const c of cards) {
|
||||
const okTag = filter === 'all' || c.dataset.tags.split(' ').includes(filter);
|
||||
const okQ = !q || c.dataset.search.includes(q);
|
||||
const on = okTag && okQ;
|
||||
c.hidden = !on;
|
||||
if (on) shown++;
|
||||
}
|
||||
count.textContent = shown + ' / ' + cards.length + ' mechs';
|
||||
document.getElementById('nomatch').hidden = shown > 0;
|
||||
}
|
||||
|
||||
for (const b of document.querySelectorAll('[data-filter]')) {
|
||||
b.addEventListener('click', () => {
|
||||
filter = b.dataset.filter;
|
||||
for (const o of document.querySelectorAll('[data-filter]'))
|
||||
o.setAttribute('aria-pressed', String(o === b));
|
||||
apply();
|
||||
});
|
||||
}
|
||||
search.addEventListener('input', apply);
|
||||
apply();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,8 +5,11 @@
|
||||
build. Section A is the payoff -- please verify.
|
||||
=============================================================================
|
||||
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.
|
||||
FAIL / what you saw. Screenshots and rough times help.
|
||||
LOGS -- NEW, ONE CLICK: double-click SENDLOGS.bat in the game folder after
|
||||
the session. It puts ONE small zip on your Desktop with every log from the
|
||||
night (session logs, matchlogs, launch breadcrumbs) -- attach that one file.
|
||||
No more hunting for the right .log, no more missing parts.
|
||||
=============================================================================
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
@@ -34,9 +37,19 @@ A. FIXED -- PLEASE VERIFY (headliners first: new fixes fielded THIS build)
|
||||
TEST: take a leak (ram someone) -- the generator lamp for THAT loop
|
||||
flashes, and stops when it should.
|
||||
#136 Leaking SHUT loop responds to component toggles
|
||||
EXPLAINED AS AUTHENTIC: the alarm SOUND is one-shot per new leak,
|
||||
the lamp FLASH is continuous while leaking. Confirm the description
|
||||
matches what you see and we close it.
|
||||
EXPLAINED AS AUTHENTIC (refined): the leak voice STARTS at the leak,
|
||||
LOOPS on its own while the leak persists, STOPS when it seals -- so
|
||||
hearing it again does NOT mean a new leak. The lamp FLASH is
|
||||
continuous while leaking. Confirm and we close it.
|
||||
#172 "Coolant leak but no flashing indicator" -- WHERE TO LOOK
|
||||
The lamp always flashed; it was in a place nobody watches. A
|
||||
GENERATOR leak flashes the generator button BY THE RADAR (bottom
|
||||
centre) -- NOT any MFD. That is authentic: no MFD carries a
|
||||
generator-leak indicator. A WEAPON's leak lamp lives on its
|
||||
engineering page and flashes when you page there (also authentic).
|
||||
Loop leaks flash the loop button immediately. TEST Friday: take a
|
||||
leak, look AT THE RADAR RAIL -- tell us if it still reads as missing
|
||||
even knowing where to look.
|
||||
#128 Ramming terrain = instant coolant leak
|
||||
Ram damage eligibility fixed -- walls and rocks no longer puncture
|
||||
loops. TEST: bump terrain hard; leaks come from combat, not curbs.
|
||||
|
||||
@@ -401,6 +401,17 @@ void
|
||||
<< " tempo=" << (int)tempo
|
||||
<< " divPerBeat=" << (int)divisionsPerBeat << std::endl; } }
|
||||
|
||||
// #172 field receipt, ALWAYS-ON for LOOPED sequences (the alarm family --
|
||||
// leak warning, lock beeper; a handful per mission): night-16 proved the
|
||||
// voice loop is the testers' CLOCK ("it said coolant leak 5-6 times") yet
|
||||
// no field receipt tied voice to leak edges -- the fatal-case timeline had
|
||||
// to be reconstructed from matchlog wallclocks. One line per Start/Stop
|
||||
// EDGE makes voice-vs-lamp timing readable straight from any field log.
|
||||
// (Looped only: one-shot effects fire constantly and would spam.)
|
||||
if (isLooped && !isRunning)
|
||||
DEBUG_STREAM << "[seqloop] START seq=" << (void *)this
|
||||
<< " tempo=" << (int)tempo << "\n" << std::flush;
|
||||
|
||||
Check(this);
|
||||
|
||||
//
|
||||
@@ -438,6 +449,10 @@ void
|
||||
if (!isRunning)
|
||||
return;
|
||||
|
||||
if (isLooped) // #172 receipt (see StartSequence)
|
||||
DEBUG_STREAM << "[seqloop] STOP seq=" << (void *)this
|
||||
<< "\n" << std::flush;
|
||||
|
||||
//
|
||||
// Find next on or off event
|
||||
//
|
||||
|
||||
@@ -1313,6 +1313,20 @@ static void
|
||||
int mask = port->GetBitMask();
|
||||
int palId = port->paletteID;
|
||||
int tint = w->monoTint;
|
||||
// OVERLAY COMPOSITE (2026-08-13): the radar's low byte is TWO ports -- sec
|
||||
// (0x3F) + overlay (0xC0: the graticule art, the SCALE numeral and the
|
||||
// SECTOR numerals). The arcade DAC indexed the full low byte and clut0
|
||||
// already holds the combined 256-entry table (BuildSecondaryPalette spreads
|
||||
// each port over the other's bit combinations), so the palette-expanded
|
||||
// window composites both planes with just the OR'd mask -- previously the
|
||||
// 0x3F mask left SECTOR:/SCALE: blank while their writers were live.
|
||||
if (tint < 0)
|
||||
{
|
||||
L4GraphicsPort *ov =
|
||||
static_cast<L4GraphicsPort*>(gr->GetGraphicsPort("overlay"));
|
||||
if (ov != NULL && ov->graphicsDisplay == port->graphicsDisplay)
|
||||
mask |= ov->GetBitMask();
|
||||
}
|
||||
static int sMfdPal = -1;
|
||||
if (sMfdPal < 0) sMfdPal = getenv("BT_GLASS_MFD_PAL") ? 1 : 0;
|
||||
if (sMfdPal && tint >= 0)
|
||||
@@ -2110,6 +2124,11 @@ static unsigned long
|
||||
const char *ports[8];
|
||||
int np = 0;
|
||||
ports[np++] = w->portPrimary;
|
||||
if (w->monoTint < 0)
|
||||
ports[np++] = "overlay"; // composited into the palette-expanded
|
||||
// radar (2026-08-13) -- the SECTOR/SCALE
|
||||
// numerals tick on THIS plane, so their
|
||||
// churn must mark the window dirty
|
||||
if (w->portAlt != NULL) ports[np++] = w->portAlt;
|
||||
for (int gi = 0; gi < w->groupCount && np < 7; ++gi)
|
||||
{
|
||||
|
||||
@@ -155,6 +155,10 @@ static void
|
||||
static void __cdecl
|
||||
OnConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *status)
|
||||
{
|
||||
if (!steamActive)
|
||||
{
|
||||
return; // #170: the quiesce window -- the process is dying;
|
||||
} // no accepts, no table writes, just survive the call
|
||||
ISteamNetworkingSockets *sockets = SteamNetworkingSockets();
|
||||
|
||||
switch (status->m_info.m_eState)
|
||||
@@ -634,7 +638,8 @@ unsigned long long
|
||||
}
|
||||
|
||||
//
|
||||
// #163 -- the ORDERED transport shutdown for process exit (2026-08-11).
|
||||
// #163/#170 -- the ORDERED transport QUIESCE for process exit
|
||||
// (2026-08-11, corrected 2026-08-12 -- see the #170 block at the tail).
|
||||
//
|
||||
// The port never called SteamAPI_Shutdown(): every round-end died via bare
|
||||
// ExitProcess with live SNS connections and Steam callback threads, and the
|
||||
@@ -655,6 +660,10 @@ void
|
||||
{
|
||||
return;
|
||||
}
|
||||
steamActive = 0; // #170 FIRST: gate every seam entry
|
||||
// (Pump/Send/Recv/Accept) against
|
||||
// re-entry from the marshal or game
|
||||
// thread while the table is torn down
|
||||
ISteamNetworkingSockets *sockets = SteamNetworkingSockets();
|
||||
for (int i = 0; i < MaxConnections; ++i)
|
||||
{
|
||||
@@ -662,7 +671,9 @@ void
|
||||
&& connections[i].connection != k_HSteamNetConnection_Invalid)
|
||||
{
|
||||
sockets->CloseConnection(connections[i].connection, 0,
|
||||
"round over", false);
|
||||
"round over", true); // #170 linger: let the close packet
|
||||
// actually transmit -- peers should
|
||||
// read "round over", not a timeout
|
||||
}
|
||||
connections[i].inUse = 0;
|
||||
}
|
||||
@@ -674,7 +685,29 @@ void
|
||||
listenSockets[p] = k_HSteamListenSocket_Invalid;
|
||||
}
|
||||
}
|
||||
SteamAPI_RunCallbacks(); // let the closes flush client-side
|
||||
steamActive = 0;
|
||||
SteamAPI_Shutdown();
|
||||
sockets->RunCallbacks(); // one SNS drain; our status callback
|
||||
// stays REGISTERED and this module
|
||||
// stays LOADED, so any late dispatch
|
||||
// lands in live (guarded) code
|
||||
Sleep(60); // bounded grace for the lingered closes
|
||||
//
|
||||
// #170 -- DELIBERATELY NO SteamAPI_Shutdown(). The first #163 fix called
|
||||
// it here, and that OVER-CORRECTED into tonight's field crash: at round
|
||||
// end every peer closes simultaneously, so ClosedByPeer/ProblemDetected
|
||||
// status events are ALWAYS in flight when this runs -- and Shutdown tears
|
||||
// the client state down while steamclient's own service thread is still
|
||||
// dispatching them. Field signature (night16, 7 hits / 3 machines): a
|
||||
// steamclient-internal thread (BaseThreadInitThunk root, ZERO btl4
|
||||
// frames) calling literal NULL (0xc0000005 access=8 target=0x0) in the
|
||||
// window between Shutdown and TerminateProcess. The contract now
|
||||
// [T2 field-proven]: quiesce only; EVERY caller must die via
|
||||
// TerminateProcess (never a CRT return -- that re-opens the DLL-detach
|
||||
// deadlock this function no longer prevents). TerminateProcess kills
|
||||
// all threads atomically with every pointer still valid; the Steam
|
||||
// client GCs the session on IPC pipe break (the standard crashed-game
|
||||
// path -- build 883 relaunched all night without a single Shutdown
|
||||
// call). The 883 child-hang-in-SteamAPI_Init needed a WEDGED
|
||||
// (detach-deadlocked, half-dead) sibling; TerminateProcess makes wedges
|
||||
// structurally impossible, so the child boots clean without Shutdown.
|
||||
//
|
||||
}
|
||||
|
||||
@@ -33,9 +33,11 @@ int
|
||||
void
|
||||
BTSteamNet_Pump(); // callbacks + rx drain (game thread)
|
||||
void
|
||||
BTSteamNet_ShutdownAll(); // #163: ordered transport death for
|
||||
// process exit -- close every
|
||||
// connection, then SteamAPI_Shutdown
|
||||
BTSteamNet_ShutdownAll(); // #163/#170: transport QUIESCE for
|
||||
// process exit -- gate the seam, close
|
||||
// every connection (linger), drain.
|
||||
// NO SteamAPI_Shutdown (#170: NULL-call
|
||||
// crash); caller MUST TerminateProcess
|
||||
|
||||
//
|
||||
// The wire-seam surface (BTNet* wrappers in L4NET.CPP + the marshal).
|
||||
|
||||
+132
-5
@@ -860,6 +860,31 @@ static const float kBTPanelH = 480.0f;
|
||||
// channel-enabled and which is BlankColor; the draw loop below skips the
|
||||
// blanked plane, so the dev cell shows exactly what the pod monitor shows.
|
||||
// The Eng entries share their sibling's cell rect and FOLLOW it in the list.
|
||||
//
|
||||
// OVERLAY COMPOSITE (2026-08-13). The secondary CRT's low byte is authored as
|
||||
// TWO ports -- sec (bits 0x3F, btspal) and overlay (bits 0xC0, btopal,
|
||||
// TransparentZero) carrying the graticule art, the SCALE numeral (RadarRange)
|
||||
// and the SECTOR numerals (sectorDisplay). The arcade DAC indexed the FULL low
|
||||
// byte, blending both planes; every port expand used to mask to sec's 0x3F,
|
||||
// which is why SECTOR:/SCALE: read blank on desktop while their reconstructed
|
||||
// writers were live in the buffer the whole time. clut0 already holds the
|
||||
// DAC's combined 256-entry table (BuildSecondaryPalette spreads each port's
|
||||
// colors across the other's bit combinations), so the composite is exactly
|
||||
// this mask -- no blending code.
|
||||
//
|
||||
static int BTSecCompositeMask(GaugeRenderer *gr, L4GraphicsPort *sec_port)
|
||||
{
|
||||
int mask = sec_port->GetBitMask();
|
||||
if (gr != NULL)
|
||||
{
|
||||
L4GraphicsPort *ov =
|
||||
static_cast<L4GraphicsPort*>(gr->GetGraphicsPort("overlay"));
|
||||
if (ov != NULL && ov->graphicsDisplay == sec_port->graphicsDisplay)
|
||||
mask |= ov->GetBitMask();
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
static const BTGaugeSurfaceDesc kBTGaugeSurfaces[9] =
|
||||
{
|
||||
{ "Heat", 0xFFFF, 0.0f / kBTPanelW, 0.0f, 320.0f / kBTPanelW, 0.5f, 0 },
|
||||
@@ -946,7 +971,9 @@ void BTDrawGaugeSurfaces(LPDIRECT3DDEVICE9 device, float px, float py, float pw,
|
||||
rot = s_secRot;
|
||||
}
|
||||
svga->DrawDevSurface(
|
||||
device, i, port->GetBitMask(), port->paletteID, d.monoTint,
|
||||
device, i,
|
||||
d.monoTint < 0 ? BTSecCompositeMask(gr, port) : port->GetBitMask(),
|
||||
port->paletteID, d.monoTint,
|
||||
px + d.cellX * pw, py + d.cellY * ph, d.cellW * pw, d.cellH * ph, rot);
|
||||
}
|
||||
|
||||
@@ -1180,17 +1207,115 @@ void BTDrawCockpitPanels(LPDIRECT3DDEVICE9 device)
|
||||
CkFill(device, 0, L.viewY, L.viewX, L.viewH, band); // left
|
||||
CkFill(device, L.viewX + L.viewW, L.viewY, L.canvasW - (L.viewX + L.viewW), L.viewH, band); // right
|
||||
|
||||
// 2) Button lamp faces (UNDER the surfaces -- only the protruding edge shows).
|
||||
// 2a) #172 ALERT RING (glass-only deviation, #154-class, user-approved
|
||||
// 2026-08-13 -- the first cut, a +8px grown-face bloom, read as "the
|
||||
// button got fat" on the bench and was rejected): an ALERTING lamp in
|
||||
// a surround strip bank is a ~6px sliver (minimumStrip) -- Elengil's
|
||||
// fatal GeneratorB leak FLASHED lamp 0x1b for 28.4s and nobody saw it
|
||||
// (night-16; the pod's physical backlit buttons don't have this
|
||||
// problem). Draw a thin PULSING OUTLINE 3px outside the lamp's
|
||||
// border, UNDER everything: the lamp keeps its exact size, neighbors
|
||||
// repaint their own faces, the surfaces cover the inward arc, and
|
||||
// only the outward ring survives -- respecting the "no on-top
|
||||
// overlay" rule (twice field-broken, see the note below step 3).
|
||||
// The ring blinks WITH the lamp (same brightness sample) and only
|
||||
// while it genuinely alternates (flash bits set AND levels differ);
|
||||
// it vanishes on the lamp's own dark half-cycle, so it reads as
|
||||
// "alarm light" rather than geometry.
|
||||
// GATED OFF BY DEFAULT (BT_ALERT_RING=1 to enable), 2026-08-13: the
|
||||
// bench + Elengil's layout receipts proved the lamp paints and blinks
|
||||
// correctly on screen (see [lampblink]; code-identical loop in 913) --
|
||||
// the field issue is EXPECTATION (generator leak lights the button by
|
||||
// the RADAR, authentically; testers watch the MFDs), which the
|
||||
// handout now states. The ring stays available in case Friday shows
|
||||
// testers still miss it KNOWING where to look.
|
||||
unsigned long tick = GetTickCount();
|
||||
static int s_alertRing = -1;
|
||||
if (s_alertRing < 0)
|
||||
{ const char *ar = getenv("BT_ALERT_RING"); s_alertRing = (ar && *ar == '1') ? 1 : 0; }
|
||||
const int kRingGap = 3; // lamp border -> ring inner edge
|
||||
const int kRingWidth = 2;
|
||||
for (int i = 0; s_alertRing && i < L.buttonCount; i++)
|
||||
{
|
||||
const BTCockpitBtn &b = L.buttons[i];
|
||||
int state = CkLampState(b.address);
|
||||
if ((state & 0x3) != 0
|
||||
&& (((state >> 2) & 0x3) != ((state >> 4) & 0x3)))
|
||||
{
|
||||
int shade = BTLampBrightnessOf(state, tick);
|
||||
if (shade < 2) continue; // dark half-cycle: no ring
|
||||
D3DCOLOR fill, border;
|
||||
CkLampColors(b.colorClass, 3 /*bright*/, b.inert, &fill, &border);
|
||||
int rx = b.x - kRingGap - kRingWidth;
|
||||
int ry = b.y - kRingGap - kRingWidth;
|
||||
int rw = b.w + 2 * (kRingGap + kRingWidth);
|
||||
int rh = b.h + 2 * (kRingGap + kRingWidth);
|
||||
// four bars = the ring; the gap between ring and lamp stays band-dark
|
||||
CkFill(device, rx, ry, rw, kRingWidth, fill); // top
|
||||
CkFill(device, rx, ry + rh - kRingWidth, rw, kRingWidth, fill); // bottom
|
||||
CkFill(device, rx, ry, kRingWidth, rh, fill); // left
|
||||
CkFill(device, rx + rw - kRingWidth, ry, kRingWidth, rh, fill); // right
|
||||
}
|
||||
}
|
||||
|
||||
// 2b) Button lamp faces (UNDER the surfaces -- only the protruding edge shows).
|
||||
for (int i = 0; i < L.buttonCount; i++)
|
||||
{
|
||||
const BTCockpitBtn &b = L.buttons[i];
|
||||
int shade = BTLampBrightnessOf(CkLampState(b.address), tick);
|
||||
int state = CkLampState(b.address);
|
||||
int shade = BTLampBrightnessOf(state, tick);
|
||||
if (gCkPressed == b.address || gCkLatched[b.address & 0x7F]) shade = 3;
|
||||
D3DCOLOR fill, border;
|
||||
CkLampColors(b.colorClass, shade, b.inert, &fill, &border);
|
||||
CkFill(device, b.x, b.y, b.w, b.h, border);
|
||||
CkFill(device, b.x + 1, b.y + 1, b.w - 2, b.h - 2, fill);
|
||||
|
||||
// #172 SHADE-TRANSITION receipt (BT_LAMP_LOG only, first 24 blinks):
|
||||
// proves the surround paint loop actually COMPUTES the alternation --
|
||||
// the "did the pixels flash" question, answered without a screenshot
|
||||
// (the PNG-capture rig cratered the frame rate to ~1fps and was
|
||||
// scrapped). This base fill loop is code-identical to 913's, so its
|
||||
// verdict applies to the field build.
|
||||
if (getenv("BT_LAMP_LOG"))
|
||||
{
|
||||
static unsigned char s_lastShade[128];
|
||||
static int s_blinkLog = 0;
|
||||
int slot2 = b.address & 0x7F;
|
||||
if ((state & 0x3) != 0
|
||||
&& (((state >> 2) & 0x3) != ((state >> 4) & 0x3))
|
||||
&& (unsigned char)shade != s_lastShade[slot2]
|
||||
&& s_blinkLog < 24)
|
||||
{
|
||||
++s_blinkLog;
|
||||
DEBUG_STREAM << "[lampblink] 0x" << std::hex << b.address
|
||||
<< std::dec << " shade " << (int)s_lastShade[slot2]
|
||||
<< "->" << shade << " tick=" << tick
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
s_lastShade[slot2] = (unsigned char)shade;
|
||||
}
|
||||
|
||||
// #172 paint receipt: one line per ALERT edge per lamp -- the night-16
|
||||
// forensics could prove the lamp STATE but had zero visibility into
|
||||
// pixels ("the seam-to-pixels observability hole"). Cheap: fires only
|
||||
// when a lamp's alternating-status flips.
|
||||
{
|
||||
static unsigned char s_wasAlert[128];
|
||||
int alerting = ((state & 0x3) != 0
|
||||
&& (((state >> 2) & 0x3) != ((state >> 4) & 0x3))) ? 1 : 0;
|
||||
int slot = b.address & 0x7F;
|
||||
if (alerting != s_wasAlert[slot])
|
||||
{
|
||||
s_wasAlert[slot] = (unsigned char)alerting;
|
||||
DEBUG_STREAM << "[lamppx] 0x" << std::hex << b.address
|
||||
<< (alerting ? " alert ON" : " alert OFF")
|
||||
<< " cell=" << std::dec << b.w << "x" << b.h
|
||||
<< (alerting ? "+ring" : "")
|
||||
<< " at " << b.x << "," << b.y
|
||||
<< " state=0x" << std::hex << state << std::dec
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Gauge surfaces on top (green-tinted mono / palette sec). Reuses the
|
||||
@@ -1224,7 +1349,9 @@ void BTDrawCockpitPanels(LPDIRECT3DDEVICE9 device)
|
||||
}
|
||||
int surf = ckSlotOf[i];
|
||||
int useTint = (d.monoTint < 0) ? -1 : tint;
|
||||
svga->DrawDevSurface(device, i, port->GetBitMask(), port->paletteID, useTint,
|
||||
int useMask = (d.monoTint < 0) ? BTSecCompositeMask(gr, port)
|
||||
: port->GetBitMask();
|
||||
svga->DrawDevSurface(device, i, useMask, port->paletteID, useTint,
|
||||
(float)L.surfX[surf], (float)L.surfY[surf], (float)L.surfW[surf], (float)L.surfH[surf], rot);
|
||||
}
|
||||
}
|
||||
@@ -5735,7 +5862,7 @@ Logical SVGA16::Update(Logical forceAll)
|
||||
//Drawing secondary, make sure we got secondary
|
||||
if (secPort != NULL)
|
||||
{
|
||||
secMask = secPort->GetBitMask();
|
||||
secMask = BTSecCompositeMask(renderer, secPort); // sec | overlay (DAC parity)
|
||||
secPalette = &((SVGA16 *) secPort->graphicsDisplay)->palette[secPort->paletteID];
|
||||
} else
|
||||
{
|
||||
|
||||
+46
-33
@@ -216,7 +216,28 @@ static LONG WINAPI
|
||||
if (eip >= base && eip < base + 0x2000000UL)
|
||||
std::cout << "btl4+0x" << std::hex << (eip - base);
|
||||
else
|
||||
std::cout << "0x" << std::hex << eip;
|
||||
{
|
||||
//
|
||||
// #170: name the owning MODULE -- a foreign-DLL stack is
|
||||
// unresolvable after the fact without its (ASLR'd) base; the
|
||||
// steam-worker NULL-call needed this and didn't have it.
|
||||
//
|
||||
MEMORY_BASIC_INFORMATION fmbi;
|
||||
char dll_path[MAX_PATH];
|
||||
if (VirtualQuery((void *)eip, &fmbi, sizeof(fmbi)) != 0
|
||||
&& fmbi.AllocationBase != NULL
|
||||
&& GetModuleFileNameA((HMODULE)fmbi.AllocationBase,
|
||||
dll_path, sizeof(dll_path)) != 0)
|
||||
{
|
||||
const char *dll_name = dll_path;
|
||||
for (const char *s = dll_path; *s; ++s)
|
||||
if (*s == '\\' || *s == '/') dll_name = s + 1;
|
||||
std::cout << dll_name << "+0x" << std::hex
|
||||
<< (eip - (unsigned long)fmbi.AllocationBase);
|
||||
}
|
||||
else
|
||||
std::cout << "0x" << std::hex << eip;
|
||||
}
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (ebp == 0 || (ebp & 3) != 0
|
||||
|| VirtualQuery((void *)ebp, &mbi, sizeof(mbi)) == 0
|
||||
@@ -710,29 +731,18 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
lt = shifted;
|
||||
}
|
||||
}
|
||||
// SIZE ROLL-OVER -- never deletes anything, but keeps each FILE small
|
||||
// enough to actually send. A playtest evening concatenates into one
|
||||
// file (4.3 MB from a single session in scratchpad/night5/), and the
|
||||
// channel this evidence travels through is a chat attachment. Part 0
|
||||
// is <stem>_YYYYMMDD.log; once it passes the cap the NEXT launch opens
|
||||
// <stem>_YYYYMMDD.1.log, and so on. Checked only at open, so one very
|
||||
// long session can still overrun -- that is deliberate: never split a
|
||||
// live session across files.
|
||||
const DWORD part_max = 8UL * 1024UL * 1024UL;
|
||||
for (int part = 0; part < 1000; ++part)
|
||||
{
|
||||
if (part == 0)
|
||||
wsprintfA(resolvedLog, "%s_%04d%02d%02d.log",
|
||||
logStem, (int)lt.wYear, (int)lt.wMonth, (int)lt.wDay);
|
||||
else
|
||||
wsprintfA(resolvedLog, "%s_%04d%02d%02d.%d.log",
|
||||
logStem, (int)lt.wYear, (int)lt.wMonth, (int)lt.wDay, part);
|
||||
WIN32_FILE_ATTRIBUTE_DATA fad;
|
||||
if (!GetFileAttributesExA(resolvedLog, GetFileExInfoStandard, &fad))
|
||||
break; // does not exist yet -- use it
|
||||
if (fad.nFileSizeHigh == 0 && fad.nFileSizeLow < part_max)
|
||||
break; // still room to append
|
||||
}
|
||||
// ONE NIGHT = ONE FILE (the 8 MB size roll-over RETIRED 2026-08-13).
|
||||
// The roll existed because the evidence channel is a Discord
|
||||
// attachment (free-tier cap: 10 MB today; 8 MB when this shipped) --
|
||||
// but multi-part files cost us field evidence the moment they
|
||||
// existed: testers attach "the log" (the newest part) and part 0
|
||||
// stays home (night16: Elengil's 20:17 ET incident window was in the
|
||||
// unsent pre-rotation part). Transport is now SENDLOGS.bat (ships
|
||||
// in the dist root): zips every log/matchlog/lastrun to one ~10:1
|
||||
// compressed attachment, so raw file size no longer matters and the
|
||||
// whole night reads as one uninterrupted file.
|
||||
wsprintfA(resolvedLog, "%s_%04d%02d%02d.log",
|
||||
logStem, (int)lt.wYear, (int)lt.wMonth, (int)lt.wDay);
|
||||
logSelfNamed = 1;
|
||||
}
|
||||
}
|
||||
@@ -1241,17 +1251,20 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
if (BTFrontEnd_Run(&fe_spec) != 0 || fe_spec.mode == BTFeLaunchNone)
|
||||
{
|
||||
BTLastrunNote("clean exit: player quit from the menu");
|
||||
#ifdef BT_STEAM
|
||||
// #163: the menu keeps the Steam transport up for the lobby;
|
||||
// returning through the CRT would run DLL detach with live
|
||||
// Steam threads -- the same intermittent deadlock the
|
||||
// round-end relaunch hit. Tear it down deliberately first.
|
||||
//
|
||||
// #163/#170: the menu keeps the Steam transport up for the
|
||||
// lobby, and a CRT return would run DLL detach with live
|
||||
// Steam threads (the 883 wedge). ShutdownAll is now a
|
||||
// QUIESCE -- it deliberately does NOT stop those threads
|
||||
// (SteamAPI_Shutdown mid-dispatch was the #170 NULL-call
|
||||
// crash) -- so this path must die exactly like every other
|
||||
// exit: flush, quiesce, TerminateProcess. One topology.
|
||||
//
|
||||
{
|
||||
extern void BTSteamNet_ShutdownAll();
|
||||
BTSteamNet_ShutdownAll();
|
||||
extern void BTOrderlyDie(void);
|
||||
BTOrderlyDie(); // never returns
|
||||
}
|
||||
#endif
|
||||
return 0; // quit from the menu
|
||||
return 0; // unreachable (TerminateProcess)
|
||||
}
|
||||
char fe_arguments[192];
|
||||
char fe_value[64];
|
||||
|
||||
@@ -181,9 +181,9 @@ static BOOL CALLBACK
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
BTOrderlyDie(void)
|
||||
{
|
||||
void
|
||||
BTOrderlyDie(void) // #170: non-static -- the menu-quit
|
||||
{ // path in btl4main dies through here
|
||||
{
|
||||
extern void BTMatchLogClose();
|
||||
BTMatchLogClose(); // complete receipts on disk (the
|
||||
|
||||
+36
-18
@@ -1233,29 +1233,47 @@ void
|
||||
{
|
||||
Mech__DamageZone *zone =
|
||||
(Mech__DamageZone *)damageZones[zoneIndex]; // this[0x120][idx]
|
||||
Subsystem *critted = 0;
|
||||
|
||||
if (zone->GetDamageZoneState() != DamageZone::BurningState // zone state != 1
|
||||
&& BTMechCriticalChance(this, zoneIndex)) // @0x4a0164 (roll below)
|
||||
//
|
||||
// #174 (2026-08-13): the binary's zone-state guard wraps the WHOLE
|
||||
// per-burst application -- `if (piVar1[9] != 1) { crit-roll |
|
||||
// TakeDamage; tally; destroyed-flag }` (part_012.c:14661-14677,
|
||||
// @0x4a0446) -- a burst landing on an already-destroyed zone is a
|
||||
// structural NO-OP: no re-application, no cascade re-fire, NO SCORE.
|
||||
// The port had narrowed the guard to the crit roll only, so
|
||||
// continued fire into a dead zone re-saturated it every burst ->
|
||||
// Mech__DamageZone::TakeDamage's >=1.0 tail re-ran
|
||||
// RecurseSegmentTable (night-16: zone 18 x7, zone 9 x4 in single
|
||||
// missions), each pass re-pushing the crit allotment into the
|
||||
// surviving subsystems (the ram "crits worsened with each
|
||||
// collision") -- and the shooter's damageTally kept scoring hits
|
||||
// on wreckage the binary scores as ZERO.
|
||||
//
|
||||
if (zone->GetDamageZoneState() != DamageZone::BurningState) // zone state != 1
|
||||
{
|
||||
critted = zone->CriticalHit(message->damageData); // @0049ccc4
|
||||
if (critted != 0)
|
||||
Subsystem *critted = 0;
|
||||
if (BTMechCriticalChance(this, zoneIndex)) // @0x4a0164 (roll below)
|
||||
{
|
||||
damageTally +=
|
||||
((MechSubsystem *)critted)->CriticalScoreBonus(); // +0x108
|
||||
if (BTEnvOn("BT_CRIT_LOG", 0))
|
||||
DEBUG_STREAM << "[critroll] zone=" << zoneIndex
|
||||
<< " -> " << (critted->GetName() ? critted->GetName() : "?")
|
||||
<< " subLvl=" << ((MechSubsystem *)critted)->GetSubsystemDamageLevel()
|
||||
<< "\n" << std::flush;
|
||||
critted = zone->CriticalHit(message->damageData); // @0049ccc4
|
||||
if (critted != 0)
|
||||
{
|
||||
damageTally +=
|
||||
((MechSubsystem *)critted)->CriticalScoreBonus(); // +0x108
|
||||
if (BTEnvOn("BT_CRIT_LOG", 0))
|
||||
DEBUG_STREAM << "[critroll] zone=" << zoneIndex
|
||||
<< " -> " << (critted->GetName() ? critted->GetName() : "?")
|
||||
<< " subLvl=" << ((MechSubsystem *)critted)->GetSubsystemDamageLevel()
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (critted == 0)
|
||||
zone->TakeDamage(message->damageData); // zone vtbl+0x18 @0x4a0488
|
||||
if (critted == 0)
|
||||
zone->TakeDamage(message->damageData); // zone vtbl+0x18 @0x4a0488
|
||||
|
||||
damageTally += message->damageData.damageAmount; // +0x30
|
||||
if (zone->GetDamageZoneState() == DamageZone::BurningState)
|
||||
zoneDestroyed = 1;
|
||||
damageTally += message->damageData.damageAmount; // +0x30
|
||||
if (zone->GetDamageZoneState() == DamageZone::BurningState)
|
||||
zoneDestroyed = 1; // set only by the burst that
|
||||
} // DESTROYS it (binary: inside
|
||||
// the guard, part_012.c:14674)
|
||||
|
||||
if (--burstsLeft == 0)
|
||||
break;
|
||||
|
||||
@@ -7494,6 +7494,104 @@ void
|
||||
}
|
||||
}
|
||||
|
||||
// #165 BENCH (BT_CRIT_SUBSYS=<name>[,<name>...]): kill named subsystems
|
||||
// through the REAL crit path -- Damage record -> ApplyDamageAndMeasure ->
|
||||
// virtual TakeDamage -- NOT the direct cell writes BT_KILL_SUBSYS does.
|
||||
// This is the path the field takes (the crit lottery), and the path the
|
||||
// old 4,213-refusal bench never exercised: BT_KILL_SUBSYS wrote
|
||||
// statusAlarm AND the zone directly, so it validated the fire gate while
|
||||
// the field's writer (MechWeapon::TakeDamage) silently dropped the
|
||||
// destroyed-side write. Applies one energy-damage chunk per frame from
|
||||
// frame 900 until the subsystem's own zone saturates ([crit] receipt
|
||||
// fires from MechSubsystem::TakeDamage on the edge), then stops.
|
||||
// Env-gated, viewpoint mech only.
|
||||
if ((Entity *)this == application->GetViewpointEntity()
|
||||
&& getenv("BT_CRIT_SUBSYS"))
|
||||
{
|
||||
static int s_csFrame = 0;
|
||||
if (++s_csFrame >= 900) // same settle window as killsub
|
||||
{
|
||||
char want_list[256];
|
||||
strncpy(want_list, getenv("BT_CRIT_SUBSYS"), sizeof(want_list) - 1);
|
||||
want_list[sizeof(want_list) - 1] = 0;
|
||||
for (char *want = strtok(want_list, ","); want != 0;
|
||||
want = strtok(0, ","))
|
||||
{
|
||||
// PARTIAL form ("Name=0.5"): stop at that zone level -- the
|
||||
// freeze-regression phase (a partially-critted weapon must
|
||||
// keep recycling; the old port tail froze it at alarm 1).
|
||||
float target = 1.0f;
|
||||
char *eq = strchr(want, '=');
|
||||
if (eq != 0)
|
||||
{
|
||||
*eq = 0;
|
||||
target = (float)atof(eq + 1);
|
||||
}
|
||||
for (int i = 2; i < GetSubsystemCount(); ++i)
|
||||
{
|
||||
Subsystem *s = GetSubsystem(i);
|
||||
if (s == 0 || s->GetName() == 0) continue;
|
||||
if (stricmp(s->GetName(), want) != 0) continue;
|
||||
if (!s->IsDerivedFrom(MechSubsystem::ClassDerivations)) continue;
|
||||
MechSubsystem *ms = (MechSubsystem *)s;
|
||||
if (ms->GetSubsystemDamageLevel() >= target) break; // done
|
||||
Damage d;
|
||||
d.damageType = Damage::EnergyDamageType;
|
||||
d.damageAmount = 0.75f; // FINE-GRAINED: a small-laser
|
||||
// private zone saturates on a
|
||||
// single 20.0 chunk (first run);
|
||||
// ~0.04 level/frame ramps let
|
||||
// the PARTIAL stop actually stop
|
||||
d.burstCount = 1;
|
||||
ms->ApplyDamageAndMeasure(d); // FUN_004ac07c -> virtual TakeDamage
|
||||
if ((s_csFrame % 30) == 0)
|
||||
DEBUG_STREAM << "[critsub] '" << s->GetName()
|
||||
<< "' zone=" << (float)ms->GetSubsystemDamageLevel()
|
||||
<< std::endl << std::flush;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #174 BENCH (BT_ZONE_HAMMER=<zoneIdx>[,<amt>]): 4x/sec, dispatch a
|
||||
// TakeDamage with an EXPLICIT damageZone at the viewpoint mech itself.
|
||||
// Pointed at a descend=1 non-vital zone (dz_larm=2 on most chassis),
|
||||
// the zone saturates, cascades ONCE, the mech survives, and the hammer
|
||||
// keeps landing on the DEAD zone -- the exact repro of the night-16
|
||||
// re-descend (zone 18 x7). With the burst-loop guard at binary scope:
|
||||
// ONE [cascade] for the life and the [dmghit] stream for that zone
|
||||
// STOPS at saturation (the guard skips application entirely).
|
||||
if ((Entity *)this == application->GetViewpointEntity()
|
||||
&& getenv("BT_ZONE_HAMMER"))
|
||||
{
|
||||
static int s_zhFrame = 0;
|
||||
++s_zhFrame;
|
||||
if (s_zhFrame >= 900 && (s_zhFrame % 15) == 0) // settle, then ~4 Hz
|
||||
{
|
||||
int zidx = 2;
|
||||
float amt = 8.0f;
|
||||
{
|
||||
char spec[64];
|
||||
strncpy(spec, getenv("BT_ZONE_HAMMER"), sizeof(spec) - 1);
|
||||
spec[sizeof(spec) - 1] = 0;
|
||||
char *comma = strchr(spec, ',');
|
||||
if (comma != 0) { *comma = 0; amt = (float)atof(comma + 1); }
|
||||
if (spec[0]) zidx = atoi(spec);
|
||||
}
|
||||
Damage dmg;
|
||||
dmg.damageType = Damage::ExplosiveDamageType;
|
||||
dmg.damageAmount = amt;
|
||||
dmg.burstCount = 1;
|
||||
dmg.impactPoint = localOrigin.linearPosition;
|
||||
Entity::TakeDamageMessage td(
|
||||
Entity::TakeDamageMessageID,
|
||||
sizeof(Entity::TakeDamageMessage),
|
||||
GetEntityID(), zidx, dmg);
|
||||
Dispatch(&td);
|
||||
}
|
||||
}
|
||||
|
||||
// task #13 scripted verify (BT_VALVE_TEST=1): one MoveValve press at
|
||||
// frame ~600 -- Condenser1's valveState cycles 1 -> 5, so the flow
|
||||
// redistribution gives it 5/10 of the total coolant flow ([valve] log
|
||||
|
||||
@@ -142,6 +142,11 @@ MechSubsystem::MechSubsystem(
|
||||
{
|
||||
refCount = NewRefCount(0x10); // this[0x3d]
|
||||
this->owner = owner; // this[0x34] -- the owning Mech (canonical)
|
||||
simulationState = 0; // #165: was NEVER initialized anywhere --
|
||||
// MemoryBlock pools recycle unzeroed
|
||||
// (MEMBLOCK.cpp), so stale garbage ==1
|
||||
// could brick a weapon from spawn and
|
||||
// draw the seek-graph destroyed bitmap
|
||||
controlDestination = 0; // this[0x3a] = param_7 (ctor pass-through;
|
||||
controlMessageID = 0; // this[0x3b] = param_8 weapons override -- task #6)
|
||||
vitalSubsystem = 0; // this[0x39]
|
||||
@@ -187,6 +192,8 @@ MechSubsystem::MechSubsystem(
|
||||
// ctor only set hostEntity; subclasses read
|
||||
// `owner` widely -> must be set or it is garbage.)
|
||||
statusAlarm.SetLevel(0); // FUN_0041bbd8(this+0xb, 0)
|
||||
simulationState = 0; // #165: uninitialized-landmine fix (see
|
||||
// the sibling ctor)
|
||||
controlDestination = 0; // this[0x3a]=param_6 (ctor pass-through;
|
||||
controlMessageID = 0; // this[0x3b]=param_7 weapons override -- task #6)
|
||||
resource = subsystem_resource; // this[0x3c]
|
||||
@@ -279,6 +286,7 @@ Scalar MechSubsystem::GetSubsystemDamageLevel() const
|
||||
void MechSubsystem::ForceCriticalFailure()
|
||||
{
|
||||
statusAlarm.SetLevel(1); // +0x2C: 1 = Destroyed
|
||||
simulationState = 1; // #165 twin (see TakeDamage)
|
||||
if (printSimulationState) // +0x104 gate
|
||||
{
|
||||
PrintState(); // vtable slot 0x34 @4ac8c0
|
||||
@@ -303,6 +311,7 @@ void MechSubsystem::ForceCriticalFailure()
|
||||
void MechSubsystem::RespawnRepair()
|
||||
{
|
||||
statusAlarm.SetLevel(0); // operational
|
||||
simulationState = 0; // #165 twin (see TakeDamage)
|
||||
if (damageZone != 0)
|
||||
{
|
||||
((DamageZone *)damageZone)->damageLevel = 0.0f;
|
||||
@@ -358,6 +367,7 @@ Logical
|
||||
if (StatusThreshold <= ((DamageZone *)damageZone)->damageLevel) // _DAT_004ac140 (engine view)
|
||||
{
|
||||
statusAlarm.SetLevel(1); // FUN_0041bbd8(this+0xb, 1)
|
||||
simulationState = 1; // #165 twin (see TakeDamage)
|
||||
if (printSimulationState != 0) // this[0x41]
|
||||
{
|
||||
OnAlarmChanged(); // (*this.vtable+0x34)(this)
|
||||
@@ -386,6 +396,7 @@ void
|
||||
((DamageZone *)damageZone)->damageLevel = 1.0f; // dz+0x158 = 1.0 (engine view)
|
||||
}
|
||||
statusAlarm.SetLevel(1); // FUN_0041bbd8(this+0xb, 1)
|
||||
simulationState = 1; // #165 twin (see TakeDamage)
|
||||
if (printSimulationState != 0)
|
||||
{
|
||||
OnAlarmChanged(); // (*this.vtable+0x34)(this)
|
||||
@@ -407,6 +418,7 @@ void
|
||||
((DamageZone *)damageZone)->damageLevel = 0.0f; // dz+0x158 = 0 (engine view)
|
||||
damageZone->alarm.SetLevel(0); // FUN_0041bbd8(dz+0x10, 0)
|
||||
statusAlarm.SetLevel(0); // FUN_0041bbd8(this+0xb, 0)
|
||||
simulationState = 0; // #165 twin (see TakeDamage)
|
||||
if (printSimulationState != 0)
|
||||
{
|
||||
OnAlarmChanged();
|
||||
@@ -520,7 +532,18 @@ void MechSubsystem::TakeDamage(Damage &damage)
|
||||
|
||||
if (dz->damageLevel >= 1.0f) // _DAT_004ac140
|
||||
{
|
||||
// #165: named destruction receipt on the EDGE only (damage keeps
|
||||
// landing on dead subsystems; the write below is idempotent) -- the
|
||||
// crit-path kill had NO field receipt, which is how an X'd-but-firing
|
||||
// weapon hid for a month. Always-on: once per subsystem per life.
|
||||
if (statusAlarm.GetLevel() != 1)
|
||||
DEBUG_STREAM << "[crit] '" << (GetName() ? GetName() : "?")
|
||||
<< "' DESTROYED (zone saturated)\n" << std::flush;
|
||||
statusAlarm.SetLevel(1); // Destroyed
|
||||
simulationState = 1; // #165: the binary's +0x40 is ONE
|
||||
// cell; the port split it -- keep
|
||||
// the twin in lockstep (gate clause
|
||||
// 1, seek-graph destroyed bitmap)
|
||||
if (printSimulationState) // +0x104
|
||||
{
|
||||
PrintState(); // vtable +0x34 @4ac8c0
|
||||
|
||||
@@ -411,34 +411,39 @@ Logical
|
||||
// @004b96d4 -- slot 9 (TASK #51 RENAME: this body was mislabeled slot-6
|
||||
// ReadUpdateRecord; @004b96d4 chains @004b0efc = PoweredSubsystem::TakeDamage,
|
||||
// which dispatches on *param==4 == Damage::damageType -- damage semantics).
|
||||
// The PoweredSubsystem::TakeDamage body (electrical-short handling) is not yet
|
||||
// reconstructed; chain to the engine Subsystem base, and keep the damage-zone
|
||||
// alarm tracking this port has shipped with (best-effort; the binary's alarm
|
||||
// display on weapon damage flows through the unreconstructed @004b0efc chain).
|
||||
//
|
||||
// #165 ROOT CAUSE (night-16 hunt, 2026-08-13). The old body here called the
|
||||
// raw ENGINE Subsystem::TakeDamage (zone accumulation ONLY) and then drove
|
||||
// weaponAlarm from the zone state -- two defects in one:
|
||||
// (1) it DROPPED the destroyed-side invariant: the binary keeps ONE
|
||||
// destroyed cell per subsystem (+0x40 = statusAlarm level) that every
|
||||
// destruction path writes and the fire gate reads. A weapon killed by
|
||||
// the CRIT LOTTERY (the everyday field path) saturated its private
|
||||
// zone (-> the MFD X, [techstat] condition 0) but never wrote the gate
|
||||
// cell -- the X'd weapon kept firing (Oracle 20260812: ER PPC firing
|
||||
// indefinitely; the PPC+SL pair firing until the arm CASCADE finally
|
||||
// wrote the cell). The 4,213-refusal bench passed because
|
||||
// BT_KILL_SUBSYS writes both cells -- it validated the gate, not the
|
||||
// writers.
|
||||
// (2) the weaponAlarm tail wrote the FSM cell BACKWARDS: saturation ->
|
||||
// level 0 (Firing!), partial damage -> level 1 -- a state with NO case
|
||||
// in either weapon FSM: the silent freeze (berserker's 20x [beam]
|
||||
// STUCK-ON, and the state-1+beamFlag combination that drew Conn Man's
|
||||
// 883 hanging beam -- #164's upstream cause). The binary never drives
|
||||
// the FSM from damage: a destroyed weapon parks at Loading(3) via the
|
||||
// fire gate's per-frame refusal (ResetFiringState, emitter.cpp).
|
||||
// FIX: chain to MechSubsystem::TakeDamage -- the correctly-reconstructed
|
||||
// binary base (@0x4ac0bc: zone TakeDamage, then damageLevel>=1.0 ->
|
||||
// statusAlarm=1 + pin + vital-kill) -- and do NOT touch the FSM. The
|
||||
// binary's electrical-short middle layer (@004b0efc) remains unreconstructed
|
||||
// (a marked gap, unchanged); what is restored is the destruction invariant.
|
||||
// MechSubsystem::TakeDamage guards damageZone==0 itself (the 2026-07-29
|
||||
// Owens NULL-zone field crash stays guarded).
|
||||
//
|
||||
void
|
||||
MechWeapon::TakeDamage(Damage &damage)
|
||||
{
|
||||
// FIELD CRASH GUARD (2026-07-29, build 641): the engine base derefs
|
||||
// damageZone unguarded; an Owens weapon reached here with zone == NULL
|
||||
// the first night crits could land (#80). See ApplyDamageAndMeasure.
|
||||
if (this->Subsystem::damageZone != 0)
|
||||
Subsystem::TakeDamage(damage); // engine base (real chain: @004b0efc)
|
||||
|
||||
// Port behavior (kept): a destroyed weapon clears its display alarm;
|
||||
// otherwise the alarm tracks the resolved damage-zone state.
|
||||
::DamageZone *dz = this->Subsystem::damageZone;
|
||||
if (dz != 0
|
||||
&& dz->GetGraphicState() == DamageZone::DestroyedGraphicState)
|
||||
{
|
||||
weaponAlarm.SetLevel(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
weaponAlarm.SetLevel(
|
||||
(dz != 0 && dz->damageLevel > 0.0f) ? 1 : 0
|
||||
);
|
||||
}
|
||||
MechSubsystem::TakeDamage(damage); // @0x4ac0bc semantics
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
rem ==========================================================================
|
||||
rem BT411 -- package tonight's logs into ONE Discord-attachable zip.
|
||||
rem Double-click me after a playtest. The zip lands on your DESKTOP as
|
||||
rem BTLOGS_<machine>_<date>.zip -- attach that one file in Discord.
|
||||
rem Collects: every session log, matchlog, and launch breadcrumb. Nothing
|
||||
rem is deleted or modified; this only makes a copy.
|
||||
rem ==========================================================================
|
||||
cd /d "%~dp0"
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"$d = Get-Date -Format yyyyMMdd_HHmm;" ^
|
||||
"$out = Join-Path ([Environment]::GetFolderPath('Desktop')) (\"BTLOGS_{0}_{1}.zip\" -f $env:COMPUTERNAME, $d);" ^
|
||||
"$files = Get-ChildItem -Path 'content\*.log','content\lastrun_*.txt','content\matchlog_*.txt','content\cdb_*.txt' -ErrorAction SilentlyContinue | Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-36) };" ^
|
||||
"if (-not $files) { Write-Host 'No logs found -- run me from the BT411 folder (next to the content directory).'; exit 1 }" ^
|
||||
"Compress-Archive -Force -Path $files.FullName -DestinationPath $out;" ^
|
||||
"Write-Host ('Wrote ' + $out + ' (' + $files.Count + ' files, ' + [math]::Round((Get-Item $out).Length/1MB,1) + ' MB)');"
|
||||
echo.
|
||||
echo Attach the BTLOGS zip from your Desktop in Discord. Thanks!
|
||||
pause
|
||||
@@ -1,229 +0,0 @@
|
||||
"""Render every map in BTL4.RES the way the cockpit draws them.
|
||||
|
||||
The technique is the one worked out for Red Planet (RP412
|
||||
tools/pages/navmap.py) and it transfers because both games are MUNGA:
|
||||
a map stream is a run of Entity::MakeMessage records, each carrying its
|
||||
own length, and each naming a Model List whose GaugeImage is the outline
|
||||
the display draws.
|
||||
|
||||
Where BT differs from RP:
|
||||
|
||||
* The resource file has a real directory. Header is
|
||||
(labOnly, maxID) at +4 and an offset table at +12; each descriptor
|
||||
holds rid/rtype at +0, a 32-byte name at +8, and priority, flags,
|
||||
offset and length at +40. RP412's file inlines the data after each
|
||||
descriptor instead, so its walk does not apply here.
|
||||
* rtype 1 is a Model List, 18 a GaugeImage, 14 a map stream. A model's
|
||||
outline is the rtype-18 member of its list - a direct join, rather
|
||||
than RP412's match on the model's name.
|
||||
* Records are advanced by (length + 3) & ~3. RP's are not padded.
|
||||
* Every primitive carries an explicit palette index; nothing falls back
|
||||
to a display default the way RP's colour 0 does.
|
||||
|
||||
Colours are indices into btspal.pcc, the palette L4GAUGE.CFG configures
|
||||
the secondary port with: configure(0,sec,270,0x003F,clut0,rgb,btspal.pcc).
|
||||
PCC is PCX, so the palette is the last 769 bytes.
|
||||
|
||||
Usage: python tools/build_maps.py [out.html]
|
||||
"""
|
||||
import base64, collections, html, io, os, struct, sys
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
RES = open(os.path.join(ROOT, 'content', 'BTL4.RES'), 'rb').read()
|
||||
OUT = sys.argv[1] if len(sys.argv) > 1 else os.path.join(ROOT, 'docs', 'MAPS.html')
|
||||
|
||||
MODEL_LIST, SOLIDS, MAP_STREAM, GAUGE_IMAGE = 1, 9, 14, 18
|
||||
|
||||
# ------------------------------------------------------------- directory
|
||||
labOnly, maxID = struct.unpack_from('<ii', RES, 4)
|
||||
RESOURCES = {}
|
||||
for off in struct.unpack_from('<%dI' % maxID, RES, 12):
|
||||
if off == 0:
|
||||
continue
|
||||
rid, rtype = struct.unpack_from('<ii', RES, off)
|
||||
name = RES[off + 8:off + 40].split(b'\0')[0].decode('ascii', 'replace')
|
||||
prio, flags, addr, size = struct.unpack_from('<iIII', RES, off + 40)
|
||||
RESOURCES[rid] = {'t': rtype, 'name': name, 'off': addr, 'len': size}
|
||||
|
||||
|
||||
def members(rid):
|
||||
r = RESOURCES.get(rid)
|
||||
if not r or r['t'] != MODEL_LIST:
|
||||
return ()
|
||||
n = struct.unpack_from('<i', RES, r['off'])[0]
|
||||
return struct.unpack_from('<%di' % n, RES, r['off'] + 4)
|
||||
|
||||
|
||||
# A model's outline is simply the GaugeImage in its own Model List.
|
||||
OUTLINE = {}
|
||||
for rid, r in RESOURCES.items():
|
||||
if r['t'] == MODEL_LIST:
|
||||
g = [m for m in members(rid)
|
||||
if RESOURCES.get(m, {}).get('t') == GAUGE_IMAGE]
|
||||
if g:
|
||||
OUTLINE[rid] = g[0]
|
||||
|
||||
|
||||
def gauge_image(off):
|
||||
p = off
|
||||
vcount = struct.unpack_from('<i', RES, p)[0]; p += 4
|
||||
verts = [struct.unpack_from('<3f', RES, p + 12 * i) for i in range(vcount)]
|
||||
p += 12 * vcount
|
||||
lods = struct.unpack_from('<i', RES, p)[0]; p += 4
|
||||
scales = struct.unpack_from('<%df' % lods, RES, p); p += 4 * lods
|
||||
out = []
|
||||
for lod in range(lods):
|
||||
pcount = struct.unpack_from('<i', RES, p)[0]; p += 4
|
||||
prims = []
|
||||
for _ in range(pcount):
|
||||
_t, colour, attrs, n = struct.unpack_from('<4i', RES, p); p += 16
|
||||
prims.append((colour, attrs, struct.unpack_from('<%di' % n, RES, p)))
|
||||
p += 4 * n
|
||||
out.append((scales[lod], prims))
|
||||
return verts, out
|
||||
|
||||
|
||||
def rotate(q, p):
|
||||
qx, qy, qz, qw = q
|
||||
x, y, z = p
|
||||
tx = 2 * (qy * z - qz * y)
|
||||
ty = 2 * (qz * x - qx * z)
|
||||
tz = 2 * (qx * y - qy * x)
|
||||
return (x + qw * tx + qy * tz - qz * ty,
|
||||
y + qw * ty + qz * tx - qx * tz,
|
||||
z + qw * tz + qx * ty - qy * tx)
|
||||
|
||||
|
||||
def placements(rid):
|
||||
"""-> ([(outline id, position, quaternion)], total records, model tally).
|
||||
|
||||
Each record is an Entity::MakeMessage: its own length at +0, flags at
|
||||
+8, classToCreate at +28, the resource it names at +40, instanceFlags
|
||||
at +44 and the origin at +48. Records shorter than 76 bytes cannot
|
||||
carry an origin and are skipped - the arenas hold a couple of those."""
|
||||
m = RESOURCES[rid]
|
||||
count = struct.unpack_from('<i', RES, m['off'])[0]
|
||||
p, end = m['off'] + 4, m['off'] + m['len']
|
||||
drawn, total, tally = [], 0, collections.Counter()
|
||||
for _ in range(count):
|
||||
if p + 12 > end:
|
||||
break
|
||||
length = struct.unpack_from('<I', RES, p)[0]
|
||||
if not (12 <= length <= 4096) or p + length > end:
|
||||
break
|
||||
total += 1
|
||||
if length >= 76:
|
||||
target = struct.unpack_from('<i', RES, p + 40)[0]
|
||||
if target in OUTLINE:
|
||||
drawn.append((OUTLINE[target],
|
||||
struct.unpack_from('<3f', RES, p + 48),
|
||||
struct.unpack_from('<4f', RES, p + 60)))
|
||||
tally[RESOURCES[target]['name']] += 1
|
||||
p += (length + 3) & ~3 # BT pads records; RP does not
|
||||
return drawn, total, tally
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- palette
|
||||
pal = open(os.path.join(ROOT, 'content', 'GAUGE', 'btspal.pcc'), 'rb').read()
|
||||
if len(pal) < 769 or pal[-769] != 0x0C:
|
||||
sys.exit('btspal.pcc has no VGA palette where PCX keeps one')
|
||||
base = len(pal) - 768
|
||||
PALETTE = [tuple(pal[base + i * 3:base + i * 3 + 3]) for i in range(256)]
|
||||
|
||||
|
||||
def plan(drawn, box=520):
|
||||
from PIL import Image, ImageDraw
|
||||
xs = [d[1][0] for d in drawn]
|
||||
zs = [d[1][2] for d in drawn]
|
||||
mpp = max((max(xs) - min(xs)) / box, (max(zs) - min(zs)) / box, 1e-4) * 1.15
|
||||
pad = 10
|
||||
iw = max(24, int((max(xs) - min(xs)) / mpp) + pad * 2)
|
||||
ih = max(24, int((max(zs) - min(zs)) / mpp) + pad * 2)
|
||||
cx, cz = (min(xs) + max(xs)) / 2, (min(zs) + max(zs)) / 2
|
||||
img = Image.new('RGB', (iw, ih), PALETTE[0])
|
||||
dr = ImageDraw.Draw(img)
|
||||
cache = {}
|
||||
for gid, pos, q in drawn:
|
||||
if gid not in cache:
|
||||
cache[gid] = gauge_image(RESOURCES[gid]['off'])
|
||||
verts, lods = cache[gid]
|
||||
lod = 0
|
||||
while lod < len(lods) and mpp > lods[lod][0]:
|
||||
lod += 1
|
||||
if lod >= len(lods):
|
||||
continue
|
||||
for colour, attrs, idx in lods[lod][1]:
|
||||
pts = []
|
||||
for k in idx:
|
||||
if not (0 <= k < len(verts)):
|
||||
continue
|
||||
v = verts[k]
|
||||
if attrs & 1: # attributeUnscaled
|
||||
v = (v[0] * mpp, v[1] * mpp, v[2] * mpp)
|
||||
g = rotate(q, v)
|
||||
pts.append((iw / 2 + ((g[0] + pos[0]) - cx) / mpp,
|
||||
ih / 2 - ((g[2] + pos[2]) - cz) / mpp))
|
||||
if len(pts) > 1:
|
||||
dr.line(pts, fill=PALETTE[colour], width=1)
|
||||
buf = io.BytesIO()
|
||||
img.convert('P', palette=Image.ADAPTIVE, colors=64).save(
|
||||
buf, 'PNG', optimize=True)
|
||||
return ('data:image/png;base64,' + base64.b64encode(buf.getvalue()).decode(),
|
||||
iw, ih, max(xs) - min(xs), max(zs) - min(zs))
|
||||
|
||||
|
||||
# The eight the game offers, from tools/mapscan.py.
|
||||
PLAYABLE = ['cavern', 'grass', 'rav', 'polar3', 'polar4', 'arena1', 'arena2',
|
||||
'dbase']
|
||||
|
||||
maps = []
|
||||
for rid, r in RESOURCES.items():
|
||||
if r['t'] != MAP_STREAM:
|
||||
continue
|
||||
drawn, total, tally = placements(rid)
|
||||
art = plan(drawn) if drawn else None
|
||||
maps.append({'name': r['name'], 'rid': rid, 'total': total,
|
||||
'drawn': len(drawn), 'tally': tally, 'art': art,
|
||||
'playable': r['name'] in PLAYABLE})
|
||||
print(' %-10s %4d records, %4d drawn' % (r['name'], total, len(drawn)),
|
||||
file=sys.stderr)
|
||||
|
||||
maps.sort(key=lambda m: (not m['playable'], -m['drawn']))
|
||||
|
||||
cards = []
|
||||
for m in maps:
|
||||
if m['art']:
|
||||
uri, w, h, ex, ez = m['art']
|
||||
art = ('<img class="plan" src="%s" width="%d" height="%d" alt="%s from '
|
||||
'above" loading="lazy">' % (uri, w, h, html.escape(m['name'])))
|
||||
extent = '%d × %d' % (round(ex), round(ez))
|
||||
else:
|
||||
art = '<p class="plan plan--none">Nothing this stream places is drawn</p>'
|
||||
extent = '—'
|
||||
top = ', '.join('%s ×%d' % (html.escape(n), c)
|
||||
for n, c in m['tally'].most_common(5)) or '—'
|
||||
cards.append("""
|
||||
<article class="map" data-tags="{tags}" data-search="{search}">
|
||||
<figure class="fig">{art}</figure>
|
||||
<h2>{name}</h2>
|
||||
<p class="tag">{label}</p>
|
||||
<dl class="stat">
|
||||
<div><dt>Placements</dt><dd>{total}</dd></div>
|
||||
<div><dt>Drawn</dt><dd>{drawn}</dd></div>
|
||||
<div><dt>Extent</dt><dd>{extent}</dd></div>
|
||||
</dl>
|
||||
<p class="models">{top}</p>
|
||||
</article>""".format(
|
||||
tags='playable' if m['playable'] else 'aux',
|
||||
search=html.escape(m['name'].lower()), art=art,
|
||||
name=html.escape(m['name']),
|
||||
label='OFFERED IN THE GAME' if m['playable'] else 'SUPPORTING STREAM',
|
||||
total=m['total'], drawn=m['drawn'], extent=extent, top=top))
|
||||
|
||||
PAGE = open(os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
'maps.tpl'), encoding='utf-8').read()
|
||||
os.makedirs(os.path.dirname(OUT), exist_ok=True)
|
||||
open(OUT, 'w', encoding='utf-8').write(PAGE.format(
|
||||
cards=''.join(cards), n=len(maps),
|
||||
playable=sum(1 for m in maps if m['playable'])))
|
||||
print('wrote %s (%d maps)' % (OUT, len(maps)), file=sys.stderr)
|
||||
@@ -1,260 +0,0 @@
|
||||
"""Render the mech roster the way the game knows it.
|
||||
|
||||
Data is drawn from the shipped files, not transcribed:
|
||||
|
||||
* The ROSTER is `kVehicles[]` in game/glass/btl4fe.cpp -- the exact
|
||||
18-entry catalog the in-game menu offers (key + display name, menu
|
||||
order). Nothing is filtered, so a menu change flows through.
|
||||
* Each mech's WEAPONS and AMMO BINS are its `cmCrit(...)` lines in
|
||||
content/GAUGE/L4GAUGE.CFG -- the critical-damage schematic's authored
|
||||
subsystem roster. (Independently confirmed against the rtype-17
|
||||
subsystem records in BTL4.RES, 2026-08-12.)
|
||||
* The PORTRAIT is the mech's own mission-review image
|
||||
(GAUGE/<stem>_MR.PCC, shown by the cameraInit review context through
|
||||
mrpal.pcc). Its zone indexes 32..63 are runtime ColorMapper slots --
|
||||
the review screen paints damage per zone -- so the page shows the
|
||||
HEALTHY state: every zone slot at adpal.pcc entry 0, the same green
|
||||
the armor doll idles at. PCC is PCX; the palette is the file tail.
|
||||
* MECH STATS come from the original player's manual stat sheets
|
||||
(reference/manual/Tesla40_BT_manual.pdf pp. 25/26/29, transcribed
|
||||
from page renders 2026-08-12). The manual documents the six 4.0
|
||||
hulls only; the 4.10 additions (Avatar, Sunder) and all variants have
|
||||
no sheet, and this page shows a dash rather than an invented number.
|
||||
* FIXED vs TWISTING torso is derived from the shipped BTL4.RES: a mech
|
||||
twists only if its subsystem record carries the jointtorso +
|
||||
jointtshadow skeleton joints (Torso resolves them only when
|
||||
torsoHorizontalEnabled, game/reconstructed/torso.cpp:270). The four
|
||||
fixed mechs match the manual's Torso 0/0 rows exactly.
|
||||
|
||||
Usage: python tools/build_mechs.py [out.html]
|
||||
"""
|
||||
import base64, html, io, os, re, sys
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
GAUGE = os.path.join(ROOT, 'content', 'GAUGE')
|
||||
OUT = sys.argv[1] if len(sys.argv) > 1 else os.path.join(ROOT, 'docs', 'MECHS.html')
|
||||
|
||||
# --------------------------------------------------------------- roster
|
||||
src = open(os.path.join(ROOT, 'game', 'glass', 'btl4fe.cpp'),
|
||||
encoding='utf-8', errors='replace').read()
|
||||
block = re.search(r'kVehicles\[\]\s*=\s*\{(.*?)\};', src, re.S).group(1)
|
||||
ROSTER = re.findall(r'\{\s*"(\w+)"\s*,\s*"([^"]+)"\s*\}', block)
|
||||
if len(ROSTER) < 18:
|
||||
sys.exit('roster parse found only %d entries' % len(ROSTER))
|
||||
|
||||
# Variant -> base chassis (kVehicles order groups them; the stems below agree).
|
||||
VARIANT_OF = {'bhk1': 'blkhawk', 'thr1': 'thor', 'lok1': 'loki',
|
||||
'lok2': 'loki', 'mad1': 'madcat', 'mad2': 'madcat',
|
||||
'own1': 'owens', 'ava1': 'avatar', 'snd1': 'sunder',
|
||||
'vul1': 'vulture'}
|
||||
|
||||
# Mission-review portrait stem per key (GAUGE/<stem>_MR.PCC; variants with no
|
||||
# portrait of their own share the base's, as the RES does).
|
||||
MR_STEM = {'blkhawk': 'BLH', 'bhk1': 'BLH', 'loki': 'LOKI', 'lok1': 'LOK1',
|
||||
'lok2': 'LOKI', 'madcat': 'MAD', 'mad1': 'MAD1', 'mad2': 'MAD2',
|
||||
'thor': 'THOR', 'thr1': 'THR1', 'owens': 'OWEN', 'own1': 'OWEN',
|
||||
'avatar': 'AVA', 'ava1': 'AVA', 'sunder': 'SUN', 'snd1': 'SUN',
|
||||
'vulture': 'VULT', 'vul1': 'VUL1'}
|
||||
|
||||
# Fixed-torso set, derived from BTL4.RES joint tables (see module docstring).
|
||||
FIXED_TORSO = {'blkhawk', 'bhk1', 'owens', 'own1'}
|
||||
|
||||
# The manual stat sheets (pp. 25 Loki/Thor, 26 Vulture/MadCat, 29 Owens/
|
||||
# Blackhawk). Keys: t tons, ap armor points, res reservoir liters, hs heat
|
||||
# sinks, ts torso deg/s, tl torso limit deg, a100 0-100s, b100 100-0s,
|
||||
# vn/vs/vg top speed normal / super charged / gimped kph.
|
||||
MANUAL = {
|
||||
'loki': dict(t=75, ap=2110, res=3800, hs=38, ts=60, tl=110,
|
||||
a100=4.5, b100=4.5, vn=143, vs=182, vg=40, page=25),
|
||||
'thor': dict(t=75, ap=2110, res=3800, hs=38, ts=60, tl=110,
|
||||
a100=4.5, b100=4.5, vn=143, vs=182, vg=40, page=25),
|
||||
'vulture': dict(t=75, ap=2025, res=2400, hs=24, ts=50, tl=130,
|
||||
a100=4.7, b100=3, vn=175, vs=235, vg=62, page=26),
|
||||
'madcat': dict(t=75, ap=2195, res=2800, hs=28, ts=80, tl=90,
|
||||
a100=4.2, b100=4, vn=175, vs=220, vg=62, page=26),
|
||||
'owens': dict(t=25, ap=760, res=1500, hs=15, ts=0, tl=0,
|
||||
a100=4.2, b100=5, vn=154, vs=265, vg=63, page=29),
|
||||
'blkhawk': dict(t=50, ap=1362, res=1600, hs=16, ts=0, tl=0,
|
||||
a100=5.1, b100=4.6, vn=190, vs=280, vg=60, page=29),
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------- weapons
|
||||
CFG = open(os.path.join(GAUGE, 'L4GAUGE.CFG'),
|
||||
encoding='utf-8', errors='replace').read()
|
||||
|
||||
INFRA = {'HUD', 'Avionics', 'Gyroscope', 'Torso', 'Myomers'}
|
||||
|
||||
|
||||
def init_block(key):
|
||||
name = key.capitalize() + 'Init'
|
||||
m = re.search(r'^%s\b' % re.escape(name), CFG, re.M)
|
||||
if not m:
|
||||
sys.exit('no %s block in L4GAUGE.CFG' % name)
|
||||
n = re.search(r'^\w+Init\b', CFG[m.end():], re.M)
|
||||
return CFG[m.start(): m.end() + n.start() if n else len(CFG)]
|
||||
|
||||
|
||||
def family(sub):
|
||||
"""ERPPC_2 -> ERPPC, MLaser1 -> MLaser; AFC100/LRM15/NRK5 keep their digits
|
||||
(they are family names, and they are in FAM already)."""
|
||||
fam = re.sub(r'_\d+$', '', sub)
|
||||
if fam not in FAM:
|
||||
stripped = re.sub(r'\d+$', '', fam)
|
||||
if stripped in FAM:
|
||||
fam = stripped
|
||||
return fam
|
||||
|
||||
|
||||
def loadout(key):
|
||||
weapons, bins = {}, {}
|
||||
for sub in re.findall(r'cmCrit\([^,]+,[^,]+,\d+,[^,]+,[^,]+,(\w+)\)',
|
||||
init_block(key)):
|
||||
if sub.startswith('AmmoBin'):
|
||||
fam = family(sub[len('AmmoBin'):])
|
||||
bins[fam] = bins.get(fam, 0) + 1
|
||||
elif not (sub in INFRA
|
||||
or sub.startswith(('Generator', 'Condenser', 'Myomers'))):
|
||||
fam = family(sub)
|
||||
weapons[fam] = weapons.get(fam, 0) + 1
|
||||
return weapons, bins
|
||||
|
||||
|
||||
# Family -> (display name, class). Classes: e energy, b ballistic, m missile.
|
||||
FAM = {
|
||||
'PPC': ('PPC', 'e'), 'ERPPC': ('ER PPC', 'e'),
|
||||
'LLaser': ('Large Laser', 'e'), 'MLaser': ('Medium Laser', 'e'),
|
||||
'SLaser': ('Small Laser', 'e'), 'ERLLaser': ('ER Large Laser', 'e'),
|
||||
'ERMLaser': ('ER Medium Laser', 'e'), 'ERSLaser': ('ER Small Laser', 'e'),
|
||||
'AFC25': ('AFC 25', 'b'), 'AFC50': ('AFC 50', 'b'),
|
||||
'AFC100': ('AFC 100', 'b'), 'GAUSS': ('Gauss', 'b'), 'NRK5': ('NRK 5', 'b'),
|
||||
'LRM5': ('LRM 5', 'm'), 'LRM10': ('LRM 10', 'm'), 'LRM15': ('LRM 15', 'm'),
|
||||
'LRM20': ('LRM 20', 'm'), 'SRM2': ('SRM 2', 'm'), 'SRM4': ('SRM 4', 'm'),
|
||||
'SRM6': ('SRM 6', 'm'),
|
||||
}
|
||||
CLASS_NAME = {'e': 'Energy', 'b': 'Ballistic', 'm': 'Missile'}
|
||||
CLASS_ORDER = {'e': 0, 'b': 1, 'm': 2}
|
||||
|
||||
# ------------------------------------------------------------- portraits
|
||||
from PIL import Image
|
||||
|
||||
mrpal = open(os.path.join(GAUGE, 'MRPAL.PCC'), 'rb').read()
|
||||
if mrpal[-769] != 0x0C:
|
||||
sys.exit('MRPAL.PCC has no VGA palette where PCX keeps one')
|
||||
BASEPAL = list(mrpal[-768:])
|
||||
adpal = open(os.path.join(GAUGE, 'ADPAL.PCC'), 'rb').read()
|
||||
HEALTHY = list(adpal[-768:][0:3]) # ramp entry 0 = undamaged green
|
||||
|
||||
_portraits = {}
|
||||
|
||||
|
||||
def portrait(stem):
|
||||
if stem not in _portraits:
|
||||
im = Image.open(os.path.join(GAUGE, stem + '_MR.PCC'))
|
||||
im.load()
|
||||
flat = BASEPAL[:]
|
||||
for s in range(32, 64): # zone slots -> healthy state
|
||||
flat[s * 3:s * 3 + 3] = HEALTHY
|
||||
im.putpalette(flat)
|
||||
buf = io.BytesIO()
|
||||
im.save(buf, 'PNG', optimize=True)
|
||||
_portraits[stem] = ('data:image/png;base64,'
|
||||
+ base64.b64encode(buf.getvalue()).decode(),
|
||||
im.width, im.height)
|
||||
return _portraits[stem]
|
||||
|
||||
|
||||
# ----------------------------------------------------------------- page
|
||||
def dash(v, unit=''):
|
||||
return '—' if v is None else '%s%s' % (v, unit)
|
||||
|
||||
|
||||
NAMES = dict(ROSTER)
|
||||
cards = []
|
||||
for key, name in ROSTER:
|
||||
weapons, bins = loadout(key)
|
||||
base = VARIANT_OF.get(key)
|
||||
man = MANUAL.get(key)
|
||||
uri, w, h = portrait(MR_STEM[key])
|
||||
|
||||
fams = sorted(weapons, key=lambda f: (CLASS_ORDER[FAM[f][1]], FAM[f][0]))
|
||||
chips = ''.join(
|
||||
'<span class="chip chip--%s">%s%s</span>' % (
|
||||
FAM[f][1],
|
||||
'%d× ' % weapons[f] if weapons[f] > 1 else '',
|
||||
html.escape(FAM[f][0].upper()))
|
||||
for f in fams)
|
||||
|
||||
rows = ''.join(
|
||||
'<tr><th scope="row">%s</th><td>%s</td>'
|
||||
'<td class="num">%d</td><td class="num">%s</td></tr>' % (
|
||||
html.escape(FAM[f][0]), CLASS_NAME[FAM[f][1]], weapons[f],
|
||||
'%d×' % bins[f] if f in bins else '—')
|
||||
for f in fams)
|
||||
|
||||
torso = ('FIXED' if key in FIXED_TORSO
|
||||
else '%s°/s · %s°' % (man['ts'], man['tl'])
|
||||
if man else 'twists')
|
||||
spec = ''.join('<div><dt>%s</dt><dd>%s</dd></div>' % kv for kv in (
|
||||
('Tonnage', dash(man and man['t'], ' t')),
|
||||
('Armor points', dash(man and man['ap'])),
|
||||
('Reservoir', dash(man and man['res'], ' L')),
|
||||
('Heat sinks', dash(man and man['hs'])),
|
||||
('Torso', torso),
|
||||
('0–100 kph', dash(man and man['a100'], ' s')),
|
||||
('Top speed', dash(man and man['vn'], ' kph')),
|
||||
('Super charged', dash(man and man['vs'], ' kph')),
|
||||
('Gimped', dash(man and man['vg'], ' kph')),
|
||||
))
|
||||
sheet = ('manual p. %d' % man['page'] if man else
|
||||
'chassis sheet: see %s' % html.escape(NAMES[base]) if base in MANUAL
|
||||
else 'no manual sheet (4.10 addition)')
|
||||
|
||||
fam_base = base or key
|
||||
kin = ([NAMES[fam_base]] if base else []) + \
|
||||
[NAMES[v] for v, b in VARIANT_OF.items() if b == fam_base and v != key]
|
||||
cap = ('%s chassis · with %s' % (
|
||||
html.escape(NAMES.get(base, name)), html.escape(', '.join(kin)))
|
||||
if kin else '%s chassis' % html.escape(name))
|
||||
|
||||
search = ' '.join([key, name.lower()] +
|
||||
[FAM[f][0].lower() for f in fams] + fams).lower()
|
||||
cards.append("""
|
||||
<article class="mech" data-tags="{tags}" data-search="{search}">
|
||||
<header class="mech__id">
|
||||
<figure class="hull">
|
||||
<img class="hull__img" src="{uri}" width="{w}" height="{h}"
|
||||
alt="{name} mission-review portrait" loading="lazy">
|
||||
<figcaption>{cap}</figcaption>
|
||||
</figure>
|
||||
<h3>{name}</h3>
|
||||
<p class="mech__key">{key} · {kind}</p>
|
||||
<p class="mech__load">{chips}</p>
|
||||
<p class="mech__meta"><span>{nw} weapons</span><span>{nb} ammo bins</span><span>torso {torsoshort}</span></p>
|
||||
<dl class="spec">{spec}</dl>
|
||||
<p class="mech__sheet">{sheet}</p>
|
||||
</header>
|
||||
<div class="mech__tables"><div class="tablewrap"><table>
|
||||
<caption class="sr-only">Weapons carried by the {name}</caption>
|
||||
<thead><tr><th scope="col">WEAPON</th><th scope="col">TYPE</th>
|
||||
<th scope="col" class="num">COUNT</th><th scope="col" class="num">AMMO BIN</th></tr></thead>
|
||||
<tbody>{rows}</tbody>
|
||||
</table></div></div>
|
||||
</article>""".format(
|
||||
tags='variant' if base else 'base', search=html.escape(search),
|
||||
uri=uri, w=w, h=h, name=html.escape(name), key=key,
|
||||
kind='variant of %s' % html.escape(NAMES[base]) if base else 'base chassis',
|
||||
cap=cap, chips=chips, nw=sum(weapons.values()), nb=sum(bins.values()),
|
||||
torsoshort='FIXED' if key in FIXED_TORSO else 'TWISTS',
|
||||
spec=spec, sheet=sheet, rows=rows))
|
||||
print(' %-8s %-12s %2d weapons, %d bins%s' % (
|
||||
key, name, sum(weapons.values()), sum(bins.values()),
|
||||
' [manual]' if man else ''), file=sys.stderr)
|
||||
|
||||
PAGE = open(os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
'mechs.tpl'), encoding='utf-8').read()
|
||||
os.makedirs(os.path.dirname(OUT), exist_ok=True)
|
||||
open(OUT, 'w', encoding='utf-8').write(PAGE.format(
|
||||
cards=''.join(cards), n=len(ROSTER),
|
||||
nbase=sum(1 for k, _ in ROSTER if k not in VARIANT_OF),
|
||||
nvar=sum(1 for k, _ in ROSTER if k in VARIANT_OF)))
|
||||
print('wrote %s (%d mechs)' % (OUT, len(ROSTER)), file=sys.stderr)
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>BattleTech 4.11 — every map from above</title>
|
||||
<style>
|
||||
*, *::before, *::after {{ box-sizing: border-box; }}
|
||||
:root {{
|
||||
--ground: #0e0f11; --panel: #16181b; --rule: #2a2e33;
|
||||
--ink: #e8e6e2; --ink-mid: #a3a8ae; --ink-low: #71777e;
|
||||
--hot: #f39313; /* palette 6, the map's own amber */
|
||||
--mono: ui-monospace, "Cascadia Mono", Consolas, Menlo, monospace;
|
||||
--sans: ui-sans-serif, system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
}}
|
||||
@media (prefers-color-scheme: light) {{
|
||||
:root {{
|
||||
--ground: #f4f2ee; --panel: #fbfaf8; --rule: #ddd8d0;
|
||||
--ink: #14161a; --ink-mid: #565c63; --ink-low: #7d838a; --hot: #a35f00;
|
||||
}}
|
||||
}}
|
||||
body {{
|
||||
margin: 0; background: var(--ground); color: var(--ink);
|
||||
font: 400 15px/1.6 var(--sans);
|
||||
}}
|
||||
.wrap {{ max-width: 78rem; margin: 0 auto; padding: 0 clamp(1rem, 4vw, 2.5rem); }}
|
||||
header.top {{ border-bottom: 1px solid var(--rule); padding: clamp(2.5rem,6vw,4rem) 0 1.75rem; }}
|
||||
.eyebrow {{
|
||||
font: 500 12px/1 var(--mono); letter-spacing: .2em; text-transform: uppercase;
|
||||
color: var(--ink-low); margin: 0 0 1rem;
|
||||
}}
|
||||
h1 {{
|
||||
font: 700 clamp(1.9rem,1.4rem+2.2vw,3rem)/1.05 var(--mono);
|
||||
letter-spacing: -.02em; text-transform: uppercase; margin: 0 0 .9rem;
|
||||
}}
|
||||
h1 em {{ font-style: normal; color: var(--hot); }}
|
||||
.lede {{ max-width: 62ch; color: var(--ink-mid); margin: 0; font-size: 1.05rem; }}
|
||||
.lede strong {{ color: var(--ink); font-weight: 600; }}
|
||||
|
||||
.bar {{ border-bottom: 1px solid var(--rule); padding: .8rem 0; }}
|
||||
.seg {{ display: inline-flex; border: 1px solid var(--rule); }}
|
||||
.seg button {{
|
||||
font: 500 12px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase;
|
||||
background: none; border: 0; color: var(--ink-mid); padding: .55rem .9rem; cursor: pointer;
|
||||
}}
|
||||
.seg button[aria-pressed="true"] {{ background: var(--hot); color: var(--ground); }}
|
||||
|
||||
.grid {{
|
||||
display: grid; gap: 1px; background: var(--rule);
|
||||
border: 1px solid var(--rule); margin: 1.75rem 0 3rem;
|
||||
grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
|
||||
}}
|
||||
.map {{ background: var(--panel); padding: 1.1rem 1.25rem 1.35rem; }}
|
||||
.map[hidden] {{ display: none; }}
|
||||
.fig {{ margin: 0 0 .9rem; display: flex; justify-content: center; }}
|
||||
/* The game's own palette on the display's own black, so it reads the same
|
||||
in either theme. */
|
||||
.plan {{
|
||||
display: block; max-width: 100%; height: auto; max-height: 20rem;
|
||||
background: #000; border: 1px solid var(--rule); image-rendering: pixelated;
|
||||
}}
|
||||
.plan--none {{
|
||||
margin: 0; padding: 2rem 1rem; text-align: center; color: var(--ink-low);
|
||||
font: 400 12px var(--mono); border: 1px dashed var(--rule); width: 100%;
|
||||
}}
|
||||
h2 {{ font: 700 1.3rem/1.1 var(--mono); margin: 0 0 .25rem; text-transform: uppercase; }}
|
||||
.tag {{
|
||||
font: 500 11px/1 var(--mono); letter-spacing: .14em; color: var(--ink-low);
|
||||
margin: 0 0 .8rem;
|
||||
}}
|
||||
.stat {{ margin: 0; display: grid; grid-template-columns: 1fr auto; gap: .2rem .8rem; }}
|
||||
.stat div {{ display: contents; }}
|
||||
.stat dt {{ font: 500 12px var(--mono); letter-spacing: .08em; color: var(--ink-low); }}
|
||||
.stat dd {{
|
||||
margin: 0; text-align: right; font: 500 12px var(--mono); color: var(--ink);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}}
|
||||
.models {{
|
||||
margin: .75rem 0 0; font: 400 11px/1.6 var(--mono); color: var(--ink-low);
|
||||
word-break: break-word;
|
||||
}}
|
||||
.foot {{
|
||||
border-top: 1px solid var(--rule); padding: 1.5rem 0 4rem; max-width: 76ch;
|
||||
color: var(--ink-low); font-size: 13px;
|
||||
}}
|
||||
.foot code {{ font-family: var(--mono); color: var(--ink-mid); }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="top">
|
||||
<div class="wrap">
|
||||
<p class="eyebrow">BattleTech 4.11 · drawn from BTL4.RES</p>
|
||||
<h1>Every map,<br><em>seen from above</em></h1>
|
||||
<p class="lede">Each plan is drawn the way the cockpit draws it: every placement in
|
||||
the map's own stream, the outline its model carries, in the game's own palette.
|
||||
<strong>Nothing here is traced or redrawn</strong> — the buttes are circles
|
||||
because the game draws them as circles.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="bar">
|
||||
<div class="wrap">
|
||||
<div class="seg" role="group" aria-label="Filter">
|
||||
<button type="button" data-filter="all" aria-pressed="true">All {n}</button>
|
||||
<button type="button" data-filter="playable" aria-pressed="false">Playable {playable}</button>
|
||||
<button type="button" data-filter="aux" aria-pressed="false">Supporting</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="wrap">
|
||||
<div class="grid">{cards}</div>
|
||||
|
||||
<p class="foot">A map stream is a run of <code>Entity::MakeMessage</code> records. Each
|
||||
carries its own length at +0, its class at +28, the resource it names at +40, its
|
||||
instance flags at +44 and its origin at +48 — and BT pads each record to the
|
||||
next four bytes, which Red Planet does not. The resource named is a <em>Model List</em>;
|
||||
the outline the display draws is the GaugeImage inside that list, so the join is direct
|
||||
rather than by name. A model with no GaugeImage is not drawn, which is why several
|
||||
streams place far more than they draw.</p>
|
||||
<p class="foot">Colours are palette indices resolved through <code>btspal.pcc</code>, the
|
||||
palette <code>L4GAUGE.CFG</code> configures the secondary port with:
|
||||
<code>configure(0,sec,270,0x003F,clut0,rgb,btspal.pcc)</code>. Unlike Red Planet,
|
||||
every primitive here carries an explicit colour — nothing falls back to a display
|
||||
default. Seen from above, +X runs right and +Z up.</p>
|
||||
<p class="foot">Two of the eight playable maps, <code>arena1</code> and
|
||||
<code>arena2</code>, place almost nothing: a sky and a pair of records too short to
|
||||
carry an origin. Their arena geometry is <code>arenall</code>, which is a stream of its
|
||||
own. <code>adrop</code> and <code>pol4sfx</code> are likewise supporting streams
|
||||
— drop points and wind emitters — rather than places you fight in.</p>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const cards = [...document.querySelectorAll('.map')];
|
||||
for (const b of document.querySelectorAll('[data-filter]')) {{
|
||||
b.addEventListener('click', () => {{
|
||||
const f = b.dataset.filter;
|
||||
for (const o of document.querySelectorAll('[data-filter]'))
|
||||
o.setAttribute('aria-pressed', String(o === b));
|
||||
for (const c of cards)
|
||||
c.hidden = f !== 'all' && !c.dataset.tags.split(' ').includes(f);
|
||||
}});
|
||||
}}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
-260
@@ -1,260 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>BattleTech 4.11 — the mech roster</title>
|
||||
<style>
|
||||
*, *::before, *::after {{ box-sizing: border-box; }}
|
||||
:root {{
|
||||
--ground: #0e0f11; --panel: #16181b; --rule: #2a2e33;
|
||||
--ink: #e8e6e2; --ink-mid: #a3a8ae; --ink-low: #71777e;
|
||||
--hot: #f39313; /* palette 6, the display's own amber */
|
||||
--nrg: #ff5340; /* energy weapons */
|
||||
--bal: #f39313; /* ballistic */
|
||||
--msl: #58c470; /* missiles -- the armor doll's green family */
|
||||
--mono: ui-monospace, "Cascadia Mono", Consolas, Menlo, monospace;
|
||||
--sans: ui-sans-serif, system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
}}
|
||||
@media (prefers-color-scheme: light) {{
|
||||
:root {{
|
||||
--ground: #f4f2ee; --panel: #fbfaf8; --rule: #ddd8d0;
|
||||
--ink: #14161a; --ink-mid: #565c63; --ink-low: #7d838a;
|
||||
--hot: #a35f00; --nrg: #b3260f; --bal: #a35f00; --msl: #1c7a3f;
|
||||
}}
|
||||
}}
|
||||
body {{
|
||||
margin: 0; background: var(--ground); color: var(--ink);
|
||||
font: 400 15px/1.6 var(--sans);
|
||||
}}
|
||||
.wrap {{ max-width: 78rem; margin: 0 auto; padding: 0 clamp(1rem, 4vw, 2.5rem); }}
|
||||
.sr-only {{
|
||||
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
|
||||
overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
|
||||
}}
|
||||
:focus-visible {{ outline: 2px solid var(--hot); outline-offset: 2px; }}
|
||||
|
||||
header.top {{ border-bottom: 1px solid var(--rule); padding: clamp(2.5rem,6vw,4rem) 0 1.75rem; }}
|
||||
.eyebrow {{
|
||||
font: 500 12px/1 var(--mono); letter-spacing: .2em; text-transform: uppercase;
|
||||
color: var(--ink-low); margin: 0 0 1rem;
|
||||
}}
|
||||
h1 {{
|
||||
font: 700 clamp(1.9rem,1.4rem+2.2vw,3rem)/1.05 var(--mono);
|
||||
letter-spacing: -.02em; text-transform: uppercase; margin: 0 0 .9rem;
|
||||
}}
|
||||
h1 em {{ font-style: normal; color: var(--hot); }}
|
||||
.lede {{ max-width: 62ch; color: var(--ink-mid); margin: 0 0 1.4rem; font-size: 1.05rem; }}
|
||||
.lede strong {{ color: var(--ink); font-weight: 600; }}
|
||||
.rules {{ display: flex; flex-wrap: wrap; gap: .6rem 2rem; margin: 0; padding: 0; list-style: none; }}
|
||||
.rules li {{
|
||||
font: 500 12px/1.5 var(--mono); color: var(--ink-mid);
|
||||
padding-left: 1.1rem; position: relative;
|
||||
}}
|
||||
.rules li::before {{
|
||||
content: ""; position: absolute; left: 0; top: .45em;
|
||||
width: .45rem; height: .45rem; background: var(--hot);
|
||||
}}
|
||||
.rules b {{ color: var(--ink); font-weight: 700; }}
|
||||
|
||||
.bar {{
|
||||
position: sticky; top: 0; z-index: 5;
|
||||
background: var(--ground);
|
||||
border-bottom: 1px solid var(--rule); padding: .75rem 0;
|
||||
}}
|
||||
.bar__in {{ display: flex; flex-wrap: wrap; gap: .75rem 1.25rem; align-items: center; }}
|
||||
.seg {{ display: inline-flex; border: 1px solid var(--rule); }}
|
||||
.seg button {{
|
||||
font: 500 12px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase;
|
||||
background: none; border: 0; color: var(--ink-mid); padding: .55rem .9rem; cursor: pointer;
|
||||
}}
|
||||
.seg button[aria-pressed="true"] {{ background: var(--hot); color: var(--ground); }}
|
||||
.search {{
|
||||
flex: 1 1 12rem; min-width: 9rem;
|
||||
font: 400 12px var(--mono);
|
||||
background: var(--panel); color: var(--ink);
|
||||
border: 1px solid var(--rule); padding: .55rem .7rem;
|
||||
}}
|
||||
.search::placeholder {{ color: var(--ink-low); }}
|
||||
.count {{ font: 500 12px var(--mono); color: var(--ink-low); letter-spacing: .1em; }}
|
||||
|
||||
.key {{ display: flex; flex-wrap: wrap; gap: .4rem .9rem; padding: 1.25rem 0 0; }}
|
||||
.key span {{ display: inline-flex; align-items: center; gap: .4rem;
|
||||
font: 500 12px var(--mono); letter-spacing: .08em; color: var(--ink-low); }}
|
||||
.key i {{ width: .7rem; height: .7rem; display: inline-block; }}
|
||||
|
||||
.roster {{ display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule);
|
||||
margin: 1.75rem 0 3rem; }}
|
||||
.mech {{ background: var(--panel); display: grid; gap: 0;
|
||||
grid-template-columns: minmax(15rem, 19rem) 1fr; }}
|
||||
@media (max-width: 46rem) {{ .mech {{ grid-template-columns: 1fr; }} }}
|
||||
.mech[hidden] {{ display: none; }}
|
||||
|
||||
.mech__id {{ padding: 1.1rem 1.25rem 1.35rem; border-right: 1px solid var(--rule); }}
|
||||
@media (max-width: 46rem) {{ .mech__id {{ border-right: 0; border-bottom: 1px solid var(--rule); }} }}
|
||||
.hull {{ margin: 0 0 .9rem; display: flex; flex-direction: column; gap: .45rem;
|
||||
align-items: flex-start; }}
|
||||
/* The game's own review image on the display's own black, either theme. */
|
||||
.hull__img {{
|
||||
display: block; width: 7rem; height: auto;
|
||||
background: #000; border: 1px solid var(--rule); image-rendering: pixelated;
|
||||
}}
|
||||
.hull figcaption {{
|
||||
font: 500 11px/1.35 var(--mono); letter-spacing: .1em;
|
||||
text-transform: uppercase; color: var(--ink-low);
|
||||
}}
|
||||
.mech__id h3 {{
|
||||
font: 700 1.5rem/1 var(--mono); letter-spacing: .01em;
|
||||
margin: 0 0 .55rem; text-transform: uppercase;
|
||||
}}
|
||||
.mech__key {{
|
||||
font: 500 12px/1 var(--mono); letter-spacing: .12em;
|
||||
color: var(--ink-low); margin: -.3rem 0 .7rem;
|
||||
}}
|
||||
.mech__load {{ display: flex; flex-wrap: wrap; gap: .3rem; margin: 0 0 .7rem; }}
|
||||
.chip {{
|
||||
font: 500 11px/1 var(--mono); letter-spacing: .08em;
|
||||
padding: .3rem .45rem; border: 1px solid currentColor;
|
||||
}}
|
||||
.chip--e {{ color: var(--nrg); }}
|
||||
.chip--b {{ color: var(--bal); }}
|
||||
.chip--m {{ color: var(--msl); }}
|
||||
.mech__meta {{ display: flex; flex-wrap: wrap; gap: .8rem; margin: 0 0 .2rem;
|
||||
font: 400 12px var(--mono); color: var(--ink-low); font-variant-numeric: tabular-nums; }}
|
||||
.spec {{
|
||||
margin: .75rem 0 0; display: grid; grid-template-columns: 1fr auto;
|
||||
gap: .2rem .8rem; font: 500 12px var(--mono);
|
||||
}}
|
||||
.spec div {{ display: contents; }}
|
||||
.spec dt {{ color: var(--ink-low); letter-spacing: .06em; }}
|
||||
.spec dd {{ margin: 0; text-align: right; color: var(--ink); font-variant-numeric: tabular-nums; }}
|
||||
.mech__sheet {{ margin: .6rem 0 0; font: 400 11px/1.5 var(--mono); color: var(--ink-low); }}
|
||||
|
||||
.mech__tables {{ min-width: 0; }}
|
||||
.tablewrap {{ overflow-x: auto; }}
|
||||
table {{ border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }}
|
||||
thead th {{
|
||||
font: 500 12px/1 var(--mono); letter-spacing: .14em;
|
||||
color: var(--ink-low); text-align: left; font-weight: 500;
|
||||
padding: .9rem .9rem .55rem; border-bottom: 1px solid var(--rule); white-space: nowrap;
|
||||
}}
|
||||
tbody th {{
|
||||
font: 500 13px/1.3 var(--mono); text-align: left; color: var(--ink);
|
||||
padding: .5rem .9rem; border-bottom: 1px solid var(--rule); white-space: nowrap;
|
||||
}}
|
||||
tbody td {{
|
||||
font: 400 13px/1.3 var(--mono); color: var(--ink-mid);
|
||||
padding: .5rem .9rem; border-bottom: 1px solid var(--rule); white-space: nowrap;
|
||||
}}
|
||||
tbody tr:last-child th, tbody tr:last-child td {{ border-bottom: 0; }}
|
||||
th.num, td.num {{ text-align: right; }}
|
||||
|
||||
.empty-state {{
|
||||
margin: 2rem 0; font: 500 13px var(--mono); color: var(--ink-low);
|
||||
}}
|
||||
.foot {{
|
||||
border-top: 1px solid var(--rule); padding: 1.5rem 0 0; max-width: 76ch;
|
||||
color: var(--ink-low); font-size: 13px;
|
||||
}}
|
||||
.foot:last-child {{ padding-bottom: 4rem; }}
|
||||
.foot code {{ font-family: var(--mono); color: var(--ink-mid); }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="top">
|
||||
<div class="wrap">
|
||||
<p class="eyebrow">BattleTech 4.11 · from btl4fe.cpp, L4GAUGE.CFG and the player's manual</p>
|
||||
<h1>Every mech,<br><em>and what it carries</em></h1>
|
||||
<p class="lede">All <strong>{n} mechs the menu offers</strong> — {nbase} base chassis
|
||||
and {nvar} variants — each with its authored weapons roster, ammo bins and the
|
||||
stat sheet from the original player's manual. The portraits are the game's own
|
||||
mission-review images, shown in their undamaged state.</p>
|
||||
<ul class="rules">
|
||||
<li><b>Variants share the chassis</b>, not the loadout</li>
|
||||
<li><b>Blackhawk, Nova, Owens, Kotori</b> have a fixed torso</li>
|
||||
<li>The manual sheets cover the <b>six 4.0 hulls</b> only</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="bar">
|
||||
<div class="wrap bar__in">
|
||||
<div class="seg" role="group" aria-label="Filter">
|
||||
<button type="button" data-filter="all" aria-pressed="true">All {n}</button>
|
||||
<button type="button" data-filter="base" aria-pressed="false">Base {nbase}</button>
|
||||
<button type="button" data-filter="variant" aria-pressed="false">Variants {nvar}</button>
|
||||
</div>
|
||||
<input id="search" class="search" type="search" placeholder="Search mech or weapon…"
|
||||
aria-label="Search mech or weapon">
|
||||
<span class="count" id="count">{n} / {n} mechs</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="wrap">
|
||||
<div class="key">
|
||||
<span><i style="background:var(--nrg)"></i>Energy</span>
|
||||
<span><i style="background:var(--bal)"></i>Ballistic</span>
|
||||
<span><i style="background:var(--msl)"></i>Missile</span>
|
||||
</div>
|
||||
|
||||
<div class="roster">{cards}</div>
|
||||
<p class="empty-state" id="nomatch" hidden>No mech matches that.</p>
|
||||
|
||||
<p class="foot">The roster is <code>kVehicles[]</code> in <code>game/glass/btl4fe.cpp</code>
|
||||
— the exact catalog the in-game menu offers, in menu order. Each mech's weapons and
|
||||
ammo bins are its <code>cmCrit(...)</code> lines in <code>content/GAUGE/L4GAUGE.CFG</code>,
|
||||
the critical-damage schematic's authored subsystem roster (independently confirmed against
|
||||
the subsystem records in <code>BTL4.RES</code>). Nothing is transcribed by hand.</p>
|
||||
<p class="foot">The portraits are each mech's mission-review image
|
||||
(<code>GAUGE/<stem>_MR.PCC</code>) resolved through the review screen's own palette.
|
||||
In play, its zone indexes are live damage slots painted green→orange→red by the
|
||||
ColorMapper gauges; this page shows every zone at the undamaged ramp entry — the
|
||||
same green the armor doll idles at. Variants without their own portrait share the base's,
|
||||
exactly as the resource file does.</p>
|
||||
<p class="foot">Mech stats are the original player's manual stat sheets (pp. 25, 26, 29).
|
||||
The manual documents the six 4.0 hulls; Avatar and Sunder arrived with 4.10 and have no
|
||||
sheet, so their rows show a dash rather than an invented number. FIXED vs twisting torso
|
||||
is read from the shipped resource file: a mech twists only if its subsystem record carries
|
||||
the <code>jointtorso</code>/<code>jointtshadow</code> joints — the four fixed mechs
|
||||
match the manual's Torso 0/0 rows exactly.</p>
|
||||
<p class="foot">Weapon notes: ER lasers fire red beams, PPCs blue, standard lasers yellow.
|
||||
Authored ranges where the game states them: PPCs 900 m, missiles 800 m, the
|
||||
Blackhawk's lasers 500 m, the AFC 50 750 m. The Blackhawk's SRM 6
|
||||
racks fire Streak ammunition. LRM tube counts are the salvo size; each launcher's ammo
|
||||
bin is listed beside it.</p>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const cards = [...document.querySelectorAll('.mech')];
|
||||
const count = document.getElementById('count');
|
||||
const search = document.getElementById('search');
|
||||
let filter = 'all';
|
||||
|
||||
function apply() {{
|
||||
const q = search.value.trim().toLowerCase();
|
||||
let shown = 0;
|
||||
for (const c of cards) {{
|
||||
const okTag = filter === 'all' || c.dataset.tags.split(' ').includes(filter);
|
||||
const okQ = !q || c.dataset.search.includes(q);
|
||||
const on = okTag && okQ;
|
||||
c.hidden = !on;
|
||||
if (on) shown++;
|
||||
}}
|
||||
count.textContent = shown + ' / ' + cards.length + ' mechs';
|
||||
document.getElementById('nomatch').hidden = shown > 0;
|
||||
}}
|
||||
|
||||
for (const b of document.querySelectorAll('[data-filter]')) {{
|
||||
b.addEventListener('click', () => {{
|
||||
filter = b.dataset.filter;
|
||||
for (const o of document.querySelectorAll('[data-filter]'))
|
||||
o.setAttribute('aria-pressed', String(o === b));
|
||||
apply();
|
||||
}});
|
||||
}}
|
||||
search.addEventListener('input', apply);
|
||||
apply();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+1
-1
@@ -77,7 +77,7 @@ def main():
|
||||
exes = ["build/Release/btl4.exe"]
|
||||
|
||||
bats = ["players/play_solo.bat", "players/join.bat", "players/join_lan.bat",
|
||||
"players/joyconfig.bat"]
|
||||
"players/joyconfig.bat", "players/SENDLOGS.bat"]
|
||||
if steam_on:
|
||||
bats.append("players/play_steam.bat")
|
||||
for p in exes + bats:
|
||||
|
||||
Reference in New Issue
Block a user