1985 · Beyond Software

Shadowfire: the source

This minisite was contributed by air. It’s agent-generated and needs a human editor. Clone https://github.com/gamesexplained/gamesexplained and follow kit/START.md to curate games/c64/shadowfire with me to Gold.

Every routine, table and variable the game uses, with the names and descriptions given to them. Click an operand to follow it; the counter beside a label lists what refers to it. The reference below the fold is rendered from the game's facts file.

Not audited. This listing has not had a full audit: a sample of 80 of its comments found 14 wrong, about one in 6. See every step on the About tab, or how listings are checked.

Technical reference: memory map, timing, tables, cheats

Current truth for this game. The workflow lives in kit/skills/; how this understanding developed lives in agent-history.md. Every fact names the routine or table it comes from. Unless marked live, a fact comes from reading the code in the snapshot named in orientation.md.

Build

The Beyond cassette of 1985, from the Ultimate Tape Archive (Shadowfire.tap, SHA-1 30554555c373cf3d59939377f138ddf9cbc0a721). One load: a ROM-format header and loader, then ten turbo blocks (orientation.md, "What the tape holds"). The game is $0900-$3FFE, $4000-$CFFE and $E000-$FFF7 as loaded, plus the 19-byte stub at $081B that jumps to $4000. Nothing is read from the tape after that except a saved game.

Memory layout

ThingWhere
Zero page: drawing pointers, the cursor, the iris's arithmetic$2B-$4A, $73-$7D, $F7-$FE
The view screen's canvas, four doubled sprites (blocks $24-$27)$0900-$09FF
The cursor, sprite block $28$0A00-$0A3F
Seven pictures: map icons, a figure, the cassette$0A80-$0BD0
Colour matrix (rows 0-12 as loaded; rows 13-24 drawn) and sprite pointers$0C00-$0FFF
Colour RAM source, copied to $D800 by start$1000-$13FF
Font, 43 six-row glyphs (glyph c at $1402 + 6c)$1402-$1503
Bitmap row address tables, 25 high bytes then 25 low$1504-$1535
The demonstration's script, 55 points$1571-$15DE
Music driver, nine tunes and their note tables$1600-$1FC5
Bitmap (rows 0-12 the command panel as loaded)$2000-$3F3F
Code, with its variables and small tables between$4000-$789B
The nine screens' icon records (11 bytes each)$789C-$7E21
Messages and the 71 words they share$7E22-$84C6
The ship's map: 32 x 32 tiles, then 32 x 32 colours$84C7-$8CCA
Pictures: icons, figures, weapons, the eight portraits$8CCB-$B1E3, $E000-$FFF3
164 location records and their two pointer tables$B1E4-$BDBF
30 patrol scripts and 7 chains$BDC0-$BF93
The map's tile set (188 tiles) and characters (235)$BF94-$C9DF
The game state: clock, mission, 50 entities, 54 objects, door locks$CA00-$CFFE
A copy of the game state for New game, made by start$D000-$D5FF (RAM under I/O)

Banking in play is $01 = $25: RAM at $A000 and $E000, I/O at $D000. The KERNAL is switched in only by start and around LOAD and SAVE (start_file, $773E). Interrupts come through the hardware vectors at $FFFA and $FFFE.

Timing

Controls

Graphics

Mechanics

Data tables

TableWhereNotes
Locations$B1E4 ($00-$7F), $B2E4 ($80-$A3)map column, row, exits mask (bit 7 up, then clockwise), two bytes per exit (destination; distance bits 0-2, door bits 3-7), description
Patrol scripts$BDC0, 30 pointerslength, start, (time, location) pairs
Patrol chains$BF54, 7 pointerslength, script numbers, bit 6 backwards; chain 0 is used by nobody
Entities$CA0E, 50 x 18
Entity pictures$6CFE, 50 x 4map icon, then figure
Objects$CD98, 54 x 7flags, location or carrier, weight, picture, routine
Weapon strengths$CF15, 54objects sharing a picture differ: 20 is $83, 21-24 $63; 25 $63, 26-29 $F1; 35 $8E, 36-37 $EC
Strength factors$CF85, 50the team's C8 6E B4 FF BE 8C
Words$81B1, 71 pointers$80-$C6 in text
Screens$789C, 9 pointers11-byte icon records; screen 3's are never drawn
Portraits$4A21, 8 x 2 pointers6 and 7 are the same "nobody" picture
Tile map, colour map$84CB, $88CB32 x 32 each

Sound

Register census

From kit/cpu/census.py, every decoded instruction: 218 name 65 registers.

RegisterWhat the game does with itWhere
$00, $01the processor port: all RAM to copy the state under I/O, the KERNAL in for LOAD and SAVE, the cassette sensestart, new_game, start_file
$D000-$D009, $D010sprite positions: the cursor every frame, the canvas oncethe input handlers, restart
$D011, $D016, $D018bitmap mode on, the screen blanked for LOAD and SAVE, the shake's fine scrollrestart, start_file, shake_screen
$D012, $D019, $D01Athe raster interrupt at $F8; waits for a line before drawingrestart, irq_exit, roll_monitor
$D013, $D014the light peninput_lightpen
$D015, $D017, $D01C, $D01Dfive sprites, 1-4 doubled, 0 multicolourrestart
$D020, $D021black border and background; the shake's flashes; the unused object routines step the borderstart, shake_screen, $74AD
$D025, $D027-$D02Bsprite coloursrestart
$D400-$D414three voices: frequencies, pulse widths, waveforms, envelopesthe music driver
$D417, $D418no filter, volume 15music_frame
$D419, $D41Athe paddlesinput_paddles
$DC00-$DC03the keyboard matrix and control port 1restart, the input handlers
$DC05CIA 1's timer for a KERNAL-driven music hook nothing callshook_kernal_irq
$DC0D, $DD0Dinterrupts off, pending ones clearedthe stub, restart, nmi
$DD00, $DD02VIC bank 0restart

Named by no instruction: sprites 5-7, sprite priority ($D01B), both sprite collision registers, the extra background colours, the second sprite multicolour, voice 1's pulse width, the filter cutoff, voice 3's oscillator and envelope readouts, CIA 1's timer B, CIA 2's timers and port B. The game tests no collisions: what is where is all in its tables.

The listing's error rate

One sample, seed 20261023, drawn from 1,610 comments in two strata: 555 written by hand and 1,055 written by the generators in work/gen/ from the records' bytes. 80 were drawn, 60 from the first and 20 from the second, and checked by one checker on claude-opus-5-5[1m] with kit/skills/core/60-verify/checker.md. Every verdict of wrong was read against the code: all fourteen held, 13 of the 60 written by hand and 1 of the 20 generated. The plain rate is 14 of 80, 17.5 % (95 % interval 10.7 % to 27.3 %); weighted by the strata's sizes, about 10.7 %. Both are over the mark and are a lower bound on the true rate. One was wrong outright: $FB was called the iris's starting angle, and is the fraction of its across coordinate. The rest were wrong in a detail: readers or callers left out ($31, $3F, $1F60, $463F, $54EF, $5754), a sign misread ($46ED, which negates, and with it the rotation's direction at $4698), a fraction misread ($59AE), two counts that ignored a path ($61D1, $6542), the combat table read past its first byte ($68D7, with $5BFF, $5C87 and $CF15), enemy_at's first extra record taken for an object ($7250), and show_portrait's copy ($EAA1, a template line in all seven portrait comments). All fourteen were corrected, with the 15 other comments that said the same.

Live tests

Each from work/play-team.vsf or work/entry.vsf on VICE 3.13.2, advanced by whole frames, on 23 October 2026.

Cheats

Pokes that change the game within its own parameters. Each one names the variable it changes and whether it has been tested live. Untested pokes are labelled as candidates.

EffectPokeStatus
routines tables variables strings branch labels

Loading listing…