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