mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
3672ea6be8
Improved Tactician Gunner prox mine detection in missionpack DLL. Implemented Zaero modifications (can be pushed off ledge) to exploding barrels in missionpack DLL. Changed incomplete vector parsing check in ED_ParseField() to a warning instead of an error in all game DLLs.
708 lines
16 KiB
C
708 lines
16 KiB
C
#include "g_local.h"
|
|
|
|
|
|
extern qboolean is_quad;
|
|
extern byte is_silenced;
|
|
|
|
void playQuadSound (edict_t *ent);
|
|
void Weapon_Generic (edict_t *ent,
|
|
int FRAME_ACTIVATE_LAST,
|
|
int FRAME_FIRE_LAST,
|
|
int FRAME_IDLE_LAST,
|
|
int FRAME_DEACTIVATE_LAST,
|
|
int *pause_frames,
|
|
int *fire_frames,
|
|
void (*fire)(edict_t *ent));
|
|
void NoAmmoWeaponChange (edict_t *ent);
|
|
void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed);
|
|
void barrel_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
|
|
|
|
void Grenade_Explode (edict_t *ent);
|
|
void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result);
|
|
|
|
//#ifdef USE_ZAERO_ITEMS_WEAPONS
|
|
void zCam_TrackEntity (struct edict_s *player, struct edict_s *track, qboolean playerVisiable, qboolean playerOffset);
|
|
void zCam_Stop (struct edict_s *player);
|
|
//#endif // USE_ZAERO_ITEMS_WEAPONS
|
|
|
|
void fire_empnuke(edict_t *ent, vec3_t center, int radius);
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
|
|
misc_securitycamera
|
|
|
|
This is where the visor locates too...
|
|
|
|
======================================================================
|
|
*/
|
|
//#ifdef USE_ZAERO_ITEMS_WEAPONS
|
|
void use_securitycamera (edict_t *self, edict_t *other, edict_t *activator)
|
|
{
|
|
self->active = !self->active;
|
|
}
|
|
|
|
#define CAMERA_FRAME_FIRST 0
|
|
#define CAMERA_FRAME_LAST 59
|
|
void securitycamera_think (edict_t *self)
|
|
{
|
|
if (self->active)
|
|
{
|
|
self->s.frame++;
|
|
if (self->s.frame > CAMERA_FRAME_LAST)
|
|
self->s.frame = CAMERA_FRAME_FIRST;
|
|
}
|
|
|
|
if (self->timeout > level.time)
|
|
{
|
|
self->s.effects |= EF_COLOR_SHELL;
|
|
self->s.renderfx |= RF_SHELL_GREEN;
|
|
}
|
|
else
|
|
{
|
|
self->s.effects &= ~EF_COLOR_SHELL;
|
|
self->s.renderfx &= ~RF_SHELL_GREEN;
|
|
}
|
|
|
|
self->nextthink = level.time + FRAMETIME;
|
|
}
|
|
|
|
void camera_pain (edict_t *self, edict_t *other, float kick, int damage)
|
|
{
|
|
self->timeout = level.time + FRAMETIME * 2;
|
|
}
|
|
|
|
void SP_misc_securitycamera (edict_t *self)
|
|
{
|
|
vec3_t offset, forward, up;
|
|
|
|
// no message? error
|
|
if (!self->message)
|
|
{
|
|
gi.error("misc_securitycamera w/o message");
|
|
G_FreeEdict(self);
|
|
return;
|
|
}
|
|
|
|
self->solid = SOLID_BBOX;
|
|
self->movetype = MOVETYPE_NONE;
|
|
self->s.modelindex = gi.modelindex("models/objects/camera/tris.md2");
|
|
|
|
// set the bounding box
|
|
VectorSet(self->mins, -16, -16, -32);
|
|
VectorSet(self->maxs, 16, 16, 0);
|
|
|
|
// set the angle of direction
|
|
VectorCopy(self->mangle, self->move_angles);
|
|
VectorSet(self->s.angles, 0, self->mangle[YAW], 0);
|
|
|
|
// get an offset
|
|
AngleVectors(self->s.angles, forward, NULL, up);
|
|
VectorSet(offset, 0, 0, 0);
|
|
VectorMA(offset, 8, forward, offset);
|
|
VectorMA(offset, -32, up, offset);
|
|
VectorAdd(self->s.origin, offset, self->move_origin);
|
|
|
|
if (self->targetname)
|
|
{
|
|
self->use = use_securitycamera;
|
|
self->active = false;
|
|
}
|
|
else
|
|
{
|
|
self->active = true;
|
|
}
|
|
self->think = securitycamera_think;
|
|
self->nextthink = level.time + FRAMETIME;
|
|
self->health = 1000; // Knightmare- was 1
|
|
self->takedamage = DAMAGE_IMMORTAL; // health will not be deducted
|
|
self->pain = camera_pain;
|
|
|
|
self->common_name = "Security Camera";
|
|
self->class_id = ENTITY_MISC_SECURITYCAMERA;
|
|
|
|
gi.linkentity(self);
|
|
}
|
|
|
|
char *camera_statusbar =
|
|
"xv 26 yb -75 string \"Tracking %s\" "
|
|
// timer
|
|
"if 24 " // was "if 20"
|
|
" xv 246 "
|
|
" num 3 25 " // was " num 3 21"
|
|
" xv 296 "
|
|
" pic 24 " // was " pic 20"
|
|
"endif "
|
|
;
|
|
|
|
void updateVisorHud (edict_t *ent)
|
|
{
|
|
static char buf[1024];
|
|
|
|
gi.WriteByte (svc_layout);
|
|
Com_sprintf(buf, sizeof(buf), camera_statusbar, ent->client->zCameraTrack->message);
|
|
gi.WriteString(buf);
|
|
}
|
|
|
|
void startVisorStatic (edict_t *ent)
|
|
{
|
|
ent->client->zCameraStaticFramenum = level.time + FRAMETIME * 2;
|
|
}
|
|
|
|
void startVisor (edict_t *ent, edict_t *e)
|
|
{
|
|
// don't do anything if we're already at the destination camera
|
|
if (e == ent->client->zCameraTrack)
|
|
return;
|
|
|
|
// no more time?
|
|
if (ent->client->pers.visorFrames <= 0)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "No time left for visor\n");
|
|
return;
|
|
}
|
|
|
|
// look thru the camera
|
|
zCam_TrackEntity (ent, e, true, true);
|
|
|
|
startVisorStatic (ent);
|
|
updateVisorHud (ent);
|
|
gi.unicast (ent, true); // reliably send to ent
|
|
ent->client->showscores = true;
|
|
|
|
// play activation sound
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("items/visor/act.wav"), 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void stopCamera (edict_t *self)
|
|
{
|
|
zCam_Stop (self);
|
|
self->client->showscores = false;
|
|
gi.sound (self, CHAN_AUTO, gi.soundindex("items/visor/deact.wav"), 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
edict_t *findNextCamera (edict_t *old)
|
|
{
|
|
edict_t *e = NULL;
|
|
|
|
// first of all, are there *any* cameras?
|
|
e = G_Find(NULL, FOFS(classname), "misc_securitycamera");
|
|
if (e == NULL)
|
|
return NULL;
|
|
|
|
// start with the current and try to find another good camera
|
|
e = old;
|
|
while(1)
|
|
{
|
|
e = G_Find(e, FOFS(classname), "misc_securitycamera");
|
|
if (e == NULL)
|
|
continue; // loop back around
|
|
|
|
if (e == old)
|
|
return e;
|
|
|
|
if (!e->active)
|
|
continue;
|
|
|
|
return e;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void Use_Visor (edict_t *ent, gitem_t *item)
|
|
{
|
|
if (ent->client->zCameraTrack == NULL)
|
|
{
|
|
edict_t *e = findNextCamera(NULL);
|
|
if (e == NULL)
|
|
{
|
|
gi.cprintf(ent, PRINT_HIGH, "No cameras are available\n");
|
|
return;
|
|
}
|
|
|
|
if (ent->client->pers.visorFrames == 0)
|
|
ent->client->pers.visorFrames = (sk_visor_time->value * 10);
|
|
startVisor (ent, e);
|
|
}
|
|
else
|
|
{
|
|
edict_t *e = findNextCamera(ent->client->zCameraTrack);
|
|
if (e != NULL &&
|
|
e != ent->client->zCameraTrack)
|
|
{
|
|
ent->client->zCameraTrack = e;
|
|
// play sound
|
|
gi.sound(ent, CHAN_AUTO, gi.soundindex("items/visor/act.wav"), 1, ATTN_NORM, 0);
|
|
startVisorStatic (ent);
|
|
updateVisorHud (ent);
|
|
gi.unicast (ent, true); // reliably send to ent
|
|
}
|
|
}
|
|
}
|
|
//#endif // USE_ZAERO_ITEMS_WEAPONS
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
|
|
EMP Nuke
|
|
|
|
======================================================================
|
|
*/
|
|
void weapon_EMPNuke_fire (edict_t *ent)
|
|
{
|
|
fire_empnuke (ent, ent->s.origin, 1024);
|
|
// fire_empnuke (ent, ent->s.origin, sk_empnuke_radius->value);
|
|
|
|
ent->client->pers.inventory[ent->client->ammo_index]--;
|
|
|
|
if (ent->client->pers.inventory[ent->client->ammo_index])
|
|
{
|
|
ent->client->weaponstate = WEAPON_ACTIVATING;
|
|
ent->client->ps.gunframe = 0;
|
|
}
|
|
else
|
|
{
|
|
NoAmmoWeaponChange (ent);
|
|
ChangeWeapon(ent);
|
|
}
|
|
}
|
|
|
|
|
|
void Weapon_EMPNuke (edict_t *ent)
|
|
{
|
|
static int pause_frames[] = {25, 34, 43, 0};
|
|
static int fire_frames[] = {16, 0};
|
|
|
|
#ifndef KMQUAKE2_ENGINE_MOD // Knightmare- no need to worry about overflows...
|
|
if (deathmatch->value)
|
|
#endif
|
|
{
|
|
if (ent->client->ps.gunframe == 0)
|
|
{
|
|
gi.sound(ent, CHAN_AUTO, gi.soundindex("items/empnuke/emp_act.wav"), 1, ATTN_NORM, 0);
|
|
}
|
|
else if (ent->client->ps.gunframe == 11)
|
|
{
|
|
gi.sound(ent, CHAN_AUTO, gi.soundindex("items/empnuke/emp_spin.wav"), 1, ATTN_NORM, 0);
|
|
}
|
|
else if (ent->client->ps.gunframe == 35)
|
|
{
|
|
gi.sound(ent, CHAN_AUTO, gi.soundindex("items/empnuke/emp_idle.wav"), 1, ATTN_NORM, 0);
|
|
}
|
|
}
|
|
|
|
Weapon_Generic (ent, 9, 16, 43, 47, pause_frames, fire_frames, weapon_EMPNuke_fire);
|
|
}
|
|
|
|
|
|
void empnukeFinish (edict_t *ent)
|
|
{
|
|
// gi.sound(ent, CHAN_VOICE, gi.soundindex("items/empnuke/empdie.wav"), 1, ATTN_NORM, 0);
|
|
G_FreeEdict(ent);
|
|
}
|
|
|
|
|
|
void empBlastAnim (edict_t *ent)
|
|
{
|
|
ent->s.frame++;
|
|
ent->s.skinnum++;
|
|
|
|
if (ent->s.frame > 5)
|
|
{
|
|
ent->svflags |= SVF_NOCLIENT;
|
|
ent->s.modelindex = 0;
|
|
ent->s.frame = 0;
|
|
ent->s.skinnum = 0;
|
|
|
|
// ent->s.sound = gi.soundindex ("items/empnuke/empactive.wav");
|
|
|
|
ent->think = empnukeFinish;
|
|
ent->nextthink = level.time + 30;
|
|
}
|
|
else
|
|
{
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
}
|
|
}
|
|
|
|
|
|
void fire_empnuke (edict_t *ent, vec3_t center, int radius)
|
|
{
|
|
edict_t *empnuke;
|
|
|
|
// gi.sound(ent, CHAN_VOICE, gi.soundindex("items/empnuke/empfire.wav"), 1, ATTN_NORM, 0);
|
|
gi.sound(ent, CHAN_VOICE, gi.soundindex("items/empnuke/emp_trg.wav"), 1, ATTN_NORM, 0);
|
|
|
|
empnuke = G_Spawn();
|
|
empnuke->owner = ent;
|
|
empnuke->dmg = radius;
|
|
VectorCopy(center, empnuke->s.origin);
|
|
empnuke->classname = "EMPNukeCenter";
|
|
/// empnuke->svflags |= SVF_NOCLIENT;
|
|
empnuke->movetype = MOVETYPE_NONE;
|
|
empnuke->s.modelindex = gi.modelindex("models/objects/b_explode/tris.md2");
|
|
empnuke->s.skinnum = 0;
|
|
// empnuke->s.renderfx = RF_TRANSLUCENT | RF_FULLBRIGHT;
|
|
// empnuke->s.renderfx = RF_TRANSLUCENT;
|
|
empnuke->moreflags |= FL2_DO_NOT_REFLECT; // Knightmare- do not reflect flag
|
|
|
|
empnuke->think = empBlastAnim;
|
|
empnuke->nextthink = level.time + FRAMETIME;
|
|
|
|
// empnuke->think = G_FreeEdict;
|
|
// empnuke->nextthink = level.time + 30;
|
|
|
|
empnuke->common_name = "EMP Nuke Center";
|
|
empnuke->class_id = ENTITY_Z_EMPNUKECENTER;
|
|
|
|
gi.linkentity (empnuke);
|
|
|
|
// gi.sound(empnuke, CHAN_VOICE, gi.soundindex("items/empnuke/emp_exp.wav"), 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
|
|
qboolean EMPNukeCheck (edict_t *ent, vec3_t pos)
|
|
{
|
|
edict_t *check = NULL;
|
|
|
|
while ((check = G_Find (check, FOFS(classname), "EMPNukeCenter")) != NULL)
|
|
{
|
|
vec3_t v;
|
|
|
|
if (check->owner != ent)
|
|
{
|
|
VectorSubtract (check->s.origin, pos, v);
|
|
if (VectorLength(v) <= check->dmg)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
|
|
Plasma Shield
|
|
|
|
======================================================================
|
|
*/
|
|
//#ifdef USE_ZAERO_ITEMS_WEAPONS
|
|
void PlasmaShield_die (edict_t *self)
|
|
{
|
|
#ifndef KMQUAKE2_ENGINE_MOD // Knightmare- no need to worry about overflows...
|
|
if (deathmatch->value)
|
|
#endif
|
|
{
|
|
gi.sound(self, CHAN_VOICE, gi.soundindex("items/plasmashield/psdie.wav"), 1, ATTN_NORM, 0);
|
|
}
|
|
G_FreeEdict(self);
|
|
}
|
|
|
|
|
|
void PlasmaShield_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
|
{
|
|
PlasmaShield_die(self);
|
|
}
|
|
|
|
|
|
void Use_PlasmaShield (edict_t *ent, gitem_t *item)
|
|
{
|
|
int ammoIdx = ITEM_INDEX(item);
|
|
edict_t *PlasmaShield;
|
|
vec3_t forward, right, up, frontbottomleft, backtopright;
|
|
|
|
if (!ent->client->pers.inventory[ammoIdx])
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (EMPNukeCheck(ent, ent->s.origin))
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("items/empnuke/emp_missfire.wav"), 1, ATTN_NORM, 0);
|
|
return;
|
|
}
|
|
|
|
if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
|
|
ent->client->pers.inventory[ammoIdx]--;
|
|
|
|
#ifndef KMQUAKE2_ENGINE_MOD // Knightmare- no need to worry about overflows...
|
|
if (deathmatch->value)
|
|
#endif
|
|
{
|
|
gi.sound(ent, CHAN_VOICE, gi.soundindex("items/plasmashield/psfire.wav"), 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
PlasmaShield = G_Spawn();
|
|
// PlasmaShield->owner = ent;
|
|
PlasmaShield->classname = "PlasmaShield";
|
|
PlasmaShield->movetype = MOVETYPE_PUSH;
|
|
PlasmaShield->solid = SOLID_BBOX;
|
|
PlasmaShield->s.modelindex = gi.modelindex("sprites/plasmashield.sp2");
|
|
PlasmaShield->s.effects |= EF_POWERSCREEN;
|
|
PlasmaShield->s.sound = gi.soundindex ("items/plasmashield/psactive.wav");
|
|
|
|
AngleVectors (ent->client->v_angle, forward, right, up);
|
|
vectoangles (forward, PlasmaShield->s.angles);
|
|
|
|
VectorMA (ent->s.origin, 50, forward, PlasmaShield->s.origin);
|
|
|
|
// fudge the bbox
|
|
VectorScale(forward, 10, frontbottomleft);
|
|
VectorMA(frontbottomleft, -30, right, frontbottomleft);
|
|
VectorMA(frontbottomleft, -30, up, frontbottomleft);
|
|
|
|
VectorScale(forward, 5, backtopright);
|
|
VectorMA(backtopright, 30, right, backtopright);
|
|
VectorMA(backtopright, 50, up, backtopright);
|
|
|
|
ClearBounds (PlasmaShield->mins, PlasmaShield->maxs);
|
|
|
|
AddPointToBounds (frontbottomleft, PlasmaShield->mins, PlasmaShield->maxs);
|
|
AddPointToBounds (backtopright, PlasmaShield->mins, PlasmaShield->maxs);
|
|
|
|
PlasmaShield->health = PlasmaShield->max_health = sk_plasmashield_health->value; // was 4000
|
|
PlasmaShield->die = PlasmaShield_killed;
|
|
PlasmaShield->takedamage = DAMAGE_YES;
|
|
|
|
PlasmaShield->think = PlasmaShield_die;
|
|
PlasmaShield->nextthink = level.time + sk_plasmashield_life->value; // was 10
|
|
|
|
PlasmaShield->common_name = "Plasma Shield";
|
|
PlasmaShield->class_id = ENTITY_Z_PLASMASHIELD;
|
|
|
|
|
|
gi.linkentity (PlasmaShield);
|
|
}
|
|
//#endif // USE_ZAERO_ITEMS_WEAPONS
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
|
|
misc_crate
|
|
|
|
======================================================================
|
|
*/
|
|
|
|
void setupCrate (edict_t *self)
|
|
{
|
|
self->solid = SOLID_BBOX;
|
|
self->movetype = MOVETYPE_FALLFLOAT;
|
|
// self->movetype = MOVETYPE_STEP;
|
|
|
|
if (!self->mass)
|
|
self->mass = 400;
|
|
|
|
self->touch = barrel_touch;
|
|
self->think = M_droptofloor;
|
|
self->nextthink = level.time + 2 * FRAMETIME;
|
|
|
|
self->common_name = "Pushable Crate";
|
|
self->class_id = ENTITY_MISC_CRATE;
|
|
|
|
gi.linkentity(self);
|
|
}
|
|
|
|
void SP_misc_crate (edict_t *self)
|
|
{
|
|
// setup specific to this size
|
|
self->s.modelindex = gi.modelindex("models/objects/crate/crate64.md2");
|
|
VectorSet (self->mins, -32, -32, 0);
|
|
VectorSet (self->maxs, 32, 32, 64);
|
|
|
|
// generic crate setup
|
|
setupCrate (self);
|
|
}
|
|
|
|
void SP_misc_crate_medium (edict_t *self)
|
|
{
|
|
// setup specific to this size
|
|
self->s.modelindex = gi.modelindex("models/objects/crate/crate48.md2");
|
|
VectorSet (self->mins, -24, -24, 0);
|
|
VectorSet (self->maxs, 24, 24, 48);
|
|
|
|
// generic crate setup
|
|
setupCrate (self);
|
|
}
|
|
|
|
void SP_misc_crate_small (edict_t *self)
|
|
{
|
|
// setup specific to this size
|
|
self->s.modelindex = gi.modelindex("models/objects/crate/crate32.md2");
|
|
VectorSet (self->mins, -16, -16, 0);
|
|
VectorSet (self->maxs, 16, 16, 32);
|
|
|
|
// generic crate setup
|
|
setupCrate (self);
|
|
}
|
|
|
|
/*
|
|
======================================================================
|
|
|
|
misc_seat
|
|
|
|
======================================================================
|
|
*/
|
|
|
|
void SP_misc_seat (edict_t *self)
|
|
{
|
|
self->s.modelindex = gi.modelindex("models/objects/seat/tris.md2");
|
|
VectorSet(self->mins, -16, -16, 0);
|
|
VectorSet(self->maxs, 16, 16, 40);
|
|
|
|
// make this pushable
|
|
setupCrate (self);
|
|
|
|
self->common_name = "Ejection Seat";
|
|
self->class_id = ENTITY_MISC_SEAT;
|
|
}
|
|
|
|
/*
|
|
======================================================================
|
|
|
|
misc_commdish
|
|
|
|
======================================================================
|
|
*/
|
|
|
|
void Anim_CommDish (edict_t *self)
|
|
{
|
|
self->s.frame++;
|
|
|
|
if (self->s.frame >= 98)
|
|
{
|
|
self->s.frame = 98;
|
|
}
|
|
else
|
|
{
|
|
self->nextthink = level.time + FRAMETIME;
|
|
}
|
|
}
|
|
|
|
void Use_CommDish (edict_t *ent, edict_t *other, edict_t *activator)
|
|
{
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
ent->think = Anim_CommDish;
|
|
ent->use = NULL;
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex ("misc/commdish.wav"), 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
void SP_misc_commdish (edict_t *self)
|
|
{
|
|
if (deathmatch->value)
|
|
{ // auto-remove for deathmatch
|
|
G_FreeEdict (self);
|
|
return;
|
|
}
|
|
|
|
self->class_id = ENTITY_MISC_COMMDISH;
|
|
|
|
self->solid = SOLID_BBOX;
|
|
self->movetype = MOVETYPE_STEP;
|
|
|
|
self->model = "models/objects/satdish/tris.md2";
|
|
self->s.modelindex = gi.modelindex (self->model);
|
|
VectorSet (self->mins, -100, -100, 0);
|
|
VectorSet (self->maxs, 100, 100, 275);
|
|
|
|
self->monsterinfo.aiflags = AI_NOSTEP;
|
|
|
|
self->think = M_droptofloor;
|
|
self->nextthink = level.time + 2 * FRAMETIME;
|
|
self->use = Use_CommDish;
|
|
|
|
gi.linkentity (self);
|
|
}
|
|
|
|
/*
|
|
======================================================================
|
|
|
|
func_barrier
|
|
|
|
======================================================================
|
|
*/
|
|
|
|
qboolean thruBarrier (edict_t *targ, edict_t *inflictor)
|
|
{
|
|
trace_t tr;
|
|
edict_t *e = inflictor;
|
|
while(e)
|
|
{
|
|
tr = gi.trace(e->s.origin, NULL, NULL, targ->s.origin, e, MASK_SHOT);
|
|
if (!tr.ent || tr.fraction >= 1.0)
|
|
return false;
|
|
|
|
if (tr.ent == targ)
|
|
return false;
|
|
|
|
if (tr.ent->classname && Q_stricmp(tr.ent->classname, "func_barrier") == 0)
|
|
return true;
|
|
|
|
if (e == tr.ent)
|
|
break;
|
|
|
|
e = tr.ent;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void barrier_think (edict_t *self)
|
|
{
|
|
if (self->timeout > level.time)
|
|
{
|
|
self->svflags &= ~SVF_NOCLIENT;
|
|
}
|
|
else
|
|
{
|
|
self->svflags |= SVF_NOCLIENT;
|
|
}
|
|
|
|
self->nextthink = level.time + FRAMETIME;
|
|
}
|
|
|
|
void barrier_pain (edict_t *self, edict_t *other, float kick, int damage)
|
|
{
|
|
self->timeout = level.time + FRAMETIME * 2;
|
|
if (self->damage_debounce_time < level.time)
|
|
{
|
|
gi.sound (self, CHAN_AUTO, gi.soundindex("weapons/lashit.wav"), 1, ATTN_NORM, 0);
|
|
self->damage_debounce_time = level.time + FRAMETIME * 2;
|
|
}
|
|
}
|
|
void barrier_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
if (other == world)
|
|
return;
|
|
|
|
self->timeout = level.time + FRAMETIME * 2;
|
|
if (self->touch_debounce_time < level.time)
|
|
{
|
|
gi.sound (self, CHAN_AUTO, gi.soundindex("weapons/lashit.wav"), 1, ATTN_NORM, 0);
|
|
self->touch_debounce_time = level.time + FRAMETIME * 2;
|
|
}
|
|
}
|
|
|
|
void SP_func_barrier (edict_t *self)
|
|
{
|
|
self->class_id = ENTITY_FUNC_BARRIER;
|
|
|
|
self->solid = SOLID_BBOX;
|
|
self->movetype = MOVETYPE_NONE;
|
|
self->s.modelindex = gi.modelindex("models/objects/wall/tris.md2");
|
|
self->svflags = SVF_NOCLIENT;
|
|
self->s.effects = EF_BFG;
|
|
|
|
self->think = barrier_think;
|
|
self->nextthink = level.time + FRAMETIME;
|
|
self->touch = barrier_touch;
|
|
self->health = 1000; // Knightmare- was 1
|
|
self->takedamage = DAMAGE_IMMORTAL; // health will not be deducted
|
|
self->pain = barrier_pain;
|
|
|
|
gi.linkentity(self);
|
|
}
|