Adding Various Laser Devices to your mod


Posted by Maj.Bitch (12.145.208.*) at 9:32 AM, 3/7/2001:


Here is a complete file which contains my LaserSweep Weapon, my LaserFence Device, and my Laser Corral device. Simple to add but pretty awesome stuff!

The LaserSweep looks like the arm of a clock as it slowly sweeps around and around obliterating anything which it touches.. Great for defending large open areas.

The LaserFence device is cool too. You hit your aliased key and a fence which looks like laserbeams is generated which will block anybody from getting thru. Great for setting up defenses or for fencing off narrow hallways or passageways so the badguys won't be able to come at you thru there.

The LaserCorral is an extension of the laser fence. It is basically a small square area created out of 4 laser fences. You can use it for whatever purpose you want. What would be really cool is to modify my teleporter tutorial so that players are beamed into the enclosed area of the corral. If they touch the corral fence then they get fried!! heheh

Here it is:

Simple.. Just create a new file called g_laser.c and add in ALL the following source..

<C&NBSP;CODE>
#include "g_local.h"

//=======================================================
//============= ELECTRIC FENCE ROUTINES =================
//=======================================================

// Add this MOD obit flag to your g_local.h file so
// you can use it in your ClientObituary() function.
#define MOD_LASERSWEEP  55


#define FENCE_LENGTH 120

//==============================================================
void abs_vector(vec3_t vec1,vec3_t vec2,vec3_t result){
int j;
  for (j=0; j<3; j++)
    result[j]=abs(vec1[j]-vec2[j]);
}

//==============================================================
void min_vector(vec3_t start,vec3_t end1,vec3_t end2,vec3_t result){
vec3_t eorg1,eorg2;

  VectorClear(eorg1);
  VectorClear(eorg2);

  abs_vector(start,end1,eorg1);
  abs_vector(start,end2,eorg2);

  if (VectorLengthSqr(eorg1) < VectorLengthSqr(eorg2))
    VectorCopy(end1,result);
  else
    VectorCopy(end2,result);
}

//=======================================================
void beam_laser_think(edict_t *beam) {
vec3_t end;
trace_t tr;

  // Has the time expired?
  if (beam->wait < level.time) {
    G_FreeEdict(beam);
    return; }

  VectorMA(beam->s.origin,beam->spawnflags,beam->movedir,end);

  tr=gi.trace(beam->s.origin,NULL,NULL,end,beam,MASK_ALL);

  // Sparks on top of Post.
  if (beam->spawnflags==55)
    G_Spawn_Splash(TE_LASER_SPARKS,4,Laser_BlueRed,end,zvec);

  // Anybody step across these laser beam traces yet?
  if ((tr.ent) && !(tr.ent->flags & FL_IMMUNE_LASER))
    T_Damage(tr.ent,beam,beam->activator,beam->movedir,tr.endpos,zvec,beam->dmg,1,DAMAGE_ENERGY,MOD_TARGET_LASER);

  VectorCopy(tr.endpos,beam->s.old_origin);

  beam->nextthink = level.time + 0.1;
}

//=======================================================
// Spawns a 2 post 4 rail Electric Laser Fence..
//=======================================================
void Spawn_LaserFence(edict_t *ent) {
edict_t *beam[6];
int i;
vec3_t post1,post2;
vec3_t forward,up,right,end,torigin,torigin2,len;
trace_t tr;

  VectorCopy(ent->s.origin,torigin);
  AngleVectors(ent->s.angles,forward,right,up);
  // Move torigin forward 50 units to end.
  VectorMA(torigin,50,forward,end);
  // Trace this path to see what we hit.
  tr = gi.trace(torigin,NULL,NULL,end,NULL,MASK_SOLID);
  // torigin2 is the shorter of these vectors.
  min_vector(torigin,tr.endpos,end,torigin2);
  VectorClear(end);
  // Move left from torigin2 1/2 fence length to end.
  VectorMA(torigin2,-FENCE_LENGTH*0.5,right,end);
  // Trace this path to see what we hit.
  tr = gi.trace(torigin2,NULL,NULL,end,NULL,MASK_SHOT);
  // Left post1 is the shorter of these vectors.
  min_vector(torigin2,tr.endpos,end,post1);
  VectorClear(end);
  // Move right from post1 entire length to end.
  VectorMA(post1,FENCE_LENGTH,right,end);
  // Trace this path to see what we hit.
  tr = gi.trace(torigin2,NULL,NULL,end,NULL,MASK_SHOT);
  // Right post2 is the shorter of these vectors.
  min_vector(torigin2,tr.endpos,end,post2);

  // Get length of fence.
  abs_vector(post1,post2,len);

  // Okay,let's make the damn beam already!!
  for (i=0; i<=5; i++) {
    beam[i] = G_Spawn();
    beam[i]->owner = beam[i];
    beam[i]->classname= "LaserFence";
    beam[i]->activator = ent; // Must set for frags!!
    beam[i]->movetype = MOVETYPE_NONE;
    beam[i]->solid = SOLID_NOT;
    beam[i]->svflags &= ~SVF_NOCLIENT;
    beam[i]->s.renderfx = RF_BEAM;
    beam[i]->s.modelindex = 1;
    beam[i]->spawnflags = VectorLength(len); // Store Length here..
    beam[i]->s.skinnum = Laser_Red;
    if (i==0) // Only need sound for first beam..
      beam[i]->s.sound = gi.soundindex("world/laser.wav");
    else
      beam[i]->s.sound=0;
    beam[i]->s.frame=2;
    VectorSet(beam[i]->mins,-8,-8,-8);
    VectorSet(beam[i]->maxs,8,8,8);
    beam[i]->dmg = 25; // Each Rail..
    VectorClear(beam[i]->s.angles);
    VectorCopy(right,beam[i]->movedir);
    VectorCopy(post1,beam[i]->s.origin);
    VectorCopy(post1,beam[i]->s.old_origin);

    switch (i) {
      case 0: // Bottom Fence Rail
              VectorMA(beam[i]->s.origin,-15,up,beam[i]->s.origin);
              break;
      case 1: // Mid-Lower Fence Rail
              break;
      case 2: // Mid-Upper Fence Rail
              VectorMA(beam[i]->s.origin,15,up,beam[i]->s.origin);
              break;
      case 3: // Top Fence Rail
              VectorMA(beam[i]->s.origin,30,up,beam[i]->s.origin);
              break;
      case 4: // Make 1st Fence Post.
              beam[i]->spawnflags = 55;
              beam[i]->s.frame *= 4;
              VectorCopy(post1,beam[i]->s.origin);
              VectorMA(beam[i]->s.origin,-20,up,beam[i]->s.origin);
              VectorCopy(up,beam[i]->movedir);
              beam[i]->s.skinnum = Laser_Blue;
              break;
      case 5: // Make 2nd Fence Post.
              beam[i]->spawnflags = 55;
              beam[i]->s.frame *= 4;
              VectorCopy(post2,beam[i]->s.origin);
              VectorMA(beam[i]->s.origin,-20,up,beam[i]->s.origin);
              VectorCopy(up,beam[i]->movedir);
              beam[i]->s.skinnum = Laser_Blue;
              break; }
    beam[i]->wait = level.time + 60.0;  // 1 Minute to beam Destruct.
    beam[i]->think = beam_laser_think;
    beam[i]->nextthink = level.time + 1.0;
    gi.linkentity(beam[i]); }
}

//============================================================
void Cmd_LaserFence_f(edict_t *ent) {
  Spawn_LaserFence(ent);
}


//=======================================================
//============== ELECTRIC LASER CORRAL ==================
//=======================================================

#define CORRAL_LENGTH 80

//=======================================================
// Spawns an Electric Laser Coral
//=======================================================
void Spawn_LaserCorral(edict_t *ent) {
int i,j;
edict_t *beam[4][4];
vec3_t post[4],tangles,len;
vec3_t forward,up,right,dir,end;
vec3_t torigin,torigin2;
trace_t tr;

  // Don't allow dead/respawning players to do this!
  if (!G_ClientInGame(ent)) return;

  VectorCopy(ent->s.origin,torigin);

  for (j=0; j<=3; j++) {
    switch (j) {
      case 0: // Get first post position
              VectorCopy(ent->s.angles,tangles);
              AngleVectors(tangles,forward,right,up);
              VectorMA(torigin,50,forward,end);
              tr = gi.trace(torigin,NULL,NULL,end,NULL,MASK_SOLID);
              min_vector(torigin,tr.endpos,end,torigin2);
              VectorClear(end);
              VectorMA(torigin2,-CORRAL_LENGTH/2,right,end);
              tr = gi.trace(torigin2,NULL,NULL,end,NULL,MASK_SHOT);
              min_vector(torigin2,tr.endpos,end,post[j]);
              break;
      case 1: // Next post
      case 2: // Next post
      case 3: // Next post
              // Get dir of post[j-1] --> post[j]
              VectorSubtract(post[j],post[j-1],dir);
              // Split dir into angle vectors.
              vectoangles(dir,tangles);
              // Find which way is 'right' of post[j].
              AngleVectors(tangles,NULL,right,NULL); }

     // post[j+1] is CORRAL_LENGTH 'right' of post[j]
     VectorClear(end);
     VectorMA(post[j],CORRAL_LENGTH,right,end);
     tr = gi.trace(torigin2,NULL,NULL,end,NULL,MASK_SHOT);
     min_vector(torigin2,tr.endpos,end,post[j+1]);
     AngleVectors(tangles,NULL,right,NULL);
     VectorClear(end);

     // Rails need to know length between posts!
     abs_vector(post[j],post[j+1],len);

     for (i=0; i<=3; i++) {
       beam[j][i] = G_Spawn();
       beam[j][i]->owner = beam[j][i];
       beam[j][i]->classname= "LaserCorral";
       beam[j][i]->activator = ent; // Must set for frags!!
       beam[j][i]->movetype = MOVETYPE_NONE;
       beam[j][i]->solid = SOLID_NOT;
       beam[j][i]->svflags &= ~SVF_NOCLIENT;
       beam[j][i]->s.renderfx = RF_BEAM;
       beam[j][i]->s.modelindex = 1;
       beam[j][i]->spawnflags = VectorLength(len); // Store Length here..
       beam[j][i]->s.skinnum = Laser_Red;
       if (i==0) // Only need sound for first one..
         beam[j][i]->s.sound = gi.soundindex("world/laser.wav");
       else
         beam[j][i]->s.sound=0;
       beam[j][i]->s.frame=2;
       VectorSet(beam[j][i]->mins,-8,-8,-8);
       VectorSet(beam[j][i]->maxs,8,8,8);
       beam[j][i]->dmg = 50; // Damage for each Rail..
       VectorClear(beam[j][i]->s.angles);
       VectorCopy(right,beam[j][i]->movedir);
       VectorCopy(post[j],beam[j][i]->s.origin);
       VectorCopy(post[j],beam[j][i]->s.old_origin);
       switch (i) {
         case 0: // Mid-Lower Fence Rail
                break;
         case 1: // Mid-Upper Fence Rail
                VectorMA(beam[j][i]->s.origin,15,up,beam[j][i]->s.origin);
                break;
         case 2: // Make a Fence Post.
                beam[j][i]->spawnflags = 56; // No particles.
                beam[j][i]->s.frame *= 4;
                VectorCopy(post[j],beam[j][i]->s.origin);
                VectorMA(beam[j][i]->s.origin,-20,up,beam[j][i]->s.origin);
                VectorCopy(up,beam[j][i]->movedir);
                beam[j][i]->s.skinnum = Laser_Blue;
                break; }
       beam[j][i]->wait = level.time + 60.0;  // 1 Minute to Destruct.
       beam[j][i]->think = beam_laser_think;
       beam[j][i]->nextthink = level.time + 2.0;
       gi.linkentity(beam[j][i]); } }
}

//==========================================================
//============== LASER SWEEPER ROUTINES ====================
//==========================================================

#define SWEEPARM_LENGTH 200

//==========================================================
// Alternately think for Post and SweepArm...
//==========================================================
void Sweep_Think(edict_t *laser) {
vec3_t forward,end;
trace_t tr;
int degrees=5;

  // Time to self-destruct?
  if (laser->wait < level.time) {
    G_FreeEdict(laser);
    return; }

  // Is this the SweepArm thinking?
  if (laser->s.frame == 4) {
    // Warzone: thanks for the help!
    laser->s.angles[YAW]=(int)((laser->s.angles[YAW]+180)+degrees)%360-180;
    AngleVectors(laser->s.angles,forward,NULL,NULL);
    VectorCopy(forward,laser->movedir);  }

  // What is the end vector for this update?
  VectorMA(laser->s.origin,laser->spawnflags,laser->movedir,end);

  // Trace laser beam from origin to end (Draws the Laser Beam!)
  tr=gi.trace(laser->s.origin,NULL,NULL,end,NULL,MASK_SHOT);

  // Is this the SweepArm thinking?
  if (laser->s.frame == 4)
    // Spawn sparks at end of Sweep arm.
    G_Spawn_Splash(TE_LASER_SPARKS,4,Laser_Red,tr.endpos,zvec);
  else
    // Spawn sparks at top of Post..
    G_Spawn_Splash(TE_LASER_SPARKS,4,Laser_Green,tr.endpos,zvec);

  // Anybody get hit by laser beam?  Yes? then cut'em in half!!
  if ((tr.ent) && !(tr.ent->flags & FL_IMMUNE_LASER))
    T_Damage(tr.ent,laser,laser->activator,laser->movedir,tr.endpos,zvec,laser->dmg,1,DAMAGE_ENERGY,MOD_LASERSWEEP);

  VectorCopy(tr.endpos,laser->s.old_origin);
  laser->nextthink = level.time + 0.1;
}

//==========================================================
void MultiBlade_Think(edict_t *laser) {
vec3_t forward,end;
trace_t tr;
int i,degrees=10;

  // Time to self-destruct?
  if (laser->wait < level.time) {
    G_FreeEdict(laser);
    return; }

  for (i=1; i<=3; i++) {
    laser->s.angles[YAW]=(int)((laser->s.angles[YAW]+180)+(90*i)+degrees)%360-180;
    AngleVectors(laser->s.angles,forward,NULL,NULL);
    VectorCopy(forward,laser->movedir);
    VectorMA(laser->s.origin,laser->spawnflags,laser->movedir,end);
    tr=gi.trace(laser->s.origin,NULL,NULL,end,NULL,MASK_SHOT);
    if (tr.fraction != 1.0)
      G_Spawn_Splash(TE_LASER_SPARKS,4,Laser_Red,tr.endpos,zvec);
    if ((tr.ent) && !(tr.ent->flags & FL_IMMUNE_LASER))
      T_Damage(tr.ent,laser,laser->activator,laser->movedir,tr.endpos,zvec,laser->dmg,1,DAMAGE_ENERGY,MOD_LASERSWEEP); }

  VectorCopy(tr.endpos,laser->s.old_origin);
  laser->nextthink = level.time + 0.1;
}

//===========================================================
void Spawn_LaserSweep(edict_t *ent) {
edict_t *post,*sweep;
vec3_t forward,up,torigin;

  AngleVectors(ent->s.angles,forward,NULL,up);
  VectorMA(ent->s.origin,50,forward,torigin);
  // Okay,torigin is the location of the Main Post

  // Now,let's create the main post for the sweeper
  post = G_Spawn();
  post->owner = NULL;
  post->classname= "LaserSweep";
  post->activator = ent; // Must set for frags!!
  post->movetype = MOVETYPE_NONE;
  post->solid = SOLID_NOT;
  post->svflags &= ~SVF_NOCLIENT;
  post->s.renderfx = RF_BEAM;
  post->s.modelindex = 1;
  post->s.skinnum = Laser_Green;
  post->s.sound = gi.soundindex("world/laser.wav");
  VectorSet(post->mins,-8,-8,-8);
  VectorSet(post->maxs,8,8,8);
  post->dmg = 0;
  post->takedamage = DAMAGE_NO;
  VectorCopy(ent->s.angles,post->s.angles);
  VectorCopy(up,post->movedir);
  VectorCopy(torigin,post->s.origin);
  VectorCopy(torigin,post->s.old_origin);
  post->spawnflags = 35; // height of post
  post->s.frame = 8;     // width of post
  VectorMA(post->s.origin,-20,up,post->s.origin);

  post->wait = level.time + 60.0;  // 1 Minute to beam Destruct.
  post->think = Sweep_Think;
  post->nextthink = level.time + 1.0;
  gi.linkentity(post);

  // Now,let's create the Sweep Arm
  sweep = G_Spawn();
  sweep->owner = NULL;
  sweep->activator = ent; // Must set for frags!!
  sweep->movetype = MOVETYPE_NONE;
  sweep->solid = SOLID_NOT;
  sweep->svflags &= ~SVF_NOCLIENT;
  sweep->s.renderfx = RF_BEAM;
  sweep->s.modelindex = 1;
  sweep->s.skinnum = Laser_Red;
  sweep->s.sound = gi.soundindex("world/laser.wav");
  VectorSet(sweep->mins,-8,-8,-8);
  VectorSet(sweep->maxs,8,8,8);
  sweep->dmg = 20;
  sweep->takedamage = DAMAGE_NO;
  VectorCopy(ent->s.angles,sweep->s.angles);
  AngleVectors(sweep->s.angles,forward,NULL,NULL);
  VectorCopy(forward,sweep->movedir);
  VectorCopy(torigin,sweep->s.origin);
  VectorCopy(torigin,sweep->s.old_origin);
  sweep->spawnflags = SWEEPARM_LENGTH; // length of sweep arm
  sweep->s.frame = 4;      // width of sweep arm
  sweep->angle=0;
  // Move sweep arm to top of post
  VectorMA(sweep->s.origin,15,up,sweep->s.origin);
  sweep->wait = level.time + 60.0;  // 1 Minute to beam Destruct.
  sweep->think = MultiBlade_Think;
  sweep->nextthink = level.time + 1.0;
  gi.linkentity(sweep);
}

//==========================================================
//==========================================================
//==========================================================

//==========================================================
void Blade_Think(edict_t *laser) {
vec3_t torigin,up,end;
trace_t tr;
int i,degrees=10;

  // Time to self-destruct?
  if (laser->wait < level.time) {
    G_FreeEdict(laser);
    return; }

  VectorCopy(laser->owner->s.origin,torigin);
  VectorCopy(laser->owner->movedir,laser->movedir);

  for (i=1; i<=3; i++) {
    laser->s.angles[ROLL]=(int)((laser->s.angles[ROLL]+180)+(90*i)+degrees)%360-180;
    AngleVectors(laser->s.angles,NULL,NULL,up);
    VectorCopy(up,laser->movedir);
    VectorMA(torigin,laser->spawnflags,laser->movedir,end);
    tr=gi.trace(torigin,NULL,NULL,end,NULL,MASK_SHOT);
    if (tr.fraction != 1.0)
      G_Spawn_Splash(TE_LASER_SPARKS,4,Laser_Red,tr.endpos,zvec);
    if ((tr.ent) && !(tr.ent->flags & FL_IMMUNE_LASER))
      T_Damage(tr.ent,laser,laser->activator,laser->movedir,tr.endpos,zvec,laser->dmg,1,DAMAGE_ENERGY,MOD_LASERSWEEP); }

  VectorCopy(tr.endpos,laser->s.old_origin);
  laser->nextthink = level.time + 0.1;
}

//================================================================
void Spawn_Arms(edict_t *grenade) {
edict_t *sweep;
vec3_t up;

  // Now,let's create the Sweep Arm
  sweep = G_Spawn();
  sweep->owner = grenade;
  sweep->activator = grenade->activator; // Must set for frags!!
  sweep->movetype = MOVETYPE_NONE;
  sweep->solid = SOLID_NOT;
  sweep->svflags &= ~SVF_NOCLIENT;
  sweep->s.renderfx = RF_BEAM;
  sweep->s.modelindex = 1;
  sweep->s.skinnum = Laser_Red;
  sweep->s.sound = gi.soundindex("world/laser.wav");
  VectorSet(sweep->mins,-8,-8,-8);
  VectorSet(sweep->maxs,8,8,8);
  sweep->dmg = 20;
  sweep->takedamage = DAMAGE_NO;
  VectorCopy(grenade->s.angles,sweep->s.angles);
  AngleVectors(sweep->s.angles,NULL,NULL,up);
  VectorCopy(up,sweep->movedir);
  VectorCopy(grenade->s.origin,sweep->s.origin);
  VectorCopy(grenade->s.origin,sweep->s.old_origin);
  sweep->spawnflags = 20; // length of sweep arm
  sweep->s.frame = 4;    // width of sweep arm
  sweep->wait = level.time + 60.0;  // 1 Minute to beam Destruct.
  sweep->think = Blade_Think;
  sweep->nextthink = level.time + 1.0;
  gi.linkentity(sweep);
}

//==========================================================
void Cmd_LaserSweep_f(edict_t *ent) {
  Spawn_LaserSweep(ent);
}

</C&NBSP;CODE>

That's it! Now all you have to do is to do some prototyping and add some commands to your ClientCommand() function in your g_cmds.c file so that you can easily call any of these command functions. Bind keys in your autoexec.cfg file and you're there!

Have Fun!

Maj.Bitch