Quake-C Manual
Warning
The definitions below are valid only for Quake version 1.00
and 1.01. Future versions may differ.
Copyright
This document is part of the Unofficial Quake Specifications,
Copyright (c) 1996 by Olivier Montanuy.
All the informations below are Copyright (c) 1996, id software.
The content of this file was derived from code and comments
released by John Carmack, of id software.
This is a very crude manual of Quake-C. It is rather incomplete.
Names are a maximum of 64 characters, must begin with A-Z,a-z, or _, and can continue with those characters or 0-9.
The field types are used to put a name on the different fields of a C structure.
.type name
Beware of the dirty hack:
In the first file read by the Quake-C compiler, defs.qc,
there must be a definition for the entity fields, and world fields.
This definition is hard coded. You had better not touch it,
or you will have to recompile Quake itself.
The globals are defined before the special definition void end_sys_globals;
The entity fields are defined before the special definition void end_sys_fields;
It's not important if you don't understand the nonsense above. It's an ugly hack. Just don't modify defs.qc before those two tags, and you won't be in trouble.
type variable1, variable2;where type is one of the pre-defined simple types.
You can also affect default values to variables, for instance:
type variable1 = value;
There are two levels of scoping: global, and function. The parameter list of a function and any vars declared inside a function with the "local" statement are only visible within that function,
The general structure of a function definition is:
type (type param1, typeparam2, ... ) function =
{
... code ...
};
Don't forget the ; after the brackets.
Here are some examples:
void() think = {...};
entity() FindTarget = {...};
void(vector destination, float speed, void() callback) SUB_CalcMove = {...};
If you want to use a function before defining it, you must declare it, otherwise the Quake-C compiler will not be able to use it.
The general structure of a function declaration is:
type (type param1, typeparam2, ... ) function;
if( expression )
{
statements
}
else
{
statements
}
while( expression )
{
statements
}
or
do
{
statements
}while( expression )
Call a function:
function_name ( parameter1, parameter2,... )The cannot be more than 8 parameters.
Return a value:
return( expression )
! (logical not) && (logical and) || (logical or)Beware that in if() conditional expressions, the complete expression is always evaluated (like in Basic, and countrary to the C language).
<= < >= > == (equal) != (not equal)Operations on floats or integer
* / - +Use parenthesis to remove ambiguities.Those operators perform bitwise operations on integers:
& (bitwise and) | (bitwise or)They are generally meant to be used with bit masks.
Simple Types
Type: void
An empty result, mostly used for definition of procedures (i.e. functions that return no result at all).Type: float
A floating point value.
Floats are also used to store booleans (TRUE, FALSE) or integer values linke counters, or bit flags.
Valid syntax: 12 1.6 0.5 -100 Invalid syntax: .5A parsing ambiguity is present with negative constants. "a-5" will be parsed as "a", then "-5", causing an error. Seperate the - from the digits with a space "a - 5" to get the proper behavior.
Type: vector
A vector, made of 3 float coordinates.
Used to represent positions or directions in 3D space.
Valid syntax: '0 0 0' or '20.5 -10 0.00001'
Note the simple quotes around the vector. Do not use double quotes, they are reserved for strings.
If you declare a vector foobar, then you can access it's x, y and z fields with: foobar_x, foobar_y,foobar_z.
Type: string
A character string.
Used to indicate file names, or messages to be broadcast to players.
Valid syntax: "maps/jrwiz1.bsp" or "ouch!\n"
Use \n for newline.Quake-C Manual Type: entity
The reference of an entity in the game, like things, players, monsters.
The entity type is a structured type: a detailed description of each field is available.There are two default entity references available to functions, as global variables:
(Derived from information published by Steve Tietze)
Here are a few definitions that are commonly found in the Quake-C code defining the behavior of animated models (monsters, players, etc...).
Most of this information is not interpreted by the Quake-C compiler, but it's useful for the program modelgen that generates the models.
$modelname namename is the name of the model file defining the object.
$cd dirSpecify the directory where your model file (.MDL) is located.
$flags rotationThis field is not interpreted by Quake-C, but it's useful for the program modelgen that generates the models.
$origin x y zThis field is not interpreted by Quake-C, but it's useful for the program modelgen that generates the models.
$scale numberThis field is not interpreted by Quake-C, but it's useful for the program modelgen that generates the models.
$base objectThis field is not interpreted by Quake-C, but it's useful for the program modelgen that generates the models.
$skin skinfileThis field is not interpreted by Quake-C, but it's useful for the program modelgen that generates the models.
$frame frame1 frame2 ...This defines several animation frames of the object.
$frame walk1 walk2 walk3 walk4
void() man_walk1 = [ $walk1, man_walk2 ] { ... some code ... };
void() man_walk2 = [ $walk2, man_walk3 ] { ... some code ... };
void() man_walk3 = [ $walk3, man_walk4 ] { ... some code ... };
void() man_walk4 = [ $walk4, man_walk1 ] { ... some code ... };
In the brackets, the first parameter defines the name of the frame (as found in the model file), and the second parameter defined the function that is to be executed in the next frame (by setting the value of self.nextthink).
Most of these functions do nothing special, but some can be very complex (for instance, the functions that are called when the monster tries to see a player).
void() MyFunction; // the prototype
void() MyFunction = // the initialization
{
dprint ("we're here\n");
};
Execution of Quake-C
Code execution is initiated by C code in quake from two main places:
the timed think routines for periodic control, and the touch function when
two objects impact each other.
Execution is also caused by a few uncommon events, like the
addition of a new client to an existing server.
There is a runnaway counter that stops a program if 100000
statements are executed, assuming it is in an infinite loop.
It is acceptable to change the system set global variables.
This is usually done to pose as another entity by changing
self and calling a function.
The interpretation is fairly efficient, but it is still over
an order of magnitude slower than compiled C code. All time
consuming operations should be made into built in functions.
A profile counter is kept for each function, and incremented
for each interpreted instruction inside that function. The
"profile" console command in Quake will dump out the top 10
functions, then clear all the counters. The "profile all"
command will dump sorted stats for every function that has
been executed.
afunc ( 4, bfunc(1,2,3));
will fail because there is a shared parameter marshaling
area, which will cause the 1 from bfunc to overwrite the 4
allready placed in parm0. When a function is called, it
copies the parms from the globals into it's privately scoped
variables, so there is no collision when calling another
function.
total = factorial(3) + factorial(4);
Will fail because the return value from functions is held in
a single global area. If this really gets on your nerves,
tell me and I can work around it at a slight performance and
space penalty by allocating a new register for the function
call and copying it out.