Last active
September 2, 2021 09:16
-
-
Save pratikone/f0fbd11c3e16a4e852e9c0bbef891b73 to your computer and use it in GitHub Desktop.
This is script to reverse engineer and extract images and sounds assets from Zombie Wars game (also known as Halloween Harry 2)
This file contains 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
# Utility to extract image and sound assets from Zombie Wars game (also known as Halloween Harry 2) | |
# takes some inspiration from Wombat https://www.szevvy.com/ | |
# Pratik Anand 2021 (twitter : @pratikone) | |
# Blog post : https://pratikone.github.io/gaming/2021/09/02/reverse-engineer-zombiewars.html | |
# Running : | |
# Download DEARK from https://entropymine.com/deark/ and keep it somewhere and modify DEARK_PATH_WIN to point to deark.exe | |
# set GAME_FOLDER_PATH to point to folder containing game assets like GFX.SB0, SFX.SB0 | |
# run the script (install binario using pip). You don't need to provide any args. | |
# folders will be created for each .SB0 like gfx. If the extracted assets contain RAW files deark convert it to png and store | |
# it in converted folder within the parent folder like gfx. | |
import binario | |
import os | |
import subprocess | |
cwd = os.getcwd() | |
# for converting HSI RAW images to png | |
DEARK_PATH_WIN = cwd + "\\deark\\x64\\deark.exe" # https://entropymine.com/deark/ | |
print("DEARK : " + DEARK_PATH_WIN ) | |
GAME_FOLDER_PATH = "C:\games\ZWARS" | |
print("game path : " + GAME_FOLDER_PATH ) | |
# swap bytearray to little endian | |
def swap_endian(x): | |
return int.from_bytes(x, byteorder='little', signed=False) | |
def write_file(name : str, path : str, filedata) : | |
filepath = os.path.join(path, name) | |
print("creating file " + filepath) | |
f = binario.Writer(filepath, binario.LITTLE_ENDIAN) | |
f.write(filedata) | |
f.close() | |
def convert_png(name : str, path : str, output : str ) : | |
print("converting file " + name) | |
filepath = os.path.join(path, name) | |
subprocess.run([DEARK_PATH_WIN, filepath, "-o", os.path.join(output, name)]) | |
def decode_SB0_file(filename, folder) : | |
l = [] | |
r = binario.Reader(filename, binario.LITTLE_ENDIAN) | |
r.read(12) #ignore | |
name = r.read(12) | |
while name != b'------------' : | |
name = name.decode().strip() | |
name = ''.join(x for x in name if x.isprintable()) | |
name = name.split('.')[0] + '.' + name.split('.')[1][:3] # only take first 3 letters of extension for name, rest is filler | |
offset = swap_endian(bytearray(r.read(4))) | |
size = swap_endian(bytearray(r.read(4))) | |
skip = r.read() | |
l.append([name, offset, size]) | |
name = r.read(12) | |
# r.read(8) #skip 8 bytes of gap - not needed as we are going to read by offset | |
print(l) | |
targetPath = os.path.join(cwd, folder) | |
if not os.path.exists(targetPath): | |
print("creating folder :" + targetPath) | |
os.mkdir(targetPath) | |
os.chdir(targetPath) | |
png_path = os.path.join(targetPath, "converted") | |
if not os.path.exists(png_path): | |
print("creating folder :" + png_path) | |
os.mkdir(png_path) | |
for entry in l : | |
name, offset, size = entry | |
r.seek(0 + offset) | |
filedata = r.read(size) | |
# print(filedata) | |
write_file(name, targetPath, filedata) | |
convert_png(name, targetPath, png_path) # will be no-op for non-RAW files | |
print("====") | |
# print(r.read(6)) | |
if __name__ == '__main__' : | |
decode_SB0_file(GAME_FOLDER_PATH + "\GFX.SB0", "gfx") | |
decode_SB0_file(GAME_FOLDER_PATH + "\SFX.SB0", "sfx") | |
decode_SB0_file(GAME_FOLDER_PATH + "\local.SB0", "local") | |
decode_SB0_file(GAME_FOLDER_PATH + "\levels.SB0", "levels") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment