Adding a new weapon
Adding a new weapon to Quake2 is surprisingly easy. In this tutorial I'll explain the function and importance of the various weapon functions that need to be coded in order to work in a new weapon into Quake2. I'll also go over how to add the weapon as a pick-up item that enables you to place the weapon in a map.
The weapon this tutorial adds is pretty useless - it's a flaregun. All it does is light up things and shoot sparks every once in a while. The flaregun is not meant to be used or distributed; it is merely a basic weapon used to illustrate how to add new weapons.
You'll need to get the .zip file that contains the modified models to do the tutorial.
Basic Setup
The actual .md2 models used by the flaregun already exist (except for the flare itself) in the models/weapons/v_flareg and models/weapons/g_flareg. I've modified these models a little, and therefore we're going to have to use the modified models instead of the ones in the game. To do this, we are going to duplicate the directory structure of quake2/baseq2 in our mod directory (let's call it quake2/flaremod). It also contains the item icon for the flaregun (used while cycling through the itemlist using [ and ]).
The content of the tutorial .zip file (see above) has this directory structure, so just unzip the whole thing to the drive that contains the quake2 folder. You'll end up with a flaremod directory under /quake2.
Weapon models
There are two distinct models you will need to make for your weapon. The first is the model that will be used to represent the weapon in the map - its the one that spins. This model has only one frame, and goes in the /models/weapons/g_weaponname directory. In our case, the model goes in /models/weapons/g_flareg.
The second model is the one that you see when firing the weapon. The model has four animations in it - enable (unholster), fire, idle, and disable (holster). Check out some of the model sites around for info on creating models. This model goes in the /models/weapons/v_weaponname directory. In our case, it goes in /models/weapons/v_flareg.
I also made a very simple model to use as the actual flare. It goes in the /models/objects/flare directory.
Itemlist icon
The itemlist icon that appears when
you scroll through the itemlist is specified in the g_item structure (which
we will look at later). It is a 23x23 .pcx, and as you can see I
didn't spend too much time on mine :). It goes in the /pics directory.
Coding the new weapon
Ok, here we go. We're going
to build the functions that make a weapon work in a "ground up" manner.
There are three functions that make a weapon work, and each are interdependant
to each other. Here they are, in ascending order:
fire_<weaponname>
Source file: g_weapon.c
Placement: At end of file
/*
* Drops a spark from the flare flying thru the air. Checks to make * sure we aren't in the water. */ void flare_sparks(edict_t *self) { vec3_t dir; vec3_t forward, right, up;
// Spawn some sparks. This isn't net-friendly at all, but will
// If we are still moving, calculate the normal to the direction
gi.WriteDir (up);
/*
Purpose: The think function of a flare round. It generates sparks
Notes:
- I haven't seen self->timestamp used anywhere else in the code,
}
void
flare_touch( edict_t *ent, edict_t *other,
void
fire_flaregun (edict_t *self, vec3_t start, vec3_t aimdir,
vectoangles
(aimdir, dir);
flare
= G_Spawn();
flare->s.modelindex
= gi.modelindex ("models/objects/flare/tris.md2");
|
fire_flaregun is the lowest of the three required weapon functions. fire_flaregun is responsible for spawning the projectile (if any) and determining who gets hurt because the weapon was fired. It accepts a bunch of parameters that specify the entity firing the weapon, where the weapon is aiming, the damage it will do, and other weapon-specific parameters.
Looking at the code, you see that
there are a couple of support functions.
flare_think is the think function
for the actual flare itself (not the gun). It takes care of killing
the flare after 15 seconds and other things. flare_sparks is a function
called by flare_think in order to make the flare shoot sparks. The
flare_touch function is called when the flare bumps into something.
weapon_<weaponname>_fire
Source file: p_weapon.c
Placement: At end of file
/*
* Forward declaration for fire_flaregun(), which is defined in * g_weapon.c. */ void fire_flaregun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius); /*
//
Setup the parameters used in the call to fire_flaregun()
VectorScale
(forward, -2, ent->client->kick_origin);
//
Make the flaregun actually shoot the flare
//
Bump the gunframe
PlayerNoise(ent, start, PNOISE_WEAPON); //
Subtract one cell from our inventory
|
weapon_flaregun_fire is in the middle
of the weapon function heirarchy. It accepts one parameter, a pointer
to the edict_t that is firing the weapon. It is responsible for calling
the weapon's fire_<weaponname> function and updating the ammo inventory
(if necessary). Because of this, it is important to remember to give
a forward declaration for the fire_<weaponname> function in p_weapon.c.
Weapon_FlareGun
Source file: p_weapon.c
Placement: At end of file
/*
* Weapon_FlareGun (edict_t *ent) * * This is the function that is referenced in the itemlist structure * defined in g_items.c. It is called every frame when our weapon is * active. It calls Weapon_Generic() to handle per-frame weapon * handling (like animation and stuff). Haven't delved too deeply * into Weapon_Generic()'s responsiblities... if someone has insight * drop me a line :) */ void Weapon_FlareGun (edict_t *ent) { static int pause_frames[] = {39, 45, 50, 53, 0}; static int fire_frames[] = {9, 17, 0};
// Check the top of p_weapon.c for definition of Weapon_Generic
|
Weapon_FlareGun is the top-level
weapon function. This function does some interesting things... First,
it declares two arrays of integers - both of which I am not sure how they
are used. It then calls Weapon_Generic, which is used once per frame
to handle weapon frames and other such things. It passes the two
integer arrays and a pointer to the weapon_flaregun_fire function, which
is called when the user presses the attack button.
Finally, in order for Quake2 to see our new weapon, we need to add it to the item list that is built in g_items.c. We are going to add a new gitem_t structure in the middle of the list defined in g_items.c. It should go right after the gitem_t structure that describes the bfg:
Source file: g_items.c
Placement: Right after the one for
the BFG and before the ammo gitem_t's.
/*QUAKED
weapon_flaregun (.3 .3 1) (-16 -16 -16) (16 16 16)*/
{
"weapon_flaregun",// class name
|
The code above is pretty self-explanatory. It simply adds the flare gun as a new weapon type to Quake2. Look at the gitem_s struct defined in the Quake2 source for in-depth info.
Aftermath
After cutting/pasting all this code into your own gamex86 source, compile and everything should go well. Then start Quake2 with the +set game flaremod and let 'er rip.
I've included a map specifically built to use the flaregun, rob3.bsp, that was built by Spawn22 of Skinning for Dummies. The skin for the flaregun was also written by Spawn22. If you want to use the flaregun on a normal map, do a "give flare gun" and a "use flare gun" in order to use it. You might also want to bind a key sequence to "use flare gun" so that you don't have to type it in every time you want to use it.
I hope this tutorial on adding new weapons gives you insight on how to add new weapons to Quake2. Hopefully the new weapons you write will be more usefull than the flaregun :) If you have any questions at all , don't hesitate to email me.
The next installment in this series will show you how to implement the lasergun I'm working on currently. It should be pretty cool, so keep your eyes peeled to Inside3D.