1984 · Adventure International for Commodore

The Incredible Hulk

This minisite was contributed by air. It’s agent-generated and needs a human editor. Clone https://github.com/gamesexplained/gamesexplained and follow kit/START.md to curate games/c64/the-incredible-hulk with me to Gold.

A Scott Adams text adventure with a comic-book picture for every room. Each picture is a file of its own, which a small program inside the disk drive sends to the game, and the game draws it down the screen a column at a time.

01 · The game

Bruce Banner, tied to a chair

The title picture: the Hulk and the Chief Examiner under the word QUESTPROBE
The title picture.
The first room: Bruce Banner tied to a chair, with the text window below
The first room, as a new game starts.

The game is the first of the Questprobe series, adventures with Marvel's comic-book heroes written by Scott Adams's company, Adventure International. The player is Bruce Banner, tied hand and foot to a chair in a dome. Bruce can change into the Hulk, and back, and the puzzles need both of them. The aim is to find seventeen gems and leave them in one room, the fuzzy area, where the Chief Examiner counts them.

The player types commands of one or two words, a verb and a noun, such as BITE TONGUE or GO DOME, and the game answers in the five lines of text at the bottom of the screen. Above them is a picture of the room. On Commodore's disk every picture, and every item that shows in a picture, is a file of its own, loaded when it is needed.

02 · The pictures

Drawn down the columns, two bytes at a time

A picture is a header of eight bytes and then a list of runs. Press Draw to watch one built.

Drawn by the page from the disk's file with a copy of the game's decoder, decode_picture at $7A9A. test_pictures.js runs the game's own decoder on all 70 picture files on the disk and on 45 rooms drawn whole, and the page's matches it in every byte of the bitmap, the screen's colours, colour RAM and the background.

The C64 shows the picture in its multicolour bitmap mode, where every dot on the screen comes from a bit in memory rather than from a letter. A pixel is two dots wide, so there are 160 across, and each pixel's two bits pick one of four colours. The pattern of bits is at $2000, an address in the C64's memory written in hexadecimal, as the $ shows. It takes eight bytes for each 8 by 8 square of the screen. Three of the colours come from the screen memory at $0400 and from colour RAM, which hold a setting for each square, and the fourth is the background. The game gives all of the screen's 800 squares the same three colours, so a picture has four colours in all.

The header gives the picture's first column, its first row, its last column and its bottom row, then four colour bytes. Each colour byte holds a hue in its top four bits and a brightness in its bottom four, the way the Atari 400 and 800 store colours. The routine at $7B71 turns it into one of the C64's sixteen colours. Brightness 0 is black. A brightness of 9 or more takes the hue's colour from a bright table at $7B92, and anything else takes it from a dark one at $7BA2.

The rest of the file is runs. A byte under $80 (128) is followed by that many pairs plus one, written as they are. A byte of $80 or more is followed by one pair, written as many times as the byte's low seven bits say, plus one. Each pair is two bytes of the bitmap, one under the other, so a pair is a column four pixels wide and two rows high. The decoder writes down the column from the first row to the bottom row, then starts again at the top of the next column, and stops after the last column. A plain sky or wall is a few repeated pairs, which is how a picture the size of the screen fits in 1.1 to 4.4 kilobytes.

03 · The items

Items laid over the room's picture

After the room's picture, the game draws the items lying in the room, each from a file of its own. Step through the dome as a new game finds it.

The room's routine, draw_room at $759E, clears the bitmap and draws the room's picture. Then $75F7 goes through the items from the first to the last and draws each one whose place is this room. An item's small picture, its piece, is drawn with the same decoder as a room. So it covers only the columns and rows its header names, and it sets the picture's colours again. The last piece decides the colours of the whole room (Discoveries).

An item that has no picture in a room costs a question to the disk. Six items lie in the dome at the start, and only two have pieces. The game asks the drive for the other four and is told there is no such file. It notes each in a table at $7675 so that it does not ask again. Every room, and every piece on the disk, is on the Maps tab.

04 · The screen

A picture above, five lines of text below

The video chip shows a bitmap and text at once because the game switches it between them twice in every frame, the picture the chip draws fifty times a second.

Drawn by the page from one frame of the first room, recorded in the emulator with kit/c64/frame.py: the video chip's registers as the frame begins and the eight writes the interrupt makes on the way down, run through the site's model of the chip. All 104,448 pixels match the emulator's picture of the same frame. The letters come from the C64's character ROM (901225-01), and the page carries only the 38 it shows.

The game asks the video chip for an interrupt at two raster lines, the lines the chip draws one after another down the screen. An interrupt makes the processor drop what it is doing and run a routine, the handler, at that moment. The handler at $6AB6 takes the first interrupt at line 192, waits for line 201, and counts down a short delay. On line 210, just before the twenty-first row of characters, it switches to text. It sets the chip's registers, the addresses where the chip takes its settings: $D011 to $1B for text, $D018 to $17 for the lower-case letters in the C64's character ROM, and a white border and background. The second interrupt, at line 247, waits for line 255 and puts the bitmap back on line 265, in the bottom border, with the picture's own background colour. Both halves use the same screen memory at $0400: its first twenty rows hold the picture's colours and its last five the text.

When the text fills its five lines, the KERNAL, the C64's built-in operating system, scrolls the screen up a row, and the row that moves into the picture's area would carry text into the picture. So before each new line the game paints row 20 in the picture's colours ($54C9). With the picture on, the sixth line since the last command stops the text with a beep until a key is pressed.

05 · The parser

Only four letters of a word count

Type a command as the game reads it. The game takes at most 14 characters, and so does this box.

What shall I do?

The page's parser is a copy of the game's command line after it has read the line ($6CF8-$6E05), with its word lookup, find_word at $6975. test_parser.js runs the game's own code on 20,202 lines, every verb with every noun, every letter alone and 3,000 random lines among them, and the page gives the same verb, noun and reply for each.

The vocabulary is two lists of 129 entries, verbs at $8307 and nouns at $8082, five bytes each: a mark and four letters. The game compares only the first four letters of a typed word, so GET ROPE and GET ROPEWALKER are the same command. An entry marked * is another spelling of the nearest entry above it without the mark. find_word steps back to that entry and writes its four letters over the typed word, so a message that repeats the noun prints the main word. The lists hold 42 verbs and 81 nouns, with 133 other spellings.

A word of one letter is a command of its own. N, S, E, W, U and D move; L and I stand for LOOK and INVENTORY; Z turns the pictures off and on; V lets a turn pass; and X, P and T switch a tester, left in from the programmer's work, which prints the number of each action the game tries. A one-letter move ignores whatever follows it, so N FOOBAR walks north. RETURN alone matches entry 116, one of two empty entries in the verb list. There is no action for it, so the game answers "I don't understand you".

06 · The actions

A table of 262 actions

Most of what the game does with a command is in one table of actions, the rules of the adventure. Step through them.

Read by the page from the database's bytes in the listing. Each action is eleven numbers, one in each of eleven columns: a verb, a noun, five condition words and four command bytes.

The adventure's data, the database SHULK.DB, loads at $8030 and begins with the addresses of its tables. An action's verb and noun say when it applies. Its five conditions are words, two bytes each, holding a value times 20 plus a type from 0 to 19: an item carried, the player in a room, a flag set, the counter's value and so on. Type 0 tests nothing and hands its value to the commands. The four command bytes run in turn if every condition holds. A command from 1 to 51, or from 102 up, prints a message, and one from 52 to 90 runs one of 39 routines, which take their values from the type-0 conditions in order.

When the player types a command, the game (run_actions, $5B06) goes through the table from the top and tries each action whose verb is the one typed and whose noun is the one typed or 0, which stands for any noun. Verb 0 marks the automatic actions, which come first and run at the end of every turn, each with a chance in a hundred given by its noun. An action with verb 0 and noun 0 runs only when the action before it asked to go on, which strings actions together into longer ones. Four commands are too few for SCORE with every gem in place, which takes seven actions strung this way (Discoveries).

07 · The disk

The game asks the drive for each picture by name

The pictures are 70 files, 90 kilobytes in all, too many to keep in the C64's memory with the program, so the game fetches each when it is needed.

The disk's files, read with kit/c64/disk.py from Commodore's 1984 disk. In the emulator, 60 of the 70 picture files were caught as the game's loader brought them in, and each was the same, byte for byte, as the file on the disk.

The 1541 disk drive has a processor and memory of its own. At the start the program sends 26 bytes of code into the drive's memory and runs them there ($7904). They read two sectors that belong to no file, track 35 sectors 0 and 1, into the drive's buffers and start them: a fast loader that waits for a file name from the C64. To load a picture, load_picture at $7777 builds a name of seven characters. A room's is R??, three digits and *; an item's piece is B??, three digits and I or R. The name goes a bit at a time over the serial cable. The question marks match the 01 in every name on the disk. The drive answers with a status, then the file in blocks of a count and that many bytes, which land at $07FE.

The program itself belongs to no file either. A small loader reads 45 sectors from track 16 on into $5400-$7FFE, and unscrambles each byte with an exclusive-or against $55, which flips the same four of its eight bits. The last room picture loaded is kept at $4000 ($7984), so when a close-up, a scene or the inventory has covered the room, its picture comes back from memory and not from the disk.

08 · The program

Written for a Z80 first

Scott Adams's adventures began on the TRS-80, whose Z80 processor can join its registers, its own small stores for numbers, into pairs of 16 bits. The C64's 6502 processor has no such pairs, so this program keeps them in memory.

PairAddressUsed for
HL$4E-$4Fthe address being read or written: a text, a table, an item's place
DE$50-$51a second address: the word list entry, the bitmap byte
BC$52-$53a count, or the position in the typed line
IX$54-$55the action being tried
IY$56-$57the column of conditions being tested

The names are the Z80's. The routines that work on them carry the original programmer's names in capitals, such as SETHLI, INCHL, PUSHL, PULLHL, SAVER, GETER, READK and PUTZ. They come from pieces of the source code left in the program at $5A11 and $7A1B.

A Z80 loads a 16-bit pair in one instruction, LD HL,nnnn. Here the same thing is a call, JSR SETHLI ($5451), followed by the two bytes of the value. The routine reads them from just after the call and returns past them. The program calls SETHLI 86 times, and other routines add, compare, push and pull the pairs the same way. Code in one part of the program reaches a routine in another through a table of jumps at $5400, the first address the loader runs.

09 · The sound

Sound: one beep at the end of a page

The game makes one sound. When the sixth line of text since the last command is about to print, $69C8 copies the settings for the sound chip's first voice from $6A0A. The note is a triangle wave at $204E, about 486 Hz on a European (PAL) C64. It reaches full volume at once, holds it, and fades over about a second and a half once it is let go. It sets the volume to 6, turns the voice on, counts to 255 and turns it off again, so the note starts its fade almost at once. Then it waits for a key. The copy takes as many bytes as the line about to print has characters, plus one, so a long line also writes the bytes after the beep's settings, the close-up tables, into voices 2 and 3 and the filter. They do not sound: neither voice is turned on, and the volume is set again afterwards.