ADD_SCORE has two callers. The kill of a small creature (KILL_MONSTER)
adds 155, whether it was shot, walked into or caught by the player's death;
killing Frankenstein's monster with the spanner (MOVE_FRANKENSTEIN) adds 1000 more.
Nothing else scores: not keys, objects, rooms or escaping, and the other
four of the big five cannot be killed at all -- none of them tests for the
weapon (CHECK_SHOT_HIT is called only by the small creatures' movers), so the axe,
the spell and the sword pass through them. Watched in the emulator: a game
won by walking straight to the door, with the three pieces staged in the
inventory, ended with a score of 0.
Dying is worth 155 a head
While the player sinks or rises, every small creature in the room is killed
on its next move (STEP_ACTOR, the tail of MOVE_ACTOR), with the 155 points of
any other kill. The big five are exempt. Watched in the emulator: with three
creatures just materialising in the first room, starving the player took the
score from 0 to 465 and emptied all three slots.
The humpback eats treasure
Eight of the collectables -- $82 to $89 -- have no use: nothing asks whether
they are carried. Nothing, that is, except the humpback (MOVE_HUMPBACK), which looks
for one of them in its room (SCAN_COLLECTABLES), walks to it and empties its record, so
the object is gone for the game. It does this whether the player is there or
not. Watched in the emulator: object $82 put in the humpback's room, room
$56, was gone 40 frames later, the humpback standing where it had been.
Dracula fears the crucifix
MOVE_DRACULA asks FIND_CARRIED whether the yellow crucifix is carried; if it is,
Dracula reverses whatever HOME_IN would have him do, and runs from the player
instead of towards him. Watched in the emulator: Dracula put 12 pixels from
the player in the first room closed in and had the life force down to 4 in
80 frames; with the crucifix in the inventory he backed away, 13 pixels to
48, and the player lost only hunger's 4.
The spanner kills Frankenstein's monster
Touched while the cyan spanner is carried, Frankenstein's monster
(MOVE_FRANKENSTEIN) scores 1000, is killed like any small creature, for 155 more, and
never comes back -- his slot is not refilled. Without the spanner he costs
8 a pass like the others. Watched in the emulator: put on the player, he
took the life force from 240 to 46 in 40 frames; with the spanner in the
inventory, the score went to 1155 at once and his record was emptied.
The mummy has an errand
Object $80, a red leaf-like thing, starts in room $09. If it is ever in the
mummy's room, MOVE_MUMMY abandons patrol and pursuit alike, walks to it, and on
reaching it moves it to room $6B, leaving it at the same x and y; then it
takes up its business again. Room $09 is one of the eight rooms the mummy can
be put in (with the red key), so in those games it does this at once.
Watched in the emulator: the object put in the mummy's room reached by the
mummy in 148 frames, and its room byte became $6B.
Never 100 per cent
The third figure on the end screens is a percentage of the castle seen
(DRAW_SUMMARY): COUNT_ROOMS_EXPLORED counts the rooms marked in the visited map, scores 2 for
each complete three and adds 1. All 149 rooms give 99; the starting room
alone gives 1. Watched in the emulator: a game won by walking from the first
room straight through the A.C.G. door, having seen two rooms, showed 01.
Food grows back
Eaten food is not gone for good. Once every 512 passes, REGROW_FOOD moves on to
the next of the eighty food records, and if it is empty and not in the
player's room it is filled again, in the same place, with one of the eight
kinds chosen from FRAMES -- not necessarily the kind that was eaten. A whole round of the
eighty takes about half an hour of play. Watched in the emulator: an emptied
record came back as food $56 when the cursor reached it. (Except the very
first record: see the bugs.)
Doors timed by the ROM
About half the plain doors in each game open and shut by themselves. At the
start, CHOOSE_TIMED_DOORS walks the doors reading a byte of the ROM for each -- the
Spectrum's own code used as random numbers -- and a byte below $70 makes that
door a timed one, shut to begin with. In play they share one countdown of 94
steps, taken on every other pass by whichever timed door is in the player's
room, so a room with two of them toggles twice as often. They move only while
the player is in their room: their handlers are run from the room's list and
nowhere else. (Read from the code. The first game converts 68 of the 125
plain door halves, counted in the simulator.)
One door, four walls
There is one picture of a door, not four. The top three bits of a door's +$05
choose one of eight drawing routines (PIXEL_DRAWERS), and the eight are the eight
ways to lay a rectangle down -- as stored, mirrored, turned either way, upside
down, a half turn, and mirrored across either diagonal -- each with a matching
routine for the colours (COLOUR_DRAWERS). A door's mode is its wall. The four locked
doors are the same picture again with four colour tables, and the furniture
uses the same eight modes: see the architecture page.
A crowded room slows the monsters, not the player
MAIN_LOOP runs flat out, moving every monster once a pass, and calls FRAME_TICK --
the player, the weapon, the sound and the clock -- each time the ROM's frame
counter has moved. So the player always moves at 50 frames a second, while
everything else moves once a pass, and a pass is longer in a room with more
furniture and creatures (about 1.7 frames in the empty first room, measured
in the simulator). Hunger is counted in passes too (PLAYER_TICK
drains on every sixteenth), so the roast lasts longer in a busy room.
The eight NOPs are not padding
Every one is a hole the game pokes an instruction into. Each has a LD (nn),A a
few bytes earlier that writes the AND, OR or XOR combining a sprite with what is
already on the screen. Remove them and sprite drawing breaks.
Two sprites share four bytes
Sprite $54 at GFX_54 says eighteen rows, which runs four bytes past GFX_58 where
sprite $58 begins. Neither is wrong. Drawing $54 reads all eighteen rows and the
seventeenth continues the taper of the sixteenth exactly; the byte they share,
$0C, is the last row's left half and also $58's row count. Three bytes saved by
a coincidence someone noticed.
A sprite that is entirely zero
$31 draws nothing at all. It is what DRAW_INVENTORY draws for an empty slot, and
the type of the drop controller at $EE58, a record that follows the player from
room to room so that the main loop runs PUT_DOWN on every pass.
Shape $0C is the trapdoor fall
Twelve nested rectangles, appearing in no room's entry -- if you read the first
149 entries of ROOM_TABLE. The table has 151, and the last is not a room but the
fall. Drawn with the walk limits closing in, concentric squares read as dropping
down a shaft. This one caught the author of these pages, which is why it is
written down.
What was checked and found sound
Every branch in the game -- 4823 instructions' worth of JP, JR, CALL and DJNZ --
lands on an instruction boundary. None jumps into the middle of another, which
is worth knowing in a game that patches its own code in eight places and enters
routines part-way through in a dozen more.
Nothing writes to an address below $4000, so no write is silently thrown away
against the ROM. And the disassembly reassembles to the same 30208 bytes the
tape produces, so nothing on these pages describes a byte that is not there.
Two graphics formats, chosen by sprite code
A creature or object is two bytes wide with a single byte of row count. The
pieces the rooms are furnished with -- the clock, the bookcase, the barrel, the
skeleton in chains -- are drawn by different code and carry a width as well.
Nothing in the bytes says which is which: the rule is the sprite code, and
codes above $A1 are furniture.
Reading the furniture as sprites makes each one nine or eleven bytes long
instead of a hundred and thirty, and leaves the rest of every one of them
looking like artwork nothing points at. That is exactly what this disassembly
said until it was compared against pobtastic's, whose graphics macro reads a
width where this one had assumed a row count.
And the rows are stored bottom up. Every picture here is flipped vertically to
match what the game draws.
Code and data that nothing reaches
Two routines are complete, correct and called from nowhere: NEXT_PIXEL_ROW,
which steps a screen address down one pixel row, and SETUP_BOTH_BANKS. Neither
address appears anywhere in the game as a call, a jump or a table entry.
Shapes $06 and $07 are two of the four orientations of the staircase, sharing
their edge list with $05 and $08 and differing only in their corners; the game
uses the other two.
With the 251 bytes of padding at the top of the image that comes to 444 bytes,
one and a half per cent, removable without changing anything a player would see.
An earlier version of this page claimed 556 bytes of unreferenced artwork on top
of that. There is none: those bytes were the tails of the room furniture, read
in the sprite format instead of their own and so cut to a fraction of their real
length. See the note beside GFX_FIRST.