Skip to content

Instantly share code, notes, and snippets.

@heisvoid
Created July 20, 2019 10:50
Show Gist options
  • Save heisvoid/085b2aa979c6eb94b14dbf9a17af4aac to your computer and use it in GitHub Desktop.
Save heisvoid/085b2aa979c6eb94b14dbf9a17af4aac to your computer and use it in GitHub Desktop.
# -*- 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):
buf = f.read(3)
buf = struct.unpack('<BBB', buf)
pal.append((buf[0], buf[1], buf[2]))
# extract sprites
with open(args.spr, 'rb') as f:
f.seek(0, os.SEEK_END)
file_len = f.tell()
f.seek(0, os.SEEK_SET)
# header
f.seek(0x42, os.SEEK_SET)
# total number of sprites
buf = f.read(2)
buf = struct.unpack('<H', buf)
num = buf[0]
print(num)
# zero padding
f.seek(60, os.SEEK_CUR)
for n in range(num):
# total length of compressed pixel data
buf = f.read(4)
buf = struct.unpack('<I', buf)
length = buf[0]
# width and height of a sprite
buf = f.read(2)
buf = struct.unpack('<H', buf)
width = buf[0]
buf = f.read(2)
buf = struct.unpack('<H', buf)
height = buf[0]
assert 320 >= width
assert 200 >= height
# unknown
f.seek(24, os.SEEK_CUR)
# number of compressed chunks
buf = f.read(2)
buf = struct.unpack('<H', buf)
chunks = buf[0]
# reset monitor
#monitor = range(MONITOR_WIDTH * MONITOR_HEIGHT)
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):
assert f.tell() < file_len
buf = f.read(2)
buf = struct.unpack('<H', buf)
blanks = buf[0]
idx = idx + blanks
assert f.tell() < file_len
buf = f.read(1)
buf = struct.unpack('<B', buf)
drawn = 4 * buf[0]
assert f.tell() < file_len
buf = f.read(1)
buf = struct.unpack('<B', buf)
drawn = drawn + buf[0]
for d in range(drawn):
assert f.tell() < file_len
buf = f.read(1)
buf = struct.unpack('<B', buf)
pal_idx = buf[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]))
assert f.tell() == file_len
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment