1984 · Epyx
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.
| What | Bytes | Of 64 KB |
|---|---|---|
| Program | 54,759 | 83.6 % |
| Code | 20,461 | 31.2 % |
| Graphics | 6,431 | 9.8 % |
| Level data | 5,031 | 7.7 % |
| Sound | 1 | 0.0 % |
| Text | 1,001 | 1.5 % |
| Tables | 21,623 | 33.0 % |
| Variables | 211 | 0.3 % |
| Screen, bitmap, colour, stack, I/O | 9,628 | 14.7 % |
| ROM the game runs under | 288 | 0.4 % |
| Unused | 861 | 1.3 % |
| Tier | silver |
|---|---|
| Coverage | 100 % of the bytes the game uses have a description |
| Build analysed | |
| Copy | agent-draft |
| Tools | host: Linux 6.18 x86_64, Ubuntu 24.04 cloud container with four cores and no display, emulator: VICE, release v3.13.1, v3.13.1-linux-x86_64-gui.zip, disassembler: regenerator2000 0.9.20, python: 3.11.15, node: 22.22.0 |
| Model | claude-opus-5-5 |
| Kit version | 0.0.49 |
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:
https://www.c64-wiki.com/wiki/Impossible_Mission, over HTTPS and plain HTTP), Wikipedia, the Internet Archive and its Wayback Machine, Lemon64 (game page and manual, https://www.lemon64.com/doc/impossible-mission/301), MobyGames, GameFAQs, StrategyWiki, manualzz and the fan site impossible-mission.krissz.hu. What could be read were the result summaries of a web search engine, 1 October 2026, which quote or paraphrase those pages and the manual. Everything below marked "(search)" comes from those summaries: second-hand, and each row is to be checked against the code like any other claim.30-text (facts.md, Text alphabets), 1 October 2026.| Feature | Status | Where |
|---|---|---|
| Loading screen: three framed panels, EPYX PRESENTS / IMPOSSIBLE MISSION / LOADING | live | loader, orientation.md |
| Title state: the agent stands in a lift; fire on joystick port 2 starts the game | live | lift_loop $39CF |
| Speech: "Another visitor. Stay a while, stay forever!" at the start (search) | traced | voice lines 2 and 3 are spoken by the start-up after the load and after every restart ($39AE); the words were not heard in this run. Live: no line is spoken when fire starts a game |
| Speech: "Destroy him, my robots!" and other lines, six in all, two of them a scream as the agent falls and Elvin's laugh (search) | differs | the data holds eight voice lines and the code speaks seven: 1 entering a room after a game hour, 7 a fall, 5 time up, 4 the end picture, 0 the end screen, 2 and 3 the greeting; line 6 is never called (say_line $BED9). Which words each holds was not checked |
| Speech data is digitised samples by Electronic Speech Systems, played without extra hardware (search) | confirmed | file words at $E000; the driver at $0880 plays 4-bit levels through the SID volume register from CIA 2 timer NMIs. The company's name is not in the image |
Six hours of game time to finish; the clock runs on the pocket computer (search); the pocket computer shows a clock, 12:14:06 at the first start of this run | live | game_clock $83A2: from 12:00:00 to six o'clock, 60 ticks a second (7 h 12 min of real time on PAL). The clock also runs in the title state |
| Each death costs ten minutes (search) | live | agent_death $95E4: 12:24:47 became 12:34:47 |
| When the six hours run out, Elvin laughs and the game ends (search) | traced | wait_tick_or_end $83F4: shaking screen, voice line 5, the end screen with MISSION TERMINATED. The laugh's words were not heard |
| The agent walks, and somersaults to cross gaps (search) | confirmed | agent_animate $8817, agent_move $8859; fire starts the somersault (frames $10-$1B) |
| The stronghold: rooms joined by lifts and tunnels; 31 or 32 rooms, sources differ (search) | confirmed | 32 room records ($0E70), two of them the code rooms; placed on a 9 × 6 grid of shafts and corridors (make_map $B2BD) |
| Rooms, lifts, the placement of puzzle pieces and the robots' abilities are chosen at random for each game (search) | confirmed | new_game_setup $7236 (facts.md, "A new stronghold every game"); the room layouts themselves are fixed |
| Furniture can be searched; a search yields a puzzle piece, a snooze password, a lift-init password, or nothing (search) | confirmed | search_object $97FB, search_result $98FB; 36 pieces, 9 snoozes and 9 lift inits hidden among 128 pieces of furniture (hide_items $B26D) |
| Lifting platforms (striped) in rooms, moved up and down by the agent (search) | confirmed | lift_platforms $AC88 |
| 36 puzzle pieces, nine sets of four; each set makes one letter of a nine-letter password (search) | confirmed | make_pieces $B180, check_solution $80C3 |
| Pieces overlap, so three can be assembled before the player finds they must start again; pieces may need flipping horizontally or vertically (search) | differs | the four pieces of one puzzle divide its picture exactly: the first mask and its complement, each split by a second mask (make_pieces $B180, build_piece $9C47; the port on the page matches the game's routine on all 36 pieces). Only the frame drawn on every piece is shared, and the overlap test ($8037) allows that and nothing else. Flips: confirmed, random per piece |
| A piece's colour depends on the room it was found in; four pieces must share a colour to fit, and colour keys change a piece's colour (search) | confirmed | the room's background colour becomes the piece's ($98FB); COLORS MUST MATCH (pc_select_slot $3B4D); colour keys (recolour_piece $7A29) |
| Pocket computer: map of the rooms and tunnels entered; memory window with two pieces; arrow keys; flip keys; colour keys; password area; phone key "dials out for help" (search) | live | pocket_computer $3A80; screenshots reference/pocket-computer.png, phone-menu.png, pocket-computer-map.png |
| Pocket computer usable only in a lift or a corridor (search) | confirmed | only lift_loop opens it on fire; in a room fire starts a somersault |
Pocket computer readout SNOOZES: and LIFT INITS: counters and PSW: | live | status text at $3431 |
| Security terminals: stand in front and push up to use a snooze (robots in the room stop for a while) or a lift init (platforms return to their start) (search) | live | security_terminal $9D16, terminal_select $A0DE; screenshot reference/security-terminal.png; the snooze stopped the robots for 764 ticks |
| Robots: electrified bodies, some fire a short-range ray; each is a mix of can/can't shoot, can/can't turn, and detects the agent at some distance or not; some patrol, some follow, some react only when close, some stay put (search) | confirmed | the behaviours are scripts (robots_run $8ECC, tbl_robot_scripts $2112) chosen at random per game from 32 starts; touching a robot or its zap kills (agent_hit_check $9504) |
| A black floating ball in some rooms (six, by one source) kills on touch and follows the agent (search) | confirmed | six room records have a ball; ball_run $92CB homes in on the agent's centre in some scripts |
| Two code rooms: a terminal with a large chequered screen plays a tone sequence; pointing at the squares in ascending pitch earns a password (search) | traced | rooms $11 and $1B, code_room_puzzle $A771; not played live in this run |
| The end: reach Elvin's control room with the full password; an ending with more speech, in a female voice (search) | live | elvin_terminal $AA40: Elvin's face in close-up, talking (voice line 4); forced live, reference/end-elvin.png. The voice was not heard |
| Score: points for puzzle pieces found and assembled, and for reaching the control room with time left (search) | live | compute_score $BA08: 100 a piece, 100 a password, 500 a puzzle, 1 a second left and 1,000 for the mission; 21,113 in the forced win |
| Security terminal menu (game text): SECURITY TERMINAL, SELECT FUNCTION, RESET LIFTING PLATFORMS IN THIS ROOM., TEMPORARILY DISABLE ROBOTS IN THIS ROOM., LOG OFF.; PASSWORD REQUIRED / PASSWORD ACCEPTED | live | text $A01E, $A229; the number after SECURITY TERMINAL is the room's |
Pocket computer messages (game text): PUSH BUTTON, COLORS MUST MATCH, IMAGES CAN'T OVERLAP, NO IMAGE SELECTED, END OF MEMORY, CAN'T UNDO, TIME IS SUSPENDED, WE JUST DID THIS ONE, NOTHING IN MEMORY, and a confirmation that the orientation has been put right (its exact wording is in the listing at $7D22) | confirmed | show_message $81C5; each message traced to the routine that prints it |
| The phone (game text): HAVE WE ENOUGH PIECES TO SOLVE THE UPPER LEFT PUZZLE, A SOLUTION EXISTS / NEED MORE PIECES, CORRECT ORIENTATIONS OF LEFTMOST PIECES, HANG UP | live | the menu was shown live; the answers are traced (phone_answer_enough $7FD7, phone_answer_orient $7F8D); a call costs two minutes |
| End of game tally (game text): PUZZLE PIECES FOUND, PASSWORDS FOUND, PUZZLES SOLVED, SECONDS REMAINING, MISSION COMPLETE or MISSION TERMINATED, TOTAL SCORE, THIS SURPASSES THE PREVIOUS HIGH SCORE OF, HALL OF FAME | live | end_of_game $B786; reference/end-tally.png |
| High-score name entry (game text): ENTER YOUR I.D. CODE ON THE KEYBOARD; HIT RESTORE OR RUN/STOP FOR NEW GAME | live | hall_of_fame $BC04 |
| A list of nine-letter words in the code (SWORDFISH, ASPARAGUS, ARTICHOKE, CROCODILE, ALLIGATOR, ALBATROSS, BUTTERFLY, CORMORANT): candidates for the password | live | choose_password $B0CD picks one per game; SWORDFISH in this run |
| Cheat POKEs listed by one cheat site: "Cheat mode: POKE 26831,169" and "No opponents: POKE 27028,0, POKE 31005,12, POKE 21006,221" (search). Those addresses are for some unknown version and may not match this image | differs | in this image 26831 ($68CF) and 27028 ($6994) are inside the agent's sprites, 31005 ($791D) is in flip_piece_v, 21006 ($520E) in the room character set: none of them is a sensible cheat here, so the pokes are for another version or another loader |
Found in the code, not in the manual.
orientation.md).rts, and the interrupt jams the processor unless $D024 still holds the loader's value (facts.md, "Copy protection"). Both tested live.orientation.md).How to get from the contributor's own copy to the analysed state. Someone else must be able to follow this exactly.
impossible_missionepyx_1984pal.d64 as uploaded by the contributor (325,814 bytes, SHA-256 c394df35280f6cd4ec542c7035f3e99dcbeeaa656cf2560591feccdd0891e4ff). Despite the .d64 in its name it is a G64, a GCR-level copy of the disk (its header reads GCR-1541, 42 tracks), and it was renamed to work/impossible_mission.g64 so that VICE treats it as one. A G64 keeps the original's copy protection, and this one needs it: the loader checks the disk (below).
The directory, as VICE's c1541 lists it (every entry reports 0 blocks):
0 ". imposs.miss." im 2a 0 "" prg 0 "5im-cass " prg 0 "bpage" prg 0 "col" prg 0 "im..." prg 0 "load-0800" prg 0 "loader2" prg 0 "main0800" prg 0 "scr" prg 0 "words" prg 462 blocks free.
c1541 could read seven of the files through the standard DOS chain: col ($D800-$DBFF), scr ($0400-$07FF), im... ($0334-$03FE), load-0800 ($0800-$08EC), loader2 ($C000-$C3FF), bpage ($B000-$B1FF) and words ($E000-$F77F). main0800 reads as a single block ($0800-$08FF); the rest of the program is fetched by the fast loader. "" and 5im-cass did not read. No trainer, intro or cracker's credit appears anywhere: the screens are Epyx's own, and the image behaves like the original disk.
vice_machine_reset, mode: hard), resume it and let it reach READY..work/impossible_mission.g64 (VICE loads *, the first file). The machine is PAL (MachineVideoStandard 1). With VICE's default drive settings (true drive emulation on) it loads with no vicerc changes.$3855) in about two minutes of host time (136 s to the last loader stage at $C02D, measured 1 October 2026); with warp off it is much slower. Turn warp off again once the game's screen is up.SNOOZES:0 LIFT INITS:0, PSW: and a clock (12:14:06 the first time; it runs).Snapshots in work/, each saved without ROMs:
| File | State |
|---|---|
loader-b000.vsf | a stopping checkpoint on $B000, from a power-cycled machine: the loader's jmp $B000 at $C317, the first instruction of the bpage unpacker, before the program is moved and unpacked |
entry.vsf (also kept as gamestart.vsf) | from loader-b000.vsf, a stopping checkpoint on $3855: the unpacked game's first instruction, $01 = $25. This is the hand-over listing.py compares the play snapshot with |
title.vsf | the title state of step 4, before fire |
play-room1.vsf | step 6: the agent has just entered the first room. The disassembler and the listing are built from this one (why, below) |
In play: $01 = $35 (RAM at $A000 and $E000, I/O at $D000). The hardware IRQ vector $FFFE = $82F4 and the NMI vector $FFFA = $388C; the KERNAL's RAM vectors at $0314 still hold their defaults and nothing goes through them with the KERNAL banked out. The IRQ handler at $82F4 acknowledges $D019 and splits the screen by raster line (it compares $D012 with $F0 and reprograms $D012 to $AA), which is the boundary between the room above and the pocket computer below. The video chip looks at bank 1 ($DD00 = $C6, bits 0-1 %10, $4000-$7FFF).
Compared byte for byte with entry.vsf, the play image differs in:
$3855-$3865: the start-up clears these 17 bytes, its own first instructions, in the same loop that clears the sprite registers (sta $D002,x / sta $3855,x at $389C). The bytes as the loader left them are in entry.vsf: lda #$60 / sta $DD03 / nop / nop / lda #$54 / sta $0318 / lda #$38 / sta $0319 / sei / cld.$C000-$D7FF and $F800-$FFFF: tables and graphics the start-up builds or moves there (at $3855 the block that ends up at $D000 is still at $C800).$0800-$08FF: loader code at the start, game data in play.The rest of $0900-$BFFF is unchanged between the two, so nothing is reloaded: once the game runs, the image in memory is the whole game. The play image is the one to read, because it holds everything the running game uses; the only code it lacks is those 17 bytes, recorded above.
Snapshot title.vsf and play-room1.vsf differ only in variables, the screen and $C100-$C4FF.
The first file loads over the KERNAL's vectors and takes the CHROUT vector ($0326) to $02A7, which clears the screen and loads col, scr and im... with the KERNAL: the three framed panels. im... ($0334) opens the command channel, loads bpage ($B000) and load-0800, and jumps to $0810, which loads loader2 at $C000. That loads words (the speech samples, $E000-$F77F) and main0800, sets $01 to $36 and jumps to $C300. $C300 first calls $C31A, which opens the command channel and a data channel on the drive and reads characters back; what exactly it asks the drive was not traced, since the loader is not the subject. Only if $C3DA is then non-zero does it write three bytes into bpage: $38 to $B0B9, $B0 to $B0C6 and $60 to $B143. The bpage file on the disk holds $55, $E0 and $78 there, which make the final jump jmp $5555, the self-copy read from $E000 instead of $B000, and the unpacker's rts a sei. So the program on the disk is broken on purpose, and the drive check is what repairs it: a copy that fails the check crashes after loading. With this image $C3DA was $FF and the three bytes were repaired (read in loader-b000.vsf and in the file, 1 October 2026). $B000 copies itself to $0400, moves $0800-$AEFF up by $2800 to $3000-$D6FF, top page first, unpacks it with a run-length decoder ($BF n: n zeros; $CF n b: n copies of b), and jumps to $3855, the game.
Emulator: release v3.13.1, v3.13.1-linux-x86_64-gui.zip. check-emulator passed 56 of 57; failed: pause-at-instruction (stops are made with pause() in kit/c64/vice.py).
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.