160 lines
6.7 KiB
Python
160 lines
6.7 KiB
Python
#!/usr/bin/env python3
|
|
# genC64Data.py -- emit the C64 game data the JoeyLib Space Taxi port
|
|
# needs at runtime as C source: the custom charset (rendering AND the
|
|
# exact sprite-to-background collision bits), the standard sprite
|
|
# bitmaps (cab, passenger, flame, warp, death, intro star, leaving
|
|
# cels), the demo-mode RNG table ($446A), the SID SFX programs (the
|
|
# 9-byte blocks fed to $42E9), the engine-flame pointer table ($6DB0)
|
|
# and the level-intro star velocity tables ($450C/$4513).
|
|
#
|
|
# Everything comes straight out of stuff/spacetaxi/raw.bin (a VICE
|
|
# "bank ram" dump, 2-byte load-address header) so the port has one
|
|
# source of truth: the original bytes. Output:
|
|
# examples/spacetaxi/stC64Data.c / stC64Data.h (committed, do not edit)
|
|
|
|
import os
|
|
import sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
RAW = os.path.join(HERE, "..", "..", "..", "stuff", "spacetaxi", "raw.bin")
|
|
OUT_C = os.path.join(HERE, "..", "stC64Data.c")
|
|
OUT_H = os.path.join(HERE, "..", "stC64Data.h")
|
|
|
|
SPRITE_PTR_FIRST = 0xC0
|
|
SPRITE_PTR_LAST = 0xEC # $E9-$EC = passengers-leaving cels
|
|
SPRITE_BYTES = 63
|
|
|
|
# (enum name, address of the 9-byte program, comment)
|
|
SFX = [
|
|
("ST_SFX_GEAR", 0x6410, "landing gear toggle ($63DD)"),
|
|
("ST_SFX_CASH", 0x6DBB, "refuel ka-ching ($6E5B)"),
|
|
("ST_SFX_FUEL_LOW", 0x6DC4, "fuel below 3 cells ($6EBD)"),
|
|
("ST_SFX_FUEL_FULL", 0x6DCD, "tank full ($6E9E)"),
|
|
("ST_SFX_LAND_HARD", 0x6DD6, "hard landing ($6520)"),
|
|
("ST_SFX_IMPACT", 0x6DDF, "wreck hits the floor ($6AE1)"),
|
|
("ST_SFX_LAND_SOFT", 0x6DE8, "soft landing ($650F)"),
|
|
("ST_SFX_CRASH", 0x6DF1, "crash start ($6A56)"),
|
|
]
|
|
|
|
|
|
def load_raw():
|
|
with open(RAW, "rb") as fp:
|
|
raw = fp.read()
|
|
if len(raw) == 0x10002:
|
|
raw = raw[2:]
|
|
if len(raw) != 0x10000:
|
|
sys.exit(f"{RAW}: unexpected size {len(raw)}")
|
|
return raw
|
|
|
|
|
|
def c_bytes(data, per_line=16, indent=" "):
|
|
lines = []
|
|
for i in range(0, len(data), per_line):
|
|
chunk = data[i:i + per_line]
|
|
lines.append(indent + ", ".join(f"0x{b:02X}" for b in chunk) + ",")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def main():
|
|
raw = load_raw()
|
|
sprite_count = SPRITE_PTR_LAST - SPRITE_PTR_FIRST + 1
|
|
|
|
h = []
|
|
h.append("// Generated by assets/genC64Data.py from stuff/spacetaxi/raw.bin.")
|
|
h.append("// Do not hand-edit; re-run the generator.")
|
|
h.append("")
|
|
h.append("#ifndef ST_C64_DATA_H")
|
|
h.append("#define ST_C64_DATA_H")
|
|
h.append("")
|
|
h.append("#include <stdint.h>")
|
|
h.append("")
|
|
h.append("// The game's custom character set ($2800-$2FFF): 256 glyphs x 8 rows,")
|
|
h.append("// bit 7 = leftmost pixel. Used to paint the screen AND for the")
|
|
h.append("// sprite-to-background collision test (a set bit is background data).")
|
|
h.append("#define ST_CHARSET_CHARS 256u")
|
|
h.append("extern const uint8_t kStCharset[ST_CHARSET_CHARS][8];")
|
|
h.append("")
|
|
h.append("// Standard sprite bitmaps (VIC bank 0, block ptr * 64). 21 rows x 3")
|
|
h.append("// bytes. Index = ptr - ST_SPRITE_PTR_FIRST.")
|
|
h.append(f"#define ST_SPRITE_PTR_FIRST 0x{SPRITE_PTR_FIRST:02X}u")
|
|
h.append(f"#define ST_SPRITE_PTR_LAST 0x{SPRITE_PTR_LAST:02X}u")
|
|
h.append(f"#define ST_SPRITE_COUNT {sprite_count}u")
|
|
h.append(f"#define ST_SPRITE_BYTES {SPRITE_BYTES}u")
|
|
h.append("extern const uint8_t kStSpriteBitmaps[ST_SPRITE_COUNT][ST_SPRITE_BYTES];")
|
|
h.append("")
|
|
h.append("// Demo-mode RNG lookup ($446A): rnd = table[t1] + t2 (see stSim.c).")
|
|
h.append("#define ST_RNG_TABLE_SIZE 64u")
|
|
h.append("extern const uint8_t kStRngTable[ST_RNG_TABLE_SIZE];")
|
|
h.append("")
|
|
h.append("// SID SFX programs, 9 bytes each, in $42E9 order: freq lo, freq hi,")
|
|
h.append("// pulse lo, pulse hi, control, AD, SR, release ticks, voice index.")
|
|
h.append("typedef enum {")
|
|
for name, addr, comment in SFX:
|
|
h.append(f" {name}, // ${addr:04X} {comment}")
|
|
h.append(" ST_SFX_COUNT")
|
|
h.append("} StSfxE;")
|
|
h.append("#define ST_SFX_PROGRAM_BYTES 9u")
|
|
h.append("extern const uint8_t kStSfxPrograms[ST_SFX_COUNT][ST_SFX_PROGRAM_BYTES];")
|
|
h.append("")
|
|
h.append("// Engine-flame cel pointer by direction mask ($6DB0, 1=UP 2=DOWN 4=LEFT")
|
|
h.append("// 8=RIGHT); 0 = no cel for that combination.")
|
|
h.append("extern const uint8_t kStFlameCelByDirMask[16];")
|
|
h.append("")
|
|
h.append("// Level-intro star velocities per sprite 0..6 ($450C / $4513).")
|
|
h.append("extern const int8_t kStIntroStarDx[7];")
|
|
h.append("extern const int8_t kStIntroStarDy[7];")
|
|
h.append("")
|
|
h.append("#endif")
|
|
|
|
c = []
|
|
c.append("// Generated by assets/genC64Data.py from stuff/spacetaxi/raw.bin.")
|
|
c.append("// Do not hand-edit; re-run the generator.")
|
|
c.append("")
|
|
c.append('#include "stC64Data.h"')
|
|
c.append("")
|
|
c.append("const uint8_t kStCharset[ST_CHARSET_CHARS][8] = {")
|
|
for ch in range(256):
|
|
rows = raw[0x2800 + ch * 8:0x2800 + ch * 8 + 8]
|
|
c.append(" { " + ", ".join(f"0x{b:02X}" for b in rows) + " }, // $" + f"{ch:02X}")
|
|
c.append("};")
|
|
c.append("")
|
|
c.append("const uint8_t kStSpriteBitmaps[ST_SPRITE_COUNT][ST_SPRITE_BYTES] = {")
|
|
for ptr in range(SPRITE_PTR_FIRST, SPRITE_PTR_LAST + 1):
|
|
base = ptr * 64
|
|
c.append(f" {{ // ptr ${ptr:02X}")
|
|
for row in range(21):
|
|
b = raw[base + row * 3:base + row * 3 + 3]
|
|
c.append(" " + ", ".join(f"0x{x:02X}" for x in b) + ",")
|
|
c.append(" },")
|
|
c.append("};")
|
|
c.append("")
|
|
c.append("const uint8_t kStRngTable[ST_RNG_TABLE_SIZE] = {")
|
|
c.append(c_bytes(raw[0x446A:0x446A + 64]))
|
|
c.append("};")
|
|
c.append("")
|
|
c.append("const uint8_t kStSfxPrograms[ST_SFX_COUNT][ST_SFX_PROGRAM_BYTES] = {")
|
|
for name, addr, comment in SFX:
|
|
b = raw[addr:addr + 9]
|
|
c.append(" { " + ", ".join(f"0x{x:02X}" for x in b) + " }, // " + name)
|
|
c.append("};")
|
|
c.append("")
|
|
flame = list(raw[0x6DB0:0x6DB0 + 11]) + [0] * 5
|
|
c.append("const uint8_t kStFlameCelByDirMask[16] = {")
|
|
c.append(c_bytes(flame))
|
|
c.append("};")
|
|
c.append("")
|
|
dx = [b - 256 if b >= 128 else b for b in raw[0x450C:0x450C + 7]]
|
|
dy = [b - 256 if b >= 128 else b for b in raw[0x4513:0x4513 + 7]]
|
|
c.append("const int8_t kStIntroStarDx[7] = { " + ", ".join(str(v) for v in dx) + " };")
|
|
c.append("const int8_t kStIntroStarDy[7] = { " + ", ".join(str(v) for v in dy) + " };")
|
|
c.append("")
|
|
|
|
with open(OUT_H, "w", encoding="ascii") as fp:
|
|
fp.write("\n".join(h) + "\n")
|
|
with open(OUT_C, "w", encoding="ascii") as fp:
|
|
fp.write("\n".join(c) + "\n")
|
|
print(f"wrote {OUT_H} and {OUT_C}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|