510 lines
15 KiB
C
510 lines
15 KiB
C
#include "g_local.h"
|
|
/*
|
|
===============
|
|
Plasma Bomb
|
|
===============
|
|
*/
|
|
void DefusePlasmabomb(edict_t *ent, pmenu_t *p)
|
|
{
|
|
float dist;
|
|
vec3_t distance;
|
|
distance[0]=ent->s.origin[0]-ent->selectedsentry->s.origin[0];
|
|
distance[1]=ent->s.origin[1]-ent->selectedsentry->s.origin[1];
|
|
distance[2]=ent->s.origin[2]-ent->selectedsentry->s.origin[2];
|
|
dist=VectorLength(distance);
|
|
if(dist>100)
|
|
{
|
|
safe_cprintf(ent, PRINT_HIGH, "Plasmabomb too far away.\n");
|
|
PMenu_Close(ent);
|
|
return;
|
|
}
|
|
//Set the time for defusing
|
|
ent->selectedsentry->sentrydelay= level.time + 0.4;
|
|
ent->selectedsentry->selectedsentry=ent;
|
|
ent->cantmove = 1;
|
|
VectorCopy(ent->s.origin,ent->LockedPosition);
|
|
PMenu_Close(ent);
|
|
}
|
|
|
|
void Plasma_Near (edict_t *ent, edict_t *other)
|
|
{
|
|
//Skip if they already have a menu up
|
|
if ((other->client) && (other->client->menu))
|
|
return;
|
|
|
|
if(other->sentrydelay>level.time)
|
|
return;
|
|
|
|
//Only show menu a max of every 1 second
|
|
|
|
//set up menu
|
|
// if (other->client && (other->wf_team != ent->wf_team) && (other->client->player_special & SPECIAL_DEFUSEPLASMABOMB))
|
|
if(!other->bot_client)
|
|
if (other->client && (other->wf_team != ent->wf_team) && (other->client->player_special & SPECIAL_PLASMA_BOMB))
|
|
{
|
|
PMenu_Close(other);
|
|
|
|
sprintf(other->client->wfsentrystr[0], "*%s's Plasmabomb", ent->owner->client->pers.netname);
|
|
other->client->sentrymenu[0].text = other->client->wfsentrystr[0];
|
|
other->client->sentrymenu[0].SelectFunc = NULL;
|
|
other->client->sentrymenu[0].align = PMENU_ALIGN_CENTER;
|
|
other->client->sentrymenu[0].arg = 0;
|
|
other->client->sentrymenu[1].text = "1. Defuse";
|
|
other->client->sentrymenu[1].SelectFunc = DefusePlasmabomb;
|
|
other->client->sentrymenu[1].align = PMENU_ALIGN_LEFT;
|
|
other->client->sentrymenu[1].arg = 0;
|
|
|
|
other->selectedsentry = ent;//Actually selected plasmabomb
|
|
|
|
PMenu_Open(other, other->client->sentrymenu, -1, sizeof(other->client->sentrymenu) / sizeof(pmenu_t), true, false);
|
|
other->sentrydelay = level.time + 1.5;
|
|
|
|
//Set timeout for menu (4 seconds)
|
|
if (other->client->menu) other->client->menu->MenuTimeout = level.time + 4;
|
|
}
|
|
}
|
|
|
|
void PlasmaBombExplode(edict_t *self)
|
|
{
|
|
edict_t *ent;
|
|
float points;
|
|
vec3_t v;
|
|
float dist;
|
|
int j;
|
|
vec3_t Vec1, Vec2, Vec3, Vec4;
|
|
vec3_t Vec5, Vec6;
|
|
|
|
VectorSet(Vec1,28,28,0);
|
|
VectorSet(Vec2,28,-28,0);
|
|
VectorSet(Vec3,-28,-28,0);
|
|
VectorSet(Vec4,-28,28,0);
|
|
VectorSet(Vec5,0,0,28);
|
|
VectorSet(Vec6,0,0,-28);
|
|
VectorAdd(Vec1,self->s.origin,Vec1);
|
|
VectorAdd(Vec2,self->s.origin,Vec2);
|
|
VectorAdd(Vec3,self->s.origin,Vec3);
|
|
VectorAdd(Vec4,self->s.origin,Vec4);
|
|
VectorAdd(Vec5,self->s.origin,Vec5);
|
|
VectorAdd(Vec6,self->s.origin,Vec6);
|
|
if (self->s.frame == 0)
|
|
{
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (self->s.origin);
|
|
gi.WritePosition (Vec1);
|
|
gi.multicast (self->s.origin, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (self->s.origin);
|
|
gi.WritePosition (Vec2);
|
|
gi.multicast (self->s.origin, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (self->s.origin);
|
|
gi.WritePosition (Vec3);
|
|
gi.multicast (self->s.origin, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (self->s.origin);
|
|
gi.WritePosition (Vec4);
|
|
gi.multicast (self->s.origin, MULTICAST_PHS);
|
|
|
|
}
|
|
if (self->s.frame == 1)
|
|
{
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (Vec1);
|
|
gi.WritePosition (Vec5);
|
|
gi.multicast (Vec1, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (Vec2);
|
|
gi.WritePosition (Vec5);
|
|
gi.multicast (Vec2, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (Vec3);
|
|
gi.WritePosition (Vec5);
|
|
gi.multicast (Vec3, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (Vec4);
|
|
gi.WritePosition (Vec5);
|
|
gi.multicast (Vec4, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (Vec1);
|
|
gi.WritePosition (Vec6);
|
|
gi.multicast (Vec1, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (Vec2);
|
|
gi.WritePosition (Vec6);
|
|
gi.multicast (Vec2, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (Vec3);
|
|
gi.WritePosition (Vec6);
|
|
gi.multicast (Vec3, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (Vec4);
|
|
gi.WritePosition (Vec6);
|
|
gi.multicast (Vec4, MULTICAST_PHS);
|
|
}
|
|
if (self->s.frame == 2)
|
|
{
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (Vec5);
|
|
gi.WritePosition (self->s.origin);
|
|
gi.multicast (Vec5, MULTICAST_PHS);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_RAILTRAIL);
|
|
gi.WritePosition (Vec6);
|
|
gi.WritePosition (self->s.origin);
|
|
gi.multicast (Vec6, MULTICAST_PHS);
|
|
|
|
|
|
}
|
|
|
|
if (self->s.frame == 4)
|
|
{
|
|
/*
|
|
// the BFG effect
|
|
ent = NULL;
|
|
while ((ent = findradius(ent, self->s.origin, self->dmg_radius+500)) != NULL)
|
|
{
|
|
if (!ent->takedamage)
|
|
continue;
|
|
if (!CanDamage (ent, self))
|
|
continue;
|
|
//The next 2 lines force person to be in the room when it explodes
|
|
//if (!CanDamage (ent, self->owner))
|
|
// continue;
|
|
|
|
//G.A.R. - only damage players (new)
|
|
if (!ent->client)
|
|
continue;
|
|
|
|
//Calculate distance
|
|
VectorAdd (ent->mins, ent->maxs, v);
|
|
VectorMA (ent->s.origin, 0.5, v, v);
|
|
VectorSubtract (self->s.origin, v, v);
|
|
dist = VectorLength(v);
|
|
|
|
points = self->radius_dmg * (1.0 - sqrt(dist/self->dmg_radius));
|
|
if (ent == self->owner)
|
|
points = points * 0.5;
|
|
if (!ent->client)
|
|
points = points * 0.5;
|
|
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_BFG_EXPLOSION);
|
|
gi.WritePosition (ent->s.origin);
|
|
gi.multicast (ent->s.origin, MULTICAST_PVS);
|
|
|
|
T_Damage (ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, (int)points, 0, DAMAGE_ENERGY, MOD_PLASMABOMB);
|
|
}
|
|
*/
|
|
// ++TeT inline the findradius func so we can do some short cut checking
|
|
// and keep the resulting distance calculation
|
|
|
|
ent = g_edicts;
|
|
for ( ; ent < &g_edicts[globals.num_edicts]; ent++)
|
|
{
|
|
if (!ent->inuse)
|
|
continue;
|
|
if (ent->solid == SOLID_NOT)
|
|
continue;
|
|
if (!ent->takedamage)
|
|
continue;
|
|
|
|
// Do we want to damage other things like sentries?
|
|
//if (!ent->client)
|
|
// continue;
|
|
if (!CanDamage (ent, self))
|
|
continue;
|
|
|
|
// now we check how far it is from us
|
|
for (j = 0; j < 3; j++)
|
|
v[j] = self->s.origin[j] - (ent->s.origin[j] + (ent->mins[j] + ent->maxs[j])*0.5);
|
|
// inlined vectorLength func which returned sqrt of vecLength,
|
|
// instead we compare it to the square of dmg_radius
|
|
dist = 0;
|
|
for (j = 0; j < 3; j++)
|
|
dist += v[j] * v[j];
|
|
if (dist > (self->dmg_radius * self->dmg_radius))
|
|
continue;
|
|
// now that we have eliminated the junk, we do the sqrts here
|
|
// and make it a ratio
|
|
dist = sqrt(sqrt(dist)/self->dmg_radius);
|
|
points = self->radius_dmg * (1.0 - dist);
|
|
if (ent == self->owner)
|
|
points = points * 0.5;
|
|
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_BFG_EXPLOSION);
|
|
gi.WritePosition (ent->s.origin);
|
|
gi.multicast (ent->s.origin, MULTICAST_PVS);
|
|
|
|
T_Damage (ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, (int)points, 0, DAMAGE_ENERGY, MOD_PLASMABOMB);
|
|
|
|
}
|
|
// --TeT
|
|
}
|
|
|
|
self->nextthink = level.time + FRAMETIME;
|
|
self->s.frame++;
|
|
if (self->s.frame == 5)
|
|
self->think = G_FreeEdict;
|
|
}
|
|
|
|
void plasmabomb_think(edict_t *self)
|
|
{
|
|
// vec3_t origin;
|
|
edict_t *target;
|
|
target = NULL;
|
|
while ((target = findradius(target, self->s.origin,75)) != NULL)
|
|
{
|
|
//Don't go through walls
|
|
if (!visible(self, target))
|
|
continue;
|
|
//Check for plasma defusing
|
|
Plasma_Near(self,target);
|
|
}
|
|
if (self->delay < level.time)
|
|
{
|
|
gi.sound (self, CHAN_VOICE, gi.soundindex ("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
|
|
self->solid = SOLID_NOT;
|
|
self->touch = NULL;
|
|
VectorMA (self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
|
|
VectorClear (self->velocity);
|
|
self->s.modelindex = gi.modelindex ("sprites/s_bfg3.sp2");
|
|
self->s.frame = 0;
|
|
self->s.sound = 0;
|
|
self->s.effects &= ~EF_ANIM_ALLFAST;
|
|
self->think = PlasmaBombExplode;
|
|
self->nextthink = level.time + FRAMETIME;
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_BFG_BIGEXPLOSION);
|
|
gi.WritePosition (self->s.origin);
|
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
|
}
|
|
if (self->PlasmaDelay < level.time)
|
|
{
|
|
self->owner->cantmove = 0;
|
|
}
|
|
if((self->sentrydelay<level.time) && (self->selectedsentry))
|
|
{
|
|
if(random()<0.08)
|
|
{
|
|
safe_cprintf(self->selectedsentry, PRINT_HIGH, "Mistake defusing Plasmabomb.\n");
|
|
gi.sound (self, CHAN_VOICE, gi.soundindex ("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
|
|
self->solid = SOLID_NOT;
|
|
self->touch = NULL;
|
|
VectorMA (self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
|
|
VectorClear (self->velocity);
|
|
self->s.modelindex = gi.modelindex ("sprites/s_bfg3.sp2");
|
|
self->s.frame = 0;
|
|
self->s.sound = 0;
|
|
self->s.effects &= ~EF_ANIM_ALLFAST;
|
|
self->think = PlasmaBombExplode;
|
|
self->nextthink = level.time + FRAMETIME;
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_BFG_BIGEXPLOSION);
|
|
gi.WritePosition (self->s.origin);
|
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
|
return;
|
|
}
|
|
self->selectedsentry->cantmove = 0;
|
|
|
|
safe_cprintf(self->selectedsentry, PRINT_HIGH, "Plasmabomb defused.\n");
|
|
|
|
G_FreeEdict (self);
|
|
return;
|
|
}
|
|
self->nextthink = level.time + 0.1;
|
|
}
|
|
|
|
void DropPlasmaBomb (edict_t *self, int time)
|
|
{
|
|
edict_t *bfg;
|
|
|
|
bfg = G_Spawn();
|
|
bfg->wf_team = self->wf_team;
|
|
VectorCopy (self->s.origin, bfg->s.origin);
|
|
bfg->movetype = MOVETYPE_NONE;
|
|
bfg->clipmask = MASK_SHOT;
|
|
bfg->solid = SOLID_BBOX;
|
|
bfg->s.effects |= EF_BFG | EF_ANIM_ALLFAST;
|
|
VectorClear (bfg->mins);
|
|
VectorClear (bfg->maxs);
|
|
if(self->wf_team == CTF_TEAM1) //Shelton Red team sprite
|
|
bfg->s.modelindex = gi.modelindex ("sprites/r_bfg1.sp2");
|
|
else if(self->wf_team == CTF_TEAM2) //Shelton Blue team sprite
|
|
bfg->s.modelindex = gi.modelindex ("sprites/b_bfg1.sp2");
|
|
else
|
|
bfg->s.modelindex = gi.modelindex ("sprites/s_bfg1.sp2");
|
|
|
|
bfg->owner = self;
|
|
bfg->radius_dmg = 300; //was 3000 // TeT was 2000 pts of damage - wow
|
|
bfg->dmg_radius = 2000; //was 4000
|
|
bfg->classname = "plasma blast";
|
|
bfg->s.sound = gi.soundindex ("weapons/bfg__l1a.wav");
|
|
bfg->think = plasmabomb_think;
|
|
bfg->nextthink = level.time + FRAMETIME;
|
|
bfg->delay = level.time + time;
|
|
bfg->PlasmaDelay =level.time + 2;
|
|
self->cantmove = 1;
|
|
VectorCopy(self->s.origin,self->LockedPosition);
|
|
self->PlasmaDelay = level.time + time + 10;
|
|
gi.linkentity (bfg);
|
|
}
|
|
|
|
void DropPlasmaShort(edict_t *ent, pmenu_t *p)
|
|
{
|
|
int time;
|
|
if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] <50)
|
|
{
|
|
safe_cprintf(ent, PRINT_HIGH, "Not enough cells (50) for Plasma Bomb.\n");
|
|
PMenu_Close(ent);
|
|
return;
|
|
}
|
|
// time= (((int)(random()*1000)%10))+10;
|
|
time= 10.0;
|
|
if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
|
|
ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] =ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] - 50;
|
|
DropPlasmaBomb(ent,time);
|
|
PMenu_Close(ent);
|
|
}
|
|
void DropPlasmaMedium(edict_t *ent, pmenu_t *p)
|
|
{
|
|
int time;
|
|
if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] <50)
|
|
{
|
|
safe_cprintf(ent, PRINT_HIGH, "Not enough cells (50) for Plasma Bomb.\n");
|
|
PMenu_Close(ent);
|
|
return;
|
|
}
|
|
// time= (((int)(random()*1000)%14))+23;
|
|
time= 25.0;
|
|
if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
|
|
ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] =ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] - 50;
|
|
DropPlasmaBomb(ent,time);
|
|
PMenu_Close(ent);
|
|
}
|
|
void DropPlasmaLong(edict_t *ent, pmenu_t *p)
|
|
{
|
|
int time;
|
|
if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] <50)
|
|
{
|
|
safe_cprintf(ent, PRINT_HIGH, "Not enough cells (50) for Plasma Bomb.\n");
|
|
PMenu_Close(ent);
|
|
return;
|
|
}
|
|
// time= (((int)(random()*1000)%20))+50;
|
|
time= 50.0;
|
|
if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
|
|
ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] =ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] - 50;
|
|
DropPlasmaBomb(ent,time);
|
|
PMenu_Close(ent);
|
|
}
|
|
void PlasmaBombMenu(edict_t *ent)
|
|
{
|
|
PMenu_Close(ent);
|
|
if (!ent->bot_client)
|
|
sprintf(ent->client->wfsentrystr[0], "Plasmabomb Det Time");//acrid added s
|
|
ent->client->sentrymenu[0].text = ent->client->wfsentrystr[0];
|
|
ent->client->sentrymenu[0].SelectFunc = NULL;
|
|
ent->client->sentrymenu[0].align = PMENU_ALIGN_CENTER;
|
|
ent->client->sentrymenu[0].arg = 0;
|
|
ent->client->sentrymenu[1].text = "1. Short";
|
|
ent->client->sentrymenu[1].SelectFunc = DropPlasmaShort;
|
|
ent->client->sentrymenu[1].align = PMENU_ALIGN_LEFT;
|
|
ent->client->sentrymenu[1].arg = 0;
|
|
ent->client->sentrymenu[2].text = "2. Medium";
|
|
ent->client->sentrymenu[2].SelectFunc = DropPlasmaMedium;
|
|
ent->client->sentrymenu[2].align = PMENU_ALIGN_LEFT;
|
|
ent->client->sentrymenu[2].arg = 0;
|
|
ent->client->sentrymenu[3].text = "3. Long";
|
|
ent->client->sentrymenu[3].SelectFunc = DropPlasmaLong;
|
|
ent->client->sentrymenu[3].align = PMENU_ALIGN_LEFT;
|
|
ent->client->sentrymenu[3].arg = 0;
|
|
PMenu_Open(ent, ent->client->sentrymenu, -1, sizeof(ent->client->sentrymenu) / sizeof(pmenu_t), true, false);
|
|
}
|
|
|
|
void cmd_PlasmaBombMenu(edict_t *ent)
|
|
{
|
|
if (!ent->client)
|
|
return;
|
|
|
|
if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] <50)
|
|
{
|
|
safe_cprintf(ent, PRINT_HIGH, "Not enough cells (50) for Plasma Bomb.\n");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (ent->PlasmaDelay < level.time)
|
|
{
|
|
PlasmaBombMenu(ent);
|
|
//ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] =ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] - 50;
|
|
//DropPlasmaBomb(ent,15); // Explode in 15 seconds
|
|
}
|
|
else
|
|
{
|
|
safe_cprintf(ent, PRINT_HIGH, "Not enough time has passed since last Plasma Bomb.\n");
|
|
}
|
|
}
|
|
}
|
|
// TeT fixed command to take arguments
|
|
void cmd_PlasmaBomb(edict_t *ent)
|
|
{
|
|
char *string;
|
|
int time = 0;
|
|
|
|
string = gi.args();
|
|
|
|
if (!ent->client) return;
|
|
|
|
if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] <50)
|
|
{
|
|
safe_cprintf(ent, PRINT_HIGH, "Not enough cells (50) for Plasma Bomb.\n");
|
|
return;
|
|
}
|
|
if (ent->PlasmaDelay > level.time)
|
|
{
|
|
safe_cprintf(ent, PRINT_HIGH, "Not enough time has passed since last Plasma Bomb.\n");
|
|
return;
|
|
}
|
|
|
|
//argument = "Short", "Medium", "Long"
|
|
if (Q_stricmp ( string, "Short") == 0)
|
|
{
|
|
time = 10;
|
|
}
|
|
else if (Q_stricmp ( string, "Medium") == 0)
|
|
{
|
|
time = 25;
|
|
}
|
|
else if (Q_stricmp ( string, "Long") == 0)
|
|
{
|
|
time = 50;
|
|
}
|
|
else
|
|
{
|
|
//Otherwise pop up menu
|
|
cmd_PlasmaBombMenu(ent);
|
|
return;
|
|
}
|
|
if ( time > 0)
|
|
{
|
|
if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
|
|
ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] -= 50;
|
|
DropPlasmaBomb(ent,time);
|
|
}
|
|
}
|
|
|