Quake Style - Quake 3 Tutorials
Weapon Mods - Quake3 Translocater!
Turns the grenade launcher into a Translocater beacon launcher!

SanDan's Q3 Translocator!

This tutorial modifies the original grenade launcher so it fires one grenade that plays the role of a Translocater beacon.

The beacon is fired like a normal grenade but dose not explode. It's retrieved or teleported to by commands.

Files modified:
g_client.c
g_missile.c
g_items.c
g_combat.c
g_cmds.c

First we need to add the grenade launcher to the player from the start. Open g_client.c and go to line 940 you will find this line:

	client->ps.ammo[WP_GRAPPLING_HOOK] = -1;

Now add this code straight after:

	//SanDan: Add WP_GRENADE_LAUNCHER
	client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GRENADE_LAUNCHER );
	//SanDan: give player one Transporter Beacon aka Grenade :)
	client->ps.ammo[WP_GRENADE_LAUNCHER] = 1;


This will give the player a grenade launcher plus one grenade every time a player respwans.
Next we need to stop the grenade from exploding.

Open g_missile.c before the function fire_grenade, and at about line 280, add the new grenade think function:

/* SanDan:
================
G_FetchBeakin

Brings beacon back to Grenade launcher.
================
*/
void G_FetchBeakin( gentity_t *ent )
{
	ent->parent->client->ps.ammo[WP_GRENADE_LAUNCHER] = 1;
	//SanDan show a message to the client 
	//saying that his beacon returned!
	trap_SendServerCommand( ent->parent->client->ps.clientNum, "cp \"CLANCK...!\n\"");
	ent->freeAfterEvent = qtrue;
	trap_LinkEntity( ent );
}


Now go to the fire_grenade function, remove this old code and add this new code:

	bolt->nextthink = level.time + 2500;
	bolt->think = G_ExplodeMissile;
	/*
	SanDan:	give defense players in CTF a fighting chance!
		if they can stall attakers from geting there flag for 
		enough time they will avoid instant flag captures!
	*/
	bolt->nextthink = level.time + 50000;
	bolt->think = G_FetchBeakin; 


To stop the grenade from exploding when hiting other players go to G_MissileImpact and change the first if statment so it looks like this:

	//SanDan Don't Explode on impact with others
	if (  ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) {
		G_BounceMissile( ent, trace );
		G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
		return;
	}


EDITOR'S NOTE:Be careful, if you create any other "bouncing" projectiles in the same source code, they will bounce off objects which they would normally explode on!

You may pick up some extra grenades (hence beacons) from the map. Which is not supposed to happen. So fix that by adding this to the begining of Add_Ammo function in g_items.c:

	//SanDan: don't add more ammo to our Translocater
	if (weapon == WP_GRENADE_LAUNCHER) return; 


What if the player dies after throwing a beacon? Well we better give him/her back what is theres. open g_combat and go to player_die function there at about line 334 add:

	//SanDan: retrieve beacon if thrown
	if (!self->client->ps.ammo[WP_GRENADE_LAUNCHER]) {
		Cmd_RetreavBeakin_f(self);
	}


Now we will define the Translocater commands. Open g_cmds.c, and at the very begining just after #include "g_local.h" add:

	void G_FetchBeakin( gentity_t *ent );


We declare it here so we can use it in the commands.
At around line 1027 before ClientCommand we are going to add the command that will retreive the beacon. Add this:
  
/*SanDan: modified from Gerbil!'s pipebomb tut
=================
Cmd_GetBeacon_f

Returns Beacon to player
=================
*/
void Cmd_GetBeacon_f( gentity_t *ent)
{	gentity_t *grenades = NULL;
	while ((grenades = G_Find (grenades, FOFS(classname), "grenade")) != NULL) //search for grenade entities
	{	if (grenades->r.ownerNum == ent->s.clientNum)  //make sure its our grenade
		{
			grenades->think = G_FetchBeakin;			
			grenades->nextthink = level.time + 2;
		}	
	}
	/*
	even if we don't find any give player a grenade
	this is just incase any grenades have fallen off the map
	*/	
	ent->client->ps.ammo[WP_GRENADE_LAUNCHER] = 1;
}


After that add the code that will teleport the player to the beacon:

/*SanDan: modifid from Gerbil!'s pipebombs tut
=================
Cmd_teleport_f

Teleports player to beacon
=================
*/
void Cmd_teleport_f( gentity_t *ent)
{	gentity_t *grenades = NULL;
	vec3_t origin,angles;
	while ((grenades = G_Find (grenades, FOFS(classname), "grenade")) != NULL) //search for grenade entities
	{	if (grenades->r.ownerNum == ent->s.clientNum)  //make sure its our grenade
		{
			//SanDan: Get Grenade Postion
			BG_EvaluateTrajectory( &grenades->s.pos, level.time, origin );
			//SanDan: give teleporting kick!
			origin[2] += 9;
			//SanDan: teleport, and hold on to player viewangle
			TeleportPlayer( ent, origin, ent->client->ps.viewangles );

			//SanDan: return beakin to player
			grenades->think = G_FetchBeakin;			
			grenades->nextthink = level.time + 2;
		}
	}
}


After (at around line 1112), add the new code:

	else if (Q_stricmp (cmd, "setviewpos") == 0)
		Cmd_SetViewpos_f( ent );
	else if (Q_stricmp (cmd, "getbeacon") == 0)
		Cmd_GetBeacon_f(ent);
	else if (Q_stricmp (cmd, "teleport") == 0)
		Cmd_teleport_f(ent);

This adds two console commands /getbeacon which retrieves the beacon, or gives a new one in place of ones that fell of map, and /teleport which teleports the player to the beacon position.

Compile and run.
You will start of with the grenade launcher. Place the beacon at your team's flag and try to get the enemy's flag befor the beacon times out, or you will have to fight your way back!

-- Credits:
   Tutorial by SanDan
   Return to QS Tutorials

-- Important:
   If you do use something from QuakeStyle in your mod, please give us credit.
   Our code is copyrighted, but we give permission to everyone to use it in any way they see fit, as long as we are recognized.