1988 · SSI

Pool of Radiance

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/pool-of-radiance with me to Gold.

Every block of the ruined city is a 16 by 16 grid of walls, stored in 1,024 bytes. Everything that happens there, from the city watch moving the party along to the dragon at the end, is a script: a small program in the game's own language of 62 commands, read as the party walks.

01 · The game

A party of six in the ruins of Phlan

Pool of Radiance was the first computer game made under licence from TSR's Advanced Dungeons & Dragons. The player builds a party of up to six characters, choosing each one's race, class and alignment and rolling the six ability scores. The party arrives in New Phlan, the one civilised quarter of a city overrun by monsters, and the city council sends it out to clear the rest, block by block.

Towns and dungeons are seen from inside, in a small picture framed at the top left, and the party moves one square at a time. When monsters appear the game offers combat, waiting, fleeing, advancing or talking. A fight moves to a battlefield seen from above, where each character in turn swings, shoots, casts a spell or flees. Between fights the party camps to heal and memorise spells. The game ends when the party kills the dragon in which Tyranthraxus, the spirit behind the monsters, is living.

The title screen
The title picture, with its tune.
The 3D view at New Phlan's gateway
New Phlan: the 3D view, the party, the clock and the square, and the adventure menu.
A fight with kobolds
A fight with kobolds, on the battlefield seen from above.

02 · The screen

The 3D view is drawn with text characters

At New Phlan's gateway the play screen uses no bitmap and no sprites. Everything on it, from the frame of rope and the party list to the picture of the street ahead, is 1,000 characters on a grid of 40 by 25. Monsters met in the view are the one thing drawn with sprites ($CFF8).

The play screen at New Phlan's gateway, drawn by this page from the game's own memory: the screen, the character shapes and the video chip's settings, recorded over one frame in the emulator. All 104,448 pixels match the emulator's picture of the same frame.

The C64's video chip draws a text screen from two things in memory: a list of 1,000 character numbers, one for each place on the grid, and the shapes of 256 characters, 8 bytes each. Pool of Radiance keeps its list at $CC00 and its shapes at $D000, and turns on multicolour mode ($3A72). In that mode a character whose colour number is 8 or more is drawn as 4 double-width pixels across and 8 down, in up to four colours, and any other character in single pixels of one colour. The place $D000 is also where the processor finds the sound, video and input chips. The video chip always reads the memory underneath, but the processor has to switch the chips out of the way to write there, holding off the interrupts while it does ($84D8). The pictures shown in the window, a whole scene or a body and a head, are drawn by rewriting the shapes of characters 128 to 255 ($841C).

03 · Music

Music: the title tune, played by the game's own driver

There is one tune in the game. It plays over the title picture until a key is pressed, or until it has ended and the title has waited through 256 more silent passes.

The page plays the tune with the game's own sound driver, the code that turns the tune's bytes into sound. The driver and the tune are copied from the title's memory ($BA00-$BDD2 and $C400-$CF5A, addresses in the C64's memory written in hexadecimal, each a link to the code) and run on a model of the C64's processor, the 6502. What the driver writes goes to a model of the SID, the C64's sound chip. The page starts the tune the way the title does (start_tune, $0D4A) and calls the driver 60 times a second, as the C64's timer interrupt does, so the chip gets the same values in the same order as in the game. The notes are tuned for an American (NTSC) machine, and the page plays them at that machine's speed. The lowest notes, near 33 Hz, are below what a laptop's or a phone's speaker can play.

The driver plays three streams of commands, one for each of the SID's three voices. A note is two bytes: the first gives its length and its instrument, the second its pitch. There are eight lengths, from 6 to 96 sixtieths of a second ($BD7B), and a quarter note of 24 makes the tempo 150 beats a minute. There are eight instruments of nine bytes each ($BD8B). Each gives the waveform, the envelope (how the note's volume rises and falls), a transposition (a shift up or down in pitch), and the pulse width, which changes the tone of a square wave. A note takes whichever voice is free, so the title tune is written as a single stream and still plays chords. A pitch byte with its top bit set says another note starts at the same moment, and that note finds another free voice.

The tune is entry 12 of the title's music table ($C400). Its 1,100 notes and 92 rests last 5,976 sixtieths of a second, a minute and 40 seconds. Entries 13 to 19 start the same stream partway through, at the beginning of each of its later sections. The game never asks for them. The buttons after the first play them.

04 · Sound

Sound: eleven effects from the same driver

Once play begins, the title's driver is replaced by a twin, SOUNDFX. It has the same code, with eleven short sounds and a silence in place of the tune.

The game's SOUNDFX driver and sounds ($BA00-$BF53), run as for the tune. Each button starts a sound the way the game does: a call to $BA03 with the sound's number in the processor's A register. Sound 0 is the silence.

The sounds are not made of notes. Each one sets a voice's frequency, waveform and envelope directly. The driver then slides the frequency or the pulse width a little on every call, so a single command makes a rising burst or a warble. The table shows where the game asks for each sound.

SoundWhen it playsAsked for at
1A missile or a spell flies across the battlefield$657B
2An attack misses$17E3
3A spell is cast in a fight$A84A
4The dragon roars in the last scene$093B
6An attack hits, a spell does damage, or the party tries to bash a locked door$17E3; $0F13
8A step, in a town or a dungeon and on the battlefield; some scripts ask for it too$098B
9A step into a wall$08F4
10The spirit leaves the dragon's body; one other script asks for it$0A0B
5, 7, 11Never asked for: the game's code does not start them, and neither does any script that starts a sound through its CALL command

05 · The maps

Each block is a 16 by 16 grid of walls

Every town quarter and dungeon level is one file of four pages of 256 bytes. Each of the 256 squares has one byte in each page.

The AREA command's map in the game
Click a square.

Left: New Phlan, the block the game starts in, drawn from its map file GEO00 as the game loads it at $0400. White lines are walls, a gap with yellow ends is a door that opens, and red is a locked door. Right: the game's own AREA command at the gateway, showing the 11 by 11 squares at the top left of the same map. AREA draws only the north and east side of each square ($1266), so a wall the map gives only to a south or west side does not show there.

A square's number is its row times 16 plus its column ($C29D). The first page holds the walls on a square's north and east sides, four bits (half a byte) each, and the second page the south and west sides ($C39A). A wall's number picks one of the wall pictures the area loads, and 0 is open. The fourth page holds two bits for each side that turn a wall into a door. A 1 is a door that opens when the party walks into it, and a 2 or 3 is a locked one, which the party must pick or bash ($0E64). Only the strongest characters can bash a door of type 3. The third page holds a byte for each square, which the 3D view reads with the walls ($C3D2).

A wall between two squares is stored twice, as a side of each square, and the two can differ. Each side has its own picture number, and in 16 of the 29 maps some walls are there on one side only. A step is judged by the side the party faces in its own square ($10EC), so such a wall stops the party from one direction and lets it through from the other. A door the party bashes open is marked open on both sides ($0EE8). Every one of the 29 maps on the disks is drawn on the Maps tab.

06 · The scripts

Everything that happens in a place is a script

Most blocks have two files on the disks: a map, named GEO and a number, and a script, named ECL and the same number, so New Phlan's are GEO00 and ECL00. An ECL file is a small program written in the game's own language of commands. The game reads it one command at a time and carries each one out, where the rest of the game is machine code that the processor runs directly. The game is split into modules, programs loaded from disk one at a time, and the adventure module is the one that walks the party through towns and dungeons. It does not know where the shops are or what a room holds. The script decides, and the module runs it.

New Phlan's script, ECL00, decoded from its bytes as the game reads it ($1581), loaded at $9900. A choice above shows where the game enters it. An address in square brackets is a variable in the game's memory: [$6DD2] and [$6DD3] are how often a rest is interrupted, and [$49C9] is the hour. Command names are descriptions of what each command's routine does.

A script starts with five GOTO commands at fixed places, which are its five entries ($1A0B). The module enters the script at the first before every step and at the second when the party arrives on a square. It enters at the third when the party makes camp, at the fourth when the party comes back from a camp whose rest was interrupted, and at the fifth when the block is first entered. New Phlan's camp entry is why camping in the town never lasts. It sets the rest to be interrupted on every pass, with a chance of 101 in 100 against a roll of 0 to 99 ($1E0F). The script's fourth entry then has the city watch move the party along.

There are 62 commands ($15A9). A command is followed by its operands, the values it works on, and each operand starts with a byte saying what kind it is ($1663). It can be a number, the value stored at an address in memory, a text packed six bits to a letter, or an address itself. Among the commands are arithmetic, comparisons, menus, monster encounters and treasure. Six IF commands skip the next command when their test fails, and CALL runs the processor's own machine code anywhere in memory.

07 · Creating a character

Each ability score is the best of six rolls

A character has six ability scores, such as strength and intelligence. The game rolls three six-sided dice six times for each score and keeps the highest total.

Each press runs the code of GEN, the character-creation module (roll_ability, $0D1F), and the dice code it calls in the part of the game that stays in memory, on a model of the 6502. The page first sets the six bytes of the game's random-number generator ($03C2-$03C7) at random. The highlighted total is the one the game keeps.

A single roll of three dice averages 10.5. The best of six averages just over 14, and comes to 15 or more a little under half the time. A score of 3 needs all eighteen dice to come up 1. GEN then adjusts the score from a table by race and gender ($0D4A), which gave a new human one point more strength and constitution than the dice did, and holds it between that race's and gender's lowest and highest score.

08 · Combat

To hit, a d20 must reach THAC0 minus the target's armour class

An attack is a roll of a d20, a twenty-sided die. THAC0 is AD&D's "to hit armour class 0": the roll a character needs to hit a target of armour class 0. Lower is better for both numbers.

The rolls of a d20 that hit, as the attack routine judges them (hit_roll, $1272): the roll plus 60 less THAC0 must reach 60 less the armour class. A 1 always misses and a 20 counts as 100, which always hits. The side's own bonus, 0 here, is added too ($1613), and a spell or an item can change the roll before it is judged.

The game keeps armour class and THAC0 as 60 less their value ($3A36), so that a better figure is a bigger byte. A new first-level thief has a THAC0 of 21, and a character with no armour an armour class of 10.

Which armour class counts depends on where the blow comes from ($12B1). Each combatant has a front and a rear armour class. A backstab, and a swing at a character moving away, strike the rear one. So does an attack from a side the target does not face, once the target has been attacked twice since its last turn from directions far enough apart.