Quill QDB file format (v0.2)
.QDB is the format used for games produced by the Quill adventure system
under CP/M. It's the only distribution format of Quill games I've seen where
the database is in a separate file from the interpreter.
This document has been produced solely by studying the Amstrad PCW port of
the Very Big Cave Adventure, so I may well have missed aspects of the .QDB
file format not covered by this particular implementation.
The .QDB file is assumed to load in memory at 0x0F00. It begins with a
header:
0F00 DB 0x00 ;Unknown -- zero in both CAVE1.QDB and CAVE2.QDB
0F01 DB 0x01 ;Database version, 1
0F02 DB debugmode ;Nonzero in debug mode (interpreter prints a
;banner at startup, and issues warnings if an
;out-of-range object / location / flag is
;accessed).
0F03 DB objcount ;Number of objects
0F04 DB loccount ;Number of locations
0F05 DB msgcount ;Number of messages
0F06 DB syscount ;Number of system messages
0F07 DW response ;Address of response table
0F09 DW process ;Address of process table
0F0B DW objects ;Address of objects table
0F0D DW locations ;Address of locations table
0F0F DW messages ;Address of messages table
0F11 DW sysmsg ;Address of system messages table
0F13 DW connections ;Address of connections table
0F15 DW vocab ;Address of vocabulary table
0F17 DW ob_locs ;Address of object initial locations table
0F19 DW ob_words ;Address of object words table
0F1B DW end ;Address of database end
The format of the individual tables is then:
Process / Response
The Process table is executed before user input, the Response after. The
Response table has four bytes per entry:
DB word_id ;Verb to match, 0xFF is a wildcard
DB word_id ;Noun to match, 0xFF is a wildcard
DW address ;Address of bytecode
The Process table has only two bytes per entry: the address
of the bytecode. All entries are executed with no checking
of verb / noun.
The end of the table is marked by an all-zeroes entry.
As in PAW, but in a change from earlier versions of the Quill, there is
no distinction at the bytecode level between conditions and actions; they
can be interspersed as the game author pleases. They are:
- 0x00 loc: AT loc
- Execution continues if the player is at the specified location.
- 0x01 loc: NOTAT loc
- Execution continues if the player is not at the specified location.
- 0x02 loc: ATGT loc
- Execution continues if the player's location number is higher than the
number specified.
- 0x03 loc: ATLT loc
- Execution continues if the player's location number is lower than the
number specified.
- 0x04 obj: PRESENT obj
- Execution continues if the specified object is in the same location as
the player, carried, or worn.
- 0x05 obj: ABSENT obj
- Execution continues if the specified object is not in the same location as
the player, carried, or worn.
- 0x06 obj: WORN obj
- Execution continues if the player is wearing the specified object.
- 0x07 obj: NOTWORN obj
- Execution continues if the player is not wearing the specified object.
- 0x08 obj: CARRIED obj
- Execution continues if the player is carrying the specified object.
- 0x09 obj: NOTCARR obj
- Execution continues if the player is not carrying the specified object.
- 0x0A number: CHANCE number
- Execution continues if a pseudo-random number is less than number.
- 0x0B flag: ZERO flag
- Execution continues if the specified flag is zero.
- 0x0C flag: NOTZERO flag
- Execution continues if the specified flag is not zero.
- 0x0D flag const: EQ flag const
- Execution continues if the specified flag has the correct value.
- 0x0E flag const: GT flag const
- Execution continues if the specified flag has a value greater than the
amount indicated.
- 0x0F flag const: LT flag const
- Execution continues if the specified flag has a value less than the
amount indicated.
- 0x10 word_id: WORD3 word_id
- Execution continues if a third vocabulary word is matched in the command
after the verb and noun, and it is word.
- 0x11 word_id: WORD4 word_id
- Execution continues if a fourth vocabulary word is matched in the command
after verb, noun, and WORD3, and it is word.
- 0x12: INVEN
- Print the player's inventory.
- 0x13: DESC
- Stop bytecode processing, describe the player's current location and
prompt for a new input.
- 0x14: QUIT
- Ask the player if they want to quit. Execution continues if they say yes.
- 0x15: END
- Stop bytecode processing, display the game over message, and ask if the
player wants another go. If they do, restart the game; otherwise, return to
CP/M.
- 0x16: DONE
- Stop bytecode processing and prompt for a new input.
- 0x17: OK
- Display system message 15 ("OK") and behave as DONE.
- 0x18: ANYKEY
- Display system message 16 ("Press any key to continue") and wait
for a keypress.
- 0x19: SAVE
- Prompt for a filename to save the game state to, and save it.
- 0x1A: LOAD
- Prompt for a filename to load the game state from, and load it.
- 0x1B: TURNS
- Display the number of turns the player has taken.
- 0x1C: SCORE
- Display the player's score.
- 0x1D: CLS
- Clear the screen.
- 0x1E: DROPALL
- Move everything the player is carrying to the current location.
- 0x1F: AUTOG
- Try to match the current noun with an object number. If successful,
execute GET on that object.
- 0x20: AUTOD
- Try to match the current noun with an object number. If successful,
execute DROP on that object.
- 0x21: AUTOW
- Try to match the current noun with an object number. If successful,
execute WEAR on that object.
- 0x22: AUTOR
- Try to match the current noun with an object number. If successful,
execute REMOVE on that object.
- 0x23 ticks: PAUSE ticks
- Delay for roughly ticks/50 seconds.
- 0x24: BELL
- Sound the beeper by writing character 7 (BEL) to the screen.
- 0x25 loc: GOTO loc
- Move the player to the specified location.
- 0x26 msg: MESSAGE msg
- Display the specified message.
- 0x27 obj: REMOVE obj
- If the specified object is worn, move it to the player's inventory. If
this isn't possible, display an error saying why.
- 0x28 obj: GET obj
- If the specified object is in the current location, move it to the
player's inventory. If this isn't possible, display an error saying why.
- 0x29 obj: DROP obj
- If the specified object is in the player's inventory, move it to the
current location. If this isn't possible, display an error saying why.
- 0x2A obj: WEAR obj
- If the specified object is in the player's inventory, the player wears it.
If this isn't possible, display an error saying why.
- 0x2B obj: DESTROY obj
- Destroy the specified object. If it was in the player's inventory, the
number of objects carried decreases by 1.
- 0x2C obj: CREATE obj
- Move the specified object to the current location. If it was in the
player's inventory, the number of objects carried decreases by 1 (fixing
a bug in earlier Quill and Quill-like engines.)
- 0x2D obj1 obj2: SWAP obj1
obj2
- Exchange the locations of the two objects.
- 0x2E obj loc: PLACE obj
loc
- Move the specified object to the specified location.
- 0x2F flag: SET flag
- Set the specified flag to 255.
- 0x30 flag: CLEAR flag
- Set the specified flag to 0.
- 0x31 flag amount: PLUS flag amount
- Add amount to the specified flag. If the total exceeds 255 it
will be capped at 255.
- 0x32 flag amount: MINUS flag amount
- Subtract amount from the specified flag. If the total is less
than zero it will be set to zero.
- 0x33 flag amount: LET flag amount
- Set the value of the specified flag to amount.
- 0x34: NEWLINE
- Print a carriage return / line feed.
- 0x35 flag: PRINT flag
- Print the value of a flag as a decimal number.
- 0x36 msg: SYSMESS msg
- Display the specified system message.
- 0x37 obj loc: ISAT obj
loc
- Execution continues if the specified object is at the specified location.
- 0x38 obj flag: COPYOF obj flag
- Set flag to the location of the specified object.
- 0x39 obj1 obj2: COPYOO obj1 obj2
- Move object obj2 to the location of obj1.
- 0x3A flag obj: COPYFO flag obj
- Move object obj to the location specified in flag.
- 0x3B flag1 flag2: COPYFF flag1 flag2
- Set flag2 to the value of flag1.
- 0x3C: ISDESC
- Execution continues if the location description has been displayed this
turn.
- 0x3D nn: EXTERN nn
- Call external code, passing the supplied byte to it as a parameter.
This requires the external code to be added to the interpreter; by default
it is a no-op.
- 0xFF
- End of bytecode sequence.
Text tables
The object, location, message and system message tables are all stored in
the same way. The corresponding word in the header points to a table of
words giving the addresses of the object/location/message strings.
The strings are stored with each byte complemented (XORed with 0xFF) as
a protection against casual snooping. End of string is indicated by 0xF5,
which complemented is 0x0D (carriage return). The only other control code
I have seen used is 0x0A (newline).
Regarding character set: since CP/M has no standard character set beyond
ASCII, I would expect QDB files only to contain ASCII and not to make
assumptions about characters 0x80 and up.
Connections
As with location texts, the word in the header points to a table of words
with one entry per location. Each word points to a list of connections:
DB word_id ;Direction
DB location ;Where it leads to
The list is terminated by a word_id of 0xFF.
Vocabulary
The vocabulary table contains five bytes per word. The first four are the
word (complemented ASCII) and the fifth is its word_id. Words 1-12 are
used for movement verbs.
The end of the table is marked by an entry containing five zero bytes.
Object initial locations
One byte per object giving its start location. Values of 0xFC or greater
mean:
0xFC: Object destroyed
0xFD: Object worn
0xFE: Object carried
The table must be followed by a 0xFF byte.
Object words
One byte per object giving the word_id for that object — used by the
AUTOG / AUTOD / AUTOW / AUTOR operations. For example, in the Very Big Cave
Adventure, object 4 ("A shiny brass lamp") has word 20 (LAMP) as its name.
Objects with no name use a word_id of 0xFF.
Format of saved game state
The game state is saved as a 512-byte file with the extension .QGP. The
first 256 bytes hold flags:
DB game flags ;Flags 0-29: 30 bytes
DB score ;Flag 30: Score
DW turns ;Flags 31-32: Number of turns
DB verb ;Flag 33: Current verb
DB noun ;Flag 34: Current noun
DB word3 ;Flag 35: Third recognised word
DB word4 ;Flag 36: Fourth recognised word
DB ability ;Flag 37: Maximum number of objects player
; can carry
DB location ;Flag 38: Player's current location
;
; Flags 39-255 appear not to be used and contain zeroes.
;
The second 256 bytes hold the locations of the 256 objects, with the
following special meanings:
0xFC: Object destroyed
0xFD: Object worn
0xFE: Object carried
Interpreter header
The interpreter (RUN.COM) begins with a jump block allowing system support
to be customised:
0100 JP start ;Entry point
0103 JP cls ;Clear screen
0106 JP delay ;Delay for approx 1/50 second.
0109 JP diagnostic ;Called before each input if the game is in
;debug mode
0112 JP restart ;Start / restart the loaded game.
0115 RET ;Vector for external routines called by EXTERN
NOP ;Will be entered with A=parameter, IX-> flags
NOP
The area from 0x118 to 0x142 contains system-dependent subroutines called
from this jump block.
John Elliott 2023-09-15