The drop timer reads one record eighteen times
Things fall from the sky once DROP_TIMER has run out (SKY_DROP), and RESET_DROP_TIMER sets it at the start of every room and after every drop. By its shape it counts the quest items still to do -- a loop over the eighteen quest records at QUEST_RECORDS, adding one for each graphic of 112 to 115 -- and sets four turns for each, plus eight: 8 to 24 turns. But the loop loads DE with the record length and never adds it to HL. It tests the first record eighteen times, so the timer is 80 turns while the first quest item (the one in room 122) is still to do, and 8 once it is done, whatever the other three are.
Watched in the emulator, reading DROP_TIMER at the first turn in room 30: 80 with the quest items as a new game has them; 8 with only the first staged as done; 80 with the other three done and not the first; 8 with all four. Meant: 24, 20, 12 and 8.
Nothing done is 56 per cent
PERCENTAGE adds up the game-over score -- half the rooms seen, at most 54, 4 for each quest item done and 6 for each collectable placed -- and counts it into BCD one at a time with ADD A,1 / DAA in a DJNZ loop. With a sum of 0 the loop runs 256 times, not none, and 256 in BCD with the hundreds dropped is 56. The sum is 0 whenever a game ends before a second room has been seen, since one room halves to nothing. So a player who loses every life in the room he started in is told he has done more than half the quest.
The game-over screen of a game lost in its first room
The picture was drawn by the game's own code in SkoolKit's simulator: a first game started from the menu, the lives taken away at its first turn and the player killed; the game's own death, game over and percentage followed, and printed 56. Watched in the emulator too: the same in the start room gave 56, and with one more room seen, 01.
Steering by direction was left half done
Knight Lore let a joystick steer by direction -- push the way you want him to face -- and Pentagram keeps the code: HANDLE_LEFT_RIGHT has a directional branch, and CHK_PICKUP_DROP takes the pick-up control from bit 5 of INPUT instead of bit 4 in that mode, which bit 3 of CONTROL selects. No menu choice sets bit 3, so it is reachable only by a poke, and there it is broken three ways. READ_CONTROLS never sets bit 5, so nothing can be picked up or put down. The directional code takes bit 4 as down, but every joystick reads down as jump (bit 3) and bit 4 is the pick-up keys, so the stick can never turn him to face down and left, and the pick-up keys turn him instead. And FLASH_MENU would flash the start line of the menu, where Knight Lore had a line for this mode (read, not seen).
Watched in the emulator, with the cursor joystick chosen and a bucket staged beside him in room 30: the bottom-row key picked it up with CONTROL 4; with CONTROL 12 (bit 3 set) the bucket stayed where it was and he turned from facing 0 to facing 3; the stick's down (6) left him facing 0.
Too much in room 87 crashes the game
LIST_DRAWN writes the number of every record to be drawn into DRAW_LIST, and an $FF after the last. The list has 48 bytes -- Knight Lore's size, for its forty records -- but Pentagram has 54, and nothing checks: a list of more than 47 records runs over the first bytes of SORT_AND_DRAW, which follows it. On the first turn in a room everything is listed, because everything has to be drawn. Counted from the room data the way BUILD_ROOM reads it, the fullest rooms fill, of their 48 records: 87 (43), 80 (42), 2 (40), 59 (40), 93 (39). Room 87 lists 45 with the player's legs and body, 5 records to spare -- and the quest things he carries fill records too when they are put down there. Three of them are enough.
With 48 listed, the $FF lands on the XOR A that begins SORT_AND_DRAW and stays there. $FF is RST $38: every turn from then on starts drawing with a call to the ROM's interrupt routine, which ends with EI, so interrupts come on in a game written to run without them. The next frame interrupt lands while the sprite drawer (DRAW_OBJECT) is reading a sprite with the stack pointer pointed into it, and the return address pushed there overwrites the sprite; the game goes wrong from there. With more listed, record numbers overwrite the code as well.
Watched in the emulator, with collectables' quest records staged into room 87 (as if carried there and put down) and the room entered by the game's own restart: with two, 47 were listed and 300 turns went by normally; with three, 48 were listed, SORT_AND_DRAW began with $FF, the ROM's interrupt routine ran over and over during the first turn -- called at first from $B58B, then from all over the drawing code with the stack inside sprite data. In that run the game never finished its first turn in the room; in another, stopped differently, it went four turns with its variables overwritten -- the turn counter and the room number read as nonsense -- and hung. With five, 50 were listed and it ran six turns before it hung.
The well counts one bolt's puff and not the other's
BOLT_TOUCHING asks whether either of his two bolts is touching the well, with HIT_TEST, which ignores a puff -- graphics 64 to 71, what a bolt turns into when it hits something. The second bolt goes in at the top, but the first goes in at HIT_TEST_Z, past the test for a puff. So a bolt fired from the first record counts for the turn it touches the well and then for each of the eight turns its puff hangs there; one from the second record counts once. WELL wants 32.
Watched in the emulator, logging the well's count at the instruction that adds to it, in room 71 with a shot every five turns: 32 counts in 35 turns, from 7 shots, all but a few of them made by the first record's bolt or its puff. With the first record sent through the puff test like the second (below), the same shooting took 32 shots and 160 turns, one count a shot. Which of the two was meant is not known; the difference is only that they are not the same.
POKE 53182,22
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. But in play the keyboard reads SPACE's half-row as $7F, and the pause test (PAUSE) reads $7E every turn, whatever the controls: that puts RAM bank 7 or 6 at $C000, where most of the code and the screen buffer are, and locks the paging. The game cannot survive its first turn.
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 first turn of play READ_KEYS was called with $7F from the keyboard reader, the paging port became $7F, locked, and the machine ended in the ROM, reset. So on a 128K the game must be run in 48 mode. Knight Lore's keyboard routine has the same OUT, and its callers pass $7E too; it was not tried on a 128K. The poke that removes the OUT is with the pokes.
The last quest item's link is bent
When the fourth quest item is done, ALL_FOUR_DONE walks the quest records setting bit 4 of each pentagram piece's flags, and with each piece it also sets bit 0 of +$11 of IX -- the quest item that called it. +$10 and +$11 are that object's link to its own quest record, so the link now points 256 bytes further on. Nothing follows a quest item's link -- only a carried thing's link is used, by TAKE_OR_LEAVE, and a quest item cannot be carried -- and the record is matched by graphic when he leaves the room (QUEST_OUT_OF_ROOM), so it does no harm. What the SET was meant to do is not known.
Watched in the emulator, with three quest items staged as done and the bucket staged as carried into room 122 and put down: it rose, flew to the stone and was used up in 58 turns; the stone became graphic 116, QUEST_DONE went to 4, the lives from 4 to 5, PENTAGRAM_ON was set, and the stone's link went from $D432 to $D532.
Lives are added without BCD
LIVES is printed as two BCD digits (DRAW_LIVES) and a quest item adds one with a plain INC (QUEST_ITEM); RESTART_PLAYER takes one with a plain DEC. Past 9 the INC would make $0A, not $10. It never happens: a game starts with five, the first life takes one, and there are only four quest items, so a player who never dies ends with eight. Read from the code; the one extra life was watched (see the bug above).