GitHub - pditincho/mm-explained: Maniac Mansion C64 explained

11 min read Original article ↗

This is a reconstructed and commented disassembly of the C64 implementation of Maniac Mansion, for educational and research purposes only. It includes the main engine code, as well as the special disk loaders used.

100% of the code is now commented. There are some naming and explanation improvements still pending.

I'm sure I'm not the first to analyze the code, as crackers of old necessarily had to do so to defeat copy protection. And at least one modern conversion to cartridge format exists, which forced the author to do analysis at a relatively deep level.

My goal is to preserve and document one of the culturally and technically significant videogames of its era, from the implementation side.

Corrections and improvements are welcome. Hope you have fun.

How to understand what you're looking at

To follow the logic of each routine, you need a basic understanding of 6502 assembly language. You don’t need to be able to write assembly, but you do need to recognize the instructions and understand what they do.

To fully grasp what each routine does within the C64 environment, you also need some familiarity with the hardware. In particular:

  • Which chips matter: VIC-II for video, SID for sound, CIA for timers, input, and disk I/O
  • How the CPU communicates with these chips through memory-mapped registers
  • How interrupts work - especially the raster interrupt generated by the VIC-II
  • The basic architecture and behavior of these chips, so you can see how the routines use them

If you don’t currently know much about C64 internals or 6502 assembly - and don’t have the time to learn - you can rely on the comments and technical notes. They were written to be as approachable as possible for readers without deep background knowledge. You can treat them as authoritative explanations; aside from the possibility of human error, they accurately describe what the code does.

Game entities

The game engine works with several types of in-game entities and represents them on screen. In the codebase, these are referred to collectively as resources.

The primary resource types are:

  • rooms - Self-contained areas of the game world, connected to one another; they contain objects and scripts.
  • costumes - Characters, both player-controlled and NPCs.
  • objects - All non-character entities the player can interact with.
  • scripts - Behavioral logic that governs how objects and costumes act.
  • sounds - Audio assets, including sound effects and music.

This structure appears to be partially inspired by film-making concepts - locations, actors, props, and direction.

Representation entities

The hardware imposes strict limits on how many things can happen at once, such as:

  • how many characters can be rendered simultaneously,
  • how many sounds can be played concurrently,
  • and how many scripts can execute in parallel.

To enforce and work within these constraints, the engine introduces several representational layers:

  • actors - On-screen representations of costumes.
  • virtual sound voices - Effective instances of sound playback.
  • tasks - Active execution contexts for running scripts.

These representation entities allow the higher-level resources (rooms, objects, costumes, etc.) to be managed within the Commodore 64’s strict concurrency limits.

Game engine vs. interpreter

All of the actual game logic lives inside the script files - even the title screen, intro sequence, and save/load interface. These scripts are composed of instructions and conditions such as “make Dave walk to the door” or “if the microwave is running, play the microwave sound.” They have been fully disassembled and are available at: https://github.com/segrax/Maniac.Mansion.Disassembly

The game engine, on the other hand, is the system that reacts to those scripts (and to player input) and turns them into audiovisual behavior. This clean separation between logic and engine offers well-known advantages, including making it far easier to port the game to new hardware.

Because the engine executes script instructions one by one, it effectively behaves as an interpreter. In modern terms, it functions much like a virtual machine (VM) - similar in spirit to how the Java Virtual Machine executes bytecode.

Code layout

Once loaded, the game becomes a single monolithic block of code in memory, containing more than 500 routines. To make the code easier to understand and maintain, I reorganized it into conceptual modules, similar to how a modern software project would structure its source files.

The codebase can be viewed as two major components:

  1. The C64 audiovisual engine - the part that handles graphics, sound, input, resource loading, and all hardware-level behavior.
  2. The interpreter - the layer that translates script “operations” into concrete actions executed by the audiovisual engine.

All interpreter-related source files use the ops_ prefix to make this separation explicit.

This an index of what each file represents:

File Description
actor.asm Actor ticking, motion, animation orchestration
actor_animation.asm Limb animation and clip sequencing
actor_costume.asm Costume–actor linking and spawning
actor_motion_core.asm Motion state machine
actor_path_dda.asm DDA stepping with walkbox validation
actor_sprites.asm Sprite allocation, mapping, draw ordering
actor_targeting.asm Target selection, snapping, path staging
actor_walkbox_traversal.asm Walkbox resolution, behaviors, traversal
blit_cel.asm Animation cel rendering
camera.asm Camera control
cursor.asm Cursor physics
decompressor.asm Decompressor engine
disk_high_level.asm High-level disk routines to load, write, and stream sectors
disk_low_level.asm Low-level routines for serial communication with the disk drive
drive_setup.asm Disk drive setup for the custom fastloader
entry_point.asm Entry point of the game code
flashlight.asm Flashlight beam rendering
init_engine.asm Initialization of the game engine
irq_handlers.asm Multistage IRQ handlers for sprite/actor drawing
input_scan.asm Keyboard and joystick scanning
key_handler.asm Keypress dispatcher
main.asm Main game loop (outside interrupts)
masking.asm Graphics masking helpers
memory_mgmt.asm Memory allocator and free-space manager
misc.asm Miscellaneous routines
music.asm Music playback routines
pause.asm Pause/unpause handling
random.asm Pseudo-random number generator
render_actor.asm Onscreen rendering of actors
render_object.asm Onscreen rendering of objects
render_room.asm Room viewport rendering and scrolling
room_gfx_rsrc.asm Room rendering helpers
room_loader.asm Room resource loader
rsrc_mgmt.asm General resource loader (costumes, sounds, scripts, objects)
save_game.asm Load/save game handler
script_engine.asm Core of the script execution engine
script_primitives.asm Primitive script operations
sentence_action.asm Sentence execution engine
sentence_text.asm Sentence text renderer
shutter.asm Viewport shutter open/close effect
sid_voice_controller.asm SID low-level voice register controller
sound_engine.asm Sound player engine
start_game.asm Game start/restart helpers
ui_interaction.asm UI handlers for verbs, objects, sentence bar
ui_messages.asm UI message rendering for the top bar
voice_allocation.asm Virtual voice allocator
voice_scheduler.asm Voice scheduler for the sound engine
walkbox_dfs.asm Walkbox DFS path search
walkbox_helpers.asm General helpers for walkbox modules
walkbox_snap.asm Walkbox snapping
walkbox_waypoint_planner.asm Waypoint planner for cross-walkbox paths
ops_camera.asm Camera opcodes
ops_costume.asm Costume opcodes
ops_cutscene.asm Cutscene opcodes
ops_loading.asm Resource loading opcodes
ops_locking.asm Resource locking opcodes
ops_messages.asm Text/message display opcodes
ops_misc.asm Miscellaneous opcodes
ops_object.asm Object-related opcodes
ops_primitives.asm Comparison and bit-test/set opcodes
ops_sound.asm Sound play/stop opcodes
ops_walking.asm Walking-to-destination opcodes

Helper Files Overview

File Description
actor_motion_constants.inc Constants used in actor motion modules
constants.inc Commonly used constant definitions
cursor_physics.inc Cursor direction, acceleration, and drag tables
globals.inc Global variable declarations
hotspots_metadata.inc UI hotspots metadata
opcode_handlers.inc Interpreter operation handlers
registers.inc C64 hardware register aliases
rsrc_metadata.inc Game resource metadata (disk locations)
sound_constants.inc Sound engine constants
text_data.inc Commonly used strings

Where to start

A codebase of this size can feel overwhelming at first. There are several effective ways to begin exploring it:

  • Script-first approach: Start with the game scripts (NOT included in this repo, see the 'Game engine vs. interpreter' section), locate each corresponding operation in the interpreter (ops_*.asm), and then follow the chain down into the engine routines that implement those behaviors.

  • Bottom-up approach: Begin with the low-level modules - graphics, sound, input, disk I/O - and work upward toward the main loop and IRQ handlers.

  • Top-down approach: Start from the main loop, IRQ chain, and high-level systems, then drill down into the lower-level routines they call.

Each method offers a different perspective, and you can switch between them as needed.

Modules (from lower-level to higher-level)

Disk

  • disk_low_level - Low-level serial bus routines
  • disk_high_level - Sector load/write/streaming logic
  • drive_setup - Drive initialization for the custom fastloader

Resource Loading

  • memory_mgmt - Memory allocator and free-space manager
  • rsrc_mgmt - General resource loader (scripts, costumes, sounds, objects)
  • room_gfx_rsrc - Helpers for room graphics resources
  • room_loader - Room asset loading

Sound

  • sid_voice_controller - SID register control
  • voice_allocation - Virtual voice allocator
  • voice_scheduler - Voice scheduler for sound playback
  • sound_engine - Sound effect playback
  • music - Music playback engine

Walking / Movement

  • walkbox_helpers - General helpers for walkbox modules
  • walkbox_snap - Walkbox snapping
  • walkbox_dfs - Walkbox DFS path search
  • walkbox_waypoint_planner - Waypoint planner for cross-walkbox paths
  • actor_walkbox_traversal - Walkbox resolution, behaviors, traversal
  • actor_targeting - Target selection, snapping, path staging
  • actor_path_dda - DDA stepping with walkbox validation
  • actor_motion_core - Motion state machine

UI

  • ui_messages - Message rendering (top bar)
  • cursor - Cursor movement and physics
  • ui_interaction - Verb/object/sentence bar interaction
  • sentence_text - Sentence text renderer

Input Controls

  • input_scan - Keyboard and joystick scanning
  • key_handler - Keypress dispatcher

Rendering

  • decompressor - Graphics decompression
  • blit_cel - Cel rendering
  • masking - Foreground/background masking
  • actor_sprites - Sprite allocation, mapping, draw ordering
  • render_actor - Actor drawing
  • render_object - Object drawing
  • render_room - Room viewport rendering and scrolling
  • camera - Camera positioning
  • flashlight - Flashlight beam rendering
  • shutter - Shutter open/close transitions

Animation

  • actor_costume - Costume–actor linking and spawning
  • actor_animation - Limb animation and clip sets

Scripts

  • sentence_action - Sentence execution engine
  • script_primitives - Primitive operations used by scripts
  • script_engine - Core script interpreter

Other

  • misc - Miscellaneous helpers
  • pause - Pause/unpause logic
  • random - PRNG
  • save_game - Save/load handling

Main Flow

  • entry_point - Program entry
  • init_engine - Engine initialization
  • start_game - Game start/restart helpers
  • main - Main loop
  • irq_handlers - IRQ chains for rendering and updates

SCUMM Interpreter

  • ops_primitives
  • ops_loading
  • ops_locking
  • ops_messages
  • ops_camera
  • ops_costume
  • ops_object
  • ops_sound
  • ops_misc
  • ops_walking
  • ops_cutscene

The loader directory contains all components of the disk loader. Begin by reading loader overview.txt, which explains the structure and flow of the loader code.

The diagrams directory provides visual diagrams that accompany and clarify the loader’s operation.

** Game engine components **

Even though the original engine is not perfectly modular (there is some unavoidable coupling between layers), it can be conceptually understood as a collection of subsystems:

  • Disk I/O system — Loads sectors from disk through custom fastloader routines.

  • Memory manager — Allocates and frees memory blocks for resources, tracks free space, and performs housekeeping (compaction and coalescing).

  • Resource manager — Loads resources from disk, tracks their usage, and evicts them when memory is needed.

  • Sound system — Plays sound effects and music stored as resources.

  • UI system, composed of:

    • the top bar, which displays dialogue messages,
    • the cursor, used for player interaction,
    • the sentence bar, which shows the current action sentence,
    • the interaction area, where verbs and inventory items are displayed.
  • Video rendering system, composed of:

    • an object renderer,

    • a room renderer,

      • including a virtual camera subsystem for horizontal scrolling,
    • a costume renderer,

    • a flashlight subsystem for rendering the narrow beam of light when only the flashlight is active.

  • Animation system — Handles costume animation using limbs and cel definitions.

  • Blitter system, composed of:

    • a cel-to-sprite blitter,
    • a foreground/background masking system for costume–room occlusion,
    • a front-to-back ordering system for correct costume–costume occlusion.
  • Walkbox-based pathfinding system — Computes realistic walking paths between two points within a room.

  • Sentence system — Represents player actions using a simple grammar: verb → direct object → preposition → indirect object.

  • Script/task subsystem — Executes game-logic scripts and manages multiple concurrent tasks.

  • Raster-IRQ sprite rendering subsystem — Uses timed raster interrupts to blit actor graphics to the screen each frame.

A slightly simplified dependency diagram, where an arrow means "depends on":

                    +-------------------------+
                    |     Game Scripts / VM   |
                    | (script_engine, ops_*)  |
                    +-----------+-------------+
                                |
                                |  (drives)
                                v
+-----------------------------------------------------------+
|                     High-Level Logic                      |
|  (Actors / Animation, UI, Pathfinding, Sentence System)   |
+-----------------------------------------------------------+
|                |                     |                    |
|                v                     v                    v
|      +----------------+    +------------------+   +------------------+
|      |  Actors /      |    | UI System        |   | Pathfinding      |
|      |  Animation     |    | (verbs, cursor)  |   | (walkboxes)      |
|      +-------+--------+    +---------+--------+   +---------+--------+
|              |                         |                    |
+--------------+-------------------------+--------------------+---------+
                               |                        |
                               v                        v
                    +------------------+      +------------------+
                    | Rendering System |----->|  Camera System   |
                    | (rooms, objs,    |      | (viewport/scroll)|
                    |  costumes, light)|      +-------------------+
                    +--------+---------+
                             |
                             v
                  +------------------------+
                  |     Blitter System     |
                  | (cel blits, masking,   |----> C64 Video
                  |  front/back ordering)  |
                  +-----------+------------+
                              |
                              v
                  +-------------------------+
                  |   Decompressor System   |
                  +-------------------------+


+-----------------------------------------------------------------------+
|                           Resource Management                         |
+-----------------------------------------------------------------------+
|     +---------------------+        +---------------------+            |
|     |   Resource Manager  |<------>|   Memory Manager    |            |
|     |  (load, evict)      |        |  (alloc/free/GC)    |            |
|     +----------+----------+        +---------------------+            |
|                |                                                      |
+----------------+------------------------------------------------------+
                 |
                 v
       +----------------------+
       |    Disk I/O System   |
       | (high-level + low)   |
       +----------+-----------+
                  |
                  v
       +----------------------+
       |   Drive Setup / HW   |
       +----------------------+


+---------------------+
|    Sound System     |
+---------------------+
| voice alloc/prims   |
| sound engine        |
| music               |
+----------+----------+
           |
           v
 +---------------------+
 | SID Voice Controller|
 +---------------------+
           |
           v
       C64 Sound