456 lines
11 KiB
C
456 lines
11 KiB
C
|
#include "g_local.h"
|
||
|
#include "laser2.h"
|
||
|
|
||
|
int laser_colour[] = {
|
||
|
0xf3f3f1f1, //0 blue
|
||
|
0xf2f2f0f0, //1 red
|
||
|
// 0xf2f2f0f0, //0 red
|
||
|
// 0xf3f3f1f1, //1 blue
|
||
|
0xf3f3f1f1, //2 blue
|
||
|
// 0xd0d1d2d3, //2 green
|
||
|
0xdcdddedf, //3 yellow
|
||
|
0xe0e1e2e3, //4 bitty yellow strobe
|
||
|
0x80818283, //5 JR brownish purple I think
|
||
|
0x70717273, //6 JR light blue
|
||
|
0x90919293, //7 JR type of green
|
||
|
0xb0b1b2b3, //8 JR another purple
|
||
|
0x40414243, //9 JR a reddish color
|
||
|
0xe2e5e3e6, //10 JR another orange
|
||
|
0xd0f1d3f3, //11 JR mixture of color
|
||
|
0xf2f3f0f1, //12 JR red outer blue inner
|
||
|
0xf3f2f1f0, //13 JR blue outer red inner
|
||
|
0xdad0dcd2, //14 JR yellow outer green inner
|
||
|
0xd0dad2dc //15 JR green outer yellow inner
|
||
|
};
|
||
|
|
||
|
//By setting the color for each, players can tell the difference
|
||
|
#define LASER_DEFENSE_COLOR 4
|
||
|
#define LASER_TRIPBOMB_COLOR 12
|
||
|
|
||
|
|
||
|
/*
|
||
|
=====================
|
||
|
Laser Defense
|
||
|
=====================
|
||
|
*/
|
||
|
void laser_cleanup(edict_t *self)
|
||
|
{
|
||
|
vec3_t origin;
|
||
|
|
||
|
if (self->owner->client)
|
||
|
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
|
||
|
|
||
|
T_RadiusDamage(self, self->owner, self->dmg, NULL, self->dmg_radius, MOD_LASER_DEFENSE);
|
||
|
|
||
|
VectorMA (self->s.origin, -0.02, self->velocity, origin);
|
||
|
gi.WriteByte (svc_temp_entity);
|
||
|
if (self->waterlevel)
|
||
|
{
|
||
|
if (self->groundentity)
|
||
|
gi.WriteByte (TE_GRENADE_EXPLOSION_WATER);
|
||
|
else
|
||
|
gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (self->groundentity)
|
||
|
gi.WriteByte (TE_GRENADE_EXPLOSION);
|
||
|
else
|
||
|
gi.WriteByte (TE_ROCKET_EXPLOSION);
|
||
|
}
|
||
|
gi.WritePosition (origin);
|
||
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||
|
|
||
|
|
||
|
//reduce # active laser defenses
|
||
|
// TeT++
|
||
|
|
||
|
//Remove laser
|
||
|
if (self->creator)
|
||
|
G_FreeEdict (self->creator);
|
||
|
// TeT--
|
||
|
|
||
|
//Remove grenade
|
||
|
G_FreeEdict (self);
|
||
|
|
||
|
}
|
||
|
|
||
|
void laser_defense_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
||
|
{
|
||
|
// TeT++
|
||
|
if (self->creator)
|
||
|
{
|
||
|
self->creator->delay = level.time + 0.1;
|
||
|
}
|
||
|
// TeT--
|
||
|
|
||
|
laser_cleanup(self);
|
||
|
|
||
|
}
|
||
|
|
||
|
//Laser Defense
|
||
|
// TeT++
|
||
|
void PlaceLaser (edict_t *ent)
|
||
|
{
|
||
|
edict_t *laser,
|
||
|
*grenade;
|
||
|
vec3_t forward,
|
||
|
wallp,
|
||
|
start,
|
||
|
end;
|
||
|
trace_t tr;
|
||
|
trace_t endTrace;
|
||
|
|
||
|
// valid ent ?
|
||
|
if ((!ent->client) || (ent->health<=0))
|
||
|
return;
|
||
|
|
||
|
// cells for laser ?
|
||
|
if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] < CELLS_FOR_LASER)
|
||
|
{
|
||
|
safe_cprintf(ent, PRINT_HIGH, "Not enough cells for laser.\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//Are there too many laser defense systems now?
|
||
|
if (ent->client->pers.active_special[ITEM_SPECIAL_LASER_DEFENSE] >= MAX_SPECIAL_LASER_DEFENSE)
|
||
|
{
|
||
|
safe_cprintf(ent, PRINT_HIGH, "You can only have %d active Laser Defense Systems.\n",MAX_SPECIAL_LASER_DEFENSE );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
{
|
||
|
safe_cprintf (ent, PRINT_HIGH, "Too far from wall.\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Hit sky ?
|
||
|
if (tr.surface)
|
||
|
if (tr.surface->flags & SURF_SKY)
|
||
|
return;
|
||
|
|
||
|
// Ok, lets stick one on then ...
|
||
|
safe_cprintf (ent, PRINT_HIGH, "Laser attached.\n");
|
||
|
|
||
|
if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
|
||
|
ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] -= CELLS_FOR_LASER;
|
||
|
|
||
|
++ent->client->pers.active_special[ITEM_SPECIAL_LASER_DEFENSE];
|
||
|
|
||
|
// get enties for both objects
|
||
|
grenade = G_Spawn();
|
||
|
laser = G_Spawn();
|
||
|
grenade->special_index = ITEM_SPECIAL_LASER_DEFENSE;
|
||
|
|
||
|
// setup the Grenade
|
||
|
VectorClear (grenade->mins);
|
||
|
VectorClear (grenade->maxs);
|
||
|
VectorCopy (tr.endpos, grenade->s.origin);
|
||
|
vectoangles(tr.plane.normal, grenade->s.angles);
|
||
|
|
||
|
grenade->special_index = ITEM_SPECIAL_LASER_DEFENSE;
|
||
|
grenade->wf_team = ent->wf_team;
|
||
|
grenade -> movetype = MOVETYPE_NONE;
|
||
|
grenade -> clipmask = MASK_SHOT;
|
||
|
grenade->solid = SOLID_BBOX;
|
||
|
VectorSet(grenade->mins, -3, -3, 0);
|
||
|
VectorSet(grenade->maxs, 3, 3, 6);
|
||
|
grenade -> takedamage = DAMAGE_YES;
|
||
|
grenade -> die = laser_defense_die;
|
||
|
grenade -> s.modelindex = gi.modelindex (GRNORMAL_MODEL);
|
||
|
grenade -> owner = ent;
|
||
|
grenade -> creator = laser;
|
||
|
grenade -> monsterinfo.aiflags = AI_NOSTEP;
|
||
|
grenade -> classname = "laser_defense_gr";
|
||
|
grenade -> nextthink = level.time + LASER_TIME;
|
||
|
grenade -> think = laser_cleanup;
|
||
|
grenade -> health = 10;
|
||
|
grenade -> max_health = 10;
|
||
|
|
||
|
|
||
|
// Now lets find the other end of the laser
|
||
|
// by starting at the grenade position
|
||
|
VectorCopy (grenade->s.origin, start);
|
||
|
|
||
|
// setup laser movedir (projection of laser)
|
||
|
G_SetMovedir (grenade->s.angles, laser->movedir);
|
||
|
VectorMA (start, 2048, laser->movedir, end);
|
||
|
|
||
|
endTrace = gi.trace (start, NULL, NULL, end, ent, MASK_SOLID);
|
||
|
|
||
|
// -----------
|
||
|
// Setup laser
|
||
|
// -----------
|
||
|
laser -> wf_team = ent->wf_team;
|
||
|
|
||
|
laser -> movetype = MOVETYPE_NONE;
|
||
|
laser -> solid = SOLID_NOT;
|
||
|
laser -> s.renderfx = RF_BEAM|RF_TRANSLUCENT;
|
||
|
laser -> s.modelindex = 1; // must be non-zero
|
||
|
laser -> s.sound = gi.soundindex ("world/laser.wav");
|
||
|
laser -> classname = "laser_defense";
|
||
|
laser -> s.frame = 2; // beam diameter
|
||
|
laser -> owner = NULL;
|
||
|
laser -> s.skinnum = laser_colour[ent->wf_team];
|
||
|
laser -> dmg = LASER_DAMAGE;
|
||
|
laser -> think = pre_target_laser_def_think;
|
||
|
laser -> delay = level.time + LASER_TIME;
|
||
|
laser -> creator = grenade;
|
||
|
laser -> activator = ent;
|
||
|
|
||
|
// start off ...
|
||
|
target_laser_off (laser);
|
||
|
VectorCopy (endTrace.endpos, laser->s.old_origin);
|
||
|
|
||
|
// ... but make automatically come on
|
||
|
laser -> nextthink = level.time + 2;
|
||
|
|
||
|
// Set orgin of laser to point of contact with wall
|
||
|
VectorCopy(endTrace.endpos,laser->s.origin);
|
||
|
|
||
|
// convert normal at point of contact to laser angles
|
||
|
vectoangles(tr.plane.normal,laser->s.angles);
|
||
|
|
||
|
// setup laser movedir (projection of laser)
|
||
|
G_SetMovedir (laser->s.angles, laser->movedir);
|
||
|
|
||
|
VectorSet (laser->mins, -8, -8, -8);
|
||
|
VectorSet (laser->maxs, 8, 8, 8);
|
||
|
|
||
|
// link to world
|
||
|
gi.linkentity (laser);
|
||
|
gi.linkentity (grenade);
|
||
|
}
|
||
|
|
||
|
void pre_target_laser_def_think (edict_t *self)
|
||
|
{
|
||
|
target_laser_on (self);
|
||
|
self->think = target_laser_def_think;
|
||
|
}
|
||
|
void pre_target_laser_think (edict_t *self)
|
||
|
{
|
||
|
target_laser_on (self);
|
||
|
self->think = target_laser_think;
|
||
|
}
|
||
|
|
||
|
void pre_target_laserb_think (edict_t *self);
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
Laser Tripbombs
|
||
|
===============
|
||
|
*/
|
||
|
/*
|
||
|
for them to work need some code I will do later
|
||
|
*/
|
||
|
|
||
|
void laser_trip_cleanup(edict_t *self)
|
||
|
{
|
||
|
|
||
|
//Remove laser
|
||
|
if (self->owner)
|
||
|
G_FreeEdict (self->owner);
|
||
|
|
||
|
//Remove grenade
|
||
|
G_FreeEdict (self);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void laser_tripbomb_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
||
|
{
|
||
|
self->owner->delay = level.time + 0.1;
|
||
|
|
||
|
laser_trip_cleanup(self);
|
||
|
|
||
|
}
|
||
|
|
||
|
//Laser Tripbomb
|
||
|
void PlaceLaserb (edict_t *ent)
|
||
|
{
|
||
|
edict_t *self,
|
||
|
*grenade;
|
||
|
|
||
|
vec3_t forward,
|
||
|
wallp;
|
||
|
|
||
|
trace_t tr;
|
||
|
|
||
|
|
||
|
// valid ent ?
|
||
|
if ((!ent->client) || (ent->health<=0))
|
||
|
return;
|
||
|
|
||
|
// cells for laser ?
|
||
|
if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] < 100)
|
||
|
{
|
||
|
safe_cprintf(ent, PRINT_HIGH, "Not enough cells for laser bomb.\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//Are there too many laser defense systems now?
|
||
|
if (ent->client->pers.active_special[ITEM_SPECIAL_TRIPBOMB] >= MAX_SPECIAL_TRIPBOMB)
|
||
|
{
|
||
|
safe_cprintf(ent, PRINT_HIGH, "You can only have %d active Trip Bombs.\n",MAX_SPECIAL_TRIPBOMB );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
{
|
||
|
safe_cprintf (ent, PRINT_HIGH, "Too far from wall.\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Hit sky ?
|
||
|
if (tr.surface)
|
||
|
if (tr.surface->flags & SURF_SKY)
|
||
|
return;
|
||
|
|
||
|
// Ok, lets stick one on then ...
|
||
|
safe_cprintf (ent, PRINT_HIGH, "Laser attached.\n");
|
||
|
|
||
|
if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
|
||
|
ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] -= 100;
|
||
|
|
||
|
++ent->client->pers.active_special[ITEM_SPECIAL_TRIPBOMB];
|
||
|
|
||
|
// -----------
|
||
|
// Setup laser
|
||
|
// -----------
|
||
|
self = G_Spawn();
|
||
|
self->wf_team = ent->wf_team;
|
||
|
self->special_index = ITEM_SPECIAL_TRIPBOMB;
|
||
|
|
||
|
|
||
|
self -> movetype = MOVETYPE_NONE;
|
||
|
self -> solid = SOLID_NOT;
|
||
|
self -> s.renderfx = RF_BEAM|RF_TRANSLUCENT;
|
||
|
self -> s.modelindex = 1; // must be non-zero
|
||
|
self -> s.sound = gi.soundindex ("world/laser.wav");
|
||
|
self -> classname = "lb";
|
||
|
self -> s.frame = 2; // beam diameter
|
||
|
self -> owner = ent;
|
||
|
//GREGG
|
||
|
// self -> s.skinnum = laser_colour[((int) (random() * 1000)) % 16];
|
||
|
self -> s.skinnum = laser_colour[LASER_TRIPBOMB_COLOR];
|
||
|
self -> dmg = LASER_DAMAGE;
|
||
|
self -> think = pre_target_laserb_think;
|
||
|
self -> delay = level.time + LASER_TIME;
|
||
|
//add a laser to the amount
|
||
|
// ent->LaserBomb++;
|
||
|
// 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();
|
||
|
grenade->wf_team = ent->wf_team;
|
||
|
|
||
|
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->solid = SOLID_BBOX;
|
||
|
VectorSet(grenade->mins, -3, -3, 0);
|
||
|
VectorSet(grenade->maxs, 3, 3, 6);
|
||
|
grenade->takedamage=DAMAGE_YES;
|
||
|
grenade->die = laser_tripbomb_die;
|
||
|
grenade -> s.modelindex = gi.modelindex (GRNORMAL_MODEL);
|
||
|
grenade -> owner = self;
|
||
|
grenade -> nextthink = level.time + LASER_TIME;
|
||
|
grenade -> think = laser_trip_cleanup;
|
||
|
grenade->health= 15;
|
||
|
grenade->max_health =15;
|
||
|
|
||
|
gi.linkentity (grenade);
|
||
|
}
|
||
|
|
||
|
void pre_target_laserb_think (edict_t *self)
|
||
|
{
|
||
|
target_laser_on (self);
|
||
|
|
||
|
self->think = target_laser_think;
|
||
|
}
|
||
|
|
||
|
void cmd_LaserDefense(edict_t *ent)
|
||
|
{
|
||
|
// if (ent->LaserOrbs > MAX_LASERS -1)
|
||
|
// safe_cprintf(ent, PRINT_HIGH, "Max Lasers Already Reached.\n");
|
||
|
// else
|
||
|
PlaceLaser (ent);
|
||
|
}
|
||
|
|
||
|
void cmd_TripBomb(edict_t *ent)
|
||
|
{
|
||
|
// if (ent->LaserBomb > 4 -1)
|
||
|
// safe_cprintf(ent, PRINT_HIGH, "Max Laser Trip Bombs Already Reached.\n");
|
||
|
// else
|
||
|
PlaceLaserb (ent);
|
||
|
}
|
||
|
|
||
|
|
||
|
//Remove all laser defenses for this entity
|
||
|
void cmd_RemoveLaserDefense(edict_t *ent)
|
||
|
{
|
||
|
edict_t *blip = NULL;
|
||
|
|
||
|
while ((blip = findradius(blip, ent->s.origin, 1000)) != NULL)
|
||
|
{
|
||
|
if (!strcmp(blip->classname, "laser_defense_gr") && blip->owner == ent)
|
||
|
{
|
||
|
blip->think = laser_cleanup;
|
||
|
blip->nextthink = level.time + .1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|