Death = the burning WRECK-HULK swap (effect 104) -- the authentic chain, reconstructed
The user was right: a dead mech turns into a pile of wreckage. The authentic
1995 chain, recovered end-to-end:
kill -> the victim's per-mech DEATH ModelList ('blhdead'/'lokdead'/'owndead'/
'thrdead', .RES ids 22-25) -> its authored effects: 104 (the WRECK script) +
1007 (dnboom big explosion) + 1001 (ddthsmk rubble smoke plume) + a damage-
smoke burst (3/4/5/15).
Effect 104 = ExplosionScripts case 4 (part_008.c:2663, LIVE in the 1996 binary;
the "disabled" warning is case 6): loads the destroyed hulk + flamesml/flamebig
flame meshes with sweep flicker. Every mech ships its hulk (BLHDBR/MADDBR/
LOKDBR/... + GENDBR generic); the 1996 script hardcoded thrdbr.bgf (dev
shortcut) -- we use the victim's own.
Reconstructed as BTL4VideoRenderer::SwapToWreck: hide every segment mesh, hang
"<prefix>dbr.bgf" on the tree root (pending-swap if death precedes tree build);
routed from the engine's ExplosionClassID dispatch (effect 104 ->
BTSwapMechToWreck(explosion->GetEntityHit())). The kill now fires the
authentic 'blhdead' resource (manual 7+1 pfx calls removed -- the list carries
1007/1001 itself). Verified live:
[death] firing authentic death list 'blhdead' id=22
** effect_number = 104
[BTrender] wreck swap: victim -> 'blhdbr.bgf'
Follow-ups noted: mesh flames + hulk settle (cosmetic), DeathSplash.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
b44c0f98f6
commit
c0fa6bf21a
@@ -0,0 +1,52 @@
|
||||
import struct
|
||||
data = open(r'C:\git\bt411\content\BTL4.RES', 'rb').read()
|
||||
labOnly, maxID = struct.unpack_from('<ii', data, 4)
|
||||
offs = struct.unpack_from('<%dI' % maxID, data, 12)
|
||||
|
||||
# resource record: [id][type][name 32][size?][dataOffset?] -- find layout empirically
|
||||
# checkres used: rid, rt at +0, +4; name at +8..+40. Locate stream bounds via the
|
||||
# next resource's offset (records are packed with their data).
|
||||
recs = []
|
||||
for o in offs:
|
||||
if o == 0:
|
||||
continue
|
||||
rid, rt = struct.unpack_from('<ii', data, o)
|
||||
nm = data[o + 8:o + 40].split(b'\0')[0].decode('ascii', 'replace')
|
||||
recs.append((o, rid, rt, nm))
|
||||
recs.sort()
|
||||
|
||||
def stream_of(target_id):
|
||||
for i, (o, rid, rt, nm) in enumerate(recs):
|
||||
if rid == target_id:
|
||||
end = recs[i + 1][0] if i + 1 < len(recs) else len(data)
|
||||
# header: id,type,name32 then likely [size][...]; data runs to `end`
|
||||
return data[o:end], nm
|
||||
return None, None
|
||||
|
||||
def root_y(rid, label):
|
||||
blob, nm = stream_of(rid)
|
||||
if blob is None:
|
||||
print(label, rid, 'NOT FOUND'); return
|
||||
# find the ANI payload: after the 40-byte record header there may be extra
|
||||
# header ints; the payload starts [A][B][x] with plausible counts.
|
||||
for hdr in range(40, 72, 4):
|
||||
A, B = struct.unpack_from('<ii', blob, hdr)
|
||||
if 1 <= A <= 200 and 1 <= B <= 100:
|
||||
payload = blob[hdr:]
|
||||
# root channel = last (A+1)*12 bytes
|
||||
need = (A + 1) * 12
|
||||
if need > len(payload):
|
||||
continue
|
||||
tail = payload[len(payload) - need:]
|
||||
ys = [struct.unpack_from('<3f', tail, k * 12) for k in range(A + 1)]
|
||||
print('%s (id %d, %r): A=%d kf, B=%d joints, hdr=%d' % (label, rid, nm, A, B, hdr))
|
||||
print(' root (x,y,z) per kf:')
|
||||
for k, v in enumerate(ys):
|
||||
print(' kf%02d x=%8.3f y=%8.3f z=%8.3f' % (k, v[0], v[1], v[2]))
|
||||
return
|
||||
print(label, rid, 'no plausible header found; first ints:',
|
||||
struct.unpack_from('<8i', blob, 40))
|
||||
|
||||
root_y(908, 'blhbmp (knockdown)')
|
||||
print()
|
||||
root_y(898, 'blhwwl (walk-left, baseline)')
|
||||
@@ -0,0 +1,27 @@
|
||||
import struct, re
|
||||
data = open(r'C:\git\bt411\content\BTL4.RES', 'rb').read()
|
||||
labOnly, maxID = struct.unpack_from('<ii', data, 4)
|
||||
offs = struct.unpack_from('<%dI' % maxID, data, 12)
|
||||
recs = []
|
||||
for o in offs:
|
||||
if o == 0:
|
||||
continue
|
||||
rid, rt = struct.unpack_from('<ii', data, o)
|
||||
nm = data[o + 8:o + 40].split(b'\0')[0].decode('ascii', 'replace')
|
||||
recs.append((o, rid, rt, nm))
|
||||
recs.sort()
|
||||
print('=== all type-1 ModelLists ===')
|
||||
ml = [(o, rid, nm) for (o, rid, rt, nm) in recs if rt == 1]
|
||||
for o, rid, nm in ml:
|
||||
print(' id=%4d %-14s' % (rid, nm))
|
||||
print(len(ml), 'total')
|
||||
print()
|
||||
print('=== strings inside each ModelList stream (video object names = effect numbers) ===')
|
||||
for i, (o, rid, rt, nm) in enumerate(recs):
|
||||
if rt != 1:
|
||||
continue
|
||||
end = recs[i + 1][0] if i + 1 < len(recs) else len(data)
|
||||
blob = data[o + 40:end]
|
||||
strs = re.findall(rb'[ -~]{1,12}', blob)
|
||||
toks = [s.decode() for s in strs if s.strip()]
|
||||
print(' id=%4d %-12s -> %s' % (rid, nm, toks[:10]))
|
||||
Reference in New Issue
Block a user