1985 · Beyond Software

About this page

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.

Footprint

Every byte of the C64's 64 KB, one pixel each, 512 to a row. Lit pixels are what this game is: its code, graphics, level data, sound, text, tables and variables, exactly where they sit in memory. Dim areas are screen and working memory; dark is unused.

Status

Tiersilver
Coverage100 % of the bytes the game uses have a description
Comments checkedNot audited. No audit has checked every comment, and the last sample of 80 comments had 14 wrong, so between 11 and 27 % of the listing’s comments are likely wrong. How listings are checked
Build analysedBeyond cassette, 1985 (Ultimate Tape Archive Shadowfire.tap, SHA-1 30554555c373cf3d59939377f138ddf9cbc0a721)
Copyagent-draft
Toolsemulator: release v3.13.2, v3.13.2-linux-x86_64-gui.zip, disassembler: regenerator2000 0.9.20, host: Linux x86_64 (Ubuntu 24.04.5, cloud container)
Modelclaude-opus-5-5[1m]
Kit version0.0.224

How the listing was checked

Every step that measured the Source tab’s comments or made them more accurate, in the order it happened, with the models that did it. Accuracy of the Source explains each step and what the row above makes of them.

StepByWhat it foundOf the listing
Researchclaude-opus-5-5[1m]Looked the game up online (its manual, reviews or wiki pages) before reading its code.
Annotationclaude-opus-5-5[1m]Wrote the listing’s comments. 100 % of the program is described, in 1,610 comments.
Sample 1claude-opus-5-5[1m]14 of 80 comments wrong, so between 11 and 27 % of the listing is likely wrong. All 14 were then corrected.
60 hand-written comments (13 wrong) and 20 generated (1 wrong); 15 more corrected with them, those that shared their beliefs

likely wrong the sample’s range corrected right, or likely right not yet measured

Contributors

Other places to love this game

What the game does, and where we found it

Read this before annotating code. What the game is documented to do, with verification status against the binary. Statuses: open (documented, not found yet), traced (in the code, could not be exercised; say what was tried), confirmed (in the code, consistent with the emulator), live (observed directly), differs (the code does something else). "Absent" is not a status.

Sources:

Features

FeatureStatusWhere
Title screen shown while the tape loads ("Beyond © 1985, Shadowfire by Denton Designs")livethe loader's blocks 2-5 put it up (orientation.md); the game never shows it
Control menu: F1 keyboard, F3 digital joystick, F5 analog joystick (paddles), F7 light penliverestart ($40A3) at $41BD; fkey_codes $42CE, input_handlers $42C6. Any key on the same keyboard row line as an F key chooses it too
Keyboard control: keys by row move the cursor; F7 or any top-row key enters a commandtracedinput_keyboard $5630: the joystick's code with keyboard row-line masks (input_masks $6825)
Joystick moves the cursor over the icons; fire entersliveinput_joystick $562C, control port 1 only; a held direction speeds up from 2 to 6
Analog joystick (paddles) moves the cursortracedinput_paddles $5526: paddle 1 the row, paddle 2 the column
Light pen moves the cursor; its button or any key enterstracedinput_lightpen $54F1: any key is fire
Self-display (demonstration) mode starts after the first screen; any key leaves itlivestarts when the title music reaches tune 2 ($4216); input_demo $5570, demo_script $1571; it ends by clicking Quit twice
Scrolling welcome message in the command panel ("Welcome ally of the Empire...")livequeued by restart; the ticker $5FEF, ticker_shift $63D7
Start menu: Old game, New game, Load game, Save gamelivestart_menu $74B9, screen 7's icons at $7C78
Start menu summary: surviving Enigma Force, enemy killed or captured, mission status, Kryxix rescued or notlivesummary_text $CF4B, filled by start_menu; SUCCEEDED and FAILED shown by poking $CA05
New game starts the real-time countdown: one hour forty minuteslivethe clock starts at 99:58 and counts down a second each 50 frames ($CA00)
Save and load to cassette or disc, with a file name spelt with on-screen letters, a RUB icon and a carriage-return icon; Run/Stop on a tape failuretracedname_screen $765E, add_letter $7717, rub_out $772D, start_file $773E: saves $CA00-$CFFE through the KERNAL. Not run live
Enigma team screen: the surviving characters, chosen with the cursorliveteam_screen $6DCB, screen 0's icons at $78AE
Up and down arrows on the team screen turn the background music on and offdiffersmusic_up $7884, music_down $7891: they step the in-game tune's pulse width ($1603) between 0 and $40, a step for every pass of the loop while fire is held, so the music fades in and out. It starts at 0, silent. Live
Four screens per character: Status, Objects, Movement, Battle, reached by green, yellow and red monitor icons; Quit goes back or cancelstracedscreens 1, 2, 4 and 5 ($789C); quit_choice $7106 cancels a two-step choice
Status screen: agility, strength, stamina and weight bars; weight bar red when overloaded; weakened characters may recovertracedbars at $5761; the weight is drawn red and the strength figure green over it, so red shows the excess; recovery $58F8
Objects screen: objects in the location (left), carried (middle), weight bar; Pick-up, Drop, Ready for use, Activatetracedlist_objects_here $4CFA, list_objects_carried $4E77, pick_up $6FD9, drop $7011, ready $7056, activate $7063
Weapons fire automatically in combat, but only one held "ready for use"; otherwise bare handstracedcombat $5BFF reads the object held ready (+8) through weapon_strength $CF15; $20 for bare hands
Manto's transporter: Pick-up, Transporter, Activate, Ballistic control beams Manto to the Fighter Bay or the top or bottom Shuttle Baytracedactivate_ballistic $7406: locations $16 (FIGHTER LAUNCH TUBE ONE), $08 and $A0 (both SHUTTLE BAY)
Beaming the rest of the team: Drop, Transporter, Activate, Transporter, then the charactertracedactivate_beacon $734D: someone at one beacon goes to the other in a second
Movement screen: filled arrows show the directions possible; a text description of the locationtracedbuild_directions; the description icon at $79E8
A character refuses to move at a locked door without a key card, or when about to be attackedtraceda locked exit's arrow cannot be chosen; a defender, or an attacker off the battle screen, gets "YOU CANNOT MOVE IN COMBAT MODE" (move_by_exit $6E65)
Battle screen: Location scan (characters in this or the next location), Attack, Defend, Retreattracedbattle_screen $7119, location_scan $7166, attack $71D2
Battles in the same location or between adjacent ones; weapons differ in strength and range; "the computer will tell you if a battle cannot be resolved"differscombat $5BE6: each weapon has a strength for its own location (high nibble of weapon_strength, $CF15) and one for adjacent ones (low nibble), but only the first is ever applied (damage, $68D7, read with X 0 at $5CB3), so range makes no difference. Simulated on the game's code; "NO ENEMY TO ATTACK IN THAT DIRECTION"
A successful attacker advances into the enemy's locationtraced$5D54
Mission command panel above every screen: status icons, view screen, character in playliverows 0-12 of the bitmap as loaded, panel_row_0 $2000 onwards
Status icon colours: white inactive, blue moving, purple attacking, orange defending, yellow retreating, green picking a lock; grey when weak, black when dyingtracedstatus_colours $68B7, $5896; grey below strength $80, black below $40 ($58CB)
View screen: an iris opens on the chosen character; icons flash for each other character in the locationtracediris_open $45E2; the map icons from entity_pictures $6CFE, one cell updated each frame
Six characters with different speed, strength, stamina and carrying: Zark Montor, Syylk, Sevrina Maris, Torik, Maul, Mantotracedstrengths at $CA0E, agility_base $CFB7, strength_factor $CF85
Zark Montor is the translator: Kryxix follows only him (Wikipedia)traced$5B9A, $5D93
Syylk's hatred of Zoff "could prove a weakness"opennothing found: no comparison of entity 0 with Zoff in the combat ($5BE6), the triggers or the arrival code, and Zoff can be harmed by nobody
Sevrina picks locks (with the tool kit)tracedactivate_tool_kit $7301, $5A08: about 32 seconds a lock
Torik is the fastest; Maul slow and well protected; Manto the only transportertracedagility base $FF for Torik, $40 for Maul ($CFB7); Maul's strength and factor are $FF; nothing reduces the damage he takes. Only character 2, Manto, gets the beacons' and the transporter's flags (list_objects_here)
Enemies: General Zoff (purple icon), Captain Chur (white or grey), Marshalls, Squad leaders ("Targs"), Troopers ("Eugs"), humanoid and robotictraced42 enemy records ($CA9E onwards) with seven kinds of figure (entity_pictures $6CFE); the names are not in the game's text, except Marshalls Cavns and Xator in location names
Ambassador Kryxix appears as a green icon; he must be located and beamed offtracedmap_icon_kryxix $0AE3; rescue at $5A68
The Phantom, Zoff's invisible pet, attacks characters at random. Steve Cain of Denton Designs (Sinclair User 40, July 1985, page 58) says it was a bug in the C64 version, one wrong mnemonic, since taken outopenevery attacker is one of the 50 entities, which the interrupt runs in turn (irq_entity $66D1, $6197); each has a map icon and shows in the list of people in a location, and combat ($5BE6) runs only for one attacking, defending or retreating. Nothing found that attacks unseen. Six C64 copies hold the same program: Beyond's tape and disk, and the Yak Society (dated 30 April 1985), TBC, Radwar and TCI cracks (two more, cracks by Tuerk and FCG, were not compared). The only search past the end of the people, enemy_at ($7250), makes phantoms that never attack (discoveries.html#phantoms)
Objects: projectile pistol, lazer rifle, rocket launcher, grenade, smoke bomb, tool kit, colour-coded key cards, self-destruct card, self-destruct unit, time delay unit, transporter beacontraced54 object records at $CD98: 18 other objects and 36 weapons in 18 pictures. The game names none of them
Rocket launcher best fired into an adjacent location; grenade and smoke bomb in the same locationdiffersweapon_strength $CF15 has an adjacent strength in its low nibble, which combat never uses ($68D7): every weapon hits adjacent locations with its same-location strength. Which picture is which weapon is not in the game
Time delay unit: the character who activates it is the only thing not held in a time locktracedactivate_time_delay $7282: 120 seconds, once
Self-destruct unit, armed with the self-destruct card, counts down four minutes to the end of Zoff Vdiffersactivate_destruct_unit $747F: 256 seconds. Live. The card only makes the unit usable, and only in the unit's location, $A2 ($746C)
Transporter beacon: only Manto operates it, and only after it is dropped in a locationtracedlist_team_beacon1 $50E0: a carried beacon's list is blank
Objectives in any order: rescue Kryxix, capture Zoff, capture or destroy Zoff Vlivemission $CA05, read by start_menu
Music by Fred Graytracedthe music driver at $1606 and nine tunes; the credit is the manual's

Beyond the documentation

Found in the code, not in the manual.

Open questions

How the analysed state was reached

How to get from the contributor's own copy to the analysed state. Someone else must be able to follow this exactly.

The image

Shadowfire.tap, 627,772 bytes, SHA-1 30554555c373cf3d59939377f138ddf9cbc0a721, from the Ultimate Tape Archive's item uta_Shadowfire_1985_Beyond_2440 on archive.org, beside scans of the cassette, its inlay and the instructions. The header reads C64-TAPE-RAW, version 1: a recording of the cassette's pulses, 260 seconds of tape. It is the Beyond cassette of 1985, not a crack: no intro, trainer or menu comes up, and the blocks it loads are listed below.

A second image was looked at and not used: a D64 from archive.org's d64_Shadowfire_1985_Beyond_Software, SHA-1 fcb48d4bacc967418a26b88751a397944f919033. Its disk name ends ASS PRESENTS: and it holds two programs, SHADOWFIRE (160 blocks, loads at $0801) and SHADOWFIRE TUNER (113 blocks), the add-on the manual announces: a crack, packed into one file. It was not run.

From power-on to play

  1. Start the emulator (tools.py vice), hard-reset it, and autostart work/shadowfire.tap with autostart() in kit/c64/vice.py. VICE presses PLAY and types the load. Turn warp on with warp(rpc, True): the load then takes about 240 seconds on a four-core container. The border flashes in colour while each block loads; from about the fourth block a picture fills the screen (the Beyond and Shadowfire title, "by Denton Designs").
  2. The last block is a 19-byte stub at $081B; it masks the CIAs' interrupts, reads both interrupt registers to clear them, and jumps to $4000, the game's first instruction. A stopping checkpoint on $4000 armed after the reset and before the autostart catches it: work/entry.vsf was saved there, with SP $FA, $00 = $2F and $01 = $27 (the motor off; BASIC, I/O and KERNAL in). work/scripts/entry.py does all of this.
  3. The game shows the control menu: F1 keyboard, F3 digital joystick, F5 analog joystick, F7 light pen, under the mission panel with a message scrolling across it. F3, held half a second through the key matrix, gives the start menu with a cursor: the joystick in control port 1 moves it (port 2 does nothing). Left until the cursor's X is $1C puts it on the New game icon; fire starts the game.
  4. work/play-team.vsf was saved on the team screen that follows, the six Enigma characters in a row and the mission clock at 99:56. Left alone on the control menu, the game plays its own demonstration.

Steady state

The hand-over snapshot work/entry.vsf is the image the listing is built from: it holds every byte the tape loaded before the start-up moves any of it.

What the tape holds

Decoded from the pulses by work/scripts/tap.py. The first two blocks are in the Commodore ROM loader's format: a header and a short program. The rest is a turbo format: pulses of about 272 cycles are 0 bits and about 528 cycles 1 bits, least significant bit first; a block is a pilot of $E3 bytes, the sync byte $ED, its first address and the address after its last (low byte first), the bytes, and one more byte, which was $44 in every block. Each block's bytes were compared with the hand-over snapshot.

BlockLands atBytesIn the hand-over
ROM header and programtape buffer, and $044E-$0617 (the header's addresses)the header is still in the tape buffer; the program's bytes were overwritten
1$0300-$030B12equal: BASIC's six vectors, at their default values
2$0C00-$0FFF1,024349 equal: the loading picture's colour matrix, later overwritten by block 9
3colour RAM $D800-$DBFF1,024the picture's colour RAM
4$1400-$3FFF11,2643,475 equal: the loading picture's bitmap at $2000-$3F3F, and $1400-$1FFF beside it, all overwritten by block 9
5$D000-$D02F48the video chip's registers: multicolour bitmap at $2000, colours at $0C00, which puts the picture up
6$E000-$FFF78,184equal, every byte
7$4000-$CFFE36,863equal, every byte
8$D000-$D02F48the video chip's registers again: the display off ($D011 = $0B), the default text screen
9$0900-$3FFE14,079equal, every byte
10$081B-$082D19equal: the hand-over stub

So the game is $0900-$3FFE, $4000-$CFFE and $E000-$FFF7, all of it loaded as it stands. The loading picture (blocks 2 to 5) is the loader's: the game never shows it, and block 9 loads over it.

The loader, in a paragraph

The ROM loader reads a header and a program; the header's name and spare bytes, which stay in the tape buffer, are not 6502 code as they stand, and neither are the loader's bytes in pages 2 and 3 at the hand-over, so the loader is stored scrambled and unscrambles itself as it runs (the program counter sat at $03E5 and $03E8 while blocks loaded). It then reads the ten turbo blocks above in order, putting up the loading picture first so there is something to look at for the four minutes the rest takes, blanking the screen again before the last big block loads over the picture, and finally runs the stub at $081B, which starts the game at $4000. Not annotated further, by policy.

The symbol map for this game is symbols.json; the listing behind the Source tab is listing.json. Write-ups, facts and symbol maps are CC BY-SA 4.0. The game itself is not hosted here.