#!/usr/bin/env python3 # extractAssets.py - pull human-readable assets out of the disk: Dan Bunten's letter (track 1), # the hidden EA message (track 1 sector 17) and the loader title picture (as PNG). import os, struct, zlib ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) EXT = os.path.join(ROOT, "extracted") DOCS = os.path.join(ROOT, "docs") os.makedirs(DOCS, exist_ok=True) def raw(t, s): return open(f"{EXT}/sectors/t{t:02d}s{s:02d}.bin", "rb").read() # --- letter: track 1 sectors 1-10, plain ASCII, CR = newline, ends before the padding in sector 10 text = b"".join(raw(1, s) for s in range(1, 11)) end = text.find(b"72203") + 5 letter = text[:end].decode("latin-1").replace("\r", "\n") with open(f"{DOCS}/track1_DanBuntenLetter.txt", "w") as f: f.write("Hidden text stored in plain ASCII on track 1, sectors 1-10 of the Modem Wars disk\n") f.write("(never shown by the game; addressed to anyone who cracks or inspects the disk).\n") f.write("=" * 78 + "\n\n") f.write(letter + "\n") # --- EA message in the drive bootstrap sector d = raw(1, 17) msg = d[0x4D:].split(b"\x00")[0].decode("latin-1") with open(f"{DOCS}/track1_sector17_message.txt", "w") as f: f.write("Text embedded after the code in the 1541 bootstrap sector (track 1 sector 17):\n\n") f.write(msg + "\n") # --- title picture: multicolour bitmap at LOAD $A000, screen RAM $9C00, colour RAM $9800, background $D021=0 load = open(f"{EXT}/files/load.prg", "rb").read()[2:] bitmap = load[0xA000-0x9800:0xA000-0x9800+8000] screen = load[0x9C00-0x9800:0x9C00-0x9800+1000] color = load[0x9800-0x9800:0x9800-0x9800+1000] PALETTE = [(0,0,0),(255,255,255),(136,0,0),(170,255,238),(204,68,204),(0,204,85),(0,0,170),(238,238,119), (221,136,85),(102,68,0),(255,119,119),(51,51,51),(119,119,119),(170,255,102),(0,136,255),(187,187,187)] W, H = 320, 200 pixels = bytearray(W * H * 3) for cy in range(25): for cx in range(40): cell = cy * 40 + cx c1 = screen[cell] >> 4 c2 = screen[cell] & 15 c3 = color[cell] & 15 for row in range(8): b = bitmap[cell * 8 + row] for px in range(4): bits = (b >> (6 - px * 2)) & 3 col = [0, c1, c2, c3][bits] r, g, bl = PALETTE[col] for dup in range(2): x = cx * 8 + px * 2 + dup y = cy * 8 + row i = (y * W + x) * 3 pixels[i:i+3] = bytes((r, g, bl)) def png(path, w, h, rgb): rows = b"".join(b"\x00" + bytes(rgb[y*w*3:(y+1)*w*3]) for y in range(h)) def chunk(tag, data): c = struct.pack(">I", len(data)) + tag + data return c + struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF) with open(path, "wb") as f: f.write(b"\x89PNG\r\n\x1a\n") f.write(chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0))) f.write(chunk(b"IDAT", zlib.compress(rows, 9))) f.write(chunk(b"IEND", b"")) # scale 2x vertically too so the aspect is right scaled = bytearray() for y in range(H): row = pixels[y*W*3:(y+1)*W*3] scaled += row + row png(f"{DOCS}/titleScreen.png", W, H * 2, scaled) print("wrote", os.listdir(DOCS))