TE_LIGHTNING - the implementation a few of you want.....


 

Posted by Omega Maelstrom (pm3-08.thunderstar.net) on January 10, 19100 at 15:27:29:

 

 

Alright, here it is... i spent about 4 hours today with this thing (5 mins on the code the rest playtesting it, cuz it was oh so much fun...
the Quake1 thunderbolt. YumNum! the damage is all adjustable, fuzzysteve had made a comment about the discharge damage but, i didnt have a chance to actually give him the real REASON its so high. .. because its a radius, if its NOT, as high as it is, you dont die when you discharge if you have 200 armor. so, too bad i say! =)
also, the tutorial is in zipform as a link down at the bottom here. the zip contains the 2 models, 2 wavs i borrowed(ripped?) from q1 and rogue, and an icon i made from scatch in ab out 5 seconds. (well thats exagerration, but it didnt take long for the piece of crap that it is =))
anyway, on with the instructions/tutorial, or whateevr you wanna call it =)

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

 


the tutorial, in zip form, w/ md2&wav


Follow Ups

 

UPDATE: Thunderbolt


 

Posted by Omega Maelstrom (pm3-19.thunderstar.net) on January 11, 19100 at 13:58:02:
In reply to: TUTORIAL: TE_LIGHTNING - the implementation a few of you want..... posted by Omega Maelstrom (pm3-08.thunderstar.net) on January 10, 19100 at 15:27:29

ok, here is an update for that tut, the changes wont be included in the zip, cuz i dont want to re-upload the thing. they'll be here and ONLY here!

this little update, changes the way discharge and electrified water goes.. i was playing around in single player and i realized 'hrm, i need to fix this. because im standing on land and im shocking myself by shooting the water around me'
and so, i did. and heres the code changes for it.

you only need to modify p_weapon.c and g_weapon.c
and here they are

first change is to Weapon_Thunderbolt_Fire
add
edict_t *head;
underneath int toasty;
then replace the old statement if (waterlevel == 3) with the following:

if (ent->waterlevel == 3) //ZZZZZZZZZAAAAAAAAAAAAAAAPPPPPPP!!!!!!
{
ammo = ent->client->pers.inventory[ent->client->ammo_index];
ent->client->pers.inventory[ent->client->ammo_index] = 0;

while ((head = findradius(head, ent->s.origin, damage*ammo)) != NULL)
{
if (!(head->svflags & SVF_MONSTER) && !head->client)
continue;
if (!head->takedamage)
continue;
if (!head->waterlevel)
continue;
T_Damage (head, ent, ent, vec3_origin, head, vec3_origin, toasty, toasty/5, 0, MOD_TBOLT_DISCHARGE);
}

return;
}

thats it for p_weapon.c
now load up g_weapon.c and do the following..

add edict_t *head; underneath the other stuff, in Fire_Lightning
and then replace the T_RadiusDamage line with the following..

while ((head = findradius(head, tmpobj->s.origin, damage*4)) != NULL)
{
if (!(head->svflags & SVF_MONSTER) && !head->client)
continue;
if (!head->takedamage)
continue;
if (!head->waterlevel)
continue;

T_Damage (head, self, self, aimdir, head, vec3_origin, damage, damage, 0, MOD_TBOLT_WATER);
}


and thats it.
now you no longed kill people not in the water, by shooting it, or discharging in it.

-Omega

 


MegaManX Q2 TC