sof-sdk/Source/Game/gamecpp/w_equip.cpp
2000-06-15 00:00:00 +00:00

489 lines
13 KiB
C++

// ************************************************************************
//
// w_equip.cpp
//
// This is for all selectable items.
// While some of these items (like the C4) can still be considered "weapons",
// they don't use the "weapon" code, and so it is useful (and less of a load
// on the overburdened w_fire.cpp module) to separate "equipment" out.
// ************************************************************************
#include "g_local.h"
#include "w_weapons.h"
#include "ai_private.h" // so we know what a bodyhuman_c is
#include "../strings/items.h"
const unsigned short MEDKIT_HEAL_DEFAULT = 25;
const float REALISTIC_MOVESCALE = 0.5625;
extern edict_t *SV_TestEntityPosition (edict_t *ent);
extern void SetProjVel(edict_t &self, edict_t &newEnt, float fwd, float right, float up);
extern void SetProjPhysics(edict_t &self, float friction, float gravity, float airresistance, float bouyancy, float elasticity);
// need to know about leaning when we toss c4
extern edict_t *GetLeanBuddy(edict_t *owner);
//yurg - don't wanna make it like this but the player .dll nonsense is just too annoying to deal with
void cacheForItem(equipment_t curEquip)
{
switch(curEquip)
{
case SFE_FLASHPACK:
game_ghoul.FindObject("Items/Projectiles", "flashpak")->RegistrationLock();
gi.soundindex("Weapons/gren/bounce.wav");
break;
// case SFE_NEURAL_GRENADE:
// gi.effectindex("weapons/world/neural");
break;
case SFE_C4:
game_ghoul.FindObject("Items/Projectiles", "C4")->RegistrationLock();
gi.soundindex("Weapons/C4/c4attch.wav");
gi.soundindex("Weapons/C4/Beep.wav");
break;
case SFE_LIGHT_GOGGLES:
gi.soundindex("Weapons/Goggles/on.wav");
gi.soundindex("Weapons/Goggles/off.wav");
break;
case SFE_CLAYMORE:
game_ghoul.FindObject("Items/Projectiles", "claymore")->RegistrationLock();
gi.effectindex("weapons/world/claymore");
gi.soundindex("Weapons/C4/c4attch.wav");
gi.soundindex("Weapons/Claymore/Beep.wav");
break;
case SFE_MEDKIT:
break;
case SFE_GRENADE:
game_ghoul.FindObject("Items/Projectiles", "grenade")->RegistrationLock();
gi.effectindex("weapons/world/grenadeexplode");
gi.soundindex("Weapons/gren/bounce.wav");
break;
default:
break;
}
}
//------------------------------------MEDKIT-------------------------------------------
qboolean tryToHeal(edict_t *ent,int amountToHeal);
bool medkitUse(edict_t &ent, itemSlot_c &slot)
{
if (dm->dmRule_REALISTIC_DAMAGE())
{
// heal leg and arm damage, but not health!
bodyhuman_c *body = NULL;
if (body = (bodyhuman_c*)ent.client->body)
{
body->RemoveLimbDamage();
resetMovescale(&ent, 0);
}
gi.sound(&ent, CHAN_ITEM, gi.soundindex("dm/healthpu.wav"), 1.0, ATTN_IDLE, 0);
return true;
}
bool didWeHeal = !!tryToHeal(&ent, MEDKIT_HEAL_DEFAULT);
if (!didWeHeal)
{
// print the "We're at full health, we don't need this, Bozo!" message
gi.SP_Print(&ent, ITEMS_FULL_HEALTH);
}
return didWeHeal;
}
//------------------------------------GOGGLES-------------------------------------------
bool goggleUse(edict_t &ent, itemSlot_c &slot)
{
if (!ent.client)
return true;
if (slot.getSlotStatus())
{ // Goggles are on!
ent.client->goggles_on = true;
gi.sound(&ent, CHAN_VOICE, gi.soundindex("Weapons/Goggles/on.wav"), .6, ATTN_IDLE, 0);//fixme
}
else
{
ent.client->goggles_on = false;
if (!game.cinematicfreeze)
{
gi.sound(&ent, CHAN_VOICE, gi.soundindex("Weapons/Goggles/off.wav"), .6, ATTN_IDLE, 0);//fixme
}
}
return true;
}
//------------------------------------GRENADE-------------------------------------------
// Grenades are weapons, used by opponents as well. For this reason, most of the functionality resides in w_fire.
extern void createGrenade(edict_t *owner, vec3_t loc, vec3_t vel, qboolean enemy);
bool grenadeUse(edict_t &ent, itemSlot_c &slot)
{
vec3_t fwdV, rightV, upV;
vec3_t vel, pos;
edict_t *leanBuddy = GetLeanBuddy(&ent);
// Decide on velocity. Start by getting directional vectors.
if(ent.client)
{
AngleVectors(ent.client->ps.viewangles, fwdV, rightV, upV);
}
else
{
AngleVectors(ent.s.angles, fwdV, rightV, upV);
}
VectorMA(ent.velocity, 475.0, fwdV, vel);
VectorMA(vel, gi.flrand(-15,15), rightV, vel);
VectorMA(vel, gi.flrand(300,350), upV, vel);
// kef -- take into account player leaning
if (leanBuddy)
{
VectorCopy(leanBuddy->s.origin, pos);
pos[2] = ent.s.origin[2] + ent.viewheight-20.0;
}
else
{
VectorCopy(ent.s.origin, pos);
pos[2] += ent.viewheight-20.0;
}
createGrenade(&ent, pos, vel, false);
return true;
}
//------------------------------------FLASHPACK-------------------------------------------
void flashTouch(edict_t *self, edict_t *other, cplane_t *plane, mtexinfo_t *surf)
{
if(game.cinematicfreeze)
{ // We are in a cinematic, remove all volatile objects.
G_FreeEdict(self);
return;
}
if(plane && VectorLengthSquared(self->velocity) > 100)
{
gi.sound(self, CHAN_VOICE, gi.soundindex("Weapons/gren/bounce.wav"), .6, 2, 0);//fixme - bounce
}
}
void flashpackExplode(edict_t *ent)
{
vec3_t pos;
// if this thing is trying to explode during a cinematic, just get rid of it
if (!game.cinematicfreeze)
{
VectorCopy(ent->s.origin, pos);
pos[2] += 15;
ent->solid = SOLID_NOT;
BlindingLight(pos, 10000, 0.99, 0.15);
FX_Flashpack(pos);
T_RadiusDamage (ent, ent->owner, 20, ent, 100, MOD_FIRE, 0);
}
G_FreeEdict(ent);
//this should probably affect enemies as well...
}
void flashpackFunc(edict_t &ent)
{
edict_t *flashpack;
edict_t *leanBuddy = GetLeanBuddy(&ent);
flashpack = G_Spawn();
SetProjVel(ent, *flashpack, 400, 0, gi.flrand(200, 400));
SetProjPhysics(*flashpack, .7, 1.0, 0, 0, .7);
// kef -- take into account player leaning
if (leanBuddy)
{
VectorCopy(leanBuddy->s.origin, flashpack->s.origin);
flashpack->s.origin[2] = ent.s.origin[2] + ent.viewheight;
}
else
{
VectorCopy(ent.s.origin, flashpack->s.origin);
flashpack->s.origin[2] += ent.viewheight;
}
VectorSet (flashpack->mins, -2, -2, -3);
VectorSet (flashpack->maxs, 2, 2, 3);
flashpack->health = 100;
flashpack->think = flashpackExplode;
flashpack->nextthink = level.time + 1.5;
VectorSet(flashpack->avelocity, gi.irand(-300, 300), gi.irand(-300, 300), gi.irand(-300, 300));
//gi.setmodel(flashpack,"models/objects/generic/chunks_wall/tris.fm");
game_ghoul.SetSimpleGhoulModel(flashpack, "Items/Projectiles", "flashpak");
gi.linkentity(flashpack);
flashpack->owner = &ent;
flashpack->touch = flashTouch;
flashpack->flags = FL_THROWN_WPN;
// Play grenade throwing sound
gi.sound(&ent, CHAN_VOICE, gi.soundindex("Weapons/gren/throw.wav"), .6, 1, 0);//fixme - bounce
if(SV_TestEntityPosition(flashpack))
{
flashpack->touch(flashpack, g_edicts, 0, 0);
}
}
bool flashpackUse(edict_t &ent, itemSlot_c &slot)
{
flashpackFunc(ent);
return true;
}
//--------------------------------NEURAL GRENADE----------------------------------------
bool neuralGrenadeUse(edict_t &ent, itemSlot_c &slot)
{
#ifndef _OEM_
T_RadiusDamage (&ent, &ent, 400, &ent, 256, MOD_NEURAL_GRENADE, DT_NEURAL|DT_SHOCK|DAMAGE_NO_KNOCKBACK);
gmonster.RadiusDeafen(&ent, 400, 300);
fxRunner.setPos2(ent.s.origin);
fxRunner.exec("weapons/world/emitter", ent.s.origin);
#endif
return true;
}
//---------------------------------C4/PLASTIQUE------------------------------------------
void c4Explode(edict_t *self)
{
if(self->health < 104)
{
gmonster.SpookEnemies(self->s.origin, 160, SPOOK_EXPLOSIVE);//hahaha
gi.sound(self, CHAN_VOICE, gi.soundindex("Weapons/C4/Beep.wav"), .6, ATTN_NORM, 0);
self->health++;
self->nextthink = level.time + .4;
}
else
{
if (!game.cinematicfreeze)
{ // if we're in a cinematic don't do any of this...just free the edict.
vec3_t fwd, pos;
AngleVectors(self->s.angles, fwd, NULL, NULL);
VectorMA(self->s.origin, 10, fwd, pos);
T_RadiusDamage2(self, self->owner, pos, 250, 32, 200, NULL, MOD_C4, DT_MANGLE|DT_DIRECTIONALGORE);
BlindingLight(self->s.origin, 2500, 0.8, 0.5);
gmonster.RadiusDeafen(self, 300, 300);
fxRunner.setDir(fwd);
fxRunner.exec("weapons/world/c4explode", self->s.origin);
IncreaseSpawnIntensity(.6);
}
G_FreeEdict(self);
}
}
void c4Touch(edict_t *self, edict_t *other, cplane_t *plane, mtexinfo_t *surf)
{
if(game.cinematicfreeze)
{ // We are in a cinematic, remove all volatile objects.
G_FreeEdict(self);
return;
}
if(plane)
{
if(plane->normal)
{
if(other == g_edicts)
{
if(self->gravity)
{
gmonster.SpookEnemies(self->s.origin, 160, SPOOK_EXPLOSIVE);
gi.sound(self, CHAN_VOICE, gi.soundindex("Weapons/C4/c4attch.wav"), .6, ATTN_NORM, 0);
self->gravity = 0;
VectorClear(self->velocity);
VectorClear(self->avelocity);
if(plane)
{
vectoangles(plane->normal, self->s.angles);
}
}
}
}
}
}
bool c4use(edict_t &ent, itemSlot_c &slot)
{
edict_t *c4;
edict_t *leanBuddy = GetLeanBuddy(&ent);
c4 = G_Spawn();
game_ghoul.SetSimpleGhoulModel(c4, "Items/Projectiles", "C4");
SetProjVel(ent, *c4, 410.0, gi.flrand(-30, 30), gi.flrand(150, 180));
SetProjPhysics(*c4, 1.0, 1.0, 0, 0, 0.0);
// kef -- take into account player leaning
if (leanBuddy)
{
VectorCopy(leanBuddy->s.origin, c4->s.origin);
c4->s.origin[2] = ent.s.origin[2] + ent.viewheight;
}
else
{
VectorCopy(ent.s.origin, c4->s.origin);
c4->s.origin[2] += ent.viewheight;
}
VectorSet (c4->mins, -2, -2, -2);
VectorSet (c4->maxs, 2, 2, 2);
c4->health = 100;
c4->think = c4Explode;
c4->nextthink = level.time + .5;
gi.linkentity(c4);
c4->owner = &ent;
c4->touch = c4Touch;
c4->flags = FL_THROWN_WPN;
VectorSet(c4->avelocity, gi.irand(-300, 300), gi.irand(-300, 300), gi.irand(-300, 300));
// Play grenade throwing sound
gi.sound(&ent, CHAN_VOICE, gi.soundindex("Weapons/gren/throw.wav"), .6, 1, 0);//fixme - bounce
//c4->physicsFlags |= PHYS_ATTACHED|PHYS_ATTACH_COPYANG;
if(SV_TestEntityPosition(c4))
{
c4->touch(c4, g_edicts, 0, 0);
}
return true;
}
//-----------------------------CLAYMORE-----------------------------------
void claymoreThink(edict_t *self)
{
if(game.cinematicfreeze)
{ // We are in a cinematic, remove all volatile objects.
G_FreeEdict(self);
return;
}
self->owner = g_edicts;
CRadiusContent rad(self->s.origin, 128);
if(self->health < 3)
{ // play activate sound
gi.sound(self, CHAN_VOICE, gi.soundindex("Weapons/Claymore/Beep.wav"), .6, ATTN_NORM, 0);//fixme
self->health = 3;
}
for(int i = 0; i < rad.getNumFound(); i++)
{
edict_t *search = rad.foundEdict(i);
if(search->client || search->ai || (self->gib_health < 1))
{
if((search->health > 0)||(self->gib_health < 1))
{
vec3_t pos;
self->owner = self->targetEnt;
VectorCopy(self->s.origin, pos);
pos[2] += 10;
T_RadiusDamage2(self, self->owner, self->s.origin, 300, 150, 100, NULL, MOD_CLAYMORE, DT_MANGLE|DT_DIRECTIONALGORE);
gmonster.RadiusDeafen(self, 300, 300);
// fxRunner.exec("weapons/world/airexplode", self->s.origin);
// FX_C4Explosion(self);
// BlindingLight(pos, 5000, 0.8, 0.5);
// ShakeCameras (self->s.origin, 500, 300, 25);
IncreaseSpawnIntensity(.4);
fxRunner.exec("weapons/world/claymore", self->s.origin);
G_FreeEdict(self);
return;
}
}
}
self->gib_health--;
self->nextthink += .2;
}
void claymore_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
if(!self->gib_health)
{ //already killed myself.
return;
}
self->gib_health = 0;
self->think = claymoreThink;
self->nextthink = level.time + 0.2;
}
void claymoreTouch(edict_t *self, edict_t *other, cplane_t *plane, mtexinfo_t *surf)
{
if(self->health < 2)
{
gi.sound(self, CHAN_VOICE, gi.soundindex("Weapons/C4/c4attch.wav"), .6, ATTN_NORM, 0);
self->health = 2;
}
}
bool claymoreUse(edict_t &ent, itemSlot_c &slot)
{
#ifndef _OEM_
edict_t *claymore;
claymore = G_Spawn();
game_ghoul.SetSimpleGhoulModel(claymore, "Items/Projectiles", "claymore");
SetProjVel(ent, *claymore, 0.0, 0.0, 0.0);
SetProjPhysics(*claymore, 1.0, 1.0, 0, 0, 0.0);
VectorCopy(ent.s.origin, claymore->s.origin);
claymore->s.origin[2] += 24;
claymore->gib_health = 200;//timer
claymore->health = 10;
claymore->think = claymoreThink;
claymore->nextthink = level.time + 3.0;
claymore->owner = &ent;
claymore->targetEnt = &ent;
claymore->takedamage = 1;
claymore->die = claymore_die;
VectorSet(claymore->s.angles, 270, 90, 90);
claymore->clipmask = CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SHOT;
VectorSet (claymore->mins, -4, -4, 0);
VectorSet (claymore->maxs, 4, 4, 6);
gi.linkentity(claymore);
claymore->touch = claymoreTouch;
claymore->flags = FL_THROWN_WPN;
claymore->health = 1;
#endif
return true;
}
bool DoWeHaveTheFlag(edict_t *ent)
{
if (ent->ctf_flags)
return true;
return false;
}