Main  |  Maps  |  Programming | Links |  Files |  Demos |  Forums

This tut guides you through the process of converting the grenade launchers grenades to be little transportation balls( like UT's Translocator ) :) You can have 1 at a time. After firing a grenade type in the console( or set a bind to it )
/telegren

Open up g_local.h, we need to define G_ExplodeMissile so other files besides where it is defined( g_missile.c ) can use it. So find this:

void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm );
 void G_AddEvent( gentity_t *ent, int event, int eventParm );
 void G_SetOrigin( gentity_t *ent, vec3_t origin );

Up under those defines add this:

void G_ExplodeMissile( gentity_t *ent );

And also we have to let quake3 now where to teleport them and if there is a spot set yet, so go find:

	qboolean	botDelayBegin;

Up under it add:

	vec3_t      teleloc;
 	int         istelepoint;

Now go into g_missile.c and find near the top:

	if ( ent->s.eFlags & EF_BOUNCE_HALF ) {
 		VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta );
 		// check for stop
 		if ( trace->plane.normal[2] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 ) {
 			G_SetOrigin( ent, trace->endpos );

Add directly beneath it:

		    ent->parent->istelepoint = 1;
VectorCopy(ent->r.currentOrigin, ent->parent->teleloc);
ent->parent->teleloc[2] += 6;

What that does is once the grenade stops, it lets quake3 know we have a spot to teleport to, then it adds 5 to the z coordinate on the grenades origin so that the player does not spawn in the ground, then it copies the grenades origing( after adding 5 to the z axis ) to the clients teleportation spot. Part of the players bounding box gets stuck in the ground if you don't add that/add less than 5, you get stuck in the ground. Its fun to add a 100 or so and go THUMP to the ground when you teleport. Now we need to edit some more stuff. Go find:

/*
 =================
 fire_grenade
 =================
 */

Replace that little bit and its function below it with:

void G_ExplodeGrenade( gentity_t *ent ) {
 	ent->parent->istelepoint = 0; // client cannot teleport
 	VectorClear( ent->parent->teleloc ); // clear the teleport location
 	G_ExplodeMissile( ent );
 }
 /*
 =================
 fire_grenade
 =================
 */
 gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t dir) {
 	gentity_t	*bolt;
 
 	VectorNormalize (dir);
 
 	bolt = G_Spawn();
 	bolt->classname = "grenade";
 	bolt->nextthink = level.time + 30000;
 	bolt->think = G_ExplodeGrenade;
 	bolt->s.eType = ET_MISSILE;
 	bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
 	bolt->s.weapon = WP_GRENADE_LAUNCHER;
 	bolt->s.eFlags = EF_BOUNCE_HALF;
 	bolt->r.ownerNum = self->s.number;
 	bolt->parent = self;
 	bolt->damage = 100;
 	bolt->splashDamage = 100;
 	bolt->splashRadius = 150;
 	bolt->methodOfDeath = MOD_GRENADE;
 	bolt->splashMethodOfDeath = MOD_GRENADE_SPLASH;
 	bolt->clipmask = MASK_SHOT;
 
 	bolt->s.pos.trType = TR_GRAVITY;
 	bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;
 	VectorCopy( start, bolt->s.pos.trBase );
 	VectorScale( dir, 700, bolt->s.pos.trDelta );
 	SnapVector( bolt->s.pos.trDelta );			// save net bandwidth
 
 	VectorCopy (start, bolt->r.currentOrigin);
 
 	return bolt;
 }

Lemme explain what this does.
bolt->nextthink = level.time + 30000;
Runs G_ExplodeGrenade in 30 seconds.
bolt->think = G_ExplodeGrenade;
Calls the function to explode the grenade, tells the program that you cannot teleport, then clears the grenades position for the owner so he has no where to teleport to. Now open up g_weapons.c and find:

void weapon_grenadelauncher_fire (gentity_t *ent) {

Replace it with this following code:

void weapon_grenadelauncher_fire (gentity_t *ent) {
 	gentity_t	*m;
 	gentity_t *grenades = NULL;
 
 	while ((grenades = G_Find (grenades, FOFS(classname), "grenade")) != NULL)
 	{
 		if(grenades->r.ownerNum == ent->s.clientNum)  //make sure its ours
 		{
 			ent->istelepoint = 0; // client cannot teleport
 			VectorClear( ent->teleloc ); // clear the teleport location
 			grenades->think = G_ExplodeMissile;
 			grenades->nextthink = level.time;
 		}
 	}
 	// extra vertical velocity
 	forward[2] += 0.2;
 	VectorNormalize( forward );
 
 	m = fire_grenade (ent, muzzle, forward);
 	m->damage *= s_quadFactor;
 	m->splashDamage *= s_quadFactor;
 }  

All that does is find any entities named "grenade" and then checks to see if its ours, if so it blows it up, then fires out our new one, so we can only have out 1 at a time.

Now in g_cmds.c lets add our teleportation command. Right below the #include line(s) at the top of the file add:

/*
=================
Cmd_TeleGren_f
=================
*/
void Cmd_TeleGren_f (gentity_t *ent) {
if ( ent->istelepoint == 1 ) {
VectorCopy( ent->teleloc, ent->client->ps.origin );
} else {
G_Printf( S_COLOR_GREEN "No teleportation port\n" );
}
}

Then at the bottom of the file right up under:

	else if (Q_stricmp (cmd, "setviewpos") == 0)
Cmd_SetViewpos_f( ent );
else if (Q_stricmp (cmd, "stats") == 0)
Cmd_Stats_f( ent );

Add:

	else if (Q_stricmp (cmd, "telegren") == 0)
Cmd_TeleGren_f( ent );

There, we are done! Enjoy.

I spend my time programming and writing these tutorials, so please feel free to use this code in your mod as long as www.inolen.com and the author receive credit.

Design Copyright inolen 2000