Vampire Mod

  



In this patch we are going to add a new weapon to Quake 2. We are going to give the player the ability to fire a probe and suck the life of their victim (like the parasite monster).

OK, the first thing we need to do is to create a way to activate the probe. We could easily replace one of the existing weapons, but for this patch we'll play around with some of Quake2's built in commands. Open the file "g_cmds.c" and scroll down until you see a function named "ClientCommand". This function handles all Quake2 commands whether they are typed in at the console or bound to a key. It would be nice to add a new command to this function but it appears that the game engine doesn't allow this (if you type an invalid command at the console you will get an error and "ClientCommand" never gets called). So instead we are just going to re-use the "drop" command. Find the lines that say:

 
               else if (Q_stricmp (cmd, "drop") == 0)
                       Cmd_Drop_f (ent);                


and replace them with:

 
               else if (Q_stricmp (cmd, "drop") == 0)
                       Suck (ent);


This will replace the funtion normally called to drop stuff with our own function ("ent" in this case is the entity referring to the player).


Now we have to add in the function that actually does the blood sucking. Enter the following lines above "Client Command":

 
extern void parasite_drain_attack (edict_t *self);
 
void Suck(edict_t *self) 
{
        vec3_t end,forward;
        trace_t tr;
 
        VectorCopy(self->s.origin,end);
        AngleVectors (self->client->v_angle, forward, NULL, NULL);
        end[0]=end[0]+forward[0]*250;
        end[1]=end[1]+forward[1]*250;
        end[2]=end[2]+forward[2]*250;
 
        tr = gi.trace (self->s.origin, NULL, NULL, end, self, MASK_SHOT);
        if(tr.ent != NULL) 
        {
               self->enemy=tr.ent;
               parasite_drain_attack(self);
        }
}


The first line is an external declaration to keep the compiler happy.

 

 Next is the function declaration. Our function is going to be passed an "edict" which is just a structure containing information about a Quake2 object (the player in this case).

 

Then we declare two vectors. "End" is going to represent the location of our victim and "forward" will be the direction which we are facing. "Tr" is a trace structure which we will need to store the results of the "trace" command.

 

OK, now for the good stuff. What we need to do is to find a target for us to drain. For that we are going to call the "gi.trace" function (note: you will see a lot of things that start with "gi", these are all objects and functions that are part of the Quake2 engine (ie. not part of the gamex86.dll)). What gi.trace does is to search through an area in the Quake2 world and tell you if it found an object or hit a wall.

 

The first parameter is a vector representing the starting location of the trace and the fourth parameter is another vector for where the trace stops. I have no idea what the other parameters do (as far as I know, no documentation exists for any aspect of Quake2 programming. People just figure things out based on the source code released by ID. If anyone knows different please let me know).

We already know where the trace will start (the player's position, given by self->s.origin), so now all we need is the ending point.

 

First we will call VectorCopy to copy the player's location to the end vector.

 

Next we call AngleVectors which converts the player's pitch, yaw & roll into vectors facing up, forwards and to the right (we only want forward so we use NULL for the other parameters).

 

 Now, we have a unit vector (a vector of length 1) facing forwards so we are going to make it a little longer by multiplying it by 250 (roughly 20 feet in Quake2 space).

 

Finally we add this to the end vector giving us a location about 20 feet straight forward.

The trace command will return a trace_t structure that contains such information as where the trace ended and any objects it encountered. We are interested in the "ent" member of the structure which is a pointer to the first object encountered or NULL if no object was encountered.

If tr.ent is not NULL then we have our target. We then set this object as our enemy and then call the parasite_drain_attack function which is located in "m_parasite.c". This function basically checks if our target is valid an then sends some messages to the game engine which actually shoots out the probe from you to your enemy.

Just to make this a true vampire patch instead of just sucking the life out of our target we are going to add it to our own. Open up "m_parasite.c" and find the function "parasite_drain_attack". Go to the function's last line (the call to T_Damage) and after it add:

 
               self->health=self->health+damage;


All this does is take the damage done to the target and add it to the attacker's health.

Well, thats all the changes that need to be made so go ahead and compile everything (see Getting Started). When you start the game the first thing you probably want to do is to map a key or mouse button to the "drop" command (which we changed at the beginning of this tutorial).

 

Have fun!