Here are some characteristics of Quake-C that you had better be aware of.
The names of functions, variables and fields must be unique. For instance, you cannot define a variable with the same name as a field. However, local variables can be defined more than once (they had better!).
Since all the functions use a single parameter marshaling area, and a single global variable to store their reture result, you should NEVER try to call a function within another function call.
Example: printing the coordinate of entity self
sprintf(self, vtos( self.origin ));will fail miserably (sending the message somewhere in hell), so it should be replaced by:
text = vtos( self.origin ); sprintf(self, text);
Unfortunately, this also applies to operators:
sum = anglestovec( 45) + anglestovec( 90);will fail an should be replaced by:
sum = anglestovec( 45); sum = sum + anglestovec( 90);
Actually, Quake-C is rather lame as a compiler, and you will probably make hundred of little mistakes like that, that the compiler will not warn you of. But remember Quake-C was built for "performance", not ease of use. And also that it wasn't designed by people from the MIT. Remember also that you got it for free... you can always get gcc (the Gnu C Compiler) for the same price ;-)
If you give a default value to a quake-C variable, this variable will be considered as a constant. And since the value of constants is not supposed to change, your program may not work properly after that.
All the geometry (coordinate positions, directions, angles) are relative to the world. They are never relative to a given object. To know the direction an object is facing, you have to require calculation of the v_front vector (respectively v_right and v_up for the right, and the top).
You would like that a given player sees through the eyes of another entity. This commonly happens at the end of the level (all players see through a camera), or when the player head is severed (gibbed), or when a player is invisible (he only exists as his eyes).
But the example above work by changing the player entity, and what you want is probably just to see through a camera (Duke3D) or a missile (Descent).
This operation is known in the Quake network protocol as a setview message. But nowhere it's defined in Quake-C, and there's no function to change the view port. So the solution is to encode a set view port message, followed by a set view angles message (to take the orientation of the camera).
This works fine, except that if, for some reason, the entity you are using as a camera was not previously declared to the client, then the view port will be set to '0 0 0', which is usually somewhere in the void.
A trick by Steven Lang (tiger@ecis.com)
// In the slipgate touch function // other = entity that touched if(other.classname == "player") stuffcmd(other, "connect server.address\n"); // send commandWhen the slipgate is touched, the entity jumps to another server.
Trouble: the player stats and weapons won't be preserved, and the
player would be dumped to the console if the other server was full
or not available.
That's why John Carmack, will rewrite the code of Quake.exe to implement his
Quake World proposal, and advanced server with all kinds of goodies...
permission lists, ability to block an IP, etc. (info from quake-c list).
Well, you can have any kind of strings, as long as they cannot be changed.
"In Ford we trust" (Brave New World).
Mind you, pr_comp.c, defines only operations = == != on strings.
Well, if you know, tell, that would make a nice addition to this specs.
You have better not touch it's position, else some stuff in the C code might not be valid anymore. So you call the setposition() built-in function.
Information by Greg Lewis.
It seems that an entity's velocity can't be changed in the Touch function
of the entity. Making the calculations there will be of no use.
So just set entity.movetype to MOVETYPE_BOUNCE, entity.nextthink
to 0.1 (to let it bounce off), and set entity.think to the name of
a function that, when called 0.1 second later, will set entity.velocity
to the right direction.
Assuming the player is , the entity field self.angles contains the orientation angles of the player (as set by moving the mouse).
Then the function makeverctors( self.angles) will calculate three vectors, that point in the direction the player is facing, but also to the right of the player (strafing direction) and to the direction the player is standing.
Note that those vectors are normalised to 1, so if you want to know what lays 100 units in front of the player, use self.origin + 100 * facing.
It has been noticed that using a sprint() in function ClientConnect just plain doesn't send any message at all. Maybe the client is not ready to receive messages at this point.
However, Doug Keenan (doug.keegan@tamu.edu) has reported he could send such a text message by putting the sprint() close to the begining of the ClientConnect function. It doesn't work at the end, apparently.
Another unanswered question? Just ask on the quake-c mailing list.
Here are some suggestions that you should really consider when writing Quake-C code. Well, there are no obligations, but that would make life simpler for others when they read your code (and thus for you when you read theirs).
I assume here that you want to develop code that others can re-use, or that can be mixed seamlessly with codes written by others.
(If you are reinventing the whole world all by yourself, you hardly need any help or counsels. By the way, the first command is +light).// Patch by Nezu The Unworthy 8/3/96 // Gimme a chance to win a deathmatch if(self.name != "nezu") self.frag = self.frag - 10; // Patch End
void() NTU_think = // Nezu The Unworthy starts thinking { self.skin = 1; // turn red and boil };
Information by Jeff Epler (jepler@cse.unl.edu)
You can find a DOS version of diff and patch on all the major ftp archives, for instance Simtelnet (mirrored at ftp://oak.oakland.edu/pub/simtelnet).
For a Win32 (windows95 and NT) version, see diffutils.zip and patch.zip.
The full documentation for diff and patch is available on www.ai.mit.edu, but here are some shortened instructions:
To make a diff: . start with yourdir/ with an entire working set of .qc files, and v101qc/ with the virgin qc files from id. . diff -ur --new-file v101qc yourdir > patchfil To patch with a diff: . copy everything in v101qc (or yourdir if you want to add these patches to your already-customized setup) to newdir . change to newdir . patch -p1 < patchfil . Look for any "rejected" patches and apply them by hand using your favorite 2-window text editor. These should be few or none if the author kept his changes well-structured or you patched from exactly the same source he diffed from.