1984 · Epyx

About this page

This minisite was contributed by chunkypixel, 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/impossible-mission 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.

WhatBytesOf 64 KB
Program54,75983.6 %
Code20,46131.2 %
Graphics6,4319.8 %
Level data5,0317.7 %
Sound10.0 %
Text1,0011.5 %
Tables21,62333.0 %
Variables2110.3 %
Screen, bitmap, colour, stack, I/O9,62814.7 %
ROM the game runs under2880.4 %
Unused8611.3 %

Status

Tiersilver
Coverage100 % of the bytes the game uses have a description
Build analysed
Copyagent-draft
Toolshost: 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
Modelclaude-opus-5-5
Kit version0.0.49

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
Loading screen: three framed panels, EPYX PRESENTS / IMPOSSIBLE MISSION / LOADINGliveloader, orientation.md
Title state: the agent stands in a lift; fire on joystick port 2 starts the gamelivelift_loop $39CF
Speech: "Another visitor. Stay a while, stay forever!" at the start (search)tracedvoice 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)differsthe 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)confirmedfile 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 runlivegame_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)liveagent_death $95E4: 12:24:47 became 12:34:47
When the six hours run out, Elvin laughs and the game ends (search)tracedwait_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)confirmedagent_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)confirmed32 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)confirmednew_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)confirmedsearch_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)confirmedlift_platforms $AC88
36 puzzle pieces, nine sets of four; each set makes one letter of a nine-letter password (search)confirmedmake_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)differsthe 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)confirmedthe 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)livepocket_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)confirmedonly lift_loop opens it on fire; in a room fire starts a somersault
Pocket computer readout SNOOZES: and LIFT INITS: counters and PSW:livestatus 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)livesecurity_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)confirmedthe 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)confirmedsix 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)tracedrooms $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)liveelvin_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)livecompute_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 ACCEPTEDlivetext $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)confirmedshow_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 UPlivethe 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 FAMEliveend_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 GAMElivehall_of_fame $BC04
A list of nine-letter words in the code (SWORDFISH, ASPARAGUS, ARTICHOKE, CROCODILE, ALLIGATOR, ALBATROSS, BUTTERFLY, CORMORANT): candidates for the passwordlivechoose_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 imagediffersin 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

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

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.

From power-on to play

  1. Power-cycle the emulator (vice_machine_reset, mode: hard), resume it and let it reach READY..
  2. Autostart 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.
  3. Three framed panels appear: "EPYX PRESENTS", "IMPOSSIBLE MISSION", "LOADING". With warp mode on, the loader reaches the game's start ($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.
  4. The title state: the agent stands in a lift in a red shaft, the pocket computer below shows an empty green display. Fire on joystick port 2 starts the game: the pocket computer shows SNOOZES:0 LIFT INITS:0, PSW: and a clock (12:14:06 the first time; it runs).
  5. The joystick now drives a hand pointer over the pocket computer's buttons. Move it to the right-hand block of nine buttons, top-left button, then one down (the left button of the middle row) and press fire: the pocket computer switches off and the display shows the map view. The joystick now moves the agent.
  6. Hold left for about four seconds: the agent leaves the lift and the first room is drawn, with four robots, a bookcase pair, a desk, a sofa, a lamp and terminals. That is play.

Snapshots in work/, each saved without ROMs:

FileState
loader-b000.vsfa 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.vsfthe title state of step 4, before fire
play-room1.vsfstep 6: the agent has just entered the first room. The disassembler and the listing are built from this one (why, below)

Steady state

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:

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 loader, in a paragraph

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.