Impact-FX FORENSICS wave: the i860 specialfx engine, per-round detonations, the ram economy closed
The "we're off the rails" reinvestigation -- a 5-thread evidence workflow
(logs / PFX data / RES model lists / decomp / port audit) + the i860 firmware
decode, then surgical fixes. Every claim tiered; the wrong turns are on the
record in the KB alongside the corrections.
THE OLD-STYLE SPECIALFX ENGINE [T1, firmware-decoded from VREND.MNG]:
rebuilt scratchpad/i860dis.py (binutils opcode table); mapped the dispatch
(data+0xdd0c; sfx trigger 0xf040cda0, install 0xf040cdc0, step ~0xf0413698,
instance init 0xf04128d8); decoded the heat model EXACTLY: per 30Hz board
frame h *= cool_a; RGB_ch = h_old*(h_new*cook_ch - 0.25) + 0.25 (K=0.25 =
the ember floor @VA 0xF080; kill at h <= 1e-4 @0xF0A0); alpha fades cool_b
x RAW dt (PER-SECOND -- the x30 scaling made laser hits invisible); 7s cap;
y_off = the kill plane; "variance" is DEAD DATA (binary reads "variance",
INI authors "varience"). The 13 descriptors (PPCHit/LaserHit/MissileHit/
Chunks/Sparks/Fireball...) parse from BTDPL.INI and render via the BTPfx
layer -- heat bursts draw the FIERY sheet (brightness over fire), .PFX keeps
GRAYSCALE (authored colours: DNBOOM orange, DDAM gray).
HIT-PACKAGE CENSUS [T1, RES byte-verified]: ppchit=[8] lzrhit=[9] mghit=[7,11]
canhit=[11] mslhit=[10,12,1023] explode=[6]; all 8 mech death lists identical.
Effect routing corrected in BOTH consumers: <100 = specialfx, >=1000 = psfx.
"SILVER MIST x5" ROOT CAUSE: SHKWAVE.PFX (mslhit's 1023) authors maxIssue=5
relPeriod=0.2 rate=1 -- the ONE file where rate contradicts the window; the
emitter trusted rate -> 5 shells at exactly 1Hz. Emission rate now always
maxIssue/releasePeriod.
PER-ROUND DETONATIONS [T1 @004bef78]: every missile round spawns its own
ExplosionModelFile at ITS impact (hull + terrain) -- a volley ripples 12
fireballs like the demos; rack-tube launch spread [T3] (GUIDED rounds only --
the slot-0 deflection sent every AFC100 shell 3.4deg left/2.5deg down: the
phantom "4th gold beam"); replicant salvos detonate too (launcher index rides
the visual push). Missile damage bundles through the shooter's messmgr with
the launcher's subsystemID (mslhit fires at the consolidated point; the
binary's dedup CONFIRMED [T1 @0049b784] -- a workflow agent's per-record
claim REFUTED by direct decomp read).
DAMAGE-BAND SEMANTICS [T1]: MechDeathHandler fires the CURRENT band effect on
any damage rise (the binary's changed-flag coalescing) -- a mauled mech under
fire smokes/burns per hit; bands 3/4 are authored fire plumes.
THE RAM ECONOMY -- CLOSED (3 layers, measured live):
1. armor = POINTS (every zone: damageScale = 1/armorPoints, armor 50-140;
the [zone-armor] BT_DMG_LOG dump);
2. StaticBounce prices rams with authored moverMass ~1.3e6 -> ~59,000 pts
@10m/s; the binary dispatches it RAW but pod MP dropped it on the local
replicant (MECH.CPP:986 warns) -- ram damage was NETWORK-INERT; our
task-#47 replicant forwarding surfaced it as a one-shot. Port
normalizes x1e-3 to the point economy [T3];
3. contact EDGE (ramLastVictim/ramContactLinger): the binary's bounce made
separation implicit; our gait-derived velocity re-priced full rams at
60Hz (the respawn explode-loop). One bump = one hit; pressed = BLOCK.
PLUS: sfx size x0.5 + 1.25m visibility floor + hot-phase occlusion [T3];
particle pool 2048->8192 (missile traffic starved laser bursts -- the
"intermittent effects"); replicant beam aging (a lost beam-END record pinned
a stale beam on forever); UV-variant noise stamps (mask-safe mirror/swap);
no scroll on particle stamps (material-path only); BT_FX_TEST/fxshot.py
self-verification harness ([beam-draw]/[zone-armor]/[collide-tx] telemetry).
KB: rendering.md (specialfx engine + census + closeout), combat-damage.md
(ram economy + band semantics).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
48c9c8444f
commit
065c114590
@@ -104,6 +104,27 @@ per ER-M laser; [[decomp-reference]] §5). Flying projectiles (LRM/autocannon) a
|
||||
reconstruction (`BTPushProjectile` — the 2007 Entity is too small for the binary's raw integrator
|
||||
offsets). [T2]
|
||||
|
||||
## The RAM economy — CLOSED (2026-07-12) [T1 evidence, T3 normalization]
|
||||
Three-layer story, measured live + decomp-verified:
|
||||
1. **The armor economy is POINTS**: every zone streams `damageScale[5]` EVEN = `1/armorPoints`
|
||||
(armor 50–140; `damageLevel += amount/armor`, 1.0 = destroyed — the `[zone-armor]` dump,
|
||||
BT_DMG_LOG, mechdmg.cpp). Weapons author point-scale amounts (laser 11.77 ≈ 10 torso hits). ✓
|
||||
2. **StaticBounce prices rams with the AUTHORED moverMass ≈ 1.3e6 units** → ~600×v² ≈ 59,000
|
||||
points for a 10 m/s ram (measured: 59221@9.94, 398@0.81; `[collide-tx]` now logs mass/e).
|
||||
The binary DISPATCHES it raw (@part_012:15324-15358) — but in pod MP it landed on the local
|
||||
REPLICANT of the victim (the master never heard it; MECH.CPP:986 warns and proceeds) —
|
||||
**ram damage was network-inert in the pod**. Our task-#47 replicant forwarding (required
|
||||
for MP weapon damage) surfaced it as a one-shot. Port: `BTDispatchCollisionDamage`
|
||||
normalizes ×1e-3 to the armor-point economy (bump = points, charge = tens) [T3].
|
||||
3. **The contact EDGE**: the binary's bounce reversed the mover's velocity so the frame after
|
||||
a bump read as separating; our gait re-derives velocity per frame (still closing while
|
||||
pressed / respawn-overlapped) → sustained contact re-priced full rams at 60Hz (the respawn
|
||||
explode-loop). Port: `ramLastVictim`/`ramContactLinger` (mech.hpp) — one bump = one damage
|
||||
event; pressed = BLOCK; re-arms 0.35s after separation; cleared on Reset.
|
||||
Band effects: `MechDeathHandler::Tick` fires the CURRENT band descriptor on any damage rise
|
||||
(the binary's changed-flag semantics, workflow-verified) — a damaged mech under fire smokes/
|
||||
burns per hit; the earlier crossing-only gate was over-tight (the metronome was SHKWAVE).
|
||||
|
||||
## Damage delivery + the real damage model
|
||||
`Entity::TakeDamageMessage(id, size, inflictingEntityID, zone, Damage&)` → `target->Dispatch`.
|
||||
**Base handler IGNORES zone==−1** (`Entity::TakeDamageMessageHandler`, ENTITY.cpp:878 — returns on
|
||||
|
||||
@@ -75,6 +75,81 @@ the slice. Reading it as RGB overlaid 2-3 gray sheets = the "rainbow/graffiti" b
|
||||
resolves the mech-skin `softer` ramp (defined in OTHER libs). Every mech renders authentic gray-metal
|
||||
paint now. See [[asset-formats]]. [T2]
|
||||
|
||||
## The OLD-STYLE SPECIALFX layer (the weapon-impact action) — RECONSTRUCTED 2026-07-12 (firmware-decoded)
|
||||
The per-weapon impact visuals are fully AUTHORED in `content/BTDPL.INI` `[effects_to_load]`:
|
||||
`specialfx3..15` = Chunks1/Chunks2/Sparks/Explosion3/MachineGun/PPCHit/LaserHit/MissileHit/
|
||||
CannonHit/GroundHit/MinorHit/MajordHit/Fireball — "old-style" (version-1) descriptor sections
|
||||
(`texture/type/size/velocity/v_bias/y_off/cook(3f)/varience/gravity/cool(2f)/count/repeats`),
|
||||
most on `btfx:firesmoke1_scr_tex` (MissileHit size 12 ×7; Fireball size 14, gravity −1.5 rises;
|
||||
Chunks1/2 = ballistic debris vel 40-55 grav 34-35; Sparks NOTEX). [T1: the 1995 binary parses
|
||||
them — part_008.c:1546-1590, field strings @004f25e4-004f2663 → installer FUN_00490210 packs a
|
||||
0x44-byte board command via FUN_0048e2c0.] **Simulation semantics (type/cook/cool) live in the
|
||||
i860 firmware** `content/VREND.MNG` (same decode workflow as the task-#55 'damageize' handler).
|
||||
- **EFFECT-NUMBER ROUTING (corrects the old claim):** `effect_number < 100` = the dpl board
|
||||
EFFECT TABLE = this specialfx list (1996 case-4 comments match: 3=Chunks, 12=GroundHit,
|
||||
15=Fireball), **NOT** a psfx slot; `>= 1000` = psfx slot n−1000 (idam/ddam PFX); 100-999 =
|
||||
ExplosionScripts. The port's `<100 → psfx slot` mapping renders PPCHit(8) as ddam5 smoke and
|
||||
Chunks(3)/Sparks(5) as ddamN smoke — the "hits are just a little smoke" report. The 2007
|
||||
WinTesla loader SKIPS all version-1 descriptors (`if (version < 2) continue;` — it only reads
|
||||
the 1998 INDIE format), which is why the layer was never seen. [T1]
|
||||
- **Live hit census (mp logs):** weapon hits dispatch idam bands 1009-1013 (30×1009) + raw
|
||||
8/9 (PPCHit/LaserHit, mis-rendered); **MissileHit(10)/CannonHit(11) never appeared** — the
|
||||
projectile/salvo damage path likely doesn't thread the firing launcher's subsystemID into the
|
||||
damage records, so messmgr never queues its explosion. [T2 census; T4 cause]
|
||||
- **RECONSTRUCTION (2026-07-12, firmware-first):** the i860 sim decoded from VREND.MNG
|
||||
(dispatch table at data+0xdd0c, VA base: code 0xf0400000, data 0x1000; handlers: sfx trigger
|
||||
0xf040cda0→ca48, install 0xf040cdc0→cba0, step near 0xf0413698, spawn near 0xf0414afc —
|
||||
string-anchored via "attempt to step a NULL sfx object"; disassembler REBUILT at
|
||||
`scratchpad/i860dis.py` from binutils i860 opcodes, `scratchpad/i860_opcodes.h`).
|
||||
**The heat model [T1]:** per 30Hz board frame `h *= cool_a`; `RGB_ch = h_old*(h_new*cook_ch
|
||||
− 0.25) + 0.25` (K=0.25 @VA 0xF080 = the ember floor); kill at h ≤ 1e-4 (@0xF0A0); alpha −=
|
||||
cool_b per frame; `pos += vel`, gravity as accel. y_off = the particle KILL PLANE
|
||||
(Chunks −1 = die at the ground) [T3 data-indicated]. Burst frame randomly spun (quadratic
|
||||
small-angle rot, θ from the host-fed random table cmd 0x21). Implemented in L4VIDEO.cpp:
|
||||
`BTInstallSfx`/`BTStartSfx` + sfxMode particles in the BTPfx layer; parser beside the psfx
|
||||
page walk (`[sfx] page 'effects_to_load': 13 old-style specialfx installed`). Effect-number
|
||||
routing fixed in BOTH consumers (ExplosionClassID + DPLIndependantEffect): <100 → specialfx,
|
||||
≥1000 → psfx slot n−1000. **Missile/cannon hits now bundle** [T2]: BTProjectile carries
|
||||
shooter + weaponSubsys; contact routes through the SHOOTER's SubsystemMessageManager
|
||||
(AddDamageMessage w/ subsystemID → mslhit/acanhit explosion at the impact), mirroring the
|
||||
laser path's SendDamageMessage. Cone shape (v_bias as up-bias) + per-type draw weights are
|
||||
[T3]; the full type-0/1/2 draw-geometry decode in the firmware draw fn (0xf0416160) remains
|
||||
open.
|
||||
|
||||
## Weapon-hit forensics closeout (2026-07-12, workflow-verified) [T1]
|
||||
- **The HIT PACKAGES (BTL4.RES model lists, byte-verified):** ppchit=[8], lzrhit=[9],
|
||||
mghit=[7,11], canhit=[11] (no "acanhit"), mslhit=**[10, 12, 1023]** (MissileHit + GroundHit +
|
||||
psfx23 SHKWAVE), gndhit=[12], minhit=[1002], majhit=[1003], explode=[6]; dam1-4hit=[1002-1005],
|
||||
desthit/stephit=[1008]; cockpit "i" variants (lzrhiti etc.) = same sfx + idam 1009-1013; ALL
|
||||
eight mech death lists = ["104","3","4","5","1007","15","1001"].
|
||||
- **"Silver mist exactly 5×, perfectly timed" ROOT CAUSE:** SHKWAVE.PFX authors maxIssue=5,
|
||||
releasePeriod=0.2, **rate=1** — the ONE shipped .PFX where rate ≠ maxIssue/releasePeriod; the
|
||||
emitter trusted 'rate' → 5 huge white shells (exp 350/s) at exactly 1Hz. **Emission-window
|
||||
rule hardened:** effective rate = maxIssue/releasePeriod always (BTDrawPfx emitter).
|
||||
- **SpecialFX palette [T1 firmware]:** instance init @0xf04128d8: inst[0x19c]=cool_a (per
|
||||
board-frame heat decay), inst[0x1a4]=cool_b (× raw dt in the step = PER-SECOND fade),
|
||||
inst[0x188]=7.0s cap, heat=1.0. The heat channels are BRIGHTNESS over an inherently
|
||||
FIRE-coloured texture (firesmoke through its material ramp): sfx batch draws the FIERY-ramped
|
||||
sheet, psfx keeps GRAYSCALE (authored colours decide — DNBOOM orange, DDAM gray). Drawing sfx
|
||||
grayscale = silver mist; scaling fade ×30 = 0.1s pops ("nothing happens on laser hits").
|
||||
- **Damage-band .PFX shapes are authored GENTLE (puffy clouds):** bands 1-4 of ndam/idam/ddam
|
||||
rise at 1-4 u/s with buoyant accel; ONLY band 5 + the BOOM/SHKWAVE files are explosive-omni.
|
||||
idam = scaled-down WORLD venting smoke (half radius/counts of ddam), not cockpit-only.
|
||||
N-set = night = same physics as D-set with fewer particles. NSRM/DSRM trails = 0.1s overbright
|
||||
ORANGE directional puffs (never silver).
|
||||
- **messmgr explosion DEDUP CONFIRMED [T1, decomp-read @0049b784]:** `Find` (weaponExplosions
|
||||
vtable slot 0xC) gates `AddValue` (slot 8) — ONE explosion per unique weapon resource per
|
||||
frame, exactly as reconstructed. (A workflow agent claimed "one per record, staggered
|
||||
0.1s" — REFUTED; the stagger applies to the deduped queue.) Missile multiplicity comes from
|
||||
the ORDNANCE side instead: Missile::MoveAndCollide @004bef78 detonates per round — ported as
|
||||
BTSpawnRoundDetonation (mech4) + rack-tube launch spread [T3]. Alpha-strike drama = distinct
|
||||
per-weapon-TYPE packages (lzrhit+ppchit) + the victim's band fire, not explosion count.
|
||||
- Remaining [T3]: sfx cone shape (v_bias as up-bias), size ×0.5 + 1.25m textured floor +
|
||||
hot-phase occlusion 0.45..0.9, burst scatter ×0.2; trail
|
||||
density is frame-rate-dependent (2/frame @60fps = 2× pod density); .PFX 'repeats' unconsumed
|
||||
(all shipped files author 1); replicant visual salvo chases the stale fire-time aim point
|
||||
(no re-lead without a target handle).
|
||||
|
||||
## Weapon beams (the unported dpl_* layer)
|
||||
The `dpl_*` beam renderable was never ported → beams are drawn by `BTPushBeam`/`BTDrawBeams`
|
||||
(L4VIDEO). The real look is the `ermlaser.bgf` TUBE (native Z 0..−2000, UVs tiled) with the scrolling
|
||||
|
||||
Reference in New Issue
Block a user