A turn forgets that he was walking
Alien 8's robot turns through an in-between view (graphics 24-27) held for two turns, where Knight Lore's and Pentagram's heroes turn at once. The turn a turn starts takes no step (MOVE_PLAYER takes none with an in-between graphic), the next only lets him fall, and on the third TURNING_LEGS puts in the new facing and means to take a step if walk is held, by coming into MOVE_PLAYER at MOVE_IF_WALKING, which tests bit 2 of C, the controls. But first it makes the turn's sound (FOOTSTEP, at the entry that skips the frame test), whose loop counts C down to nought and hands it back so. The step is never taken, and gravity takes its full two units whatever is held. HANDLE_FORWARD, which makes the same sound as he walks, keeps BC round it.
Watched in the emulator, in room $2B, walking along U with A held and turning left with Z for one turn: U went 131, 134, 137, then the in-between view 26 for two turns and the new facing on the third, all at U 137, V 128, and V only began to grow on the turn after that. With BC kept round the sound (the poke), the new facing came with its first step, V 131. The same with X, turning right.
A life that starts on a valve destroys it
Knight Lore's depth sort has a case for two boxes that occupy the same space, and there it destroys a collectable; Alien 8 keeps it for its valves (BOXES_INTERSECT): unless one of the two is out of the collision tests, a loose valve (graphics 96-99) found sharing space with anything becomes graphic 64, the sparkle things vanish in, and at 65 its place in PLACES is emptied (SPARKLE_END_PLACE). The valve is gone for the rest of the game. The collision code keeps things from moving into each other, but a new life does not move the robot: it copies him from the start records (NEW_LIFE), at the spot where he last came through a doorway (read), and the appearing robot is in the collision tests. So a valve put down where he came into a room is destroyed the next time he dies in that room.
Watched in the emulator, the valve staged: a kind-0 valve in room $2B at U 128, V 128, on the floor, and the robot's death started with his start records in that room at the same spot. As he began to appear the depth sort destroyed the valve (the IY branch, with IX on his legs): its record went through graphics 65 and 1 to empty, and its place's graphic to 0. The same valve 22 units away was untouched.
Every valve may count. INIT_SPECIAL_OBJECTS deals the kinds round in turn and gives every sixteenth place an extra life instead, and places sixteen apart are of the same kind, so the kind that lands on the extra lives loses them: in a game with three extra lives that kind has six valves, as many as its sockets, and a valve lost this way leaves the twenty-fourth chamber out of reach (inferred from the dealing; see the facts).
A stray OUT pages a 128K's memory
READ_KEYS does OUT ($FD),A before IN A,($FE), with the half-rows to read in A. OUT (n),A puts A on the top half of the address bus, so the port is A * 256 + $FD. A 48K ignores it. A 128K takes any port with bits 15 and 1 clear as its paging port, $7FFD: every half-row value with bit 7 clear is a paging write. The menu tune's "any key" test (PLAY_TUNE_ONCE) reads with A = 0, which pages the 128's editor ROM in and does no harm, since the game never calls the ROM (it only reads its bytes as noise). But the pause test (HANDLE_PAUSE) reads $7E at the end of every turn, whatever the controls, and the keyboard reader reads SPACE's half-row as $7F: either puts RAM bank 6 or 7 at $C000, where the code from $C000 up and the screen buffer are, and locks the paging.
Watched in the emulator's 128K, from the loaded game put into a 128K snapshot with the 48 BASIC ROM and bank 0 paged in, as the 128's Tape Loader leaves it: the menu worked, with ROM 0 paged in by the tune's key test; at the end of the first turn of play READ_KEYS was called with $7E from the pause test, the paging port became $7E -- bank 6 at the top, the second screen shown, locked -- and the machine ran off into the ROM. So on a 128K the game must be run in 48 mode. Pentagram has the same OUT, and the same fate. The poke that removes the OUT is with the pokes.
Ten lives would show as none
LIVES counts in binary -- NEW_LIFE takes one with DEC, EXTRA_LIFE adds one with INC -- but PRINT_LIVES prints it as two BCD digits, with the font itself as the base so that digit n is the nth character (FONT). Ten lives, $0A, print as 0 and the eleventh character, which is a second nought (see the facts): 00. It cannot happen in play. A game starts with five, the first life takes one, and INIT_SPECIAL_OBJECTS deals two or three extra lives a game, never more (worked out for every value of the random number it starts from), so a player who never dies ends with at most seven.
The panel's lives with nine The panel's lives with ten, showing 00
Drawn by the game's own code in SkoolKit's simulator: a game started from the menu, LIVES staged at 9 and then at 10 as a life begins beside an extra life, which the robot touches as he appears. Watched in the emulator too: nine lives and an extra life made ten, and the panel said 00.
A collapsing block empties the place at address 0
Graphic 65, the last frame of the sparkle a thing vanishes in, empties the thing's place in PLACES through the address in +$10 and +$11 of its record (SPARKLE_END_PLACE), which is right for an extra life. But a collapsing block (COLLAPSING_BLOCK) goes through the same frames when it is stood on, and its +$10 and +$11 are nought: it writes a zero to address 0, which is ROM and ignores it. Watched in the emulator, in room $12, the robot put on the stack of two collapsing blocks: each became graphic 65, and a logpoint on the write showed HL = $0000 both times; the ROM's first byte was unchanged. Harmless.
The socket projects the wrong record
A chamber's socket (SOCKET) brings its sparkle back when nothing lies in the room from the places and the record after the socket is empty -- as when the sparkle vanished because a valve lay there and the valve has gone. It puts the sparkle's graphic in the record and then jumps to CALC_PIXEL_XY_IY, which projects the record at IY onto the screen. IY is whatever an earlier update routine left there, not the sparkle. It does no harm: the record projected is recomputed from its own position, and every object drawn is projected again by CALC_PIXEL_XY_AND_RENDER anyway, so the new sparkle is drawn where it should be. Watched in the emulator, in chamber $0C with a valve of the wrong kind in the room and then taken away as a pick-up takes it: at the jump IY was $5B88, the robot's legs, and the sparkle came back over the socket the next turn.
The hammer leaves the robot's head green
In the scene after a lost game the robot is re-programmed: a glove, a hook and a hammer take turns to strike him. Each piece of the scene colours the character cells it covers ($AC21), except any that are bright green, $44 -- the hammer's colour, so that nothing paints over the hammer as it swings. But once the hammer has swung back up, the cells it coloured on the robot's head are still bright green, and the robot, which skips them too, never gets them back. Watched in the emulator: twenty turns into the scene the robot was cyan all over; three hundred turns in, after the hammer's blows, the top of his head was green.
The lower halves' footsteps are silent
The two-part creatures (templates 17 to 19) put their lower half, graphic 11, in a record of its own, and its update routine (LOWER_HALF) asks for a footstep each time the upper half moves. LOWER_HALF_STEP plays one only for an even graphic -- Knight Lore's walkers changed graphic as they walked -- and 11 is odd, so it returns at once, every time. Read from the code; the build's sessions never ran the rest of LOWER_HALF_STEP.
A room of more than 52 records would run away
BUILD_ROOM fills records from the fifth up, as many as the room's backgrounds and templates need, and then clears the rest, stopping when its pointer is exactly BELOW_BLOCK, the end of the records (BUILD_CLEAR_REST, $CCD0). Nothing checks that the room fitted: a room of more than 52 records would build past the end of the records, and the clearing loop, testing for equality only, would never meet $6288 again and would clear its way through memory. None does. Counted from the room data the way the builder reads it, the fullest room is $74, with 49 records, three to spare, and nothing adds records to a room once it is built -- the socket's sparkle only reuses its own. Watched in the emulator: room $74, entered, had 49 records in use. Latent.
A sprite one row high would turn over 256 times
Sprites are turned in place (VFLIP_SPRITE_DATA): upside down by swapping rows in pairs from the ends inwards, half the height times. A sprite one row high makes that nought, and the DJNZ loop would run 256 times, through whatever follows the sprite. Only one sprite is one row high, graphic 5, the sides of the border (BORDER_DATA), and it is only ever mirrored, never turned upside down, so it never happens. Read from the code and the graphic table; Knight Lore's routine is the same.
A third valve in a room would overrun
FIND_SPECIAL_OBJS_HERE, as a room is built, puts every place in use in that room into records 2 and 3, and clears what is left of them. Nothing stops it at two: a third would go into record 4, the room's first, and the clearing after the loop would never meet record 4 again and would run on through memory. The 36 places start in 36 different rooms, and a valve is put down only into an empty one of the two records (TAKE_OR_LEAVE), so a room never holds three. Knight Lore's find_special_objs_here has the same shape. Read; latent.