Docs! Getting ready for more platforms.
This commit is contained in:
parent
94cc14ff28
commit
28d8852bbe
1 changed files with 0 additions and 217 deletions
|
|
@ -1,217 +0,0 @@
|
||||||
# AGI port — session handoff
|
|
||||||
|
|
||||||
This document captures the state of the AGI interpreter port as of
|
|
||||||
2026-05-15. Hand it to a fresh Claude Code session to pick up where
|
|
||||||
the previous one left off.
|
|
||||||
|
|
||||||
## Project context
|
|
||||||
|
|
||||||
JoeyLib is a unified C game-dev library targeting Apple IIgs (perf
|
|
||||||
floor / reference), Amiga, Atari ST, MS-DOS. The AGI port is a
|
|
||||||
from-scratch reimplementation of Sierra's Adventure Game Interpreter
|
|
||||||
v2 on top of JoeyLib's surface / draw / input APIs. Written from
|
|
||||||
public AGI format specs only -- NOT derived from ScummVM / NAGI /
|
|
||||||
Sarien (those are GPL'd; JoeyLib is not).
|
|
||||||
|
|
||||||
Test data: KQ3 v2, locally installed at
|
|
||||||
`examples/agi/gamedata/kq3/`. The user owns the game and is not
|
|
||||||
distributing it; gamedata is gitignored.
|
|
||||||
|
|
||||||
## Current phase
|
|
||||||
|
|
||||||
**Phase 1 sub-D** (callback-driven rendering): verified working.
|
|
||||||
Logic.0 + room 45 init paint KQ3's title screen on every supported
|
|
||||||
port. Ego sprite (VIEW 0, Graham) draws on top with priority masking,
|
|
||||||
WASD/arrow keys move him, ESC quits.
|
|
||||||
|
|
||||||
What's next: **Phase 1 sub-E** (input + animation opcodes). The
|
|
||||||
title screen does not auto-advance because the VM still stubs ~150
|
|
||||||
opcodes including `wait`, `set.menu`, `accept.input`, animation
|
|
||||||
timers, etc. Real KQ3 progression past the title requires implementing
|
|
||||||
enough of those to let logic.45 complete its intro and call new.room.
|
|
||||||
|
|
||||||
Phase 2 sub-A onward: parser, NPC actors, sound (NTP / PSG).
|
|
||||||
|
|
||||||
## What works (verified)
|
|
||||||
|
|
||||||
- Resource loader (LOGDIR / PICDIR / VIEWDIR / SNDDIR / VOL.x)
|
|
||||||
- PIC decoder (visual + priority planes, flood fill, vector draw)
|
|
||||||
- VIEW decoder (cel parse + RLE blit + priority masking + mirror)
|
|
||||||
- LOGIC VM: 256 vars, 256 flags, 8-deep call stack
|
|
||||||
- Real handlers: arithmetic (0x00-0x11), OP_IF (0xFF), OP_GOTO
|
|
||||||
(0xFE), OP_NEW_ROOM (0x12/0x13), OP_LOAD_LOGIC (0x14/0x15),
|
|
||||||
OP_CALL (0x16/0x17), OP_LOAD_PIC (0x18), OP_DRAW_PIC (0x19),
|
|
||||||
OP_SHOW_PIC (0x1A), OP_DISCARD_PIC (0x1B), OP_OVERLAY_PIC (0x1C)
|
|
||||||
- All ~180 other action opcodes are stubs (skip their arg bytes
|
|
||||||
via `kActionArgBytes[256]` table)
|
|
||||||
- Host callbacks: fetchLogic / loadPic / drawPic / showPic /
|
|
||||||
discardPic / overlayPic
|
|
||||||
- Per-platform save-under for the ego sprite (no full-stage memcpy
|
|
||||||
per frame; IIgs uses MVN-based codegen)
|
|
||||||
- Cross-platform binary works on all 4 ports (`AGI.EXE`,
|
|
||||||
`AGI.PRG`, `Agi`, IIgs `AGI`)
|
|
||||||
|
|
||||||
## What does NOT work
|
|
||||||
|
|
||||||
- **Title screen never advances.** Stubs the input / timer opcodes
|
|
||||||
the title uses. Workaround: starting-room override (argv[2]).
|
|
||||||
- **No NPC actors.** animate.obj / set.cel / set.loop are stubs.
|
|
||||||
- **No parser.** said() and the word-tokenize opcodes are stubs.
|
|
||||||
- **No sound.** Phase 3 work.
|
|
||||||
- **IIgs run path for AGI** is not wired. `scripts/run-agi.sh iigs`
|
|
||||||
prints an explicit "not yet wired" message describing the missing
|
|
||||||
disk-packager work (need bigger 2mg volume + case-folded ProDOS
|
|
||||||
names + game-data argument to `package-disk.sh`).
|
|
||||||
- **ST / Amiga can't pass argv.** Hatari `--auto` and Amiga
|
|
||||||
startup-sequence don't forward args, so the starting-room override
|
|
||||||
only works on DOS. ST / Amiga AGI starts at the title screen.
|
|
||||||
Fix needs either a config-file stage (`ROOM.TXT` read at startup)
|
|
||||||
or enough title opcodes for the title to advance naturally.
|
|
||||||
|
|
||||||
## How to test
|
|
||||||
|
|
||||||
```bash
|
|
||||||
source toolchains/env.sh
|
|
||||||
|
|
||||||
# Host-side parsers + VM (fast iteration, no emulator)
|
|
||||||
./scripts/test-agi.sh
|
|
||||||
|
|
||||||
# Cross-platform binary in DOSBox
|
|
||||||
./scripts/run-agi.sh dos # title screen
|
|
||||||
./scripts/run-agi.sh dos kq3 1 # jump to room 1
|
|
||||||
./scripts/run-agi.sh dos kq3 3 # jump to room 3
|
|
||||||
|
|
||||||
# Other platforms (no argv support yet, always title)
|
|
||||||
./scripts/run-agi.sh atarist
|
|
||||||
./scripts/run-agi.sh amiga
|
|
||||||
./scripts/run-agi.sh iigs # prints "not wired" message
|
|
||||||
```
|
|
||||||
|
|
||||||
## Files touched (this session)
|
|
||||||
|
|
||||||
New:
|
|
||||||
|
|
||||||
- `src/core/random.c` — xorshift32 PRNG (jlRandom / jlRandomRange / jlRandomSeed)
|
|
||||||
- `examples/agi/*.c` — agi.c, agiRes.c, agiPic.c, agiView.c, agiVm.c
|
|
||||||
- `examples/agi/agi.h` — all AGI types + public API
|
|
||||||
- `tests/agi/*.c` — testAgiRes / testAgiPic / testAgiView / testAgiVm / testAgiPipeline
|
|
||||||
- `scripts/test-agi.sh` — host-build runner for all five tests
|
|
||||||
- `scripts/run-agi.sh` — cross-platform emulator launcher (dos | amiga | atarist | iigs)
|
|
||||||
|
|
||||||
Modified:
|
|
||||||
|
|
||||||
- `include/joey/core.h` — random prototypes
|
|
||||||
- `include/joey/platform.h` — auto-detect from compiler defines
|
|
||||||
- `.gitignore` — examples/agi/gamedata/
|
|
||||||
- All four make/*.mk — added agi to EXAMPLES list
|
|
||||||
|
|
||||||
## Architectural decisions worth remembering
|
|
||||||
|
|
||||||
### Render loop: save-under, not full stage copy
|
|
||||||
|
|
||||||
The naive per-frame `jlSurfaceCopy(stage, gBackdrop)` is 32 KB of
|
|
||||||
memcpy + present overhead -- not acceptable on a 2.8 MHz IIgs. The
|
|
||||||
current code:
|
|
||||||
|
|
||||||
1. `cbShowPic` paints the picture onto the stage ONCE and snapshots
|
|
||||||
it as `gBackdrop`. Sets `gPicReady = true` and invalidates any
|
|
||||||
prior ego save-under.
|
|
||||||
2. Per frame: `jlSpriteRestoreUnder` the last-frame ego rect (puts
|
|
||||||
clean backdrop bytes back), `jlSpriteSaveUnder` the new ego rect,
|
|
||||||
then `agiViewDraw` paints the cel with priority masking.
|
|
||||||
3. Placeholder sprite for save-under is 4x5 tiles = 32x40 stage
|
|
||||||
pixels, sized to cover any AGI v2 ego cel. Compiled via
|
|
||||||
`jlSpriteCompile` so save/restore use the platform's compiled
|
|
||||||
fast path (MVN block-copy on IIgs, etc.) instead of the C
|
|
||||||
interpreter fallback.
|
|
||||||
|
|
||||||
Per-frame memory traffic: ~1.3 KB save+restore vs ~32 KB full copy.
|
|
||||||
|
|
||||||
### VM throttling
|
|
||||||
|
|
||||||
AGI's native cycle is ~6 Hz. Running logic.0 every frame (60 Hz) is
|
|
||||||
6800-byte switch dispatcher × 60 = ~400k opcodes/sec for nothing.
|
|
||||||
`agi.c` now runs runVmCycle once every 10 frames (~6 Hz on 60 Hz
|
|
||||||
refresh, ~5 Hz on 50 Hz PAL). Input polling, ego movement, render
|
|
||||||
still run at full refresh -- only the bytecode interp is throttled.
|
|
||||||
|
|
||||||
Startup pumps the VM until `gPicReady` (or 32 cycles) so the user
|
|
||||||
never sees a flash of COLOR_MISSING before the first room paints.
|
|
||||||
|
|
||||||
### VIEW mirror handling
|
|
||||||
|
|
||||||
Sierra's encoder writes `mirror=1, src=N` on BOTH loops in a mirror
|
|
||||||
pair, where N is the lower-numbered loop. `agiView.c:resolveMirror`
|
|
||||||
must only treat a cel as mirrored when `src != current_loop`. KQ3
|
|
||||||
view 0 hit this directly: both loop 0 (right) and loop 1 (left) had
|
|
||||||
`mirror=1, src=0`, and our original code flipped both -- so pressing
|
|
||||||
left and right both faced left. Fixed.
|
|
||||||
|
|
||||||
### Starting-room override
|
|
||||||
|
|
||||||
`agi.c` argv[2] = starting room number 1..255. When set,
|
|
||||||
`runVmCycle`'s NEW_ROOM handler substitutes the override for
|
|
||||||
`vm.newRoomId` on the FIRST NEW_ROOM halt only (one-shot). Lets the
|
|
||||||
user skip past KQ3's title room (45) into the actual game. Once the
|
|
||||||
override fires, subsequent transitions go through unchanged.
|
|
||||||
|
|
||||||
`scripts/run-agi.sh` accepts `<platform> [game] [room]` and forwards
|
|
||||||
the room to DOS via dosbox `-c "AGI.EXE . <room>"`. ST and Amiga
|
|
||||||
can't pass argv via autostart so their AGI starts at the title.
|
|
||||||
|
|
||||||
### Default game dir is "." not "agidemo"
|
|
||||||
|
|
||||||
`resolveGameDir` defaults to "." (CWD). On platforms whose autostart
|
|
||||||
can't pass argv (Hatari, AmigaDOS), `run-agi.sh` stages the AGI
|
|
||||||
binary plus the v2 game data files (LOGDIR / PICDIR / etc.) flat in
|
|
||||||
a temp directory and points the emulator at it; AGI runs from CWD =
|
|
||||||
that temp dir and finds the data files relative to "./".
|
|
||||||
|
|
||||||
## Likely next-step work
|
|
||||||
|
|
||||||
The user's natural next ask is "implement enough title opcodes to
|
|
||||||
let KQ3's title screen auto-advance." That probably means:
|
|
||||||
|
|
||||||
- `wait` (cycle.time gate)
|
|
||||||
- `input.line` / `accept.input`
|
|
||||||
- Animation timers: `cycle.time`, `current.loop`, etc.
|
|
||||||
- `set.menu` / `disable.item` (KQ3 title shows a menu)
|
|
||||||
|
|
||||||
Alternative path: skip the title work and implement enough core
|
|
||||||
opcodes to make a gameplay room functional. animate.obj,
|
|
||||||
set.view.v, set.cel, set.loop, position, draw, erase. That gets us
|
|
||||||
walking around KQ3 room 1 (Manannan's house) with Graham instead
|
|
||||||
of a static title.
|
|
||||||
|
|
||||||
The user should pick which to prioritize.
|
|
||||||
|
|
||||||
## Memory entries you should know about
|
|
||||||
|
|
||||||
The repo's auto-memory at
|
|
||||||
`~/.claude/projects/-home-scott-claude-joeylib/memory/` includes
|
|
||||||
JoeyLib-wide context (CMake quirks, IIgs toolchain gotchas, perf
|
|
||||||
constraints) plus `project_joeylib_agi_plan.md` which describes the
|
|
||||||
overall AGI port plan. All persist into the next session
|
|
||||||
automatically; no need to reload.
|
|
||||||
|
|
||||||
Specifically relevant to the AGI port:
|
|
||||||
|
|
||||||
- `project_joeylib_agi_plan.md` — overall plan, 3-4 month estimate
|
|
||||||
- AGI code uses a manual `parseArgU8` instead of atoi to keep the
|
|
||||||
IIgs link budget small.
|
|
||||||
- `project_perf_directive.md` — IIgs is the perf floor; every
|
|
||||||
other target must match or beat it
|
|
||||||
- `feedback_iigs_speed.md` — IIgs must be absolute fastest
|
|
||||||
technically possible; the save-under decision was made under
|
|
||||||
this constraint.
|
|
||||||
|
|
||||||
## Git / user preferences
|
|
||||||
|
|
||||||
- The user manages git themselves -- do NOT commit / push / branch
|
|
||||||
on JoeyLib without explicit ask (see memory
|
|
||||||
`feedback_git.md`).
|
|
||||||
- Always `source toolchains/env.sh` before any `make` -- the user
|
|
||||||
has added that to .claude/settings.local.json allow list.
|
|
||||||
- DJGPP / llvm-mos / vasm / m68k-atari-mint paths come from env.sh.
|
|
||||||
- The user does NOT need hand-holding -- they're an expert C dev.
|
|
||||||
Skip excessive explanation; describe what was done and move on.
|
|
||||||
Loading…
Add table
Reference in a new issue