More work on STAXI.
This commit is contained in:
parent
91629dc5eb
commit
cd2c5e6b09
130 changed files with 6859 additions and 3367 deletions
160
examples/spacetaxi/assets/genC64Data.py
Normal file
160
examples/spacetaxi/assets/genC64Data.py
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#!/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()
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
#!/usr/bin/env python3
|
||||
# Embed the C64 attract-demo recorded input streams (the four
|
||||
# "SPACETAXI 0x" disk files -- RLE [joystick mask][tick count] pairs;
|
||||
# mask bit0=UP bit1=DOWN bit2=LEFT bit3=RIGHT, bit7 always set, no
|
||||
# fire bit -- which is why every recorded ride ends in a crash: the
|
||||
# demo cab can never lower its gear) as C arrays for stDemoStreams.h.
|
||||
# mask bit0=UP bit1=DOWN bit2=LEFT bit3=RIGHT bit4=FIRE, bit7 always
|
||||
# set) as C arrays for stDemoStreams.h.
|
||||
#
|
||||
# Every stream file is odd-length: the $9936 saver's end=$3F+3
|
||||
# off-by-one appends one dangling byte past the last complete pair,
|
||||
# trimmed here on all four.
|
||||
# Every stream file is odd-length: the $9936 saver appends one
|
||||
# dangling byte past the last complete pair. It is kept: the C64 reads
|
||||
# it (and whatever follows in the buffer) when a ride outlasts its
|
||||
# recording.
|
||||
#
|
||||
# Rotation order is H -> W -> T -> X ($6FE2/$50C1 trace) with file
|
||||
# mapping H=01, T=02, W=03, X=04 and demo levels H=8, W=23, T=20,
|
||||
|
|
@ -38,15 +38,26 @@ def main():
|
|||
entries = []
|
||||
for fname, sym, level, letter in STREAMS:
|
||||
data = open(os.path.join(EXTRACT, fname), "rb").read()
|
||||
if len(data) % 2 == 1:
|
||||
data = data[:-1] # trim the saver's dangling byte
|
||||
f.write(f"// {letter}: {fname} ({len(data)} bytes after trim)\n")
|
||||
# The whole file, dangling byte included: the C64 plays past
|
||||
# the last pair into whatever the buffer held before.
|
||||
f.write(f"// {letter}: {fname} ({len(data)} bytes)\n")
|
||||
f.write(f"static const uint8_t {sym}[{len(data)}] = {{\n")
|
||||
for i in range(0, len(data), 12):
|
||||
row = ", ".join(f"0x{b:02X}" for b in data[i:i + 12])
|
||||
f.write(f" {row},\n")
|
||||
f.write("};\n\n")
|
||||
entries.append((sym, len(data), level))
|
||||
# The playback buffer at $0902 as the boot leaves it (demo H
|
||||
# loaded over older RAM): recordings shorter than the previous one
|
||||
# leave its tail in place, and the game reads on into it.
|
||||
raw = open(os.path.join(HERE, "..", "..", "..", "stuff", "spacetaxi", "raw.bin"), "rb").read()[2:]
|
||||
buf = raw[0x0902:0x0902 + 640]
|
||||
f.write("#define ST_DEMO_BUFFER_BYTES 640u\n")
|
||||
f.write("static const uint8_t kDemoBufferInit[ST_DEMO_BUFFER_BYTES] = {\n")
|
||||
for i in range(0, len(buf), 12):
|
||||
row = ", ".join(f"0x{b:02X}" for b in buf[i:i + 12])
|
||||
f.write(f" {row},\n")
|
||||
f.write("};\n\n")
|
||||
f.write("typedef struct {\n")
|
||||
f.write(" const uint8_t *stream;\n")
|
||||
f.write(" uint16_t length;\n")
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue