Commodore 64 · 1985 · Mastertronic (M.A.D.)
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 | 56,452 | 86.1 % |
| Code | 11,257 | 17.2 % |
| Graphics | 23,632 | 36.1 % |
| Level data | 4,096 | 6.2 % |
| Sound | 3,090 | 4.7 % |
| Text | 5,022 | 7.7 % |
| Tables | 9,160 | 14.0 % |
| Variables | 195 | 0.3 % |
| Screen, bitmap, colour, stack, I/O | 5,376 | 8.2 % |
| ROM the game runs under | 1 | 0.0 % |
| Unused | 3,707 | 5.7 % |
| Tier | silver |
|---|---|
| Coverage | 100 % of the bytes the game uses have a description |
| Build analysed | Remember's crack, release 15: cracked from tape, docs by HOK, +2 trainer by Jack Alien; one file, M.OF MAGIC+2/REM, on a disk named C64.COM. The game starts at $07F9 and runs with no trainer option taken |
| Copy | agent-draft |
| Tools | emulator: VICE 3.10 via vice-mcp 3.13.0: own build of github.com/barryw/vice-mcp, branch main, commit 00b275f2 (Linux x86_64 GTK3 build from source, run under Xvfb), disassembler: regenerator2000 0.9.20, python: 3.11.15, host: Linux 6.18 x86_64, Ubuntu 24.04 cloud container with four cores and no display, widget tests: node 22.22 (ports checked against emulator traces and a 6502 simulation of the music driver), Playwright 1.56 with Chromium 1194 (page checks) |
| Model | claude-opus-5-5 |
| Kit version | 0.0.16 |
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:
/MUSICIANS/H/Hubbard_Rob/Master_of_Magic.sid, read 2026-09-24 (HVSC).| Feature | Status | Where |
|---|---|---|
| Goal (inlay, screen, Addict): bring the Amulet of Immortality back to the pedestal by the pool where you arrived; Thelric's parting message says so at the start of every game. The Addict won by dropping it on the pedestal; the ending is text | live | PUT DOWN ($1AED) sets $03C7 to $7B when the object put down is $15, the amulet, and the player stands on map cell $9677 ($1B82-$1B96); with the amulet poked into the right hand and the player onto that cell, the ending printed (reference/ending.png). The amulet starts at $961F, on the far side of the map from the start $947B |
| The Minotaur guards the amulet and falls only to the Dagger of Death (Addict, Lemon64 snippets; a scroll: "THE DAGGER OF DEATH IS A SPECIAL KIND, WHEN USED ON THE MINOTAUR IT WEAKENS HIS MIND") | differs | he starts at $959B, a few cells from the amulet. His defence, 133, is beyond every roll; with the Dagger of Death $2B93 sets the roll to his defence, a certain hit, and $2B26 makes the damage 30 to his body, not his mind. Spells always miss him ($3AC7; live) |
| Vampires need the wooden dagger (Addict, Crash; a scroll: "AS SURELY AS THE EAST WIND BLOWS, THE DAGGER OF WOOD IS THE VAMPIRES FOE"); one of two vampires carries the Dagger of Death | traced | the dagger of wood does 30 to either vampire ($2B2B-$2B3F); its roll bonus ($2B7F) can never apply, so the first vampire (defence 60) can be hit only with the Ring of Dexterity; the second's defence reads as 25 from an overlapping table and it is always hit. The second vampire ($3E) starts holding the Dagger of Death |
| Controls (inlay, screen): joystick in port 2, or keys H up, B down, Commodore key left, SHIFT right, SPACE fire | confirmed | $0CC6 reads $DC00 (port 2) into $0387/$0388/$0389, then SHIFT and Commodore from $028D and H and B from $C5; port 2 movement and B live |
| Demonstration mode (inlay, Crash): runs on its own after the title scroller; fire or SPACE leaves it | live | it is recorded input, replayed with a saved random seed ($1888, $A540-$A7FF; facts.md); reference/demo-orc-attack.png; SPACE left it |
| Controls screen and five instruction pages (screen): "FIRE TO START OR B FOR INSTRUCTIONS"; the pages are HOW TO CONTROL THE GAME, THE DISPLAY, TO PLAY THE GAME, USING MAGIC, MAGICAL OR PHYSICAL COMBAT | live | B and stick down both open them (reference/controls-screen.png, reference/instructions-page1.png); text at $838E-$8F99, printed by $5C92 |
| Menu across the middle (inlay, screen): chosen with the stick and fire; the cursor starts on RUN; some options open submenus | live | the chooser $1320; eighteen verbs dispatched through $4C03 (facts.md) |
| The menu offers only what applies (inlay: "other options will appear"; Crash, Your Sinclair: PICK UP, OPEN, CLOSE, ATTACK appear when relevant, so ATTACK's position drifts) | live | $11A2 adds each option on a count from $128F (facts.md); with the amulet's number in the right-hand slot the menu read RUN, PUT DOWN, SWAP, INVENTORY, EXAMINE, CAST (reference/play-menu-holding.png), and holding a potion it offered DRINK; a really carried amulet adds WEAR |
| RUN (inlay): move about; fire returns to the menu | live | $08B9; one pixel a world pass, about 1.2 cells a second; fire is refused while the player's dot touches a wall ($091C) |
| Doors (inlay, Crash): OPEN in front of one, CLOSE once through; many monsters open and close doors too | traced | a door is two cells either side of the wall line; OPEN and CLOSE act on the cell the player stands on ($1BBF, $1C85), which the menu tests at the view's centre $04CD; orcs, the wizard, skeletons, vampires and the minotaur open a shut door they pass and close it behind them ($2566, $2600, $25F4); the demonstration opens one ($97FC/$987C differ in demo.vsf) |
| Doorways need exact alignment (Zzap: you can get stuck in a doorway unless exactly lined up with the passage) | live | walls stop the player's dot by the video chip's sprite-to-background collision ($038D, $0F95). The dot is 4 pixels wide and the narrow corridors and doors leave a gap of exactly 4, so only one pixel column in eight passes: pushing up level 3's narrow corridor from in-cell x = 2 to 6, only x = 4 moved and the others bounced in place. CLOSE puts the player back in the middle of his cell ($1C50), which lines him up |
| Picking up and putting down (inlay): stand on top of an object | live | PICK UP $195C lists the objects on the player's cell; PUT DOWN $1AED drops on it; a mace and a potion picked up live |
| Two hands, worn items and a backpack (inlay, Crash, Addict): the right hand's weapon is the one you fight with; the left holds a shield; WEAR/TAKE OFF; the backpack carries more; "YOU CANNOT CARRY THAT MUCH WEIGHT." | live | hands $4C01/$4C02, the right filled first; ATTACK uses the right hand ($2A73); the backpack is the only container; the limit is a total below 70 ($1A03): wearing 60, a 10 was refused and 8 then 1 taken, live. The shield in the left hand protects nothing (see Armour) |
| INVENTORY (inlay, screen) | live | "YOU ARE CARRYING -NOTHING- IN YOUR RIGHT HAND, -NOTHING- IN YOUR LEFT HAND, AND YOU ARE WEARING NOTHING BUT YOUR CLOTHES." (reference/play-inventory.png), from $1A30 |
| EXAMINE (screen, Addict): a submenu of what is near; each object and creature has a description | live (empty) | "-NOTHING-" at the start (reference/play-examine-nothing.png); $2CD4 lists what the player holds and everything on his cell; 28 descriptions, two of which no object uses (facts.md) |
| Weapons (Addict, Crash): fists, dagger, mace, axe, sword, wooden dagger, Dagger of Death | traced | damage (random AND mask) + 2: fist 2-3, daggers 2-5, sword, axe and mace 2-9 ($4E45, $2AFF); the specials above |
| Armour (Addict, Crash): helmet, shield, a suit of armour; they lower the enemy's chance to hit and the damage | differs | $24F1 lowers the creature's roll: armour 5, helmet 2; nothing lowers the damage. Both count whenever the player holds them, worn or in a hand, because the test reads the "can be worn" flag; the shield tests can never pass, so a shield does nothing |
| Potions (inlay, Addict, Crash, Lemon64): two of healing; one that restores mind, its label written backwards ("ALUMROF ECNEGILLETNI ARTXE", Extra Intelligence Formula); a trap, "POTION OF ORCANIAN INTELLECT", that lowers mind | traced | DRINK $2D5E: $0B and $0F body + 8-15; $0C mind + 8-15; $0E mind halved; and $0D, "IT SMELLS PUNGENT, THERE IS NO LABEL", body halved |
| Rings (inlay, Addict): Ring of Dexterity, Ring of Protection from Evil, others of unknown effect; a scroll says "THE SAPPHIRE IS CURSED, IT BRINGS BAD LUCK" | traced | Dexterity ($12) adds 8 to the player's roll while worn ($2AD5); Protection from Evil ($11) takes 4 off a creature's roll and the blue-stone ring ($10) adds 8 to it, whenever held ($24F1); $13 and $14 do nothing. The sapphire warning is text 3, which no object shows |
| Scrolls with hints, some misleading (inlay: "some of the messages might be misleading"; Addict: the scroll about a healing wizard, Leggoless, lies) | traced | six scrolls, read with EXAMINE ($571E); the wizard's scroll is false (nothing but two potions raises body strength, and the wizard hits hardest); "WEAKENS HIS MIND" is false too (facts.md, Text) |
| CAST, four spells known from the start (inlay, screen) | live | the submenu lists MAGIC MISSILE, FIREBALL, MAGICAL SHIELD, ENERGY DRAIN, -NOTHING- (reference/play-cast-menu.png); $2E23 |
| Magic Missile (inlay): a fiery arrow at any live target in sight; heavy damage, high chance of missing | differs | 15 damage, and no chance at all: $3AD6 overwrites the random number, so it always hits every creature but the first vampire and the minotaur, which it always misses (live, from six random states) |
| Fireball (inlay): a 15-foot radius round you, burns everyone else in it | traced | 15 to every creature in sight on the player's cell, the eight around it or two cells away straight ($2EF4-$2F1E, the distance grid $5081); misses only the minotaur |
| Energy Drain (inlay): at any creature in sight, an instant loss of some body strength; an Addict commenter says it also restores yours | differs | 7 off the target's body ($57D5, $3AC7); nothing gives any to the player: every write to his body strength is a hit, a potion or the new game |
| Magical Shield (inlay): protects you until uncast (UNCAST), draining mind power all the while | traced | 8 off every creature's roll ($57D3, $2491); 1 mind to cast, then 1 every 100 world passes ($3A40); while it is up the menu offers UNCAST instead of CAST, so no other spell can be cast |
| Spells cost mind power; "THE SPELL DID NOT WORK PROPERLY BECAUSE YOU DID NOT HAVE ENOUGH MIND POWER" (inlay, screen text); enough for about two spells at the start (Crash); mind and body never regenerate (Addict) | live | costs 6, 10, 1, 5 ($57D5), paid before the target is chosen; with too little, mind goes to 0 ($2E85). Mind starts at 30, enough for five missiles or three fireballs. Nothing regenerates: only potions raise body or mind. The M bar fell by a missile's cost live |
| Mind and body strength shown at the top (inlay, screen) | live | the M and B bars ($2BDE, reference/play-first-menu.png) |
| Body strength and hits: every creature has one; a hit takes off an amount set by the weapon and the attacker's strength; hit or miss is partly luck, and depends on protection, skill and magic (inlay) | live | to hit: random 0-31 + skill against defence; damage: random AND weapon mask + strength / 8 ($2ACC, $2484, facts.md); the minotaur's killing blow live (reference/death.png) |
| A dead monster's possessions can be picked up and used (inlay, Zzap) | live | $3B63 drops everything a dying creature held on its cell; a skeleton killed live left its dagger in the strip (reference/dead-skeleton.png) |
| DEAD stamped on a killed creature's picture, in red (Zzap, Crash) | live | a band-2 sprite spelling DEAD, light red and doubled ($156C, $A500); reference/dead-skeleton.png |
| Game clock (inlay, screen): top right; stops while you choose from the menu, and (Crash) the monsters with it | live | the clock counts world passes, one second per 8 ($2C50), and passes run only after a choice, so clock and monsters both stop in the menu; about 1.2 game seconds a real second while running (21 in 17.6 s) |
| The view window: only what is in your line of sight (inlay, Zzap, Sinclair User) | live | 28 rays cast pixel by pixel through the map's glyphs ($0B25); the window matched the map cell for cell in play-run (reference/play-corridor.png) |
| Several levels, with stairs and doors; items always in the same places (Your Sinclair, Addict, Crash) | traced | four 32 × 32 levels side by side in one 128 × 32 map ($9000); staircases move you 32 columns ($20CC); every start place is fixed ($3EF0/$3F30, copied at each new game) |
| The picture strip: pictures of every creature and object near you (inlay) | live | everything in sight, plus one picture per door and staircase in the view window ($1695, $16DA), twelve slots |
| The message window: says what is happening (inlay) | live | $2941; attack messages in the demonstration and live |
| Monster habits (inlay, Crash, Addict): varying intelligence; most hostile; want your meat and your possessions; guard treasure; some easily scared; a chaser that loses sight of you may give up and go home, go to where it last saw you and search there, or hunt you for a long time; always moving even unseen; most patrol round their lair, some wander; snakes ignore you unless you are on top of them | differs | always moving: yes ($2205). One creature is scared: snake $3B flees and never attacks. A chaser goes to where it last saw you and carries on, for 0 (bats) to 60 (wizard, minotaur) decisions ($4D49). Going home is broken: the new game zeroes the homes ($0965), so idle creatures head north; live, 17 of 24 were north of their start after 53 s. Seven wander at random. Nothing about meat, possessions or guarding, though the minotaur's start is a few cells from the amulet and he stayed there through the demonstration; a creature attacks only when it stands on the player's cell |
| Thelric's warning (inlay): "a sharpened blade may not be best!" | traced | the maces are "GOOD FOR CRUSHING BONES" and were meant to add 8 against skeletons and hellhounds, but that test can never pass ($2B63) |
| Title screen (screen): the logo over a cave picture, the story on a scroller | live | a multicolour bitmap in the RAM under the KERNAL ($E000), rebuilt exactly from memory; the story from $8009 (reference/title.png) |
| Music by Rob Hubbard, three tunes (HVSC: "Main Theme", "Game Over (You're dead)", "Game beaten"); the main theme is an arrangement of Synergy's "Shibolet" (HVSC, Wikipedia) | live | tune 0 on the title and in play ($03D1), tune 1 at the death live, tune 2 at the win ($0861); driver $C000 |
| No sound effects, only music (Addict) | differs | with the music off (M), footsteps sound: every third step of the player sets $03CF ($0D51-$0D5D), and creatures' steps set it too ($2242-$2254); the play interrupt's band 1 then plays a noise burst on voice 1 ($2782). Live: ten bursts in 2.5 s of walking, none standing still. With the music on, band 1 plays the music instead and the steps are silent |
| Credits (inlay): programmed by Richard Darling, graphics by James Wilson, music by Rob Hubbard | confirmed | the title scroller ends with "PROGRAMMED BY RICHARD DARLING, ART BY JAMES WILSON, MUSIC BY ROB HUBBARD." ($831D) |
Found in the code, not in the manual.
$0C94 toggles $03D1; with it clear the play interrupt stops calling $1949 and the voices fall silent; a second M starts them again. The scroller mentions it; the inlay does not.CBM80 at $8004 makes the KERNAL's NMI handler jump through $8002 to $0818, the restart. A reset goes the same way through $8000 (live), but leaves the 6510's data direction register at 0, so BASIC stays switched in over the game's tables at $A000: the title's colours come out scrambled and the view window stays empty (reference/reset-title.png, reference/reset-play.png).$9BAA) offers OPEN, which prints "OPEN DOOR." and does nothing (reference/pool-edge-open-door.png).How to get from the contributor's own copy to the analysed state. Someone else must be able to follow this exactly.
work/master-of-magic.d64, a 174,848-byte disk image, unpacked from the contributor's master_of_magic_the.zip (it holds Master of Magic, The.d64). SHA-256 of the image: f063d3d1ade2c1558cf4cacb7ef80fa03819d9a52cb7c8a66b28e53dea974e69. The disk is named C64.COM, id 00, and holds one program between two DEL separator entries:
This is a crack, not the original. It is release 15 of the group Remember: "cracked from tape and documents written by HOK, +2 trained by Jack Alien", with an intro by Jack Alien, as its own scroll text says. The docs close with "These docs adapted from the tape cover by HOK of REMEMBER in 1997". Everything the crackers added runs before the game and is gone, or never called again, once the game starts at $07F9.
Emulator: PAL C64 (x64sc, 6569 VIC-II, 6581 SID), no cartridge, drive 8 a 1541.
work/master-of-magic.d64 to drive 8 and autostart it. The program's BASIC line (line 1993, SYS π*656, so SYS 2060) starts a decruncher; the Remember intro appears about half a minute after the autostart: a logo, "PROUDLY PRESENTS / THE MASTER OF MAGIC +2 AND DOCUMENTS / (C) 1985 BY MASTERTRONIC" and a scroller.$10D8, $DC01 equal to $EF). The first page of the crackers' documents appears, ending "SPACE .. READ DOCS / RUN/STOP .. START GAME".$17DF).GETIN, so type them: N, N (typing NN into the keyboard buffer with vice_keyboard_type answers both). No trainer option was taken; the bytes the options would patch are checked unpatched at the entry.$07F9, the game's own entry. The game's title screen follows at once: "THE MASTER OF MAGIC" over a cave picture, a story scroller underneath and Rob Hubbard's title music. When the scroller has run, the demonstration starts on its own.The whole sequence is in a script: autostart, SPACE, RUN/STOP, SPACE with a stopping checkpoint on $3884, type NN with one on $07F9, run. Keys held through vice_keyboard_matrix for 0.4 s reach the intro and the docs reader. At the trainer, one 0.3 s matrix press of N was followed by the game starting without a second one, so type its answers instead; why the press counted twice is not established.
All saved without ROMs; the 64 KB RAM image starts at file offset 209, checked against the game's own code at $07F9 (78 D8 A2 FF 9A) and at $2653.
| File | State |
|---|---|
work/handover-3884b.vsf | stopped on the trainer's first instruction, $3884: the game fully unpacked, trainer and crack code still in memory |
work/entry-07f9.vsf | stopped on the game's first instruction, $07F9, after N and N: the loader's hand-over, for telling loaded data from drawn |
work/demo.vsf | the demonstration running |
work/controls-screen.vsf | the controls screen |
work/play-start-menu.vsf | a new game, the first menu, clock 00:00:00 |
work/play-run.vsf | RUN chosen, the player moved up and left from the start, clock running. The snapshot everything downstream is read from. |
tools.py check-emulator on this build: 56 of 56, no failed checks, so none of workarounds.md applies.$01 is $36 in play: BASIC ROM out, I/O and the KERNAL ROM in. The entry sets $37 first and calls the KERNAL's screen clear ($E544) and BASIC's RAM initialisation ($E3BF); the game later switches BASIC out.$0314 points at $2653; on the title screen and in the demonstration it points at $5D08. $0318 keeps the KERNAL's $FE47. The hardware vectors at $FFFA are the KERNAL's, so interrupts arrive through the ROM and leave through $0314, and the play handler ends in the KERNAL's $EA31 (keyboard scan and the jiffy clock) from band 0; the other two bands return directly.$2653 is a raster interrupt in three bands, counted in $03B7:| Band | From raster | What it sets | |---|---|---| | 0 | $28 | multicolour character mode, VIC bank 0: screen $0400, characters $3000; background yellow; sprites from the table at $3A00 | | 1 | $8E | background colour 8, orange, which shows brown (the menu band); the music ($1949) when $03D1 is on, else a noise burst on voice 1 when $03CF asks for one | | 2 | $B6 | multicolour bitmap, VIC bank 2: bitmap $A000, screen $A800; background black; sprites from $3A20; counts frames in $03A0 and collects sprite-background collisions into $038D |
Registers that the handler rewrites cannot be sampled from outside; reads of $D018 and $DD00 land in any of the three bands.
$0CC6 reads joystick port 2 from $DC00 into $0387 (fire), $0388 (x) and $0389 (y), then the keys from the KERNAL's scan: SHIFT right and the Commodore key left ($028D), H up and B down ($C5). $0C94, called just before it, toggles $03D1 on M.facts.md):| Range | What | |---|---| | $0340-$03FF, $0801-$080B | crack's decruncher and BASIC line, overwritten or dead | | $07F9-$2F52 | game code; variables in page 3 | | $3000-$37FF | character set for the top band | | $3800-$3903 | the crack's trainer at the hand-over; the game's sprite shapes in play | | $3A00-$5B26 | sprite register images, a little more code ($3A40-$3BCA), tables and text | | $5B27-$5E4D | title, story scroller and the start of the demonstration | | $6000-$7F3F | the picture sheet | | $8000-$8F99 | CBM80, the title scroller's text, the controls and instruction pages | | $9000-$9FFF | the dungeon map | | $A000-$BF3F | the bottom band's bank: tile tables, the demonstration, its bitmap | | $C000-$CBE6 | the music driver and its three tunes, called as $C000/$C003/$C006 | | $CC00-$CFE7, $E000-$FF3F | the title picture's screen matrix and bitmap, the bitmap in the RAM under the KERNAL ROM | | $D000-$DFFF | RAM under I/O: never written (the emulator's fill pattern) |
The disk file is the crackers' packaging round a single-load tape game. Its BASIC line starts a copy loop at $080C that moves a decruncher from $A0F8 to $0340 and runs it; that unpacks the Remember intro (logo, scroller, the docs reader with its text at $22DA in its own layout) and the still-packed game. After the docs, the loading picture is shown from a bitmap at $2000 with its colours copied from $1800 and $1C00. On SPACE, $3F40 moves the packed game up to the top of memory, copies a second decruncher to $00FD-$01AF and runs it; it unpacks the game and jumps to the trainer at $3884 with $01 at $37. The trainer's two questions patch the game only on a Y: body strength at $24D0 (SBC $038A becomes NOP / SBC #$00) and $2DF8 (LSR $4EC5 becomes LDA), mind at $2E02, $3A66 and $2E93. It ends with JMP $07F9. None of it is annotated further.
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.