John Morales

Overview

  • Difficulty: Difficult
  • Number of Steps: 15+

How-To Build and Make Updates to Quake 3

Overview

This How-To will describe how to:

  • Get the open source release of id Software's Quake 3 through ioquake3.org...
  • combine it with the patch files and PAK files from your purchased copy of Quake 3...
  • build and run the game on Ubuntu Jaunty (9.04) with OpenGL...
  • and finally show some simple examples of how to modify the source to do basic fun things like change the fire rate and projectile speed of weapons, and change the health and ammo pack ammounts.

To Build:

First we need to decide where to put our target build directory. I chose /opt/quake3_custom. Next you'll want to obtain the quake3-latest-pk3s.zip file of Quake 3 patch files from ioquake3.org. We'll decompress the .zip file and move the base3q and missionpack directories to our target build directory
(E.g., /opt/quake3_custom/baseq3 and /opt/quake3_custom/missionpack)

(Note: the quake3-latest-pk3s.zip file will not include the main PAK file, PAK0.pk3; this file must come from your purchased copy of the game. We'll describe how to link up the PAK0.pk3 file with our ioquake3 build later on in this HOW-TO.)

If you haven't already, agree to the license and grab the patch files .zip from ioquake3
$ sudo mkdir /opt/quake3_custom
$ sudo chown -R myusername:myusergroup /opt/quake3_custom
$ unzip path/to/quake3-latest-pk3s.zip
$ mv path/to/quake3-latest-pk3s/* /opt/quake3_custom/

Next we'll create symbolic links in our baseq3 and missionpack directories to the PAK0.pk3 file from our Windows installation of Quake 3. On my system, this looked like the following, where my Windows partition was mounted at /media/sda1:

$ cd /opt/quake3_custom/base3q/
$ ln -s /media/sda1/Program\ Files/Quake\ 3/Quake3/baseq3/PAK0.PK3
$ cd /opt/quake3_custom/missionpack/
$ ln -s /media/sda1/Program\ Files/Quake\ 3/Quake3/baseq3/PAK0.PK3

Now we'll create another directory for where we'll checkout the quake engine snapshot from Subversion. For reference, when I originally wrote this how-to, I had version 1.33 (svn revision 1112) of the code.

$ sudo apt-get install build-essential subversion libsdl1.2-dev libopenal-dev
$ mkdir /home/username/workspace/quake3/
$ cd /home/username/workspace/quake3/
$ svn co svn://svn.icculus.org/quake3/trunk ioquake3

At this point we're ready to try and build the tree. On my laptop, this takes about ~3-5 minutes.

$ cd ioquake3/
$ make
$ COPYDIR=/opt/quake3_custom make copyfiles

The last command from above will cause all the build files to be copied to our target directory /opt/quake3_custom/ that we created earlier. To actually run our build we'll do the following:

$ cd /opt/quake3_custom
$ ./ioquake3.i386 +set r_fullscreen 1 +set developer 1 +set vm_ui 0 +set vm_cgame 0 +set vm_game +set sv_pure 0

Quake3 should fire up!

Files To Modify:

  • /home/username/workspace/ioquake3_custom/code/game/bg_misc.c

The bg_misc.c file is where we can make changes to the amount of ammo each weapon starts with, as well as how much health, armor, and ammo each of the powerup items have.

In the code snippet below, we're increasing the amount of ammo a rocket launcher starts out with from 10 to 80:

.
.
/*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */
{ "weapon_rocketlauncher", "sound/misc/w_pkup.wav", { "models/weapons2/rocketl/rocketl.md3", NULL, NULL, NULL},
/* icon */
"icons/iconw_rocket",
/* pickup */
"Rocket Launcher",
80,
/*10,*/
IT_WEAPON, WP_ROCKET_LAUNCHER,
/* precache */
"",
/* sounds */
"" }, . .

We can modify powerups and ammo pack amounts the same way. For example, below we're increasing the number of rails in a railgun ammo pack from 10 to 50:

.
.
/*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */
{ "ammo_slugs", "sound/misc/am_pkup.wav", { "models/powerups/ammo/railgunam.md3", NULL, NULL, NULL},
/* icon */
"icons/icona_railgun",
/* pickup */
"Slugs",
50,
/*10,*/
IT_AMMO, WP_RAILGUN,
/* precache */
"",
/* sounds */
"" }, . .

Another fun trick that can be done within this file is making all the weapons of a map behave like the same weapon, say the rocket launcher. As shown in the example snippet below, we can make all instances of the shotgun behave like the rocket launcher; it will still look like you're holding the shotgun, but it will fire rockets instead of shells. This provides a really simple way to change the layout of a map without having to muck with the maps themselves.

(One note about change weapon types: the machinegun is coded differently than the other projectile weapons, so changes its weapon type will cause errors at runtime.)

.
.
/*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */
{ "weapon_shotgun", "sound/misc/w_pkup.wav", { "models/weapons2/shotgun/shotgun.md3", NULL, NULL, NULL},
/* icon */
"icons/iconw_shotgun",
/* pickup */
"Shotgun", 10, IT_WEAPON,
WP_ROCKET_LAUNCHER,
/*WP_SHOTGUN,*/
/* precache */
"",
/* sounds */
"" }, . .

  • /home/username/workspace/ioquake3_custom/code/game/bg_pmove.c

The bg_pmove.c file is where we can change how fast the weapons fire. I think simply playing with the rocket launcher and railgun updated to fire like machineguns is good for a couple hours of fun, especially on the space maps. :P

The function for changing the fire rate is PM_Weapon( void ), which is near the bottom of bg_pmove.c. We can increase the fire rate by reducing time added in between each round fired.

In the snippet below, we're making both the rocket launcher and railgun fire 5x faster than usual:

.
.
	
// fire weapon
PM_AddEvent( EV_FIRE_WEAPON ); switch( pm->ps->weapon ) { default: case WP_GAUNTLET: addTime = 400; break; case WP_LIGHTNING: addTime = 50; break; case WP_SHOTGUN: addTime = 1000; break; case WP_MACHINEGUN: addTime = 100; break; case WP_GRENADE_LAUNCHER: addTime = 800; break; case WP_ROCKET_LAUNCHER: addTime =
160;
/*800;*/
break; case WP_PLASMAGUN: addTime = 100; break; case WP_RAILGUN: addTime =
300;
/*1500;*/
break; case WP_BFG: addTime = 200; break; case WP_GRAPPLING_HOOK: addTime = 400; break;
#ifdef MISSIONPACK
case WP_NAILGUN: addTime = 1000; break; case WP_PROX_LAUNCHER: addTime = 800; break; case WP_CHAINGUN: addTime = 30; break;
#endif
. .

  • /home/username/workspace/ioquake3_custom/code/game/g_missle.c

The g_missle.c file is where we can play with how fast projectiles move and how much damage is inflicted. Space maps become great fun when this file is updated to make rockets zip by like machinegun bullets. (Video to come.)

In this file, each weapon as a function called *fire_<weaponname> which controls, among other things, each projectile's speed and damage. As shown in the snippet below, we can increase the speed of rockets by increasing the value passed to VectorScale(...).

Not changed in the snippet below, but clearly indicated are the bolt->damage, bolt->splashDamage, and bolt->splashRadius values, which can be altered as desired.

OPTIONAL: For detonating weapons (e.g., the rocket launcher and grenade launcher) this file can also be used to adjust the time before the projectile explodes with the bolt->nextthink time. Reducing the 15000 to something smaller (as shown below) has the strange/entertaining effect of making the rocket launcher a short-range weapon-- rockets detontate after only traveling 100 feet, so all rocket combat has to be in close quarters.

.
.
/* ================= fire_rocket ================= */
gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir) { gentity_t *bolt; VectorNormalize (dir); bolt = G_Spawn(); bolt->classname = "rocket"; bolt->nextthink = level.time +
5000;
/*15000; (OPTIONAL weirdness)*/
bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_ROCKET_LAUNCHER; bolt->r.ownerNum = self->s.number; bolt->parent = self; bolt->damage = 100; bolt->splashDamage = 100; bolt->splashRadius = 120; bolt->methodOfDeath = MOD_ROCKET; bolt->splashMethodOfDeath = MOD_ROCKET_SPLASH; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; bolt->s.pos.trType = TR_LINEAR; bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;
// move a bit on the very first frame
VectorCopy( start, bolt->s.pos.trBase ); VectorScale( dir,
3600,
/*900,*/
bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta );
// save net bandwidth
VectorCopy (start, bolt->r.currentOrigin); return bolt; } . .

Repeat the build and run instructions from above to test out your changes:

$ cd /home/username/workspace/ioquake3_custom/
$ make
$ COPYDIR=/opt/quake3_custom make copyfiles
$ cd /opt/quake3_custom
$ ./ioquake3.i386 +set r_fullscreen 1 +set developer 1 +set vm_ui 0 +set vm_cgame 0 +set vm_game +set sv_pure 0

Quake3 should load up with any code changes incorporated.

FINAL NOTE: when making any changes to projectiles, it's worth considering how your changes will impact the number of projectile objects that will be in your field of view on average-- the more projectiles flying around, the more systems resources are being consumed which can really bomb your framerate. For example, on my system if I play a space map where all the weapons are set to behave like rocket launchers with plenty of ammo, and all the rocket launchers are rapidfire, the screen becomes a sea of rocket trails and everything slows to a crawl.