|
Quake Style - Quake 2 Tutorials Tech Power Up Mayhem - Part 3 Defense Laser Rune |
#include "g_local.h"
#include "g_laser1.h"
void PlaceLaser (edict_t *ent)
{
edict_t *self, *grenade;
vec3_t forward, wallp;
trace_t tr;
int laser_colour[] = {
0xf2f2f0f0, // red
0xd0d1d2d3, // green
0xf3f3f1f1, // blue
0xdcdddedf, // yellow
0xe0e1e2e3 // bitty yellow strobe
};
if ((!ent->client) || (ent->health<=0))
return;
// modify this if-statement and the message
// if you want a different number of max defense
// laser which are possible at a certain time
if (ent->client->rune_count > 5)
{
gi.cprintf(ent, PRINT_HIGH, "No more than 5 defense lasers at one time\n");
return;
}
ent->client->rune_count += 1;
// Setup "little look" to close wall
VectorCopy(ent->s.origin,wallp);
// Cast along view angle
AngleVectors (ent->client->v_angle, forward, NULL, NULL);
// Setup end point
wallp[0] = ent->s.origin[0] + forward[0] * 50;
wallp[1] = ent->s.origin[1] + forward[1] * 50;
wallp[2] = ent->s.origin[2] + forward[2] * 50;
// trace
tr = gi.trace (ent->s.origin, NULL, NULL, wallp, ent, MASK_SOLID);
// Line complete ? (ie. no collision)
if (tr.fraction == 1.0)
{
gi.cprintf (ent, PRINT_HIGH, "Too far away from wall\n");
return;
}
// Hit sky ?
if (tr.surface)
if (tr.surface->flags & SURF_SKY)
return;
// Ok, lets stick one on then ...
gi.cprintf (ent, PRINT_HIGH, "Placed laser.\n");
// -------------
// Setup laser
// -------------
self = G_Spawn();
self->movetype = MOVETYPE_NONE;
self->activator = ent;
self->solid = SOLID_NOT;
self->s.renderfx = RF_BEAM|RF_TRANSLUCENT;
self->s.modelindex = 1;
self->s.sound = gi.soundindex ("world/laser.wav");
self->classname = "laser1";
self->s.frame = 2;
self->owner = self;
self->s.skinnum = laser_colour[((int) (random() * 1000)) 5];
self->dmg = LASER_DAMAGE-10;
self->think = pre_target_laser_think;
self->delay = level.time + LASER_TIME;
// Set orgin of laser to point of contact with wall
VectorCopy(tr.endpos, self->s.origin);
// convert normal at point of contact to laser angles
vectoangles(tr.plane.normal, self->s.angles);
// setup laser movedir (projection of laser)
G_SetMovedir (self->s.angles, self->movedir);
VectorSet (self->mins, -8, -8, -8);
VectorSet (self->maxs, 8, 8, 8);
// link to world
gi.linkentity (self);
// start off ...
target_laser_off (self);
// ... but make automatically come on
self->nextthink = level.time + 2;
grenade = G_Spawn();
VectorClear (grenade->mins);
VectorClear (grenade->maxs);
VectorCopy (tr.endpos, grenade->s.origin);
vectoangles(tr.plane.normal,grenade -> s.angles);
grenade->movetype = MOVETYPE_NONE;
grenade->clipmask = MASK_SHOT;
grenade->solid = SOLID_NOT;
grenade->s.modelindex = gi.modelindex ("models/objects/grenade2/tris.md2");
grenade->owner = self;
grenade->nextthink = level.time + LASER_TIME;
grenade->think = G_FreeEdict;
gi.linkentity (grenade);
}
void pre_target_laser_think (edict_t *self)
{
target_laser_on (self);
self->think = laserbarriere_think;
}
void laserbarriere_think (edict_t *self)
{
edict_t *ignore;
edict_t *ent;
vec3_t start;
vec3_t end;
trace_t tr;
vec3_t point;
vec3_t last_movedir;
int count;
// Defense Laser Rune
if (strcmp(self->classname,"laser1") == 0)
if (level.time > self->delay)
{
// bit of damage
T_RadiusDamage (self, self->activator, LASER_MOUNT_DAMAGE_RADIUS, NULL, LASER_MOUNT_DAMAGE, MOD_LASER1);
// BANG !
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_EXPLOSION1);
gi.WritePosition(self -> s.origin);
gi.multicast (self->s.origin, MULTICAST_PVS);
// bye bye laser
ent = self->activator;
ent->client->rune_count=ent->client->rune_count-1;
G_FreeEdict (self);
return;
}
if (self->spawnflags & 0x80000000)
count = 8;
else
count = 4;
if (self->enemy)
{
VectorCopy (self->movedir, last_movedir);
VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point);
VectorSubtract (point, self->s.origin, self->movedir);
VectorNormalize (self->movedir);
if (!VectorCompare(self->movedir, last_movedir))
self->spawnflags |= 0x80000000;
}
ignore = self;
VectorCopy (self->s.origin, start);
VectorMA (start, 2048, self->movedir, end);
while(1)
{
tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
if (!tr.ent)
break;
// hurt it if we can
if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER))
T_Damage (tr.ent, self, self->activator, self->movedir, tr.endpos, vec3_origin, self->dmg, 1, DAMAGE_ENERGY, MOD_LASER1);
// if we hit something that's not a monster or player or is immune to lasers, we're done
if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
{
if (self->spawnflags & 0x80000000)
{
self->spawnflags &= ~0x80000000;
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_LASER_SPARKS);
gi.WriteByte (count);
gi.WritePosition (tr.endpos);
gi.WriteDir (tr.plane.normal);
gi.WriteByte (self->s.skinnum);
gi.multicast (tr.endpos, MULTICAST_PVS);
}
break;
}
ignore = tr.ent;
VectorCopy (tr.endpos, start);
}
VectorCopy (tr.endpos, self->s.old_origin);
self->nextthink = level.time + FRAMETIME;
}
/* LASER DEFENSE RUNE */ // my functions void PlaceLaser (edict_t *ent); void pre_target_laser_think (edict_t *self); void deathpak_think(edict_t *deathpak); // controlling parameters #define LASER_TIME 30 #define LASER_DAMAGE 80 #define LASER_MOUNT_DAMAGE 40 #define LASER_MOUNT_DAMAGE_RADIUS 64 // In-built Quake2 routines void target_laser_use (edict_t *self, edict_t *other, edict_t *activator); void laserbarriere_think (edict_t *self); void target_laser_on (edict_t *self); void target_laser_off (edict_t *self); // Laser Beam Color Codes #define Laser_Red 0xf2f2f0f0 // bright red #define Laser_Green 0xd0d1d2d3 // bright green #define Laser_Blue 0xf3f3f1f1 // bright blue #define Laser_Yellow 0xdcdddedf // bright yellow #define Laser_YellowS 0xe0e1e2e3 // yellow strobe #define Laser_DkPurple 0x80818283 // dark purple #define Laser_LtBlue 0x70717273 // light blue #define Laser_Green2 0x90919293 // different green #define Laser_Purple 0xb0b1b2b3 // purple #define Laser_Red2 0x40414243 // different red #define Laser_Orange 0xe2e5e3e6 // orange #define Laser_Mix 0xd0f1d3f3 // mixture #define Laser_RedBlue 0xf2f3f0f1 // inner = red, outer = blue #define Laser_BlueRed 0xf3f2f1f0 // inner = blue, outer = red #define Laser_GreenY 0xdad0dcd2 // inner = green, outer = yellow #define Laser_YellowG 0xd0dad2dc // inner = yellow, outer = green
#define MOD_TARGET_LASER 30 #define MOD_TRIGGER_HURT 31 #define MOD_HIT 32 #define MOD_TARGET_BLASTER 33 #define MOD_GRAPPLE 34 #define MOD_LASER1 35
case MOD_TRIGGER_HURT: message = "was in the wrong place"; break; case MOD_LASER1: //have to prevent this from checking for "MOD_LASER1" //since that assumes that it was a self inflicted death if(strcmp(inflictor->classname, "laser1") && (attacker != inflictor->activator)) message = "got a defense laser up his butt"; break;
case MOD_BFG_BLAST: message = "should have used a smaller gun"; break; case MOD_LASER1: message = "was killed by the own defense laser"; break; default: if (IsFemale(self)) message = "killed herself"; else message = "killed himself"; break;
//ZOID
case MOD_GRAPPLE:
message = "was caught by";
message2 = "'s grapple";
break;
//ZOID
case MOD_LASER1:
message="got";
message2="'s defense laser up his butt";
break;
}
if (message)
{
gi.bprintf (PRINT_MEDIUM,"s s ss\n", self->client->pers.netname, message, attacker->client->pers.netname, message2);
/* Defense Laser */
{
"item_tech5",
CTFPickup_Tech,
NULL,
CTFDrop_Tech, //Should this be null if we don't want players to drop it manually?
NULL,
"items/pkup.wav",
"models/ctf/regeneration/tris.md2", EF_ROTATE,
NULL,
/* icon */ "tech4",
/* pickup */ "Defense Laser [U]",
/* width */ 2,
0,
NULL,
IT_TECH,
// 0, // NOTE: activate/deactivate this line to set up for different source bases (CTF or 3.20)
NULL,
0,
/* precache */ "ctf/tech4.wav"
},
// end of list marker
{NULL}
};
static char *tnames[] = {
"item_tech1", "item_tech2", "item_tech3", "item_tech4",
NULL
};
static char *tnames[] = {
"item_tech1", "item_tech2", "item_tech3", "item_tech4", "item_tech5",
NULL
};
void Rune_Use(edict_t *ent)
{
int index;
gitem_t *it;
char *rune_msg;
// say "no rune or automatically activated rune" if there is no
// special usage (=pressing a button) needed or if player
// doesn't own a rune
// otherwise just call the using function for that specific rune
rune_msg="No rune or automatically activated rune";
it = FindItem ("Defense Laser [U]");
index = ITEM_INDEX (it);
if (ent->client->pers.inventory[index])
{
PlaceLaser (ent);
return;
}
gi.centerprintf(ent, "s\n",rune_msg);
}