This is version 2 of the modifications programming forum FAQ. UBB (*spit*) ate two thirds of the original thread, so a great deal of the posts here were made by people other than me. Rather than chase them all up asking them to repost their messages I have done so for them including their name in brackets after the question.
If you have any questions and answers you feel should belong here do not hesistate to post them.
The weapon system in baseq3 works using an index in the ent->client->ps.stats array - STAT_WEAPONS. This is a bit list of weapons that the client currently holds, corresponding to the weapon_t enumeration. The maximum weapons count is limited to 16 since only 16 bits of an int are communicated across the network via the stats array.
Using lots of bitwise operators, it's relatively straight forward to remove this limit. Add another indice to the statIndex_t enumeration called STAT_WEAPONS2. This will simply serve as an extenstion of STAT_WEAPONS raising the weapon limit to 32.
Use the following functions (placed in bg_misc.c) to alter and query these two STAT_ indices:
code:
//TA: pack weapons into the array void BG_packWeapon( int weapon, int stats[ ] ) { int weaponList;
if ( client->ps.stats[STAT_WEAPONS] & ( 1 << i ) ) {
also in g_client.c becomes
code:
if( BG_gotWeapon( i, client->ps.stats ) ) {
You get the idea.
That is not the end of the problems however. You must also store ammo for each weapon. This varies from modification to modification however, depending on whether many weapons share ammo and clip based systems. This is a solution which uses the powerups array as well as the ammo array to store ammo quantities using bit packing to store clips (if the weapons are clip based):
code:
//TA: extract the ammo quantity from the array void BG_unpackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int *quan, int *clips, int *maxclips ) { int ammoarray[32]; int i;
for( i = 0; i <= 15; i++ ) ammoarray[ i ] = ammo[ i ];
for( i = 16; i <= 31; i++ ) ammoarray[ i ] = ammo2[ i - 16 ];
//TA: pack the ammo quantity into the array void BG_packAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int quan, int clips, int maxclips ) { int weaponvalue;
Please bear in mind you must sacrifice the powerups array (and hence all powerups) to use this method. An alternative is to split each indice of the ammo array into two 8 bit numbers, so that the ammo array stores 32 numbers total. This limits your maximum ammo value to 255 however.
Compiling the qvm's in under win9x is straightforward, you only have to modify the batch files to get this working! For my example I'll take cgame.bat:
These are the folders you find when you have extracted the game_source127g: /quake3 --/bin_nt (lcc and q3asm compiler) --/code (the code files) ----/cgame (client files) ----/game (server files) ----/q3_ui (Quake3 (vanilla) UI) ----/ui (TA Quake3 UI) --/ui (.menu files for the menu's)
now go into /quake3/cgame folder and open the cgame.bat with your favourite editor (notepad is good).
There you'll find this:
code:
mkdir vm cd vm set cc=lcc -DQ3_VM -DCGAME -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1
Hmm, you'll say: "What's wrong with this?" The problem arises from lines such as the following:
code:
%cc% ../cg_weapons.c
Under Win2k the %cc% is replaced with whatever the environment variable cc is set to. This is decided at the beginning of the batch file with the line:
This should now be repeated for every other %cc% line in the batch file until there are no instances of %cc% left.
=) Congratulations you're done with cgame..
Now do the same to game and q3_ui..
Special attention should be paid to the ui section :- since the codebase has two possible targets for the ui, vanilla q3 and team arena, the batch files produce qvms with different names so as not to overwrite each other. These are q3_ui.qvm and ui.qvm for q3 and ta respectively. The quake3 executable however, will only load the ui.qvm it finds, regardless of the game that is running. Therefore, the q3_ui.qvm file must be renamed to ui.qvm before it is copied to your mod directory.
To install qvms, create a directory underneath your mod directory named "vm" and copy each of qagame.qvm, cgame.qvm and ui.qvm there.
To run your mod with qvms, use the following command line:
0: use OS shared libraries (dll/so) - fastest, useful for debugging. 1: use interpreted qvm execution (qvm files are executed in realtime) - slow. 2: use JIT compiled qvm execution (qvm files are compiled to native instruction set "just in time") - reasonably fast.
Quake 3 is written in ANSI C. Quake 3 is not written in the object orientated language C++, although it is programmed in a relatively object orientated fashion.
ANSI C and C++ are significantly different programming languages - do not confuse them.
No one on this forum will be offensive for no reason (with a couple of exceptions ). If somebody answers with an abrasive response more often than not it is because the question asked was very vague.
For example:
"I've been playing with the Q3 source for a week now. I made some changes and now whenever I jump Q3 crashes. Anybody know why?"
Of course not. When you ask a question, post as much information as you can about the problem and be very specific about what the problem actually is:
"I've been playing with the Q3 source for a week now. I made some changes and now whenever I jump Q3 crashes. I did a little bit of research and I found that Q3 is crashing in the G_ICrashInHere() function. I've looked through it but I can't see anything wrong.
[code listing]
Can anybody see anything wrong with this block of code? Thankyou."
"Hey. I just got the Q3 source and I want to make a mod. I haven't done any programming before so I was wondering if you guys could tell me how to implement 1. Realistic weapons 2. Realistic Falling damage 3. Sniper scope 4. Survial style gameplay?"
We are not your slaves. That means we are not going to implement features in your mod for you. A better question would have been:
"Hey. I just got the Q3 source and I want to make a mod. I haven't done any programming before but I am eager to learn. Could you point me to some tutorials or guides that might help me learn programming?"
"Does anyone know how to get QVM's to compile under Windows 98 or how to get Q3 to allow more than 16 weapons?"
These questions are in this FAQ. The FAQ is there for a reason. Please read it. Oh... hangon. Nevermind.
So in summary:
Be specific
Don't expect others to do your work
Don't ask questions that have been answered before
Most importantly - be polite. And humble - programmers are a queer bunch who like to be constantly reminded how "l33t" they are
Yes. I have written an mp3 decoder for the Q3 VM. It is located here . Rememeber to acknowledge the relevant persons and parties.
It is also possible to playback mp3s using dll/so. This is how the Rocket Arena 3 MP3 player works. Juz has implemented a winamp interface on the Windows platform. If you use this tutorial, please bear in mind the drawbacks and problems associated with implementing an OS binary based modification.
One of the most frustrating and time consuming practices is that of bad posting. If you follow these steps when asking for help you should get better replies in a shorter amount of time.
1) Make your subject to the point yet catchy, but dont over do it. 2) Present the exact problem as clearly as possible 3) Provide all error messages/bugs exactly as they appear. 4) Provide all known causes and results 5) Provide as much information about what you changed as possible, preferably the code itself. 6) State all your possible solutions and/or failed attempts.
If you stick to these guideline you will save more frustration and time than it you would writing a sloppy post.
posted 03-31-2002 03:37 PMI compiled the qvm files but when I start the game my changes don't show, why? (Coyote)
If your using qvms you need to do one of two things, use the "+set sv_pure 0" in your command prompt line and put the qvms in a /vm folder of your mod directory. Or place the qvms in a /vm folder of a pk3 file and DO NOT use the "+set sv_pure 0". Which also brings us to another questions:
Why doesn't the new model I put in show up, I have it in the code right.
This is probably because your using the second method from above. One thing you must know about making the server "pure" is that all files you are using must be in pk3 files, which includes all your models etc, and two you must be using qvms, dlls in pk3 files will not work.
------------------------------------ Another thing that isn't very easy are the fonts of the game! We have three types of fonts: 1. bigchars.tga (console and game font) (loacted in /gfx/2d/bigchars.tga) 2. font1_prop.tga, font1_prop_glo.tga, font2_prop.tga (located in /menu/art/*.tga) 3. TA menu fonts (Team Arena ttf compiled fonts for the whole game) (located in /fonts/*.dat/*.tga)
These three fonts have several kinds of changing them: 1. Console and Game Font (Vanilla Q3): To change them is a bit izzy because you have to be very exact!Use photoshop 5/6 and your hands!
If you do major changes to your code , back it up! Otherwise you'll need to recode and that's not very cool. Backup on another comp or a sperate harddisk or just burn cds for backups.
You'll have to start your mod using quake3.exe from the commandline , when you try starting it ingame you'll get write protection errors. I think id did this because of cheats and such things, but now back..
make an alias to quake3.exe and put this into the command line arguement:
for example: E:\Quake3\Quake3.exe +set fs_game mymod
or put everything into a batch files:
quake3 +set fs_game mymod
Now save this file made with notepad into your quake3 dir, filename: mymod.bat
Start it , to run your mod..
You can also set: +sv_pure 0 to run the server in unpure mod.
posted 03-31-2002 03:55 PMAt the request of sensei Timbo, an explanation of localentities (LEs) verses refentities (REs) (Juz)
An LE exists over a number of frames, but uses an RE to do the drawing for it. LEs have REs associated with them. For example if you have a particle moving through an arc, you'd set up the LE with the movement information: the speed, starttime, endtime, fade stuff, direction vector etc. Every frame, the LE sets up it's RE with the LE's position, colour, alpha value etc. and then passes that RE to the renderer to get drawn, and the RE would represent the state of the particle in that frame.
So the LE is just set up once, and stays the same over the number of frames that it is "alive" for. The RE is settup once a frame to represent in the game world the position and state of the LE. The REs are what actually get drawn, the LEs are used to hold the information that dictates how the RE should be drawn in the current frame.
In a no doubt vain attempt to reduce the number of 'need coder' posts, or possibly just to give something for the mods to link to when closing such posts, I give you:
I need a coder/modeller/mapper/etc. to help with my mod, should I advertise on this board?
NO! Most of the people posting to this board will already have projects of their own, and repeated help wanted posts are very annoying. Q3W has a special forum for advertising for people: Behold the Help Wanted Forum!
You can edit every file except those starting with q_. These files are included in the main Q3 binary and editing them will usually cause strange things to happen. You can add to q_ files but it doesn't really make sense to do so since things added to bg_ files will be equally visible with respect to the game source. Generally a good policy is just not to touch the q_ files and stay on the safe side.
posted 10-04-2002 05:06 AMI want to make mods that require coding but I don't know how to code in C. How can I learn to code in C?
The best way is to pick up a book on C and try to learn it from there. There are many good books on C, it's just a matter of looking for them.
If you don't want to get a book, you can also check out some online tutorials. Here is a link to a programming homepage with links to places where you can find out about C (click on "C and C++" on the right). You can also check out Programming Tutorials.com and Kenn Hoekstra's (from Raven Soft.) guide to getting a job in the game industry which also outlines some useful coding sites.
Once you've read through some books and tutorials on the net, you can read some Quake 3 coding tutorials at Code3Arena - I am sure there are some other sites but I just can't recall them from the top of my head....
posted 01-17-2003 02:52 PMI get errors when i compile my source, even if i haven't changed anything.. or where can I get a completely debugged & compile-ready sourcecode ?
Unused/undelta'd fields between fields that are used/delta'd are sent across as padding bits.
Say you are using a tempentity to transmit a global event (SVF_BROADCAST). Your event needs to send across 2 entnums but no origin, trajectory or angles.
If you use the "obvious fields" otherEntityNum, otherEntityNum2 you will be wasting 12 bits... because the unused origin, origin2, angles, angles2 fields need to be bit-padded up.
Now think what happens when code uses event, eventParm, generic1... thats a lot of padding bits when values change!
(Hint: you could save another 18 padding bits by stuffing both entnums into eFlags, avoiding the padding from pos,apos as well! Keep in mind eflags is 24 bits).
rain gave me this rough rulechart:
code:
each entity is sent as [2 uncompressed + 8 compressed: ent num] [1 uncompressed: no change? if so, next ent] [1 uncompressed: deleted (set to 0s); if so, next ent] [8 compressed - field count] per field { [1 uncompressed - no change? if so, next field] [1 uncompressed - zeroed? if so, next field] [field data - [X bits] or { [1 uncompressed: snapped?] [float] } }
Basically, try to use fields toward the beginning of the entityState_s struct if possible. Avoid skipping fields if possible.
Also: anything that doesn't round to a whole byte will be sent uncompressed--e.g. if you have a 10 bit field (say, entityState.event), the first 2 bits will be sent uncompressed and the remaining 8 bits will be compressed.
fwiw: playerState_t follows the same rules as entityState_t
+ //Just to know if our map is correct: + Com_Printf( "Loading arena information from: [ %s ]\n", filename ); + ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] ); }
@@ -149,7 +152,8 @@ int numdirs; vmCvar_t arenasFile; char filename[128]; - char dirlist[1024]; + //It's very strange, this variable should be something like dirlist[ MAX_ARENAS ][ MAX_QPATH ] + char dirlist[ MAX_ARENAS ]; char* dirptr; int i, n; int dirlen; @@ -168,7 +172,8 @@ }
// get all arenas from .arena files - numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 ); + numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, MAX_ARENAS ); + dirptr = dirlist; for (i = 0; i < numdirs; i++, dirptr += dirlen+1) { dirlen = strlen(dirptr);