Last iteration I killed the biconditional and reported that the one-way
reading survived: all 10 bit-set sprites on GP_TITLE build 4 are eff
names, so "bit set => eff name". Checked over the disc, that is false.
sprites with a resolvable preceding name 14 709
bit SET & name has 'eff' 2 338
bit SET & name lacks 'eff' 2 657 <-- counterexamples
bit clear & name has 'eff' 1 399
bit clear & name lacks 'eff' 8 315
P(eff | set) = 0.468
P(eff | clear) = 0.144
The implication fails more often than it holds. What survives is an
association -- 3.3x enrichment -- and build 4's 10/10 was a local naming
habit in an 18-element bundle, not a format rule.
The counterexamples are the useful part: pv_loading_ring0,
pv_loading_light0-3, pv_loading_line, px_bunk_line, px_top_extra. Rings,
glows, lights, thin lines -- effect-like artwork that does not carry the
eff naming convention. Consistent with the bit marking effect sprites by
authoring intent rather than by name, which is a description and not a
decode, and is labelled as such.
Names here come from the string immediately preceding each T8aD,
validated 17/18 on build 4 against the RATC child order; the single
mismatch is the known pteff04.t32 -> registered as 8AX case, so this is
the element (opt) name rather than the sprite's registered name. That
mismatch is itself an independent confirmation of the 8AX finding,
reached from the opposite direction.
METHOD: a pattern perfect on one screen can be near-chance on the disc;
and when an association survives a refuted implication, the
counterexamples are the finding.
61 lines
2.7 KiB
Python
Executable File
61 lines
2.7 KiB
Python
Executable File
"""Disc-wide: does T8aD flag bit 0x02 imply an `eff` name?
|
|
|
|
Names come from the NAME IMMEDIATELY PRECEDING each T8aD chunk -- validated
|
|
17/18 on GP_TITLE build 4 against the known RATC child order. The single
|
|
mismatch is the documented `pteff04.t32` -> registered as `8AX` case, i.e. the
|
|
preceding name is the ELEMENT's (opt) name and the child list is the SPRITE's.
|
|
This test uses the element name and says so.
|
|
"""
|
|
import struct, zlib, glob, os, re, collections
|
|
NAME = re.compile(rb'[A-Za-z0-9_.]{2,31}\x00')
|
|
|
|
def entries(base):
|
|
stub = open(base + ".pak", "rb").read()
|
|
if stub[:4] != b"IPFB": return
|
|
n = struct.unpack_from(">I", stub, 4)[0]
|
|
segs = sorted(glob.glob(base + ".p[0-9][0-9]"))
|
|
if not segs: return
|
|
blob = b"".join(open(s, "rb").read() for s in segs)
|
|
for i in range(n):
|
|
h, off, sz = struct.unpack_from(">III", stub, 0x10 + 12 * i)
|
|
st = blob[off:off + sz]
|
|
if len(st) < 10: continue
|
|
try: yield (zlib.decompress(st[10:]) if st[:2] == b"Z1" else st)
|
|
except Exception: continue
|
|
|
|
set_eff = set_noneff = clear_eff = clear_noneff = 0
|
|
examples = []
|
|
for pak in sorted(glob.glob("/work/sylph_extract/dat/GP_*.pak")):
|
|
for d in entries(pak[:-4]):
|
|
for m in re.finditer(b"T8aD", d):
|
|
o = m.start()
|
|
try:
|
|
fl = struct.unpack_from(">I", d, o + 4)[0]
|
|
w = struct.unpack_from(">I", d, o + 0x14)[0]
|
|
h = struct.unpack_from(">I", d, o + 0x18)[0]
|
|
except Exception: continue
|
|
if not (0 < w <= 4096 and 0 < h <= 4096): continue
|
|
ms = list(NAME.finditer(d[max(0, o - 64):o]))
|
|
if not ms: continue
|
|
nm = ms[-1].group()[:-1].decode("latin1")
|
|
eff = "eff" in nm.lower()
|
|
if fl & 2:
|
|
if eff: set_eff += 1
|
|
else:
|
|
set_noneff += 1
|
|
if len(examples) < 12: examples.append((os.path.basename(pak), nm, f"{fl:08x}", f"{w}x{h}"))
|
|
else:
|
|
clear_eff += 1 if eff else 0
|
|
clear_noneff += 0 if eff else 1
|
|
tot = set_eff + set_noneff + clear_eff + clear_noneff
|
|
print(f"sprites with a resolvable preceding name: {tot}")
|
|
print(f" bit SET & name has 'eff' : {set_eff}")
|
|
print(f" bit SET & name lacks 'eff': {set_noneff} <-- counterexamples to 'set => eff'")
|
|
print(f" bit clear & name has 'eff' : {clear_eff}")
|
|
print(f" bit clear & name lacks 'eff': {clear_noneff}")
|
|
if tot: print(f"\n P(name has 'eff' | bit set) = {set_eff/max(set_eff+set_noneff,1):.3f}")
|
|
if tot: print(f" P(name has 'eff' | bit clear) = {clear_eff/max(clear_eff+clear_noneff,1):.3f}")
|
|
if examples:
|
|
print("\n counterexamples (bit set, no 'eff'):")
|
|
for e in examples: print(" ", e)
|