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

    Written by Omega Maelstrom. omega@mmxq2tc.cjb.net

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

    What you will need: tut-tbolt_omega.zip (you wont *NEED* this, but it
    helps. because its the graphics/sounds *I* used/ripped <grin> 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.

    legend:
    ***  denotes first step
    **   denotes sub-steps inbetween
    ===  denotes the END of a section
    ==== denotes the end of a step

*/

Part 1:

***open up g_local.h and add the following:

**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

===end of g_local.h===

***next, open up 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 items list.

//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

===end of g_items.c===

***next, open up g_utils.c

**paste the following two functions in. (replace the old vectoangles)

//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;
}


===end g_utils.c===


***next, open up 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


===end g_weapon.c===

***open up 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


===end p_weapon.c===

***for one of the final steps, load up p_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;
**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



===end p_client.c===

====end Step #1====

Step 2: rebuild.

====end Step #2====


Step 3: Play.Frag.Kill.Fry.Shock.you know.
====end Step #3====

that should be about it.
if you have any questions, email me.


-Omega

