Skip to content

Instantly share code, notes, and snippets.

@heisvoid
Created August 8, 2024 05:06
Show Gist options
  • Save heisvoid/f7a871a4cb20512b9a919f5668bf622a to your computer and use it in GitHub Desktop.
Save heisvoid/f7a871a4cb20512b9a919f5668bf622a to your computer and use it in GitHub Desktop.
Extract sprite type 1 in TWG
# -*- coding: utf-8 -*-
# Extract sprites
import argparse
import struct
import os
# mode 13h resolution
MONITOR_WIDTH = 320
MONITOR_HEIGHT = 200
# bright pink
SPRITE_BACKGROUND = (255, 0, 255)
parser = argparse.ArgumentParser(description='Extract sprites.')
parser.add_argument('-p', required=True, help='palette file', dest='pal')
parser.add_argument('-f', required=True, help='compressed sprites file',
dest='spr')
args = parser.parse_args()
# read palette
pal = []
with open(args.pal, 'rb') as f:
for i in range(256):
bytes = f.read(3)
bytes = struct.unpack('<BBB', bytes)
pal.append((bytes[0], bytes[1], bytes[2]))
# extract sprites
with open(args.spr, 'rb') as f:
# header
f.seek(0x42, os.SEEK_SET)
# total number of sprites
bytes = f.read(2)
bytes = struct.unpack('<H', bytes)
num = bytes[0]
# zero padding
f.seek(60, os.SEEK_CUR)
offsets = []
for n in range(num):
bytes = f.read(4)
bytes = struct.unpack('<I', bytes)
offsets.append(bytes[0])
n = 0
for ofs in offsets:
f.seek(ofs, os.SEEK_SET)
# length of compressed pixel data
bytes = f.read(4)
bytes = struct.unpack('<I', bytes)
len = bytes[0]
# width
bytes = f.read(2)
bytes = struct.unpack('<H', bytes)
width = bytes[0]
assert 320 >= width
# height
bytes = f.read(2)
bytes = struct.unpack('<H', bytes)
height = bytes[0]
assert 200 >= height
# unknown
f.seek(2, os.SEEK_CUR)
f.seek(2, os.SEEK_CUR)
# number of compressed chunks
bytes = f.read(2)
bytes = struct.unpack('<H', bytes)
chunks = bytes[0]
# reset monitor
monitor = []
for i in range(MONITOR_WIDTH * MONITOR_HEIGHT):
monitor.append(SPRITE_BACKGROUND)
# draw a sprite on monitor
idx = 0
for c in range(chunks):
bytes = f.read(2)
bytes = struct.unpack('<H', bytes)
blanks = bytes[0]
idx = idx + blanks
bytes = f.read(1)
bytes = struct.unpack('<B', bytes)
drawn = 4 * bytes[0]
bytes = f.read(1)
bytes = struct.unpack('<B', bytes)
drawn = drawn + bytes[0]
for d in range(drawn):
bytes = f.read(1)
bytes = struct.unpack('<B', bytes)
pal_idx = bytes[0]
monitor[idx] = pal[pal_idx]
idx = idx + 1
# write a sprite to file
out_name = os.path.basename(args.spr)
out_name = out_name + '.%05d' % n + '.ppm'
with open(out_name, 'w') as out:
out.write('P3\n')
out.write('%d %d\n' % (width, height))
out.write('255\n')
for h in range(height):
for w in range(width):
rgb = monitor[320 * h + w]
out.write('%d %d %d\n' % (rgb[0], rgb[1], rgb[2]))
n = n + 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment