thirtyflightsofloving/missionpack/z_item.c

710 lines
17 KiB
C
Raw Normal View History

#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);
// sprintf(buf, camera_statusbar, ent->client->zCameraTrack->message);
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);
}