Skip to content

Instantly share code, notes, and snippets.

@bbbradsmith
Created November 17, 2022 02:40
Show Gist options
  • Save bbbradsmith/345b14e02a4922ac7158bbbd8e4d019a to your computer and use it in GitHub Desktop.
Save bbbradsmith/345b14e02a4922ac7158bbbd8e4d019a to your computer and use it in GitHub Desktop.
Vigilance on Talos V DOS graphics and map extractor
# Sprite / Map dumper for Vigilance on Talos V (19960
# place in "dump" folder within Talos install directory and run
import os
import struct
import PIL.Image
DEFAULT_BG = 13 # magenta
def filename_flatten(f):
return f.replace("/","_")
def atlas_image(tiles,width=256+17,bg=DEFAULT_BG):
row_x = 1
row_y = 1
row_h = 0
coords = []
for i in range(len(tiles)):
img = tiles[i]
if (row_x + img.width + 1) > width:
if (row_x == 1): # too big: expand
width = row_w + img.width + 1
else:
row_x = 1
row_y += row_h + 1
row_h = 0
if (row_x + img.width + 1) > width:
width = row_w + img.width + 1
coords.append((row_x,row_y))
row_x += img.width + 1
row_h = max(row_h, img.height)
height = row_y + row_h + 1
img = PIL.Image.new("P",(width,height),bg)
img.putpalette(tiles[0].getpalette())
for i in range(len(tiles)):
img.paste(tiles[i],coords[i])
return img
def hexs(data):
s = ""
for b in data:
s += " %02X" % b
if len(s) > 0:
return s[1:]
return s
def read_spr(filename,verbose=True):
if verbose:
print("SPR: %s" % filename)
spr = open("../"+filename,"rb").read()
pal = []
for i in range(256):
r,g,b = spr[0xF+(i*3)+0:0xF+(i*3)+3]
r = (r * 255) // 63
g = (g * 255) // 63
b = (b * 255) // 63
pal += [r,g,b]
count = struct.unpack("<H",spr[0x30F:0x30F+2])[0] + 1
if verbose:
print("Count: %d" % count)
pos = 0x30F+2
tiles = []
for i in range(count):
spos = pos
p = struct.unpack("<H",spr[pos:pos+2])[0]
if p == 0:
(w,h) = (0,0)
pos += 2
else:
(w,h) = struct.unpack("<HH",spr[pos+2:pos+6])
pos += 6
#if verbose:
# print("%3d: %06X %2x - %3d x %3d" % (i,spos,p,w,h))
img = PIL.Image.new("P",(w,h),DEFAULT_BG)
img.putpalette(pal)
for y in range(h):
for x in range(w):
img.putpixel((x,y),spr[pos])
pos += 1
tiles.append(img)
atlas_image(tiles).save(filename_flatten(filename)+".png")
return tiles
def read_wmp(filename,tile_filename,bg=DEFAULT_BG):
tiles = read_spr(tile_filename,False)
print("WMP: %s" % filename)
wmp = open("../"+filename,"rb").read()
(head,w,h) = struct.unpack("<HHH",wmp[0:6])
print(" %04X %3d x %3d" % (head,w,h))
(tw,th) = tiles[0].size
img = PIL.Image.new("P",(w*tw,h*th),bg)
img.putpalette(tiles[0].getpalette())
for y in range(h):
for x in range(w):
to = 6+2*((y*w)+x)
t = struct.unpack("<H",wmp[to:to+2])[0]
if t < len(tiles):
img.paste(tiles[t],(x*tw,y*th))
else:
print(" %3d,%3d tile %02X out of range" % (x,y,t))
#pos = 6 + (w * h) # suffix data?
#print("%06X: %s" % (pos,hexs(wmp[pos:pos+16])))
img.save(filename_flatten(filename+"."+tile_filename)+".png")
def dump_dir_spr(path):
for dirpath, dirnames, filenames in os.walk("../" + path):
for f in filenames:
if f.lower().endswith("spr"):
read_spr(path + "/" + f)
def dump_dir_wmp(path):
for dirpath, dirnames, filenames in os.walk("../" + path):
for f in filenames:
if f.lower().endswith("wmp"):
# dunno how we're supposed to select tileset
# couldn't find relevant data in the WMP, or in any other file
# take 2 numbers from WMP name:
w0 = int(f[-7])
if f[-8] >= '0' and f[-8] <= '9':
w0 += int(f[-8])*10
w1 = int(f[-5])
# try to correlate those to TILE name
t0 = 1
t1 = w1
if path.startswith("WORLD1"):
t1 = w1
if f.startswith("BACK"):
t0 = w0
else:
t0map = { # override t0 for some maps
(4,1):2,
(9,2):2,
(11,1):1,
(14,1):1,
(14,2):2,
(15,1):2,
(17,1):1,
(17,2):3,
}
t1map = { # override t1 for some maps
(14,1):1,
(17,2):2,
}
if (w0,w1) in t0map:
t0 = t0map[(w0,w1)]
if (w0,w1) in t1map:
t1 = t1map[(w0,w1)]
#print("%d,%d > %d,%d" % (w0,w1,t0,t1))
# do it
tf = "TILE%d-%d.SPR" % (t0,t1)
read_wmp(path + "/" + f, path + "/" + tf)
# main
dump_dir_spr("CINEMAS")
dump_dir_spr("RESOURCE")
dump_dir_spr("WORLD1")
dump_dir_spr("WORLD2")
dump_dir_spr("WORLD3")
dump_dir_wmp("WORLD1")
dump_dir_wmp("WORLD2")
dump_dir_wmp("WORLD3")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment