Quake Style - Quake 2 Tutorials
New/Upgraded Weapons - Thunderbolt for Quake 2!
Surely the title explains this enough!

Thunderbolt Tutorial/instructions for Quake2.
Uses TE_LIGHTNING for the effect.
120% as good as the original (lacking the original view model of course)

Build Time: 5 mins for working code, off and on, 4 hours play testing with friends=)

What you will need:
tut-ThunderBolt-Omega.zip (you wont *NEED* this, but it helps. because its the graphics/sounds *I* used/ripped for it, as well as the c/header files I modified for this.

I wrote this whole thing in DOS Edit, and built it In LCC. (yes, as you've seen by my other posts, i do use MSVC++ usually, but for this lcc is just damned quicker.

Part 1: G_LOCAL.H

Find the MeansOfDeath defines, and add these.

//OM-LGUN
#define MOD_TBOLT               34
#define MOD_TBOLT_WATER         35
#define MOD_TBOLT_DISCHARGE     36
//OM-LGUN-END


Then scroll down to the prototypes for g_utils.c (just search for "g_utils.c") and add at the end after vectoangles:

//OM-LGUN
void vectoangles2 (vec3_t vec, vec3_t angles);
//OM-LGUN-END


Now find the rest of the weapon defines and add:

//OM-LGUN
#define WEAP_TBOLT                      12 // or whatever your last free # is
//OM-LGUN-END


Now jump to the *END* of the file, (best place for them) and add the following:

//OM-LGUN
#define TBOLT_DAMAGE 20
#define TBOLT_CELLS  1
//OM-LGUN-END


Part 2: G_ITEMS.C

Add:

//OM-LGUN
void Weapon_Thunderbolt (edict_t *ent);
//OM-LGUN-END


after the BFG (or whatever your last weapon is)

Now add this item after the bfg, or somewhere in your itemlist[].

//OM-LGUN
/*QUAKED weapon_thunderbolt (.3 .3 1) (-16 -16 -16) (16 16 16)
*/
	{
		"weapon_thunderbolt",
		Pickup_Weapon,
		Use_Weapon,
		Drop_Weapon,
		Weapon_Thunderbolt,
		"misc/w_pkup.wav",
		"models/weapons/g_hyperb/tris.md2", EF_ROTATE,
		"models/weapons/v_hyperb/tris.md2",
		"w_tbolt",
		"Thunderbolt",
		0,
		TBOLT_CELLS,
		"Cells",
		IT_WEAPON|IT_STAY_COOP,
		WEAP_TBOLT,
		NULL,
		0,
		"weapons/tesla.wav weapons/lstart.wav models/proj/lightning/tris.md2"
	},
//OM-LGUN-END


Part 3: G_UTILS.C

Paste the following two functions in. (replace the old vectoangles function)

//OM-LGUN
//NEW vectoangles plus vectoangles2, from rogue source )fixes a bug and adds
//something new.

void vectoangles (vec3_t value1, vec3_t angles)
{
	float	forward;
	float	yaw, pitch;
	
	if (value1[1] == 0 && value1[0] == 0)
	{
		yaw = 0;
		if (value1[2] > 0)
			pitch = 90;
		else
			pitch = 270;
	}
	else
	{
	// PMM - fixed to correct for pitch of 0
		if (value1[0])
			yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
		else if (value1[1] > 0)
			yaw = 90;
		else
			yaw = 270;
		if (yaw < 0)
			yaw += 360;

		forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
		pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
		if (pitch < 0)
			pitch += 360;
	}

	angles[PITCH] = -pitch;
	angles[YAW] = yaw;
	angles[ROLL] = 0;
}

void vectoangles2 (vec3_t value1, vec3_t angles)
{
	float	forward;
	float	yaw, pitch;
	
	if (value1[1] == 0 && value1[0] == 0)
	{
		yaw = 0;
		if (value1[2] > 0)
			pitch = 90;
		else
			pitch = 270;
	}
	else
	{
	// PMM - fixed to correct for pitch of 0
		if (value1[0])
			yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
		else if (value1[1] > 0)
			yaw = 90;
		else
			yaw = 270;

		if (yaw < 0)
			yaw += 360;

		forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
		pitch = (atan2(value1[2], forward) * 180 / M_PI);
		if (pitch < 0)
			pitch += 360;
	}

	angles[PITCH] = -pitch;
	angles[YAW] = yaw;
	angles[ROLL] = 0;
}


Part 4: G_WEAPON.C

Add the following code at the end:

//OM-LGUN
void fire_lightning (edict_t *self, vec3_t start, vec3_t aimdir, int damage)
{
	vec3_t		from;
	vec3_t		end;
	vec3_t		dir;
	vec3_t		forward, right, up;
	trace_t		tr;
	int		mask;
	edict_t		*tmpobj;

	vectoangles2 (aimdir, dir);
	AngleVectors (dir, forward, right, up);

	VectorMA (start, 8192, forward, end);
	mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_WATER;

	tr = gi.trace (start, NULL, NULL, end, self, mask);

	if (tr.contents & (CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_WATER))
	{
		tmpobj = G_Spawn();
		VectorCopy (tr.endpos, tmpobj->s.origin);
		tmpobj->movetype		= MOVETYPE_NONE;
		tmpobj->solid		= SOLID_NOT;
		tmpobj->classname		= "tmpobject";
		tmpobj->s.modelindex	= 0;
		tmpobj->nextthink		= level.time + 0.01;
		tmpobj->think		= G_FreeEdict;
		gi.linkentity (tmpobj);

		T_RadiusDamage(tmpobj, self, damage*2, NULL, damage*4, MOD_TBOLT_WATER);
	}
	else
	{

		if ((tr.ent != self) && (tr.ent->takedamage))
			T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, damage, 0, MOD_TBOLT);
	}

	// make the lightning bolt from the gun to the wall. (cute huh?)
	gi.WriteByte (svc_temp_entity);
	gi.WriteByte (TE_LIGHTNING);
	gi.WriteShort (tr.ent - g_edicts);  
	gi.WriteShort (self - g_edicts);    
	gi.WritePosition (tr.endpos);
	gi.WritePosition (start);
	gi.multicast (start, MULTICAST_PVS);

	// spawn some sparks at the destination (go sparky go!)
	gi.WriteByte (svc_temp_entity);
	gi.WriteByte (TE_WELDING_SPARKS);
	gi.WriteByte (15);
	gi.WritePosition (tr.endpos);
	gi.WriteDir (vec3_origin);
	gi.WriteByte (0xB2 + (rand()&3));
	gi.multicast (tr.endpos, MULTICAST_PVS);

	if (self->client)
		PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
}
//OM-LGUN-END


Part 5: P_WEAPON.C

**paste the following code at the end of the file. (easy shiz eh?)

//OM-LGUN
void Weapon_Thunderbolt_Fire (edict_t *ent)
{
	vec3_t	offset, start;
	vec3_t	forward, right;
	int ammo;
	int damage;
	int toasty;

	if (!(ent->client->buttons & BUTTON_ATTACK))
	{
		ent->client->ps.gunframe++;
	}
	else
	{
		if (! ent->client->pers.inventory[ent->client->ammo_index] )
		{
			if (level.time >= ent->pain_debounce_time)
			{
				gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
				ent->pain_debounce_time = level.time + 1;
			}
			NoAmmoWeaponChange (ent);
		}
		else
		{

			damage = TBOLT_DAMAGE;

			if (is_quad)
			{
			toasty = 8000;
			damage *= 4;
			}
			else
				toasty = 2000;

			if (ent->client->ps.gunframe == 6) // if its starting. do the initial bolt sound
				gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/lfire.wav"), 1, ATTN_NORM, 0);

			gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/tesla.wav"), .5, ATTN_NORM, 0);

			if (ent->waterlevel == 3) //ZZZZZZZZZAAAAAAAAAAAAAAAPPPPPPP!!!!!!
			{
				ent->client->pers.inventory[ent->client->ammo_index] = 0;
				T_RadiusDamage(ent, ent, toasty, NULL, toasty, MOD_TBOLT_DISCHARGE);
				return;
			}


			AngleVectors (ent->client->v_angle, forward, right, NULL);

			VectorScale (forward, -2, ent->client->kick_origin);
			VectorSet(offset, 8, 8, ent->viewheight - 8);

			P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
			fire_lightning (ent, start, forward, damage);

			PlayerNoise(ent, start, PNOISE_WEAPON);

			if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
				ent->client->pers.inventory[ent->client->ammo_index] -= TBOLT_CELLS;
		}

	}

	ent->client->ps.gunframe++;
	if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
		ent->client->ps.gunframe = 7;
}

void Weapon_Thunderbolt (edict_t *ent)
{
	static int	pause_frames[]	= {0};
	static int	fire_frames[]	= {6, 7, 8, 9, 10, 11};

	Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_Thunderbolt_Fire);
}
//OM-LGUN-END


Part 6: G_CLIENT.C

Now find the obituaries, and add these reqpectively:
Under if attacker = self ...

	//OM-LGUN
	case MOD_TBOLT_DISCHARGE:
		message = "made a shocking mistake";
		break;
	case MOD_TBOLT_WATER:
		message = "feels the tingle from the electrified liquid";
		break;


Under if attacker && attacker->client ...

	//OM-LGUN
	case MOD_TBOLT:
		message = "accepts";
		message2 = "'s shaft";
		break;
	case MOD_TBOLT_WATER:
		message = "feels the tingle from";
		message2 = "'s water shock";
		break;
	case MOD_TBOLT_DISCHARGE:
		message = "suffers the extreme pain of";
		message2 = "'s suicidal discharge";
		break;
	//OM-LGUN-END


Part 7: Rebuild

Surely that isn't too hard..

Part 8: Play. Frag. Kill. Fry. Shock. You know!

That should be about it.
If you have any questions, e-mail me.

Editor (nobody)'s note:
You will either have to give this weapon to the player when they spawn, or type "give Thunderbolt" at the console when you are playing singleplayer/cheats are enabled.

-- Credits:
   Tutorial by Omega Maelstrom
   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.