initial commit: llamamod 0.2.0 – reverse-engineered level formats (wad, map, trak, text, stpc), python tools and notes, java mod manager (iso install, mod pipeline with exe patching, save editor, wine/windows launcher) with mods (test world, debug wireframe, mirror, randomizer, fog, cheats, intro skip, practice, free camera, boot to level, level projects) and the 3d level editor (geometry, objects, cross-world import, environment, textures, play-test, manual)
This commit is contained in:
commit
b36a366240
826 files changed
+105304
No files matched your search
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Liest und schreibt Level-WADs von "Ein Königreich für ein Lama" (Argonaut).
|
||||
|
||||
Aufbau: u32 Gesamtlänge (ohne dieses Feld), dann Chunks:
|
||||
4 Byte Kennung (rückwärts gespeichert, z. B. 'OFNI' = INFO), u32 Länge, Daten
|
||||
bis zum Chunk 'END '.
|
||||
|
||||
wadtool.py list level.wad
|
||||
wadtool.py name level.wad neu.wad "Neuer Levelname"
|
||||
wadtool.py extract level.wad CHUNK datei.bin
|
||||
wadtool.py replace level.wad neu.wad CHUNK datei.bin
|
||||
"""
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
def read(path):
|
||||
d = open(path, 'rb').read()
|
||||
total = struct.unpack_from('<I', d, 0)[0]
|
||||
if total != len(d) - 4:
|
||||
raise ValueError(f'{path}: Längenfeld {total} passt nicht zu {len(d) - 4}')
|
||||
chunks, o = [], 4
|
||||
while o + 8 <= len(d):
|
||||
tag = d[o:o + 4][::-1].decode('latin1')
|
||||
ln = struct.unpack_from('<I', d, o + 4)[0]
|
||||
chunks.append([tag, d[o + 8:o + 8 + ln]])
|
||||
o += 8 + ln
|
||||
if tag == 'END ':
|
||||
break
|
||||
return chunks
|
||||
|
||||
|
||||
def write(path, chunks):
|
||||
body = b''.join(t.encode('latin1')[::-1] + struct.pack('<I', len(c)) + c for t, c in chunks)
|
||||
open(path, 'wb').write(struct.pack('<I', len(body)) + body)
|
||||
|
||||
|
||||
def get(chunks, tag):
|
||||
for c in chunks:
|
||||
if c[0] == tag:
|
||||
return c
|
||||
raise KeyError(tag)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cmd, src = sys.argv[1], sys.argv[2]
|
||||
ch = read(src)
|
||||
if cmd == 'list':
|
||||
for t, c in ch:
|
||||
extra = ''
|
||||
if t == 'NAME':
|
||||
extra = repr(c[4:].split(b'\0')[0].decode('latin1'))
|
||||
print(f'{t!r:8} {len(c):10d} {extra}')
|
||||
elif cmd == 'name':
|
||||
c = get(ch, 'NAME')
|
||||
c[1] = c[1][:4] + sys.argv[4].encode('latin1') + b'\0'
|
||||
write(sys.argv[3], ch)
|
||||
elif cmd == 'extract':
|
||||
open(sys.argv[4], 'wb').write(get(ch, sys.argv[3].ljust(4))[1])
|
||||
elif cmd == 'replace':
|
||||
get(ch, sys.argv[4].ljust(4))[1] = open(sys.argv[5], 'rb').read()
|
||||
write(sys.argv[3], ch)
|
||||
else:
|
||||
sys.exit(__doc__)
|
||||
Reference in new issue
Block a user