Last active
July 18, 2020 06:32
-
-
Save bbbradsmith/559057c5fc28443d0c38b0d0c674aa72 to your computer and use it in GitHub Desktop.
The Endless Night map dumper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# map dumper for The Endless Night (DOS, 1993, Andy Wood / MythicArts) | |
# Brad Smith, 2020-07-18 | |
# make a "dump" folder before running this | |
# Python 3 | |
import math | |
import PIL.Image | |
import PIL.ImageDraw | |
def hexs(data): | |
s = "" | |
for b in data: | |
s += " %02X" % b | |
if len(s) > 0: | |
return s[1:] | |
return s | |
def read_pal(f): | |
print("read_pal("+f+")") | |
b = open(f,"rb").read() | |
c = bytearray() | |
for i in range(7,len(b)): | |
p = b[i] | |
if ((i-7)%4) == 3: | |
assert (p == 0) # alpha channel should be 0 | |
continue | |
assert (p < 64) # out of range? | |
c.append((p*4) & 0xFF) | |
return c | |
def read_tiles(f,pal): | |
print("read_tiles("+f+")") | |
b = open(f,"rb").read() | |
t = [] | |
for i in range(0,len(b)-807,808): | |
img = PIL.Image.new("P",(20,20),255) | |
img.putpalette(pal) | |
for y in range(20): | |
for x in range(20): | |
p = b[0xB+i+(y*20)+x] | |
img.putpixel((x,y),p) | |
t.append(img) | |
#print("Tile %02X: %s" % (i//808,hexs(b[i:i+0xB]))) | |
return t | |
def read_map(f,t,pals,palmap): | |
print("read_map("+f+")") | |
b = open(f,"rb").read() | |
ww,wh = 12,8 # size of world, multiplies to 96 | |
mw,mh = 16,10 # size of each map | |
tw,th = t[0].size # size of a tile | |
wr = ww * wh | |
img = PIL.Image.new("RGB",(tw*mw*ww,th*mh*wh),255) | |
#img.putpalette(t[0].getpalette()) | |
for m in range(wr): | |
for y in range(mh): | |
for x in range(mw): | |
# 7 byte header + 3D array of [y][x][map] | |
ix = 7 + 2 * (m + (x * wr) + (y * mw * wr)) | |
p = b[ix] | |
wx = m % ww | |
wy = m // ww | |
rxy = ((wx*mw+x)*tw,(wy*mh+y)*th) | |
imt = t[p] | |
tp = palmap[wy][wx] | |
imt.putpalette(pals[tp]) | |
img.paste(imt,rxy) | |
return img | |
def arrange_tiles(t,mw,mh,pal): | |
img = PIL.Image.new("P",(20*mw,20*mh),255) | |
img.putpalette(pal) | |
for ti in range(len(t)): | |
y = 20 * (ti // mw) | |
x = 20 * (ti % mw) | |
img.paste(t[ti],(x,y)) | |
return img | |
# dunno where the per-screen palette is stored, | |
# just manually duplicating it here | |
mappals = [ | |
[0,0,0,1,1,1,1,1,1,1,1,1], | |
[0,0,0,1,1,1,1,1,1,1,1,1], | |
[0,0,0,0,0,0,0,0,0,0,0,2], | |
[0,0,0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,0,0,0,0,0,0,0,0,0], | |
[0,0,0,0,0,2,2,0,0,0,0,0], | |
[2,0,0,0,2,2,2,2,0,0,0,0], | |
] | |
pal = read_pal("NIGHT.PAL") | |
pic = read_pal("NIGHTICE.PAL") | |
psa = read_pal("NIGHTSAN.PAL") | |
spr = read_tiles("NIGHT.SPR",pal) | |
scr = read_map("NIGHT.SCR",spr,[pal,pic,psa],mappals) | |
# details to manually correct: | |
# goat on 0,4 | |
# horse 1,0 | |
# ship 11,2 | |
# cave looks weird? (0-tiles that should be grass) 11,7 | |
# sheep 9,4 | |
# merchant gap 4,4 | |
# merchant gap 5,4 | |
# yeti 7,0 | |
# eldirood 10,0 | |
open("dump\\NIGHT.PAL.pal", "wb").write(pal) | |
open("dump\\NIGHTICE.PAL.pal","wb").write(pic) | |
open("dump\\NIGHTSAN.PAL.pal","wb").write(psa) | |
for i in range(len(spr)): | |
#spr[i].save("dump\\NIGHT.SPR.%02X.png"%(i)) | |
pass | |
arrange_tiles(spr,8,4,pal).save("dump\\NIGHT.SPR.png") | |
arrange_tiles(spr,8,4,pic).save("dump\\NIGHT.SPR.ice.png") | |
arrange_tiles(spr,8,4,psa).save("dump\\NIGHT.SPR.sand.png") | |
scr.save("dump\\NIGHT.SCR.png") | |
print("Done!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment