141 lines
8.2 KiB
Markdown
141 lines
8.2 KiB
Markdown
# Space Taxi port plan
|
|
|
|
Roadmap for bringing the JoeyLib port to functional parity with the
|
|
C64 original. Sequenced so each phase delivers something testable on
|
|
its own and unblocks the next. Each phase ends with a user-test
|
|
checkpoint -- regressions must be caught before moving on.
|
|
|
|
## Workflow per subsystem
|
|
|
|
Same loop every time, so it stays cheap to iterate:
|
|
|
|
1. **Find** -- grep the live RAM dump for relevant register writes
|
|
(`$DC00`, `$D015`, `$D400-$D418`, `$07F8-$07FF`, etc.) or use
|
|
`callGraph.py` to find routines touching specific addresses.
|
|
2. **Read** -- pull the routine into a window via `disLive.py
|
|
<dump> <out> <start> <end>`, study the annotated listing.
|
|
3. **Document** -- append behavior summary to `MECHANICS.md` in
|
|
plain English. Add new labels/vars to `stuff/spacetaxi/labels.txt`.
|
|
4. **Reannotate** -- `python3 disLive.py mem0000-level1.bin
|
|
live-level1.lst` to regenerate the (annotated) listing from
|
|
the dump + labels.txt in one step. The .lst file is the only
|
|
readable form -- labels are baked in directly.
|
|
5. **Port** -- update the matching JoeyLib C file
|
|
(`stEngine.c`, `stPassenger.c`, `stRender.c`, `stAudio.c`,
|
|
`stLevel.c`, `spacetaxi.c`).
|
|
6. **Build + ship** -- `make -f make/dos.mk EXAMPLE=spacetaxi`
|
|
first, then once stable also amiga / atarist / iigs.
|
|
7. **User test** -- run `scripts/run-dos.sh staxi`, report
|
|
behavior. Do not start the next phase before this.
|
|
|
|
## Phase 0 -- foundation (DONE)
|
|
|
|
- Disassembly toolchain in `stuff/spacetaxi/`
|
|
- Full live-RAM listing + annotated variant
|
|
- `MECHANICS.md` baseline
|
|
- Asset pipeline (`tools/assetbake/assetbake.py`, extractor realigned)
|
|
- Bugfixes: sprite size in tile units, palette clobber,
|
|
tile-bank load clamp, fire-not-thrust, palette/sheet collision
|
|
- Template-velocity physics in `stEngine.c`
|
|
|
|
## Phase 1 -- physics + collision (NEXT)
|
|
|
|
Make the cab fly correctly. Highest impact: nothing else works
|
|
until the player can hover, land, and crash.
|
|
|
|
| Task | Investigate | Update |
|
|
| ---- | ----------- | ------------------------------------- |
|
|
| 1.1 | Trace `$7D95/96` gravity word writers -- when is gravity on? | `stEngine.c`: gate gravity on the same conditions |
|
|
| 1.2 | Find writers of `$721D` (player state byte). High bit = "dying". What sets it? | `stEngine.c`: crash trigger logic |
|
|
| 1.3 | Trace phase-2 handler at `$6B24` -- this is what runs after `$6A72` advances. Likely the crash / fall-to-ground sequence | New `stEngine.c` crash-anim path |
|
|
| 1.4 | Find pad-vs-wall predicate. Hardware `$D01F` says "we hit bg"; some code looks at char codes near taxi feet to decide PAD vs WALL | `stLevel.c`: pad detection by tile code |
|
|
| 1.5 | Confirm screen-edge wrap at `$6AED` -- when X-velocity carries the taxi off the right edge, does it wrap or stop? | `stEngine.c`: edge behavior |
|
|
|
|
**Checkpoint**: cab flies smoothly, can land on a pad, crashes hard.
|
|
|
|
## Phase 2 -- visuals + animation
|
|
|
|
Make the screen match the original's look frame-by-frame.
|
|
|
|
| Task | Investigate | Update |
|
|
| ---- | ----------- | ------------------------------------- |
|
|
| 2.1 | Confirm taxi has one cel only. The 2 writes to `$07F8` (taxi sprite ptr) -- are they per-level (color swap) or per-frame? Read those sites | `stRender.c`: reduce `ST_TAXI_CEL_COUNT` to 1, kill `thrustFrame` |
|
|
| 2.2 | What renders the engine flame under the taxi during thrust? Either a second sprite or a tile overwrite | `stRender.c`: flame overlay |
|
|
| 2.3 | Passenger walk: trace updates to passenger sprite Y/X in the sprite state table (NOT `$D004-$D00D`; the table memory) | `stPassenger.c`: walk frame timing |
|
|
| 2.4 | Title-screen layout: the C64 title positions logo / credits / instructions at specific char rows. The extractor pulls the screen layout; check the .txt against the disassembly's title-init routine to confirm we render the same layout | `assets/levels/title.txt`, `stRender.c` title overlay |
|
|
|
|
**Checkpoint**: the title screen, gameplay, and game-over screens
|
|
each look like the C64.
|
|
|
|
## Phase 3 -- audio
|
|
|
|
Authentic feel needs the SID engine. JoeyLib audio is per-platform,
|
|
so the abstraction is "SFX event id" -- the SID details only land in
|
|
the DOS / Amiga / ST tone-generator backend.
|
|
|
|
| Task | Investigate | Update |
|
|
| ---- | ------------------------------------------ | ------ |
|
|
| 3.1 | Music engine: voice 1+2 melodic table. Find where tunes are stored, how the row pointer advances, how note-to-freq lookup works | `stAudio.c`: music playback state machine |
|
|
| 3.2 | Thrust SFX: confirmed voice 1 freq sweep from `$721B`. Find writer of `$721B` (start of thrust) and what triggers it to stop | `stAudioSfxThrust` envelope |
|
|
| 3.3 | Crash SFX: voice 3 noise burst. `LDA #$81 STA $D412 ... LDA #$80`. Find duration / pitch envelope | `stAudioSfxCrash` |
|
|
| 3.4 | Land SFX: a successful landing must trigger some audible cue. Trace from collision dispatch when sprite-bg collision is at low vy | `stAudioSfxLand` |
|
|
| 3.5 | Door / passenger SFX: passenger enters/exits the cab on a pad. Probably also voice 3 noise or a brief tone | new SFX |
|
|
|
|
**Checkpoint**: thrust, land, crash, and at least one music loop
|
|
all play audibly on DOS. Approximate timbres OK; pitch + envelope
|
|
should roughly match.
|
|
|
|
## Phase 4 -- game logic
|
|
|
|
Make the game progress. State machine, scoring, lives.
|
|
|
|
| Task | Investigate | Update |
|
|
| ---- | ---------------------------------------- | ------ |
|
|
| 4.1 | Passenger spawn: when does fare N+1 appear after fare N is delivered? Look for writes to the passenger-active flags in the state table | `stPassenger.c` |
|
|
| 4.2 | Patience timer: a passenger has a countdown. Find the per-frame decrement and what happens at zero (passenger leaves? lose pad?) | `stPassenger.c` |
|
|
| 4.3 | Scoring: base fare from `$7D...`, tip math for time-on-board. BCD arithmetic on a 4-byte score | `stHud.c`, score storage |
|
|
| 4.4 | Level transitions: `$7215 == $19` is the "level complete" sentinel. What writes that, and how does the game pick the next level? | `spacetaxi.c` main switch |
|
|
| 4.5 | Lives: where is the lives counter? How does the game decide game-over? | `stEngine.c` crash branch, `spacetaxi.c` |
|
|
|
|
**Checkpoint**: can complete a level, advance, lose all lives,
|
|
see game-over, restart from title.
|
|
|
|
## Phase 5 -- level data
|
|
|
|
Match the original's 25 levels (or however many ship in the disk
|
|
image; verify from `SPACETAX.D64`).
|
|
|
|
| Task | Investigate | Update |
|
|
| ---- | ---------------------------------------- | ------ |
|
|
| 5.1 | Level table layout in RAM: where are per-level pad coords stored? Per-level music ID? Per-level taxi spawn? Per-level fare list? | `stLevel.c` STL1 format |
|
|
| 5.2 | Extract every level from the D64 image (we already have level1 / level2 / title dumps; need a way to dump every level state). Either replay through the game in VICE and snapshot each level, or read the level table once and reconstruct | extractor: bulk-export |
|
|
| 5.3 | Verify the title screen extraction matches the original byte-for-byte (chars + colors) | `title.dat` regenerate |
|
|
|
|
**Checkpoint**: all original levels playable, named correctly,
|
|
ordered correctly.
|
|
|
|
## Phase 6 -- cross-platform parity
|
|
|
|
DOS lands first. Then bring the other three up.
|
|
|
|
| Target | Specific work |
|
|
| ------ | ------------------------------------------------------------ |
|
|
| Amiga | Verify build still runs; PT replayer for music; joystick |
|
|
| Atari ST | Same; YM2149 for SFX, MOD for music |
|
|
| IIgs | Resolve ROOT-segment limit so the binary fits; wire asset |
|
|
| | pipeline into the disk packager (3 options in earlier note); |
|
|
| | Ensoniq sound match |
|
|
|
|
**Checkpoint**: each of the four targets boots, shows title,
|
|
plays at least one level end-to-end.
|
|
|
|
## Working notes
|
|
|
|
- All chat-side analysis must stay in plain English -- disassembly
|
|
excerpts go in local files (`MECHANICS.md`, `labels.txt`), not
|
|
pasted back into the session.
|
|
- One subsystem per session is the right cadence. Trying to "do
|
|
them all at once" without user-test feedback compounds errors.
|
|
- Keep this plan up to date: as each task lands, mark it DONE
|
|
with the commit SHA or date, and add new tasks discovered
|
|
during the work.
|