2013-04-04 14:52:42 +00:00
// Copyright (C) 1999-2000 Id Software, Inc.
//
// g_weapon.c
// perform the server side effects of a weapon firing
# include "g_local.h"
# include "be_aas.h"
static float s_quadFactor ;
static vec3_t forward , right , up ;
static vec3_t muzzle ;
// Bryar Pistol
//--------
# define BRYAR_PISTOL_VEL 1600
# define BRYAR_PISTOL_DAMAGE 10
# define BRYAR_CHARGE_UNIT 200.0f // bryar charging gives us one more unit every 200ms--if you change this, you'll have to do the same in bg_pmove
# define BRYAR_ALT_SIZE 1.0f
// E11 Blaster
//---------
# define BLASTER_SPREAD 1.6f //1.2f
# define BLASTER_VELOCITY 2300
# define BLASTER_DAMAGE 20
// Tenloss Disruptor
//----------
# define DISRUPTOR_MAIN_DAMAGE 30 //40
# define DISRUPTOR_NPC_MAIN_DAMAGE_CUT 0.25f
# define DISRUPTOR_ALT_DAMAGE 100 //125
# define DISRUPTOR_NPC_ALT_DAMAGE_CUT 0.2f
# define DISRUPTOR_ALT_TRACES 3 // can go through a max of 3 damageable(sp?) entities
# define DISRUPTOR_CHARGE_UNIT 50.0f // distruptor charging gives us one more unit every 50ms--if you change this, you'll have to do the same in bg_pmove
// Wookiee Bowcaster
//----------
# define BOWCASTER_DAMAGE 50
# define BOWCASTER_VELOCITY 1300
# define BOWCASTER_SPLASH_DAMAGE 0
# define BOWCASTER_SPLASH_RADIUS 0
# define BOWCASTER_SIZE 2
# define BOWCASTER_ALT_SPREAD 5.0f
# define BOWCASTER_VEL_RANGE 0.3f
# define BOWCASTER_CHARGE_UNIT 200.0f // bowcaster charging gives us one more unit every 200ms--if you change this, you'll have to do the same in bg_pmove
// Heavy Repeater
//----------
# define REPEATER_SPREAD 1.4f
# define REPEATER_DAMAGE 8
# define REPEATER_VELOCITY 1600
# define REPEATER_ALT_SIZE 3 // half of bbox size
# define REPEATER_ALT_DAMAGE 60
# define REPEATER_ALT_SPLASH_DAMAGE 60
# define REPEATER_ALT_SPLASH_RADIUS 128
# define REPEATER_ALT_VELOCITY 1100
// DEMP2
//----------
# define DEMP2_DAMAGE 35
# define DEMP2_VELOCITY 1800
# define DEMP2_SIZE 2 // half of bbox size
# define DEMP2_ALT_DAMAGE 8 //12 // does 12, 36, 84 at each of the 3 charge levels.
# define DEMP2_CHARGE_UNIT 700.0f // demp2 charging gives us one more unit every 700ms--if you change this, you'll have to do the same in bg_weapons
# define DEMP2_ALT_RANGE 4096
# define DEMP2_ALT_SPLASHRADIUS 256
// Golan Arms Flechette
//---------
# define FLECHETTE_SHOTS 6
# define FLECHETTE_SPREAD 4.0f
2013-04-04 18:01:17 +00:00
# define FLECHETTE_DAMAGE 10 //15
2013-04-04 14:52:42 +00:00
# define FLECHETTE_VEL 3500
# define FLECHETTE_SIZE 1
# define FLECHETTE_MINE_RADIUS_CHECK 256
# define FLECHETTE_ALT_DAMAGE 60
# define FLECHETTE_ALT_SPLASH_DAM 60
# define FLECHETTE_ALT_SPLASH_RAD 128
// Personal Rocket Launcher
//---------
# define ROCKET_VELOCITY 900
# define ROCKET_DAMAGE 100
# define ROCKET_SPLASH_DAMAGE 100
# define ROCKET_SPLASH_RADIUS 160
# define ROCKET_SIZE 3
# define ROCKET_ALT_THINK_TIME 100
// Stun Baton
//--------------
# define STUN_BATON_DAMAGE 20
# define STUN_BATON_ALT_DAMAGE 20
# define STUN_BATON_RANGE 8
extern qboolean G_BoxInBounds ( vec3_t point , vec3_t mins , vec3_t maxs , vec3_t boundsMins , vec3_t boundsMaxs ) ;
static void WP_FireEmplaced ( gentity_t * ent , qboolean altFire ) ;
void laserTrapStick ( gentity_t * ent , vec3_t endpos , vec3_t normal ) ;
void touch_NULL ( gentity_t * ent , gentity_t * other , trace_t * trace )
{
}
void laserTrapExplode ( gentity_t * self ) ;
//-----------------------------------------------------------------------------
void W_TraceSetStart ( gentity_t * ent , vec3_t start , vec3_t mins , vec3_t maxs )
//-----------------------------------------------------------------------------
{
//make sure our start point isn't on the other side of a wall
trace_t tr ;
vec3_t entMins ;
vec3_t entMaxs ;
vec3_t eyePoint ;
VectorAdd ( ent - > r . currentOrigin , ent - > r . mins , entMins ) ;
VectorAdd ( ent - > r . currentOrigin , ent - > r . maxs , entMaxs ) ;
if ( G_BoxInBounds ( start , mins , maxs , entMins , entMaxs ) )
{
return ;
}
if ( ! ent - > client )
{
return ;
}
VectorCopy ( ent - > s . pos . trBase , eyePoint ) ;
eyePoint [ 2 ] + = ent - > client - > ps . viewheight ;
trap_Trace ( & tr , eyePoint , mins , maxs , start , ent - > s . number , MASK_SOLID | CONTENTS_SHOTCLIP ) ;
if ( tr . startsolid | | tr . allsolid )
{
return ;
}
if ( tr . fraction < 1.0f )
{
VectorCopy ( tr . endpos , start ) ;
}
}
/*
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PLAYER WEAPONS
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BRYAR PISTOL
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
//----------------------------------------------
static void WP_FireBryarPistol ( gentity_t * ent , qboolean altFire )
//---------------------------------------------------------
{
int damage = BRYAR_PISTOL_DAMAGE ;
int count ;
gentity_t * missile = CreateMissile ( muzzle , forward , BRYAR_PISTOL_VEL , 10000 , ent , altFire ) ;
missile - > classname = " bryar_proj " ;
missile - > s . weapon = WP_BRYAR_PISTOL ;
if ( altFire )
{
float boxSize = 0 ;
count = ( level . time - ent - > client - > ps . weaponChargeTime ) / BRYAR_CHARGE_UNIT ;
if ( count < 1 )
{
count = 1 ;
}
else if ( count > 5 )
{
count = 5 ;
}
if ( count > 1 )
{
damage * = ( count * 1.7 ) ;
}
else
{
damage * = ( count * 1.5 ) ;
}
missile - > s . generic1 = count ; // The missile will then render according to the charge level.
// missile->count = count; // The single player stores the charge in count, which isn't accessible on the client
boxSize = BRYAR_ALT_SIZE * ( count * 0.5 ) ;
VectorSet ( missile - > r . maxs , boxSize , boxSize , boxSize ) ;
VectorSet ( missile - > r . mins , - boxSize , - boxSize , - boxSize ) ;
}
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
if ( altFire )
{
missile - > methodOfDeath = MOD_BRYAR_PISTOL_ALT ;
}
else
{
missile - > methodOfDeath = MOD_BRYAR_PISTOL ;
}
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
// we don't want it to bounce forever
// NOTENOTE These don't bounce yet.
missile - > bounceCount = 8 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
GENERIC
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
//---------------------------------------------------------
void WP_FireTurretMissile ( gentity_t * ent , vec3_t start , vec3_t dir , qboolean altFire , int damage , int velocity , int mod , gentity_t * ignore )
//---------------------------------------------------------
{
gentity_t * missile ;
missile = CreateMissile ( start , dir , velocity , 10000 , ent , altFire ) ;
missile - > classname = " generic_proj " ;
missile - > s . weapon = WP_TURRET ;
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
missile - > methodOfDeath = mod ;
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
if ( ignore )
{
missile - > passThroughNum = ignore - > s . number + 1 ;
}
// we don't want it to bounce forever
// NOTENOTE These don't bounce yet.
missile - > bounceCount = 8 ;
}
//Currently only the seeker drone uses this, but it might be useful for other things as well.
//---------------------------------------------------------
void WP_FireGenericBlasterMissile ( gentity_t * ent , vec3_t start , vec3_t dir , qboolean altFire , int damage , int velocity , int mod )
//---------------------------------------------------------
{
gentity_t * missile ;
missile = CreateMissile ( start , dir , velocity , 10000 , ent , altFire ) ;
missile - > classname = " generic_proj " ;
missile - > s . weapon = WP_BRYAR_PISTOL ;
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
missile - > methodOfDeath = mod ;
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
// we don't want it to bounce forever
// NOTENOTE These don't bounce yet.
missile - > bounceCount = 8 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BLASTER
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
//---------------------------------------------------------
void WP_FireBlasterMissile ( gentity_t * ent , vec3_t start , vec3_t dir , qboolean altFire )
//---------------------------------------------------------
{
int velocity = BLASTER_VELOCITY ;
int damage = BLASTER_DAMAGE ;
gentity_t * missile ;
// NOTENOTE Vehicle models are not yet implemented
/* if ( ent->client && ent->client->ps.vehicleModel != 0 )
{
velocity = 10000 ;
}
*/
missile = CreateMissile ( start , dir , velocity , 10000 , ent , altFire ) ;
missile - > classname = " blaster_proj " ;
missile - > s . weapon = WP_BLASTER ;
// NOTENOTE Vehicle models are not yet implemented
/* if ( ent->client && ent->client->ps.vehicleModel != 0 )
{
damage = 250 ;
}
*/
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
missile - > methodOfDeath = MOD_BLASTER ;
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
// we don't want it to bounce forever
// NOTENOTE These don't bounce yet.
missile - > bounceCount = 8 ;
}
//---------------------------------------------------------
void WP_FireEmplacedMissile ( gentity_t * ent , vec3_t start , vec3_t dir , qboolean altFire , gentity_t * ignore )
//---------------------------------------------------------
{
int velocity = BLASTER_VELOCITY ;
int damage = BLASTER_DAMAGE ;
gentity_t * missile ;
// NOTENOTE Vehicle models are not yet implemented
/* if ( ent->client && ent->client->ps.vehicleModel != 0 )
{
velocity = 10000 ;
}
*/
missile = CreateMissile ( start , dir , velocity , 10000 , ent , altFire ) ;
missile - > classname = " emplaced_gun_proj " ;
missile - > s . weapon = WP_TURRET ; //WP_EMPLACED_GUN;
// NOTENOTE Vehicle models are not yet implemented
/* if ( ent->client && ent->client->ps.vehicleModel != 0 )
{
damage = 250 ;
}
*/
missile - > activator = ignore ;
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
missile - > methodOfDeath = MOD_BLASTER ;
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
if ( ignore )
{
missile - > passThroughNum = ignore - > s . number + 1 ;
}
// we don't want it to bounce forever
// NOTENOTE These don't bounce yet.
missile - > bounceCount = 8 ;
}
//---------------------------------------------------------
static void WP_FireBlaster ( gentity_t * ent , qboolean altFire )
//---------------------------------------------------------
{
vec3_t dir , angs ;
vectoangles ( forward , angs ) ;
if ( altFire )
{
// add some slop to the alt-fire direction
angs [ PITCH ] + = crandom ( ) * BLASTER_SPREAD ;
angs [ YAW ] + = crandom ( ) * BLASTER_SPREAD ;
}
AngleVectors ( angs , dir , NULL , NULL ) ;
// FIXME: if temp_org does not have clear trace to inside the bbox, don't shoot!
WP_FireBlasterMissile ( ent , muzzle , dir , altFire ) ;
}
int G_GetHitLocation ( gentity_t * target , vec3_t ppoint ) ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DISRUPTOR
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
//---------------------------------------------------------
static void WP_DisruptorMainFire ( gentity_t * ent )
//---------------------------------------------------------
{
int damage = DISRUPTOR_MAIN_DAMAGE ;
qboolean render_impact = qtrue ;
vec3_t start , end /*, spot*/ ;
trace_t tr ;
gentity_t * traceEnt , * tent ;
float /*dist, */ shotRange = 8192 ;
int ignore , traces ;
memset ( & tr , 0 , sizeof ( tr ) ) ; //to shut the compiler up
VectorCopy ( ent - > client - > ps . origin , start ) ;
start [ 2 ] + = ent - > client - > ps . viewheight ; //By eyes
VectorMA ( start , shotRange , forward , end ) ;
// trap_Trace( &tr, start, NULL, NULL, end, ent->s.number, MASK_SHOT);
ignore = ent - > s . number ;
traces = 0 ;
while ( traces < 10 )
{ //need to loop this in case we hit a Jedi who dodges the shot
trap_Trace ( & tr , start , NULL , NULL , end , ignore , MASK_SHOT ) ;
traceEnt = & g_entities [ tr . entityNum ] ;
if ( Jedi_DodgeEvasion ( traceEnt , ent , & tr , G_GetHitLocation ( traceEnt , tr . endpos ) ) )
{ //act like we didn't even hit him
VectorCopy ( tr . endpos , start ) ;
ignore = tr . entityNum ;
traces + + ;
continue ;
}
else if ( traceEnt & & traceEnt - > client & & traceEnt - > client - > ps . fd . forcePowerLevel [ FP_SABERDEFEND ] > = FORCE_LEVEL_3 )
{
if ( WP_SaberCanBlock ( traceEnt , tr . endpos , 0 , MOD_DISRUPTOR , qtrue , 0 ) )
{ //broadcast and stop the shot because it was blocked
gentity_t * te = NULL ;
tent = G_TempEntity ( tr . endpos , EV_DISRUPTOR_MAIN_SHOT ) ;
VectorCopy ( muzzle , tent - > s . origin2 ) ;
te = G_TempEntity ( tr . endpos , EV_SABER_BLOCK ) ;
VectorCopy ( tr . endpos , te - > s . origin ) ;
VectorCopy ( tr . plane . normal , te - > s . angles ) ;
if ( ! te - > s . angles [ 0 ] & & ! te - > s . angles [ 1 ] & & ! te - > s . angles [ 2 ] )
{
te - > s . angles [ 1 ] = 1 ;
}
te - > s . eventParm = 0 ;
return ;
}
}
//a Jedi is not dodging this shot
break ;
}
if ( tr . surfaceFlags & SURF_NOIMPACT )
{
render_impact = qfalse ;
}
// always render a shot beam, doing this the old way because I don't much feel like overriding the effect.
tent = G_TempEntity ( tr . endpos , EV_DISRUPTOR_MAIN_SHOT ) ;
VectorCopy ( muzzle , tent - > s . origin2 ) ;
traceEnt = & g_entities [ tr . entityNum ] ;
if ( render_impact )
{
if ( tr . entityNum < ENTITYNUM_WORLD & & traceEnt - > takedamage )
{
// Create a simple impact type mark that doesn't last long in the world
// G_PlayEffect( G_EffectIndex( "disruptor/flesh_impact" ), tr.endpos, tr.plane.normal );
if ( traceEnt - > client & & LogAccuracyHit ( traceEnt , ent ) )
{
ent - > client - > accuracy_hits + + ;
}
G_Damage ( traceEnt , ent , ent , forward , tr . endpos , damage , DAMAGE_NORMAL , MOD_DISRUPTOR ) ;
tent = G_TempEntity ( tr . endpos , EV_DISRUPTOR_HIT ) ;
tent - > s . eventParm = DirToByte ( tr . plane . normal ) ;
if ( traceEnt - > client )
{
tent - > s . weapon = 1 ;
}
}
else
{
// Hmmm, maybe don't make any marks on things that could break
tent = G_TempEntity ( tr . endpos , EV_DISRUPTOR_SNIPER_MISS ) ;
tent - > s . eventParm = DirToByte ( tr . plane . normal ) ;
tent - > s . weapon = 1 ;
}
}
}
//---------------------------------------------------------
void WP_DisruptorAltFire ( gentity_t * ent )
//---------------------------------------------------------
{
int damage = 0 , skip ;
qboolean render_impact = qtrue ;
vec3_t start , end ;
vec3_t muzzle2 ;
trace_t tr ;
gentity_t * traceEnt , * tent ;
float shotRange = 8192 ;
// float dist, shotDist;
// vec3_t spot, dir;
int i ;
int count ;
int traces = DISRUPTOR_ALT_TRACES ;
qboolean fullCharge = qfalse ;
damage = DISRUPTOR_ALT_DAMAGE - 30 ;
/*
if ( ent - > client - > ps . zoomMode = = 1 & &
ent - > client - > ps . zoomLocked )
{ //Scale the additional 25 damage based on the zoomFov for the client.
//In this instance, zoomFov 1 is minimum zoom while zoomFov 50 is maximum.
damage + = ent - > client - > ps . zoomFov / 2 ;
}
*/
VectorCopy ( muzzle , muzzle2 ) ; // making a backup copy
VectorCopy ( ent - > client - > ps . origin , start ) ;
start [ 2 ] + = ent - > client - > ps . viewheight ; //By eyes
count = ( level . time - ent - > client - > ps . weaponChargeTime ) / DISRUPTOR_CHARGE_UNIT ;
count * = 2 ;
if ( count < 1 )
{
count = 1 ;
}
2013-04-04 18:01:17 +00:00
else if ( count > = 60 )
2013-04-04 14:52:42 +00:00
{
2013-04-04 18:01:17 +00:00
count = 60 ;
2013-04-04 14:52:42 +00:00
fullCharge = qtrue ;
}
// more powerful charges go through more things
if ( count < 10 )
{
traces = 1 ;
}
else if ( count < 20 )
{
traces = 2 ;
}
damage + = count ;
skip = ent - > s . number ;
for ( i = 0 ; i < traces ; i + + )
{
VectorMA ( start , shotRange , forward , end ) ;
trap_Trace ( & tr , start , NULL , NULL , end , skip , MASK_SHOT ) ;
if ( tr . surfaceFlags & SURF_NOIMPACT )
{
render_impact = qfalse ;
}
traceEnt = & g_entities [ tr . entityNum ] ;
if ( Jedi_DodgeEvasion ( traceEnt , ent , & tr , G_GetHitLocation ( traceEnt , tr . endpos ) ) )
{
skip = tr . entityNum ;
VectorCopy ( tr . endpos , start ) ;
continue ;
}
else if ( traceEnt & & traceEnt - > client & & traceEnt - > client - > ps . fd . forcePowerLevel [ FP_SABERDEFEND ] > = FORCE_LEVEL_3 )
{
if ( WP_SaberCanBlock ( traceEnt , tr . endpos , 0 , MOD_DISRUPTOR_SNIPER , qtrue , 0 ) )
{ //broadcast and stop the shot because it was blocked
gentity_t * te = NULL ;
tent = G_TempEntity ( tr . endpos , EV_DISRUPTOR_SNIPER_SHOT ) ;
VectorCopy ( muzzle , tent - > s . origin2 ) ;
tent - > s . shouldtarget = fullCharge ;
te = G_TempEntity ( tr . endpos , EV_SABER_BLOCK ) ;
VectorCopy ( tr . endpos , te - > s . origin ) ;
VectorCopy ( tr . plane . normal , te - > s . angles ) ;
if ( ! te - > s . angles [ 0 ] & & ! te - > s . angles [ 1 ] & & ! te - > s . angles [ 2 ] )
{
te - > s . angles [ 1 ] = 1 ;
}
te - > s . eventParm = 0 ;
return ;
}
}
// always render a shot beam, doing this the old way because I don't much feel like overriding the effect.
tent = G_TempEntity ( tr . endpos , EV_DISRUPTOR_SNIPER_SHOT ) ;
VectorCopy ( muzzle , tent - > s . origin2 ) ;
tent - > s . shouldtarget = fullCharge ;
// If the beam hits a skybox, etc. it would look foolish to add impact effects
if ( render_impact )
{
if ( traceEnt - > takedamage & & traceEnt - > client )
{
tent - > s . otherEntityNum = traceEnt - > s . number ;
// Create a simple impact type mark
// G_PlayEffect( G_EffectIndex( "disruptor/alt_hit" ), tr.endpos, tr.plane.normal );
tent = G_TempEntity ( tr . endpos , EV_MISSILE_MISS ) ;
tent - > s . eventParm = DirToByte ( tr . plane . normal ) ;
tent - > s . eFlags | = EF_ALT_FIRING ;
if ( LogAccuracyHit ( traceEnt , ent ) )
{
ent - > client - > accuracy_hits + + ;
}
}
else
{
if ( traceEnt - > r . svFlags & SVF_GLASS_BRUSH
| | traceEnt - > takedamage
| | traceEnt - > s . eType = = ET_MOVER )
{
//rww - is there some reason this was doing nothing?
if ( traceEnt - > takedamage )
{
G_Damage ( traceEnt , ent , ent , forward , tr . endpos , damage ,
2013-04-04 18:01:17 +00:00
DAMAGE_NO_KNOCKBACK /*|DAMAGE_HALF_ARMOR_REDUCTION*/ , MOD_DISRUPTOR_SNIPER ) ;
2013-04-04 14:52:42 +00:00
tent = G_TempEntity ( tr . endpos , EV_DISRUPTOR_HIT ) ;
tent - > s . eventParm = DirToByte ( tr . plane . normal ) ;
}
}
else
{
// Hmmm, maybe don't make any marks on things that could break
tent = G_TempEntity ( tr . endpos , EV_DISRUPTOR_SNIPER_MISS ) ;
tent - > s . eventParm = DirToByte ( tr . plane . normal ) ;
}
break ; // and don't try any more traces
}
if ( traceEnt - > takedamage )
{
vec3_t preAng ;
int preHealth = traceEnt - > health ;
int preLegs = 0 ;
int preTorso = 0 ;
if ( traceEnt - > client )
{
preLegs = traceEnt - > client - > ps . legsAnim ;
preTorso = traceEnt - > client - > ps . torsoAnim ;
VectorCopy ( traceEnt - > client - > ps . viewangles , preAng ) ;
}
G_Damage ( traceEnt , ent , ent , forward , tr . endpos , damage , DAMAGE_NO_KNOCKBACK , MOD_DISRUPTOR_SNIPER ) ;
if ( traceEnt - > client & & preHealth > 0 & & traceEnt - > health < = 0 & & fullCharge )
{ //was killed by a fully charged sniper shot, so disintegrate
VectorCopy ( preAng , traceEnt - > client - > ps . viewangles ) ;
traceEnt - > client - > ps . eFlags | = EF_DISINTEGRATION ;
VectorCopy ( tr . endpos , traceEnt - > client - > ps . lastHitLoc ) ;
traceEnt - > client - > ps . legsAnim = preLegs ;
traceEnt - > client - > ps . torsoAnim = preTorso ;
traceEnt - > r . contents = 0 ;
VectorClear ( traceEnt - > client - > ps . velocity ) ;
}
tent = G_TempEntity ( tr . endpos , EV_DISRUPTOR_HIT ) ;
tent - > s . eventParm = DirToByte ( tr . plane . normal ) ;
if ( traceEnt - > client )
{
tent - > s . weapon = 1 ;
}
}
}
else // not rendering impact, must be a skybox or other similar thing?
{
break ; // don't try anymore traces
}
// Get ready for an attempt to trace through another person
VectorCopy ( tr . endpos , muzzle ) ;
VectorCopy ( tr . endpos , start ) ;
skip = tr . entityNum ;
}
}
//---------------------------------------------------------
static void WP_FireDisruptor ( gentity_t * ent , qboolean altFire )
//---------------------------------------------------------
{
if ( ! ent | | ! ent - > client | | ent - > client - > ps . zoomMode ! = 1 )
{ //do not ever let it do the alt fire when not zoomed
altFire = qfalse ;
}
if ( altFire )
{
WP_DisruptorAltFire ( ent ) ;
}
else
{
WP_DisruptorMainFire ( ent ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BOWCASTER
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
static void WP_BowcasterAltFire ( gentity_t * ent )
{
int damage = BOWCASTER_DAMAGE ;
gentity_t * missile = CreateMissile ( muzzle , forward , BOWCASTER_VELOCITY , 10000 , ent , qfalse ) ;
missile - > classname = " bowcaster_proj " ;
missile - > s . weapon = WP_BOWCASTER ;
VectorSet ( missile - > r . maxs , BOWCASTER_SIZE , BOWCASTER_SIZE , BOWCASTER_SIZE ) ;
VectorScale ( missile - > r . maxs , - 1 , missile - > r . mins ) ;
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
missile - > methodOfDeath = MOD_BOWCASTER ;
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
// missile->splashDamage = BOWCASTER_SPLASH_DAMAGE;
// missile->splashRadius = BOWCASTER_SPLASH_RADIUS;
missile - > s . eFlags | = EF_BOUNCE ;
missile - > bounceCount = 3 ;
}
//---------------------------------------------------------
static void WP_BowcasterMainFire ( gentity_t * ent )
//---------------------------------------------------------
{
int damage = BOWCASTER_DAMAGE , count ;
float vel ;
vec3_t angs , dir ;
gentity_t * missile ;
int i ;
count = ( level . time - ent - > client - > ps . weaponChargeTime ) / BOWCASTER_CHARGE_UNIT ;
if ( count < 1 )
{
count = 1 ;
}
else if ( count > 5 )
{
count = 5 ;
}
if ( ! ( count & 1 ) )
{
// if we aren't odd, knock us down a level
count - - ;
}
for ( i = 0 ; i < count ; i + + )
{
// create a range of different velocities
vel = BOWCASTER_VELOCITY * ( crandom ( ) * BOWCASTER_VEL_RANGE + 1.0f ) ;
vectoangles ( forward , angs ) ;
// add some slop to the alt-fire direction
angs [ PITCH ] + = crandom ( ) * BOWCASTER_ALT_SPREAD * 0.2f ;
angs [ YAW ] + = ( ( i + 0.5f ) * BOWCASTER_ALT_SPREAD - count * 0.5f * BOWCASTER_ALT_SPREAD ) ;
AngleVectors ( angs , dir , NULL , NULL ) ;
missile = CreateMissile ( muzzle , dir , vel , 10000 , ent , qtrue ) ;
missile - > classname = " bowcaster_alt_proj " ;
missile - > s . weapon = WP_BOWCASTER ;
VectorSet ( missile - > r . maxs , BOWCASTER_SIZE , BOWCASTER_SIZE , BOWCASTER_SIZE ) ;
VectorScale ( missile - > r . maxs , - 1 , missile - > r . mins ) ;
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
missile - > methodOfDeath = MOD_BOWCASTER ;
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
// missile->splashDamage = BOWCASTER_SPLASH_DAMAGE;
// missile->splashRadius = BOWCASTER_SPLASH_RADIUS;
// we don't want it to bounce
missile - > bounceCount = 0 ;
}
}
//---------------------------------------------------------
static void WP_FireBowcaster ( gentity_t * ent , qboolean altFire )
//---------------------------------------------------------
{
if ( altFire )
{
WP_BowcasterAltFire ( ent ) ;
}
else
{
WP_BowcasterMainFire ( ent ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
REPEATER
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
//---------------------------------------------------------
static void WP_RepeaterMainFire ( gentity_t * ent , vec3_t dir )
//---------------------------------------------------------
{
int damage = REPEATER_DAMAGE ;
gentity_t * missile = CreateMissile ( muzzle , dir , REPEATER_VELOCITY , 10000 , ent , qfalse ) ;
missile - > classname = " repeater_proj " ;
missile - > s . weapon = WP_REPEATER ;
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
missile - > methodOfDeath = MOD_REPEATER ;
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
// we don't want it to bounce forever
missile - > bounceCount = 8 ;
}
//---------------------------------------------------------
static void WP_RepeaterAltFire ( gentity_t * ent )
//---------------------------------------------------------
{
int damage = REPEATER_ALT_DAMAGE ;
gentity_t * missile = CreateMissile ( muzzle , forward , REPEATER_ALT_VELOCITY , 10000 , ent , qtrue ) ;
missile - > classname = " repeater_alt_proj " ;
missile - > s . weapon = WP_REPEATER ;
// missile->mass = 10; // NOTENOTE No mass yet
VectorSet ( missile - > r . maxs , REPEATER_ALT_SIZE , REPEATER_ALT_SIZE , REPEATER_ALT_SIZE ) ;
VectorScale ( missile - > r . maxs , - 1 , missile - > r . mins ) ;
missile - > s . pos . trType = TR_GRAVITY ;
missile - > s . pos . trDelta [ 2 ] + = 40.0f ; //give a slight boost in the upward direction
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
missile - > methodOfDeath = MOD_REPEATER_ALT ;
missile - > splashMethodOfDeath = MOD_REPEATER_ALT_SPLASH ;
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
missile - > splashDamage = REPEATER_ALT_SPLASH_DAMAGE ;
missile - > splashRadius = REPEATER_ALT_SPLASH_RADIUS ;
// we don't want it to bounce forever
missile - > bounceCount = 8 ;
}
//---------------------------------------------------------
static void WP_FireRepeater ( gentity_t * ent , qboolean altFire )
//---------------------------------------------------------
{
vec3_t dir , angs ;
vectoangles ( forward , angs ) ;
if ( altFire )
{
WP_RepeaterAltFire ( ent ) ;
}
else
{
// add some slop to the alt-fire direction
angs [ PITCH ] + = crandom ( ) * REPEATER_SPREAD ;
angs [ YAW ] + = crandom ( ) * REPEATER_SPREAD ;
AngleVectors ( angs , dir , NULL , NULL ) ;
// NOTENOTE if temp_org does not have clear trace to inside the bbox, don't shoot!
WP_RepeaterMainFire ( ent , dir ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DEMP2
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
static void WP_DEMP2_MainFire ( gentity_t * ent )
{
int damage = DEMP2_DAMAGE ;
gentity_t * missile = CreateMissile ( muzzle , forward , DEMP2_VELOCITY , 10000 , ent , qfalse ) ;
missile - > classname = " demp2_proj " ;
missile - > s . weapon = WP_DEMP2 ;
VectorSet ( missile - > r . maxs , DEMP2_SIZE , DEMP2_SIZE , DEMP2_SIZE ) ;
VectorScale ( missile - > r . maxs , - 1 , missile - > r . mins ) ;
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
missile - > methodOfDeath = MOD_DEMP2 ;
//rww - Don't want this blockable, do we?
missile - > clipmask = MASK_SHOT ; // | CONTENTS_LIGHTSABER;
// we don't want it to ever bounce
missile - > bounceCount = 0 ;
}
static gentity_t * ent_list [ MAX_GENTITIES ] ;
void DEMP2_AltRadiusDamage ( gentity_t * ent )
{
float frac = ( level . time - ent - > bolt_Head ) / 800.0f ; // / 1600.0f; // synchronize with demp2 effect
float dist , radius , fact ;
gentity_t * gent ;
int iEntityList [ MAX_GENTITIES ] ;
gentity_t * entityList [ MAX_GENTITIES ] ;
2013-04-04 18:01:17 +00:00
gentity_t * myOwner = NULL ;
2013-04-04 14:52:42 +00:00
int numListedEntities , i , e ;
vec3_t mins , maxs ;
vec3_t v , dir ;
2013-04-04 18:01:17 +00:00
if ( ent - > r . ownerNum > = 0 & &
ent - > r . ownerNum < MAX_CLIENTS )
{
myOwner = & g_entities [ ent - > r . ownerNum ] ;
}
if ( ! myOwner | | ! myOwner - > inuse | | ! myOwner - > client )
{
ent - > think = G_FreeEntity ;
ent - > nextthink = level . time ;
return ;
}
2013-04-04 14:52:42 +00:00
frac * = frac * frac ; // yes, this is completely ridiculous...but it causes the shell to grow slowly then "explode" at the end
radius = frac * 200.0f ; // 200 is max radius...the model is aprox. 100 units tall...the fx draw code mults. this by 2.
fact = ent - > count * 0.6 ;
if ( fact < 1 )
{
fact = 1 ;
}
radius * = fact ;
for ( i = 0 ; i < 3 ; i + + )
{
mins [ i ] = ent - > r . currentOrigin [ i ] - radius ;
maxs [ i ] = ent - > r . currentOrigin [ i ] + radius ;
}
numListedEntities = trap_EntitiesInBox ( mins , maxs , iEntityList , MAX_GENTITIES ) ;
i = 0 ;
while ( i < numListedEntities )
{
entityList [ i ] = & g_entities [ iEntityList [ i ] ] ;
i + + ;
}
for ( e = 0 ; e < numListedEntities ; e + + )
{
gent = entityList [ e ] ;
if ( ! gent | | ! gent - > takedamage | | ! gent - > r . contents )
{
continue ;
}
// find the distance from the edge of the bounding box
for ( i = 0 ; i < 3 ; i + + )
{
if ( ent - > r . currentOrigin [ i ] < gent - > r . absmin [ i ] )
{
v [ i ] = gent - > r . absmin [ i ] - ent - > r . currentOrigin [ i ] ;
}
else if ( ent - > r . currentOrigin [ i ] > gent - > r . absmax [ i ] )
{
v [ i ] = ent - > r . currentOrigin [ i ] - gent - > r . absmax [ i ] ;
}
else
{
v [ i ] = 0 ;
}
}
// shape is an ellipsoid, so cut vertical distance in half`
v [ 2 ] * = 0.5f ;
dist = VectorLength ( v ) ;
if ( dist > = radius )
{
// shockwave hasn't hit them yet
continue ;
}
//if ( dist < ent->bolt_LArm )
if ( dist + ( 16 * ent - > count ) < ent - > bolt_LArm )
{
// shockwave has already hit this thing...
continue ;
}
VectorCopy ( gent - > r . currentOrigin , v ) ;
VectorSubtract ( v , ent - > r . currentOrigin , dir ) ;
// push the center of mass higher than the origin so players get knocked into the air more
dir [ 2 ] + = 12 ;
2013-04-04 18:01:17 +00:00
G_Damage ( gent , myOwner , myOwner , dir , ent - > r . currentOrigin , ent - > damage , DAMAGE_DEATH_KNOCKBACK , ent - > splashMethodOfDeath ) ;
2013-04-04 14:52:42 +00:00
}
// store the last fraction so that next time around we can test against those things that fall between that last point and where the current shockwave edge is
ent - > bolt_LArm = radius ;
if ( frac < 1.0f )
{
// shock is still happening so continue letting it expand
ent - > nextthink = level . time + 50 ;
}
else
{ //don't just leave the entity around
ent - > think = G_FreeEntity ;
ent - > nextthink = level . time ;
}
}
//---------------------------------------------------------
void DEMP2_AltDetonate ( gentity_t * ent )
//---------------------------------------------------------
{
gentity_t * efEnt ;
G_SetOrigin ( ent , ent - > r . currentOrigin ) ;
2013-04-04 18:01:17 +00:00
if ( ! ent - > pos1 [ 0 ] & & ! ent - > pos1 [ 1 ] & & ! ent - > pos1 [ 2 ] )
{ //don't play effect with a 0'd out directional vector
ent - > pos1 [ 1 ] = 1 ;
}
2013-04-04 14:52:42 +00:00
//Let's just save ourself some bandwidth and play both the effect and sphere spawn in 1 event
efEnt = G_PlayEffect ( EFFECT_EXPLOSION_DEMP2ALT , ent - > r . currentOrigin , ent - > pos1 ) ;
if ( efEnt )
{
efEnt - > s . weapon = ent - > count * 2 ;
}
ent - > bolt_Head = level . time ;
ent - > bolt_LArm = 0 ;
ent - > nextthink = level . time + 50 ;
ent - > think = DEMP2_AltRadiusDamage ;
ent - > s . eType = ET_GENERAL ; // make us a missile no longer
}
//---------------------------------------------------------
static void WP_DEMP2_AltFire ( gentity_t * ent )
//---------------------------------------------------------
{
int damage = DEMP2_ALT_DAMAGE ;
int count , origcount ;
float fact ;
vec3_t start , end ;
trace_t tr ;
gentity_t * missile ;
VectorCopy ( muzzle , start ) ;
VectorMA ( start , DEMP2_ALT_RANGE , forward , end ) ;
count = ( level . time - ent - > client - > ps . weaponChargeTime ) / DEMP2_CHARGE_UNIT ;
origcount = count ;
if ( count < 1 )
{
count = 1 ;
}
else if ( count > 3 )
{
count = 3 ;
}
fact = count * 0.8 ;
if ( fact < 1 )
{
fact = 1 ;
}
damage * = fact ;
if ( ! origcount )
{ //this was just a tap-fire
damage = 1 ;
}
//damage *= ( 1 + ( count * ( count - 1 )));// yields damage of 12,36,84...gives a higher bonus for longer charge
trap_Trace ( & tr , start , NULL , NULL , end , ent - > s . number , MASK_SHOT ) ;
// we treat the trace fraction like it's a time value, meaning that the shot can travel a whopping 4096 units in 1 second
//missile = CreateMissile( start, forward, DEMP2_ALT_RANGE, tr.fraction * 1000/*time*/, ent, qtrue );
missile = G_Spawn ( ) ;
G_SetOrigin ( missile , tr . endpos ) ;
//rww - I guess it's rather pointless making it a missile anyway, at least for MP.
VectorCopy ( tr . plane . normal , missile - > pos1 ) ;
missile - > count = count ;
missile - > classname = " demp2_alt_proj " ;
missile - > s . weapon = WP_DEMP2 ;
missile - > think = DEMP2_AltDetonate ;
missile - > nextthink = level . time ;
missile - > splashDamage = missile - > damage = damage ;
missile - > splashMethodOfDeath = missile - > methodOfDeath = MOD_DEMP2 ;
missile - > splashRadius = DEMP2_ALT_SPLASHRADIUS ;
2013-04-04 18:01:17 +00:00
missile - > r . ownerNum = ent - > s . number ;
2013-04-04 14:52:42 +00:00
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
// we don't want it to ever bounce
missile - > bounceCount = 0 ;
}
//---------------------------------------------------------
static void WP_FireDEMP2 ( gentity_t * ent , qboolean altFire )
//---------------------------------------------------------
{
if ( altFire )
{
WP_DEMP2_AltFire ( ent ) ;
}
else
{
WP_DEMP2_MainFire ( ent ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
FLECHETTE
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
//---------------------------------------------------------
static void WP_FlechetteMainFire ( gentity_t * ent )
//---------------------------------------------------------
{
vec3_t fwd , angs ;
gentity_t * missile ;
int i ;
for ( i = 0 ; i < FLECHETTE_SHOTS ; i + + )
{
vectoangles ( forward , angs ) ;
if ( i = = 0 )
{
// do nothing on the first shot, this one will hit the crosshairs
}
else
{
angs [ PITCH ] + = crandom ( ) * FLECHETTE_SPREAD ;
angs [ YAW ] + = crandom ( ) * FLECHETTE_SPREAD ;
}
AngleVectors ( angs , fwd , NULL , NULL ) ;
missile = CreateMissile ( muzzle , fwd , FLECHETTE_VEL , 10000 , ent , qfalse ) ;
missile - > classname = " flech_proj " ;
missile - > s . weapon = WP_FLECHETTE ;
VectorSet ( missile - > r . maxs , FLECHETTE_SIZE , FLECHETTE_SIZE , FLECHETTE_SIZE ) ;
VectorScale ( missile - > r . maxs , - 1 , missile - > r . mins ) ;
missile - > damage = FLECHETTE_DAMAGE ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ; // | DAMAGE_EXTRA_KNOCKBACK;
missile - > methodOfDeath = MOD_FLECHETTE ;
missile - > clipmask = MASK_SHOT | CONTENTS_LIGHTSABER ;
// we don't want it to bounce forever
missile - > bounceCount = Q_irand ( 5 , 8 ) ;
missile - > s . eFlags | = EF_BOUNCE_SHRAPNEL ;
}
}
//---------------------------------------------------------
void prox_mine_think ( gentity_t * ent )
//---------------------------------------------------------
{
int count , i ;
qboolean blow = qfalse ;
// if it isn't time to auto-explode, do a small proximity check
if ( ent - > delay > level . time )
{
count = G_RadiusList ( ent - > r . currentOrigin , FLECHETTE_MINE_RADIUS_CHECK , ent , qtrue , ent_list ) ;
for ( i = 0 ; i < count ; i + + )
{
if ( ent_list [ i ] - > client & & ent_list [ i ] - > health > 0 & & ent - > activator & & ent_list [ i ] - > s . number ! = ent - > activator - > s . number )
{
blow = qtrue ;
break ;
}
}
}
else
{
// well, we must die now
blow = qtrue ;
}
if ( blow )
{
//G_Sound( ent, G_SoundIndex( "sound/weapons/flechette/warning.wav" ));
ent - > think = laserTrapExplode ; //thinkF_WP_Explode;
ent - > nextthink = level . time + 200 ;
}
else
{
// we probably don't need to do this thinking logic very often...maybe this is fast enough?
ent - > nextthink = level . time + 500 ;
}
}
//-----------------------------------------------------------------------------
static void WP_TraceSetStart ( gentity_t * ent , vec3_t start , vec3_t mins , vec3_t maxs )
//-----------------------------------------------------------------------------
{
//make sure our start point isn't on the other side of a wall
trace_t tr ;
vec3_t entMins ;
vec3_t entMaxs ;
VectorAdd ( ent - > r . currentOrigin , ent - > r . mins , entMins ) ;
VectorAdd ( ent - > r . currentOrigin , ent - > r . maxs , entMaxs ) ;
if ( G_BoxInBounds ( start , mins , maxs , entMins , entMaxs ) )
{
return ;
}
if ( ! ent - > client )
{
return ;
}
trap_Trace ( & tr , ent - > client - > ps . origin , mins , maxs , start , ent - > s . number , MASK_SOLID | CONTENTS_SHOTCLIP ) ;
if ( tr . startsolid | | tr . allsolid )
{
return ;
}
if ( tr . fraction < 1.0f )
{
VectorCopy ( tr . endpos , start ) ;
}
}
void WP_ExplosiveDie ( gentity_t * self , gentity_t * inflictor , gentity_t * attacker , int damage , int mod )
{
laserTrapExplode ( self ) ;
}
//----------------------------------------------
void WP_flechette_alt_blow ( gentity_t * ent )
//----------------------------------------------
{
/*BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin ); // Not sure if this is even necessary, but correct origins are cool?
G_RadiusDamage ( ent - > r . currentOrigin , & g_entities [ ent - > r . ownerNum ] , ent - > splashDamage , ent - > splashRadius , NULL , MOD_FLECHETTE_ALT_SPLASH ) ;
G_PlayEffect ( " flechette/alt_blow " , ent - > currentOrigin ) ;
G_FreeEntity ( ent ) ; */
ent - > s . pos . trDelta [ 0 ] = 1 ;
ent - > s . pos . trDelta [ 1 ] = 0 ;
ent - > s . pos . trDelta [ 2 ] = 0 ;
laserTrapExplode ( ent ) ;
}
//------------------------------------------------------------------------------
static void WP_CreateFlechetteBouncyThing ( vec3_t start , vec3_t fwd , gentity_t * self )
//------------------------------------------------------------------------------
{
gentity_t * missile = CreateMissile ( start , fwd , 700 + random ( ) * 700 , 1500 + random ( ) * 2000 , self , qtrue ) ;
missile - > think = WP_flechette_alt_blow ;
missile - > activator = self ;
missile - > s . weapon = WP_FLECHETTE ;
missile - > classname = " flech_alt " ;
missile - > mass = 4 ;
// How 'bout we give this thing a size...
VectorSet ( missile - > r . mins , - 3.0f , - 3.0f , - 3.0f ) ;
VectorSet ( missile - > r . maxs , 3.0f , 3.0f , 3.0f ) ;
missile - > clipmask = MASK_SHOT ;
missile - > touch = touch_NULL ;
// normal ones bounce, alt ones explode on impact
missile - > s . pos . trType = TR_GRAVITY ;
missile - > s . eFlags | = ( EF_BOUNCE_HALF | EF_ALT_FIRING ) ;
missile - > bounceCount = 50 ;
missile - > damage = FLECHETTE_ALT_DAMAGE ;
missile - > dflags = 0 ;
missile - > splashDamage = FLECHETTE_ALT_SPLASH_DAM ;
missile - > splashRadius = FLECHETTE_ALT_SPLASH_RAD ;
missile - > r . svFlags = SVF_USE_CURRENT_ORIGIN ;
missile - > methodOfDeath = MOD_FLECHETTE_ALT_SPLASH ;
missile - > splashMethodOfDeath = MOD_FLECHETTE_ALT_SPLASH ;
//missile->splashMethodOfDeath = MOD_UNKNOWN;//MOD_THERMAL_SPLASH;
VectorCopy ( start , missile - > pos2 ) ;
}
//---------------------------------------------------------
static void WP_FlechetteAltFire ( gentity_t * self )
//---------------------------------------------------------
{
vec3_t dir , fwd , start , angs ;
int i ;
vectoangles ( forward , angs ) ;
VectorCopy ( muzzle , start ) ;
WP_TraceSetStart ( self , start , vec3_origin , vec3_origin ) ; //make sure our start point isn't on the other side of a wall
for ( i = 0 ; i < 2 ; i + + )
{
VectorCopy ( angs , dir ) ;
dir [ PITCH ] - = random ( ) * 4 + 8 ; // make it fly upwards
dir [ YAW ] + = crandom ( ) * 2 ;
AngleVectors ( dir , fwd , NULL , NULL ) ;
WP_CreateFlechetteBouncyThing ( start , fwd , self ) ;
}
}
//---------------------------------------------------------
static void WP_FireFlechette ( gentity_t * ent , qboolean altFire )
//---------------------------------------------------------
{
if ( altFire )
{
//WP_FlechetteProxMine( ent );
WP_FlechetteAltFire ( ent ) ;
}
else
{
WP_FlechetteMainFire ( ent ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ROCKET LAUNCHER
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
//---------------------------------------------------------
void rocketThink ( gentity_t * ent )
//---------------------------------------------------------
{
vec3_t newdir , targetdir ,
up = { 0 , 0 , 1 } , right ;
vec3_t org ;
float dot , dot2 , dis ;
int i ;
float vel = ROCKET_VELOCITY ;
if ( ! ent - > enemy | | ! ent - > enemy - > client | | ent - > enemy - > health < 1 )
{
ent - > nextthink = level . time + 10000 ;
ent - > think = G_FreeEntity ;
return ;
}
if ( ent - > enemy & & ent - > enemy - > inuse )
{
VectorCopy ( ent - > enemy - > r . currentOrigin , org ) ;
org [ 2 ] + = ( ent - > enemy - > r . mins [ 2 ] + ent - > enemy - > r . maxs [ 2 ] ) * 0.5f ;
VectorSubtract ( org , ent - > r . currentOrigin , targetdir ) ;
VectorNormalize ( targetdir ) ;
// Now the rocket can't do a 180 in space, so we'll limit the turn to about 45 degrees.
dot = DotProduct ( targetdir , ent - > movedir ) ;
// a dot of 1.0 means right-on-target.
if ( dot < 0.0f )
{
// Go in the direction opposite, start a 180.
CrossProduct ( ent - > movedir , up , right ) ;
dot2 = DotProduct ( targetdir , right ) ;
if ( dot2 > 0 )
{
// Turn 45 degrees right.
VectorMA ( ent - > movedir , 0.4f , right , newdir ) ;
}
else
{
// Turn 45 degrees left.
VectorMA ( ent - > movedir , - 0.4f , right , newdir ) ;
}
// Yeah we've adjusted horizontally, but let's split the difference vertically, so we kinda try to move towards it.
newdir [ 2 ] = ( targetdir [ 2 ] + ent - > movedir [ 2 ] ) * 0.5 ;
// let's also slow down a lot
vel * = 0.5f ;
}
else if ( dot < 0.70f )
{
// Still a bit off, so we turn a bit softer
VectorMA ( ent - > movedir , 0.5f , targetdir , newdir ) ;
}
else
{
// getting close, so turn a bit harder
VectorMA ( ent - > movedir , 0.9f , targetdir , newdir ) ;
}
// add crazy drunkenness
for ( i = 0 ; i < 3 ; i + + )
{
newdir [ i ] + = crandom ( ) * ent - > random * 0.25f ;
}
// decay the randomness
ent - > random * = 0.9f ;
// Try to crash into the ground if we get close enough to do splash damage
dis = Distance ( ent - > r . currentOrigin , org ) ;
if ( dis < 128 )
{
// the closer we get, the more we push the rocket down, heh heh.
newdir [ 2 ] - = ( 1.0f - ( dis / 128.0f ) ) * 0.6f ;
}
VectorNormalize ( newdir ) ;
VectorScale ( newdir , vel * 0.5f , ent - > s . pos . trDelta ) ;
VectorCopy ( newdir , ent - > movedir ) ;
SnapVector ( ent - > s . pos . trDelta ) ; // save net bandwidth
VectorCopy ( ent - > r . currentOrigin , ent - > s . pos . trBase ) ;
ent - > s . pos . trTime = level . time ;
}
ent - > nextthink = level . time + ROCKET_ALT_THINK_TIME ; // Nothing at all spectacular happened, continue.
return ;
}
//---------------------------------------------------------
static void WP_FireRocket ( gentity_t * ent , qboolean altFire )
//---------------------------------------------------------
{
int damage = ROCKET_DAMAGE ;
int vel = ROCKET_VELOCITY ;
int dif = 0 ;
float rTime ;
gentity_t * missile ;
if ( altFire )
{
vel * = 0.5f ;
}
missile = CreateMissile ( muzzle , forward , vel , 10000 , ent , altFire ) ;
if ( ent - > client & & ent - > client - > ps . rocketLockIndex ! = MAX_CLIENTS )
{
rTime = ent - > client - > ps . rocketLockTime ;
if ( rTime = = - 1 )
{
rTime = ent - > client - > ps . rocketLastValidTime ;
}
dif = ( level . time - rTime ) / ( 1200.0f / 16.0f ) ;
if ( dif < 0 )
{
dif = 0 ;
}
//It's 10 even though it locks client-side at 8, because we want them to have a sturdy lock first, and because there's a slight difference in time between server and client
if ( dif > = 10 /* || random() * dif > 2 || random() > 0.97f*/ & & rTime ! = - 1 )
{
missile - > enemy = & g_entities [ ent - > client - > ps . rocketLockIndex ] ;
if ( missile - > enemy & & missile - > enemy - > client & & missile - > enemy - > health > 0 & & ! OnSameTeam ( ent , missile - > enemy ) )
{ //if enemy became invalid, died, or is on the same team, then don't seek it
missile - > think = rocketThink ;
missile - > nextthink = level . time + ROCKET_ALT_THINK_TIME ;
}
}
ent - > client - > ps . rocketLockIndex = MAX_CLIENTS ;
ent - > client - > ps . rocketLockTime = 0 ;
ent - > client - > ps . rocketTargetTime = 0 ;
}
missile - > classname = " rocket_proj " ;
missile - > s . weapon = WP_ROCKET_LAUNCHER ;
// NOTENOTE No mass yet.
// missile->mass = 10;
// Make it easier to hit things
VectorSet ( missile - > r . maxs , ROCKET_SIZE , ROCKET_SIZE , ROCKET_SIZE ) ;
VectorScale ( missile - > r . maxs , - 1 , missile - > r . mins ) ;
missile - > damage = damage ;
missile - > dflags = DAMAGE_DEATH_KNOCKBACK ;
if ( altFire )
{
missile - > methodOfDeath = MOD_ROCKET_HOMING ;
missile - > splashMethodOfDeath = MOD_ROCKET_HOMING_SPLASH ;
}
else
{
missile - > methodOfDeath = MOD_ROCKET ;
missile - > splashMethodOfDeath = MOD_ROCKET_SPLASH ;
}
//rww - We don't want rockets to be deflected, do we?
missile - > clipmask = MASK_SHOT ; // | CONTENTS_LIGHTSABER;
missile - > splashDamage = ROCKET_SPLASH_DAMAGE ;
missile - > splashRadius = ROCKET_SPLASH_RADIUS ;
// we don't want it to ever bounce
missile - > bounceCount = 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
THERMAL DETONATOR
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# define TD_DAMAGE 100
# define TD_SPLASH_RAD 128
# define TD_SPLASH_DAM 90
# define TD_VELOCITY 900
# define TD_MIN_CHARGE 0.15f
# define TD_TIME 3000 //6000
# define TD_ALT_TIME 3000
# define TD_ALT_DAMAGE 60 //100
# define TD_ALT_SPLASH_RAD 128
# define TD_ALT_SPLASH_DAM 50 //90
# define TD_ALT_VELOCITY 600
# define TD_ALT_MIN_CHARGE 0.15f
# define TD_ALT_TIME 3000
//---------------------------------------------------------
void thermalDetonatorExplode ( gentity_t * ent )
//---------------------------------------------------------
{
if ( ! ent - > count )
{
G_Sound ( ent , CHAN_VOICE , G_SoundIndex ( " sound/weapons/thermal/warning.wav " ) ) ;
ent - > count = 1 ;
ent - > nextthink = level . time + 500 ;
ent - > r . svFlags | = SVF_BROADCAST ; //so everyone hears/sees the explosion?
}
else
{
vec3_t origin ;
vec3_t dir = { 0 , 0 , 1 } ;
BG_EvaluateTrajectory ( & ent - > s . pos , level . time , origin ) ;
origin [ 2 ] + = 8 ;
SnapVector ( origin ) ;
G_SetOrigin ( ent , origin ) ;
// VectorSet( pos, ent->r.currentOrigin[0], ent->r.currentOrigin[1], ent->r.currentOrigin[2] + 8 );
ent - > s . eType = ET_GENERAL ;
G_AddEvent ( ent , EV_MISSILE_MISS , DirToByte ( dir ) ) ;
ent - > freeAfterEvent = qtrue ;
if ( G_RadiusDamage ( ent - > r . currentOrigin , ent - > parent , ent - > splashDamage , ent - > splashRadius ,
ent , ent - > splashMethodOfDeath ) )
{
g_entities [ ent - > r . ownerNum ] . client - > accuracy_hits + + ;
}
trap_LinkEntity ( ent ) ;
}
}
//---------------------------------------------------------
gentity_t * WP_FireThermalDetonator ( gentity_t * ent , qboolean altFire )
//---------------------------------------------------------
{
gentity_t * bolt ;
vec3_t dir , start ;
float chargeAmount = 1.0f ; // default of full charge
VectorCopy ( forward , dir ) ;
VectorCopy ( muzzle , start ) ;
bolt = G_Spawn ( ) ;
bolt - > classname = " thermal_detonator " ;
bolt - > think = thermalDetonatorExplode ;
// bolt->mass = 10; // NOTENOTE No mass implementation yet
// How 'bout we give this thing a size...
VectorSet ( bolt - > r . mins , - 3.0f , - 3.0f , - 3.0f ) ;
VectorSet ( bolt - > r . maxs , 3.0f , 3.0f , 3.0f ) ;
bolt - > clipmask = MASK_SHOT ;
W_TraceSetStart ( ent , start , bolt - > r . mins , bolt - > r . maxs ) ; //make sure our start point isn't on the other side of a wall
if ( ent - > client )
{
chargeAmount = level . time - ent - > client - > ps . weaponChargeTime ;
}
// get charge amount
chargeAmount = chargeAmount / ( float ) TD_VELOCITY ;
if ( chargeAmount > 1.0f )
{
chargeAmount = 1.0f ;
}
else if ( chargeAmount < TD_MIN_CHARGE )
{
chargeAmount = TD_MIN_CHARGE ;
}
// normal ones bounce, alt ones explode on impact
bolt - > nextthink = level . time + TD_TIME ; // How long 'til she blows
bolt - > s . pos . trType = TR_GRAVITY ;
bolt - > parent = ent ;
bolt - > r . ownerNum = ent - > s . number ;
VectorScale ( dir , TD_VELOCITY * chargeAmount , bolt - > s . pos . trDelta ) ;
if ( ent - > health > = 0 )
{
bolt - > s . pos . trDelta [ 2 ] + = 120 ;
}
if ( ! altFire )
{
//bolt->alt_fire = qtrue;
bolt - > s . eFlags | = EF_BOUNCE_HALF ;
}
bolt - > s . loopSound = G_SoundIndex ( " sound/weapons/thermal/thermloop.wav " ) ;
bolt - > damage = TD_DAMAGE ;
bolt - > dflags = 0 ;
bolt - > splashDamage = TD_SPLASH_DAM ;
bolt - > splashRadius = TD_SPLASH_RAD ;
bolt - > s . eType = ET_MISSILE ;
bolt - > r . svFlags = SVF_USE_CURRENT_ORIGIN ;
bolt - > s . weapon = WP_THERMAL ;
bolt - > methodOfDeath = MOD_THERMAL ;
bolt - > splashMethodOfDeath = MOD_THERMAL_SPLASH ;
bolt - > s . pos . trTime = level . time ; // move a bit on the very first frame
VectorCopy ( start , bolt - > s . pos . trBase ) ;
SnapVector ( bolt - > s . pos . trDelta ) ; // save net bandwidth
VectorCopy ( start , bolt - > r . currentOrigin ) ;
VectorCopy ( start , bolt - > pos2 ) ;
bolt - > bounceCount = - 5 ;
return bolt ;
}
gentity_t * WP_DropThermal ( gentity_t * ent )
{
AngleVectors ( ent - > client - > ps . viewangles , forward , right , up ) ;
return ( WP_FireThermalDetonator ( ent , qfalse ) ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
LASER TRAP / TRIP MINE
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# define LT_DAMAGE 100
# define LT_SPLASH_RAD 256.0f
# define LT_SPLASH_DAM 105
# define LT_VELOCITY 900.0f
# define LT_SIZE 1.5f
# define LT_ALT_TIME 2000
# define LT_ACTIVATION_DELAY 1000
# define LT_DELAY_TIME 50
void laserTrapExplode ( gentity_t * self )
{
vec3_t v ;
//FIXME: damage some along line?
self - > takedamage = qfalse ;
if ( self - > activator )
{
G_RadiusDamage ( self - > r . currentOrigin , self - > activator , self - > splashDamage , self - > splashRadius , self , MOD_UNKNOWN /*MOD_LT_SPLASH*/ ) ;
}
//FIXME: clear me from owner's list of tripmines?
if ( self - > s . weapon ! = WP_FLECHETTE )
{
G_AddEvent ( self , EV_MISSILE_MISS , 0 ) ;
}
VectorCopy ( self - > s . pos . trDelta , v ) ;
//Explode outward from the surface
if ( self - > s . time = = - 2 )
{
v [ 0 ] = 0 ;
v [ 1 ] = 0 ;
v [ 2 ] = 0 ;
}
if ( self - > s . weapon = = WP_FLECHETTE )
{
G_PlayEffect ( EFFECT_EXPLOSION_FLECHETTE , self - > r . currentOrigin , v ) ;
}
else
{
G_PlayEffect ( EFFECT_EXPLOSION_TRIPMINE , self - > r . currentOrigin , v ) ;
}
self - > think = G_FreeEntity ;
self - > nextthink = level . time ;
}
void laserTrapDelayedExplode ( gentity_t * self , gentity_t * inflictor , gentity_t * attacker , int damage , int meansOfDeath )
{
self - > enemy = attacker ;
self - > think = laserTrapExplode ;
self - > nextthink = level . time + FRAMETIME ;
self - > takedamage = qfalse ;
if ( attacker & & ! attacker - > s . number )
{
//less damage when shot by player
self - > splashDamage / = 3 ;
self - > splashRadius / = 3 ;
//FIXME: different effect?
}
}
void touchLaserTrap ( gentity_t * ent , gentity_t * other , trace_t * trace )
{
// if the guy that touches this grenade can take damage, he's about to.
//if ( other->takedamage )
if ( other & & other - > s . number < 1022 )
{ //just explode if we hit any entity. This way we don't have things happening like tripmines floating
//in the air after getting stuck to a moving door
if ( ent - > activator ! = other )
{
ent - > touch = 0 ;
ent - > nextthink = level . time + FRAMETIME ;
ent - > think = laserTrapExplode ;
VectorCopy ( trace - > plane . normal , ent - > s . pos . trDelta ) ;
}
}
else
{
ent - > touch = 0 ;
if ( trace - > entityNum ! = ENTITYNUM_NONE )
{
ent - > enemy = & g_entities [ trace - > entityNum ] ;
}
laserTrapStick ( ent , trace - > endpos , trace - > plane . normal ) ;
}
}
void laserTrapThink ( gentity_t * ent )
{
gentity_t * traceEnt ;
vec3_t end ;
trace_t tr ;
//G_RunObject(ent);
trap_LinkEntity ( ent ) ;
//turn on the beam effect
if ( ! ( ent - > s . eFlags & EF_FIRING ) )
{ //arm me
G_Sound ( ent , CHAN_VOICE , G_SoundIndex ( " sound/weapons/laser_trap/warning.wav " ) ) ;
ent - > s . eFlags | = EF_FIRING ;
}
ent - > think = laserTrapThink ;
ent - > nextthink = level . time + FRAMETIME ;
// Find the main impact point
VectorMA ( ent - > s . pos . trBase , 1024 , ent - > movedir , end ) ;
trap_Trace ( & tr , ent - > r . currentOrigin , NULL , NULL , end , ent - > s . number , MASK_SHOT ) ;
traceEnt = & g_entities [ tr . entityNum ] ;
ent - > s . time = - 1 ; //let all clients know to draw a beam from this guy
if ( traceEnt - > client | | tr . startsolid )
{
//go boom
ent - > touch = 0 ;
ent - > nextthink = level . time + LT_DELAY_TIME ;
ent - > think = laserTrapExplode ;
}
}
void laserTrapStick ( gentity_t * ent , vec3_t endpos , vec3_t normal )
{
//vec3_t org;
// Back away from the wall
//VectorMA( endpos, -1, normal, org );
G_SetOrigin ( ent , endpos ) ; //org );
VectorCopy ( normal , ent - > pos1 ) ;
VectorClear ( ent - > s . apos . trDelta ) ;
// This will orient the object to face in the direction of the normal
VectorCopy ( normal , ent - > s . pos . trDelta ) ;
//VectorScale( normal, -1, ent->s.pos.trDelta );
ent - > s . pos . trTime = level . time ;
//This does nothing, cg_missile makes assumptions about direction of travel controlling angles
vectoangles ( normal , ent - > s . apos . trBase ) ;
VectorClear ( ent - > s . apos . trDelta ) ;
ent - > s . apos . trType = TR_STATIONARY ;
VectorCopy ( ent - > s . apos . trBase , ent - > s . angles ) ;
VectorCopy ( ent - > s . angles , ent - > r . currentAngles ) ;
G_Sound ( ent , CHAN_VOICE , G_SoundIndex ( " sound/weapons/laser_trap/stick.wav " ) ) ;
if ( ent - > count )
{ //a tripwire
//add draw line flag
VectorCopy ( normal , ent - > movedir ) ;
ent - > think = laserTrapThink ;
ent - > nextthink = level . time + LT_ACTIVATION_DELAY ; //delay the activation
ent - > touch = touch_NULL ;
//make it shootable
ent - > takedamage = qtrue ;
ent - > health = 5 ;
ent - > die = laserTrapDelayedExplode ;
//shove the box through the wall
VectorSet ( ent - > r . mins , - LT_SIZE * 2 , - LT_SIZE * 2 , - LT_SIZE * 2 ) ;
VectorSet ( ent - > r . maxs , LT_SIZE * 2 , LT_SIZE * 2 , LT_SIZE * 2 ) ;
//so that the owner can blow it up with projectiles
ent - > r . svFlags | = SVF_OWNERNOTSHARED ;
}
else
{
ent - > touch = touchLaserTrap ;
ent - > think = laserTrapExplode ;
ent - > nextthink = level . time + 0 ; //LT_ALT_TIME; // How long 'til she blows
}
}
void TrapThink ( gentity_t * ent )
{
ent - > nextthink = level . time + 50 ;
G_RunObject ( ent ) ;
}
void CreateLaserTrap ( gentity_t * laserTrap , vec3_t start , gentity_t * owner )
{
laserTrap - > classname = " laserTrap " ;
laserTrap - > s . eFlags = EF_BOUNCE_HALF ;
laserTrap - > s . eFlags | = EF_MISSILE_STICK ;
laserTrap - > splashDamage = LT_SPLASH_DAM ; //*2;
laserTrap - > splashRadius = LT_SPLASH_RAD ; //*2;
laserTrap - > damage = LT_DAMAGE ; //*DMG_VAR;
laserTrap - > methodOfDeath = MOD_UNKNOWN ; //MOD_TRIP_WIRE;
laserTrap - > splashMethodOfDeath = MOD_UNKNOWN ; //MOD_TRIP_WIRE;
laserTrap - > s . eType = ET_GENERAL ;
laserTrap - > r . svFlags = SVF_USE_CURRENT_ORIGIN ;
laserTrap - > s . weapon = WP_TRIP_MINE ;
laserTrap - > s . pos . trType = TR_GRAVITY ;
laserTrap - > r . contents = MASK_SHOT ;
laserTrap - > parent = owner ;
laserTrap - > activator = owner ;
laserTrap - > r . ownerNum = owner - > s . number ;
VectorSet ( laserTrap - > r . mins , - LT_SIZE , - LT_SIZE , - LT_SIZE ) ;
VectorSet ( laserTrap - > r . maxs , LT_SIZE , LT_SIZE , LT_SIZE ) ;
laserTrap - > clipmask = MASK_SHOT ;
laserTrap - > s . solid = 2 ;
laserTrap - > s . modelindex = G_ModelIndex ( " models/weapons2/laser_trap/laser_trap_w.glm " ) ;
laserTrap - > s . modelGhoul2 = 1 ;
laserTrap - > s . g2radius = 40 ;
laserTrap - > s . genericenemyindex = owner - > s . number + 1024 ;
laserTrap - > health = 1 ;
laserTrap - > s . time = 0 ;
laserTrap - > s . pos . trTime = level . time ; // move a bit on the very first frame
VectorCopy ( start , laserTrap - > s . pos . trBase ) ;
SnapVector ( laserTrap - > s . pos . trBase ) ; // save net bandwidth
SnapVector ( laserTrap - > s . pos . trDelta ) ; // save net bandwidth
VectorCopy ( start , laserTrap - > r . currentOrigin ) ;
laserTrap - > s . apos . trType = TR_GRAVITY ;
laserTrap - > s . apos . trTime = level . time ;
laserTrap - > s . apos . trBase [ YAW ] = rand ( ) % 360 ;
laserTrap - > s . apos . trBase [ PITCH ] = rand ( ) % 360 ;
laserTrap - > s . apos . trBase [ ROLL ] = rand ( ) % 360 ;
if ( rand ( ) % 10 < 5 )
{
laserTrap - > s . apos . trBase [ YAW ] = - laserTrap - > s . apos . trBase [ YAW ] ;
}
VectorCopy ( start , laserTrap - > pos2 ) ;
laserTrap - > touch = touchLaserTrap ;
laserTrap - > think = TrapThink ;
laserTrap - > nextthink = level . time + 50 ;
}
void WP_PlaceLaserTrap ( gentity_t * ent , qboolean alt_fire )
{
gentity_t * laserTrap ;
gentity_t * found = NULL ;
vec3_t dir , start ;
int trapcount = 0 ;
int foundLaserTraps [ MAX_GENTITIES ] = { ENTITYNUM_NONE } ;
int trapcount_org ;
int lowestTimeStamp ;
int removeMe ;
int i ;
//FIXME: surface must be within 64
VectorCopy ( forward , dir ) ;
VectorCopy ( muzzle , start ) ;
laserTrap = G_Spawn ( ) ;
//limit to 10 placed at any one time
//see how many there are now
while ( ( found = G_Find ( found , FOFS ( classname ) , " laserTrap " ) ) ! = NULL )
{
if ( found - > parent ! = ent )
{
continue ;
}
foundLaserTraps [ trapcount + + ] = found - > s . number ;
}
//now remove first ones we find until there are only 9 left
found = NULL ;
trapcount_org = trapcount ;
lowestTimeStamp = level . time ;
while ( trapcount > 9 )
{
removeMe = - 1 ;
for ( i = 0 ; i < trapcount_org ; i + + )
{
if ( foundLaserTraps [ i ] = = ENTITYNUM_NONE )
{
continue ;
}
found = & g_entities [ foundLaserTraps [ i ] ] ;
if ( laserTrap & & found - > setTime < lowestTimeStamp )
{
removeMe = i ;
lowestTimeStamp = found - > setTime ;
}
}
if ( removeMe ! = - 1 )
{
//remove it... or blow it?
if ( & g_entities [ foundLaserTraps [ removeMe ] ] = = NULL )
{
break ;
}
else
{
G_FreeEntity ( & g_entities [ foundLaserTraps [ removeMe ] ] ) ;
}
foundLaserTraps [ removeMe ] = ENTITYNUM_NONE ;
trapcount - - ;
}
else
{
break ;
}
}
//now make the new one
CreateLaserTrap ( laserTrap , start , ent ) ;
if ( alt_fire )
{
laserTrap - > splashRadius / = 2 ;
}
//set player-created-specific fields
laserTrap - > setTime = level . time ; //remember when we placed it
if ( alt_fire )
{ //explode after 2 second
//doesn't activate until it latches
//laserTrap->think = laserTrap;
//laserTrap->nextthink = level.time + LT_TIME; // How long 'til she blows
}
else
{ //tripwire
laserTrap - > count = 1 ;
}
//move it
laserTrap - > s . pos . trType = TR_GRAVITY ;
if ( alt_fire )
{
VectorScale ( dir , 512 , laserTrap - > s . pos . trDelta ) ;
}
else
{
VectorScale ( dir , 256 , laserTrap - > s . pos . trDelta ) ;
}
trap_LinkEntity ( laserTrap ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DET PACK
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void VectorNPos ( vec3_t in , vec3_t out )
{
if ( in [ 0 ] < 0 ) { out [ 0 ] = - in [ 0 ] ; } else { out [ 0 ] = in [ 0 ] ; }
if ( in [ 1 ] < 0 ) { out [ 1 ] = - in [ 1 ] ; } else { out [ 1 ] = in [ 1 ] ; }
if ( in [ 2 ] < 0 ) { out [ 2 ] = - in [ 2 ] ; } else { out [ 2 ] = in [ 2 ] ; }
}
2013-04-04 18:01:17 +00:00
void DetPackBlow ( gentity_t * self ) ;
2013-04-04 14:52:42 +00:00
void charge_stick ( gentity_t * self , gentity_t * other , trace_t * trace )
{
gentity_t * tent ;
if ( other & & other - > s . number < 1022 & &
( other - > client | | ! other - > s . weapon ) )
{
vec3_t vNor , tN ;
VectorCopy ( trace - > plane . normal , vNor ) ;
VectorNormalize ( vNor ) ;
VectorNPos ( self - > s . pos . trDelta , tN ) ;
self - > s . pos . trDelta [ 0 ] + = vNor [ 0 ] * ( tN [ 0 ] * ( ( ( float ) Q_irand ( 1 , 10 ) ) * 0.1 ) ) ;
self - > s . pos . trDelta [ 1 ] + = vNor [ 1 ] * ( tN [ 1 ] * ( ( ( float ) Q_irand ( 1 , 10 ) ) * 0.1 ) ) ;
self - > s . pos . trDelta [ 2 ] + = vNor [ 1 ] * ( tN [ 2 ] * ( ( ( float ) Q_irand ( 1 , 10 ) ) * 0.1 ) ) ;
self - > touch = charge_stick ;
return ;
}
else if ( other & & other - > s . number < 1022 )
{
vec3_t v ;
self - > touch = 0 ;
self - > think = 0 ;
self - > nextthink = 0 ;
self - > takedamage = qfalse ;
VectorClear ( self - > s . apos . trDelta ) ;
self - > s . apos . trType = TR_STATIONARY ;
G_RadiusDamage ( self - > r . currentOrigin , self - > parent , self - > splashDamage , self - > splashRadius , self , MOD_UNKNOWN ) ;
VectorCopy ( trace - > plane . normal , v ) ;
VectorCopy ( v , self - > pos2 ) ;
self - > count = - 1 ;
G_PlayEffect ( EFFECT_EXPLOSION_DETPACK , self - > r . currentOrigin , v ) ;
self - > think = G_FreeEntity ;
self - > nextthink = level . time ;
return ;
}
//self->s.eType = ET_GENERAL;
//FIXME: once on ground, shouldn't explode if touched by someone?
//FIXME: if owner touches it again, pick it up? Or if he "uses" it?
self - > touch = 0 ;
2013-04-04 18:01:17 +00:00
self - > think = DetPackBlow ;
self - > nextthink = level . time + 30000 ;
2013-04-04 14:52:42 +00:00
VectorClear ( self - > s . apos . trDelta ) ;
self - > s . apos . trType = TR_STATIONARY ;
self - > s . pos . trType = TR_STATIONARY ;
VectorCopy ( self - > r . currentOrigin , self - > s . origin ) ;
VectorCopy ( self - > r . currentOrigin , self - > s . pos . trBase ) ;
VectorClear ( self - > s . pos . trDelta ) ;
VectorClear ( self - > s . apos . trDelta ) ;
VectorNormalize ( trace - > plane . normal ) ;
vectoangles ( trace - > plane . normal , self - > s . angles ) ;
VectorCopy ( self - > s . angles , self - > r . currentAngles ) ;
VectorCopy ( self - > s . angles , self - > s . apos . trBase ) ;
VectorCopy ( trace - > plane . normal , self - > pos2 ) ;
self - > count = - 1 ;
G_Sound ( self , CHAN_VOICE , G_SoundIndex ( " sound/weapons/detpack/stick.wav " ) ) ;
tent = G_TempEntity ( self - > r . currentOrigin , EV_MISSILE_MISS ) ;
tent - > s . weapon = 0 ;
tent - > parent = self ;
tent - > r . ownerNum = self - > s . number ;
//so that the owner can blow it up with projectiles
self - > r . svFlags | = SVF_OWNERNOTSHARED ;
}
void DetPackBlow ( gentity_t * self )
{
vec3_t v ;
//self->touch = NULL;
self - > pain = 0 ;
self - > die = 0 ;
self - > takedamage = qfalse ;
G_RadiusDamage ( self - > r . currentOrigin , self - > parent , self - > splashDamage , self - > splashRadius , self , MOD_UNKNOWN ) ;
v [ 0 ] = 0 ;
v [ 1 ] = 0 ;
2013-04-04 18:01:17 +00:00
v [ 2 ] = 1 ;
2013-04-04 14:52:42 +00:00
if ( self - > count = = - 1 )
{
VectorCopy ( self - > pos2 , v ) ;
}
G_PlayEffect ( EFFECT_EXPLOSION_DETPACK , self - > r . currentOrigin , v ) ;
self - > think = G_FreeEntity ;
self - > nextthink = level . time ;
}
void DetPackPain ( gentity_t * self , gentity_t * attacker , int damage )
{
2013-04-04 18:01:17 +00:00
self - > think = DetPackBlow ;
self - > nextthink = level . time + Q_irand ( 50 , 100 ) ;
self - > takedamage = qfalse ;
2013-04-04 14:52:42 +00:00
}
void DetPackDie ( gentity_t * self , gentity_t * inflictor , gentity_t * attacker , int damage , int mod )
{
2013-04-04 18:01:17 +00:00
self - > think = DetPackBlow ;
self - > nextthink = level . time + Q_irand ( 50 , 100 ) ;
self - > takedamage = qfalse ;
2013-04-04 14:52:42 +00:00
}
void drop_charge ( gentity_t * self , vec3_t start , vec3_t dir )
{
gentity_t * bolt ;
VectorNormalize ( dir ) ;
bolt = G_Spawn ( ) ;
bolt - > classname = " detpack " ;
bolt - > nextthink = level . time + FRAMETIME ;
bolt - > think = G_RunObject ;
bolt - > s . eType = ET_GENERAL ;
bolt - > s . g2radius = 100 ;
bolt - > s . modelGhoul2 = 1 ;
bolt - > s . modelindex = G_ModelIndex ( " models/weapons2/detpack/det_pack_proj.glm " ) ; // w.md3");
//bolt->playerTeam = self->client->playerTeam;
bolt - > parent = self ;
bolt - > r . ownerNum = self - > s . number ;
bolt - > damage = 100 ;
bolt - > splashDamage = 200 ;
bolt - > splashRadius = 200 ;
bolt - > methodOfDeath = MOD_UNKNOWN ; //MOD_EXPLOSIVE;
bolt - > splashMethodOfDeath = MOD_UNKNOWN ; //MOD_EXPLOSIVE_SPLASH;
bolt - > clipmask = MASK_SHOT ;
bolt - > s . solid = 2 ;
bolt - > r . contents = MASK_SHOT ;
bolt - > touch = charge_stick ;
bolt - > s . genericenemyindex = self - > s . number + 1024 ;
//rww - so client prediction knows we own this and won't hit it
VectorSet ( bolt - > r . mins , - 3 , - 3 , - 3 ) ;
VectorSet ( bolt - > r . maxs , 3 , 3 , 3 ) ;
bolt - > health = 1 ;
bolt - > takedamage = qtrue ;
bolt - > pain = DetPackPain ;
bolt - > die = DetPackDie ;
bolt - > s . weapon = WP_DET_PACK ;
bolt - > setTime = level . time ;
G_SetOrigin ( bolt , start ) ;
bolt - > s . pos . trType = TR_GRAVITY ;
VectorCopy ( start , bolt - > s . pos . trBase ) ;
VectorScale ( dir , 300 , bolt - > s . pos . trDelta ) ;
bolt - > s . pos . trTime = level . time ;
bolt - > s . apos . trType = TR_GRAVITY ;
bolt - > s . apos . trTime = level . time ;
bolt - > s . apos . trBase [ YAW ] = rand ( ) % 360 ;
bolt - > s . apos . trBase [ PITCH ] = rand ( ) % 360 ;
bolt - > s . apos . trBase [ ROLL ] = rand ( ) % 360 ;
if ( rand ( ) % 10 < 5 )
{
bolt - > s . apos . trBase [ YAW ] = - bolt - > s . apos . trBase [ YAW ] ;
}
vectoangles ( dir , bolt - > s . angles ) ;
VectorCopy ( bolt - > s . angles , bolt - > s . apos . trBase ) ;
VectorSet ( bolt - > s . apos . trDelta , 300 , 0 , 0 ) ;
bolt - > s . apos . trTime = level . time ;
trap_LinkEntity ( bolt ) ;
}
void BlowDetpacks ( gentity_t * ent )
{
gentity_t * found = NULL ;
if ( ent - > client - > ps . hasDetPackPlanted )
{
while ( ( found = G_Find ( found , FOFS ( classname ) , " detpack " ) ) ! = NULL )
{ //loop through all ents and blow the crap out of them!
if ( found - > parent = = ent )
{
VectorCopy ( found - > r . currentOrigin , found - > s . origin ) ;
found - > think = DetPackBlow ;
found - > nextthink = level . time + 100 + random ( ) * 200 ;
G_Sound ( found , CHAN_BODY , G_SoundIndex ( " sound/weapons/detpack/warning.wav " ) ) ;
}
}
ent - > client - > ps . hasDetPackPlanted = qfalse ;
}
}
2013-04-04 18:01:17 +00:00
qboolean CheatsOn ( void )
{
if ( ! g_cheats . integer )
{
return qfalse ;
}
return qtrue ;
}
2013-04-04 14:52:42 +00:00
void WP_DropDetPack ( gentity_t * ent , qboolean alt_fire )
{
gentity_t * found = NULL ;
int trapcount = 0 ;
int foundDetPacks [ MAX_GENTITIES ] = { ENTITYNUM_NONE } ;
int trapcount_org ;
int lowestTimeStamp ;
int removeMe ;
int i ;
if ( ! ent | | ! ent - > client )
{
return ;
}
//limit to 10 placed at any one time
//see how many there are now
while ( ( found = G_Find ( found , FOFS ( classname ) , " detpack " ) ) ! = NULL )
{
if ( found - > parent ! = ent )
{
continue ;
}
foundDetPacks [ trapcount + + ] = found - > s . number ;
}
//now remove first ones we find until there are only 9 left
found = NULL ;
trapcount_org = trapcount ;
lowestTimeStamp = level . time ;
while ( trapcount > 9 )
{
removeMe = - 1 ;
for ( i = 0 ; i < trapcount_org ; i + + )
{
if ( foundDetPacks [ i ] = = ENTITYNUM_NONE )
{
continue ;
}
found = & g_entities [ foundDetPacks [ i ] ] ;
if ( found - > setTime < lowestTimeStamp )
{
removeMe = i ;
lowestTimeStamp = found - > setTime ;
}
}
if ( removeMe ! = - 1 )
{
//remove it... or blow it?
if ( & g_entities [ foundDetPacks [ removeMe ] ] = = NULL )
{
break ;
}
else
{
2013-04-04 18:01:17 +00:00
if ( ! CheatsOn ( ) )
{ //Let them have unlimited if cheats are enabled
G_FreeEntity ( & g_entities [ foundDetPacks [ removeMe ] ] ) ;
}
2013-04-04 14:52:42 +00:00
}
foundDetPacks [ removeMe ] = ENTITYNUM_NONE ;
trapcount - - ;
}
else
{
break ;
}
}
if ( alt_fire )
{
BlowDetpacks ( ent ) ;
}
else
{
AngleVectors ( ent - > client - > ps . viewangles , forward , right , up ) ;
CalcMuzzlePoint ( ent , forward , right , up , muzzle ) ;
VectorNormalize ( forward ) ;
VectorMA ( muzzle , - 4 , forward , muzzle ) ;
drop_charge ( ent , muzzle , forward ) ;
ent - > client - > ps . hasDetPackPlanted = qtrue ;
}
}
//---------------------------------------------------------
// FireStunBaton
//---------------------------------------------------------
void WP_FireStunBaton ( gentity_t * ent , qboolean alt_fire )
{
gentity_t * tr_ent ;
trace_t tr ;
vec3_t mins , maxs , end ;
vec3_t muzzleStun ;
VectorCopy ( ent - > client - > ps . origin , muzzleStun ) ;
muzzleStun [ 2 ] + = ent - > client - > ps . viewheight - 6 ;
muzzleStun [ 0 ] + = forward [ 0 ] * 20 ;
muzzleStun [ 1 ] + = forward [ 1 ] * 20 ;
muzzleStun [ 2 ] + = forward [ 2 ] * 20 ;
muzzleStun [ 0 ] + = right [ 0 ] * 4 ;
muzzleStun [ 1 ] + = right [ 1 ] * 4 ;
muzzleStun [ 2 ] + = right [ 2 ] * 4 ;
VectorMA ( muzzleStun , STUN_BATON_RANGE , forward , end ) ;
VectorSet ( maxs , 6 , 6 , 6 ) ;
VectorScale ( maxs , - 1 , mins ) ;
trap_Trace ( & tr , muzzleStun , mins , maxs , end , ent - > s . number , MASK_SHOT ) ;
if ( tr . entityNum > = ENTITYNUM_WORLD )
{
return ;
}
tr_ent = & g_entities [ tr . entityNum ] ;
if ( tr_ent & & tr_ent - > takedamage )
{
G_PlayEffect ( EFFECT_STUNHIT , tr . endpos , tr . plane . normal ) ;
// TEMP!
G_Sound ( tr_ent , CHAN_WEAPON , G_SoundIndex ( va ( " sound/weapons/melee/punch%d " , Q_irand ( 1 , 4 ) ) ) ) ;
if ( alt_fire )
{
G_Damage ( tr_ent , ent , ent , forward , tr . endpos , STUN_BATON_ALT_DAMAGE , DAMAGE_HALF_ABSORB , MOD_STUN_BATON ) ;
}
else
{
G_Damage ( tr_ent , ent , ent , forward , tr . endpos , STUN_BATON_DAMAGE , ( DAMAGE_NO_KNOCKBACK | DAMAGE_HALF_ABSORB ) , MOD_STUN_BATON ) ;
}
if ( tr_ent - > client )
{ //if it's a player then use the shock effect
tr_ent - > client - > ps . electrifyTime = level . time + 700 ;
}
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
/*
= = = = = = = = = = = = = = = = = = = = = =
SnapVectorTowards
Round a vector to integers for more efficient network
transmission , but make sure that it rounds towards a given point
rather than blindly truncating . This prevents it from truncating
into a wall .
= = = = = = = = = = = = = = = = = = = = = =
*/
void SnapVectorTowards ( vec3_t v , vec3_t to ) {
int i ;
for ( i = 0 ; i < 3 ; i + + ) {
if ( to [ i ] < = v [ i ] ) {
v [ i ] = ( int ) v [ i ] ;
} else {
v [ i ] = ( int ) v [ i ] + 1 ;
}
}
}
//======================================================================
/*
= = = = = = = = = = = = = = =
LogAccuracyHit
= = = = = = = = = = = = = = =
*/
qboolean LogAccuracyHit ( gentity_t * target , gentity_t * attacker ) {
if ( ! target - > takedamage ) {
return qfalse ;
}
if ( target = = attacker ) {
return qfalse ;
}
if ( ! target - > client ) {
return qfalse ;
}
if ( ! attacker - > client ) {
return qfalse ;
}
if ( target - > client - > ps . stats [ STAT_HEALTH ] < = 0 ) {
return qfalse ;
}
if ( OnSameTeam ( target , attacker ) ) {
return qfalse ;
}
return qtrue ;
}
/*
= = = = = = = = = = = = = = =
CalcMuzzlePoint
set muzzle location relative to pivoting eye
= = = = = = = = = = = = = = =
*/
void CalcMuzzlePoint ( gentity_t * ent , vec3_t forward , vec3_t right , vec3_t up , vec3_t muzzlePoint )
{
int weapontype ;
vec3_t muzzleOffPoint ;
weapontype = ent - > s . weapon ;
VectorCopy ( ent - > s . pos . trBase , muzzlePoint ) ;
VectorCopy ( WP_MuzzlePoint [ weapontype ] , muzzleOffPoint ) ;
if ( ent - > client - > ps . usingATST )
{
gentity_t * headEnt = & g_entities [ ent - > client - > damageBoxHandle_Head ] ;
VectorClear ( muzzleOffPoint ) ;
muzzleOffPoint [ 0 ] = 16 ;
muzzleOffPoint [ 2 ] = 128 ;
if ( headEnt & & headEnt - > s . number > = MAX_CLIENTS )
{
if ( headEnt - > bolt_Waist )
{
muzzleOffPoint [ 1 ] = 3 ;
}
else
{
muzzleOffPoint [ 1 ] = - 4 ;
}
}
}
# if 1
if ( weapontype > WP_NONE & & weapontype < WP_NUM_WEAPONS )
{ // Use the table to generate the muzzlepoint;
{ // Crouching. Use the add-to-Z method to adjust vertically.
VectorMA ( muzzlePoint , muzzleOffPoint [ 0 ] , forward , muzzlePoint ) ;
VectorMA ( muzzlePoint , muzzleOffPoint [ 1 ] , right , muzzlePoint ) ;
muzzlePoint [ 2 ] + = ent - > client - > ps . viewheight + muzzleOffPoint [ 2 ] ;
// VectorMA(muzzlePoint, ent->client->ps.viewheight + WP_MuzzlePoint[weapontype][2], up, muzzlePoint);
}
}
# else // Test code
muzzlePoint [ 2 ] + = ent - > client - > ps . viewheight ; //By eyes
muzzlePoint [ 2 ] + = g_debugUp . value ;
VectorMA ( muzzlePoint , g_debugForward . value , forward , muzzlePoint ) ;
VectorMA ( muzzlePoint , g_debugRight . value , right , muzzlePoint ) ;
# endif
// snap to integer coordinates for more efficient network bandwidth usage
SnapVector ( muzzlePoint ) ;
}
/*
= = = = = = = = = = = = = = =
CalcMuzzlePointOrigin
set muzzle location relative to pivoting eye
= = = = = = = = = = = = = = =
*/
void CalcMuzzlePointOrigin ( gentity_t * ent , vec3_t origin , vec3_t forward , vec3_t right , vec3_t up , vec3_t muzzlePoint ) {
VectorCopy ( ent - > s . pos . trBase , muzzlePoint ) ;
muzzlePoint [ 2 ] + = ent - > client - > ps . viewheight ;
VectorMA ( muzzlePoint , 14 , forward , muzzlePoint ) ;
// snap to integer coordinates for more efficient network bandwidth usage
SnapVector ( muzzlePoint ) ;
}
/*
= = = = = = = = = = = = = = =
FireWeapon
= = = = = = = = = = = = = = =
*/
void FireWeapon ( gentity_t * ent , qboolean altFire ) {
if ( ent - > client - > ps . powerups [ PW_QUAD ] ) {
s_quadFactor = g_quadfactor . value ;
} else {
s_quadFactor = 1 ;
}
// track shots taken for accuracy tracking. Grapple is not a weapon and gauntet is just not tracked
if ( ent - > s . weapon ! = WP_SABER & & ent - > s . weapon ! = WP_STUN_BATON )
{
if ( ent - > s . weapon = = WP_FLECHETTE ) {
ent - > client - > accuracy_shots + = FLECHETTE_SHOTS ;
} else {
ent - > client - > accuracy_shots + + ;
}
}
// set aiming directions
if ( ent - > s . weapon = = WP_EMPLACED_GUN )
{
vec3_t viewAngCap ;
VectorCopy ( ent - > client - > ps . viewangles , viewAngCap ) ;
if ( viewAngCap [ PITCH ] > 40 )
{
viewAngCap [ PITCH ] = 40 ;
}
AngleVectors ( viewAngCap , forward , right , up ) ;
}
else
{
AngleVectors ( ent - > client - > ps . viewangles , forward , right , up ) ;
}
if ( ent - > client - > ps . usingATST )
{
gentity_t * headEnt = & g_entities [ ent - > client - > damageBoxHandle_Head ] ;
if ( headEnt & & headEnt - > s . number > = MAX_CLIENTS )
{
if ( altFire )
{
headEnt - > bolt_Waist = 0 ;
}
else
{
headEnt - > bolt_Waist = 1 ;
}
}
}
// CalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle );
CalcMuzzlePoint ( ent , forward , right , up , muzzle ) ;
if ( ent - > client - > ps . usingATST )
{
WP_FireBryarPistol ( ent , qfalse ) ;
return ;
}
// fire the specific weapon
switch ( ent - > s . weapon ) {
case WP_STUN_BATON :
WP_FireStunBaton ( ent , altFire ) ;
break ;
case WP_SABER :
break ;
case WP_BRYAR_PISTOL :
WP_FireBryarPistol ( ent , altFire ) ;
break ;
case WP_BLASTER :
WP_FireBlaster ( ent , altFire ) ;
break ;
case WP_DISRUPTOR :
WP_FireDisruptor ( ent , altFire ) ;
break ;
case WP_BOWCASTER :
WP_FireBowcaster ( ent , altFire ) ;
break ;
case WP_REPEATER :
WP_FireRepeater ( ent , altFire ) ;
break ;
case WP_DEMP2 :
WP_FireDEMP2 ( ent , altFire ) ;
break ;
case WP_FLECHETTE :
WP_FireFlechette ( ent , altFire ) ;
break ;
case WP_ROCKET_LAUNCHER :
WP_FireRocket ( ent , altFire ) ;
break ;
case WP_THERMAL :
WP_FireThermalDetonator ( ent , altFire ) ;
break ;
case WP_TRIP_MINE :
WP_PlaceLaserTrap ( ent , altFire ) ;
break ;
case WP_DET_PACK :
WP_DropDetPack ( ent , altFire ) ;
break ;
case WP_EMPLACED_GUN :
WP_FireEmplaced ( ent , altFire ) ;
break ;
default :
// FIXME G_Error( "Bad ent->s.weapon" );
break ;
}
G_LogWeaponFire ( ent - > s . number , ent - > s . weapon ) ;
}
//---------------------------------------------------------
static void WP_FireEmplaced ( gentity_t * ent , qboolean altFire )
//---------------------------------------------------------
{
vec3_t dir , angs , gunpoint ; //g2r , gunaxis;
vec3_t right ;
gentity_t * gun ;
// mdxaBone_t matrix;
if ( ! ent - > client )
{
return ;
}
if ( ! ent - > client - > ps . emplacedIndex )
{
return ;
}
gun = & g_entities [ ent - > client - > ps . emplacedIndex ] ;
if ( ! gun )
{
return ;
}
VectorCopy ( /*ent->client->ps.origin*/ gun - > s . origin , gunpoint ) ;
gunpoint [ 2 ] + = 46 ;
AngleVectors ( ent - > client - > ps . viewangles , NULL , right , NULL ) ;
if ( gun - > bolt_Waist )
{
gunpoint [ 0 ] + = right [ 0 ] * 10 ;
gunpoint [ 1 ] + = right [ 1 ] * 10 ;
gunpoint [ 2 ] + = right [ 2 ] * 10 ;
gun - > bolt_Waist = 0 ;
G_AddEvent ( gun , EV_FIRE_WEAPON , 0 ) ;
}
else
{
gunpoint [ 0 ] - = right [ 0 ] * 10 ;
gunpoint [ 1 ] - = right [ 1 ] * 10 ;
gunpoint [ 2 ] - = right [ 2 ] * 10 ;
gun - > bolt_Waist = 1 ;
G_AddEvent ( gun , EV_FIRE_WEAPON , 1 ) ;
}
vectoangles ( forward , angs ) ;
if ( altFire )
{
// add some slop to the alt-fire direction
angs [ PITCH ] + = crandom ( ) * BLASTER_SPREAD ;
angs [ YAW ] + = crandom ( ) * BLASTER_SPREAD ;
}
AngleVectors ( angs , dir , NULL , NULL ) ;
// FIXME: if temp_org does not have clear trace to inside the bbox, don't shoot!
//WP_FireEmplacedMissile( ent, gunpoint, dir, altFire, gun );
WP_FireEmplacedMissile ( gun , gunpoint , dir , altFire , ent ) ;
//WP_FireTurretMissile(gun, gunpoint, dir, altFire, 15, 2000, MOD_BLASTER, ent);
}
# define EMPLACED_CANRESPAWN 1
//----------------------------------------------------------
/*QUAKED emplaced_gun (0 0 1) (-30 -20 8) (30 20 60) CANRESPAWN
count - if CANRESPAWN spawnflag , decides how long it is before gun respawns ( in ms )
*/
//----------------------------------------------------------
void emplaced_gun_use ( gentity_t * self , gentity_t * other , trace_t * trace )
{
vec3_t fwd1 , fwd2 ;
float dot ;
int oldWeapon ;
gentity_t * activator = other ;
float zoffset = 50 ;
vec3_t anglesToOwner ;
vec3_t vLen ;
float ownLen = 0 ;
if ( self - > health < = 0 )
{
// can't use a dead gun.
return ;
}
if ( self - > activator )
{
return ;
}
if ( ! activator - > client )
{
return ;
}
if ( activator - > client - > ps . emplacedTime > level . time )
{
return ;
}
if ( activator - > client - > ps . weaponTime > 0 )
{
return ;
}
if ( activator - > client - > ps . origin [ 2 ] > self - > s . origin [ 2 ] + zoffset - 8 )
{
return ;
} //can't use it from the top
if ( activator - > client - > ps . pm_flags & PMF_DUCKED )
{
return ;
}
if ( activator - > client - > ps . isJediMaster )
{ //;O
return ;
}
VectorSubtract ( self - > s . origin , activator - > client - > ps . origin , vLen ) ;
ownLen = VectorLength ( vLen ) ;
if ( ownLen > 64 )
{
return ;
}
// Let's get some direction vectors for the users
AngleVectors ( activator - > client - > ps . viewangles , fwd1 , NULL , NULL ) ;
// Get the guns direction vector
AngleVectors ( self - > pos1 , fwd2 , NULL , NULL ) ;
dot = DotProduct ( fwd1 , fwd2 ) ;
// Must be reasonably facing the way the gun points ( 110 degrees or so ), otherwise we don't allow to use it.
if ( dot < - 0.2f )
{
return ;
}
VectorSubtract ( self - > s . origin , activator - > client - > ps . origin , fwd1 ) ;
VectorNormalize ( fwd1 ) ;
dot = DotProduct ( fwd1 , fwd2 ) ;
// Must be reasonably facing the way the gun points ( 110 degrees or so ), otherwise we don't allow to use it.
if ( dot < /*-0.2f*/ 0.6f /*0.8f*/ )
{
return ;
}
self - > boltpoint1 = 1 ;
// don't allow using it again for half a second
// if ( activator->s.number == 0 && self->delay + 500 < level.time )
// {
oldWeapon = activator - > s . weapon ;
// swap the users weapon with the emplaced gun and add the ammo the gun has to the player
activator - > client - > ps . weapon = self - > s . weapon ;
activator - > client - > ps . weaponstate = WEAPON_READY ;
activator - > client - > ps . stats [ STAT_WEAPONS ] | = ( 1 < < WP_EMPLACED_GUN ) ;
//SnapVector(self->s.origin);
VectorCopy ( activator - > client - > ps . origin , self - > s . origin2 ) ;
activator - > client - > ps . emplacedIndex = self - > s . number ;
self - > s . emplacedOwner = activator - > s . number ;
self - > s . activeForcePass = NUM_FORCE_POWERS + 1 ;
// the gun will track which weapon we used to have
self - > s . weapon = oldWeapon ;
// Lock the player
// activator->client->ps.eFlags |= EF_LOCKED_TO_WEAPON;
activator - > r . ownerNum = self - > s . number ; // kind of dumb, but when we are locked to the weapon, we are owned by it.
self - > activator = activator ;
// self->delay = level.time; // can't disconnect from the thing for half a second
// Let the client know that we want to start our emplaced camera clamping
// FIXME: if you are in the gun and you switch/restart maps, emplacedClamp will still be 1 and since
// you can't change it from the console, you are stuck with really bad viewangles
// char temp[32];
// gi.cvar_set("cl_emplacedClamp", "1");
// sprintf( temp, "%f", self->pos1[0] );
// gi.cvar_set("cl_emplacedPitch", temp );
// sprintf( temp, "%f", self->pos1[1] );
// gi.cvar_set("cl_emplacedYaw", temp );
// Let the gun be considered an enemy
// self->svFlags |= SVF_NONNPC_ENEMY;
// move the player to the center of the gun and make player not solid
// activator->contents = 0;
// VectorCopy( self->currentOrigin, activator->client->ps.origin );
// FIXME: trying to force the gun to look forward, but it seems to pick up the players viewangles....and
// since you usually go up to the side of the gun to use it, you end up starting with a really annoying
// set of viewangles.
//G_SetAngles( activator, self->s.angles );
VectorSubtract ( self - > r . currentOrigin , activator - > client - > ps . origin , anglesToOwner ) ;
vectoangles ( anglesToOwner , anglesToOwner ) ;
//SetClientViewAngle(activator, /*self->s.angles*/anglesToOwner);
// VectorCopy(activator->s.angles, self->pos1);
// Overriding these may be a bad thing....
// gi.cvar_set("cg_thirdPersonRange", "20");
// gi.cvar_set("cg_thirdPersonVertOffset", "35");
// }
}
void emplaced_gun_realuse ( gentity_t * self , gentity_t * other , gentity_t * activator )
{
emplaced_gun_use ( self , other , NULL ) ;
}
//----------------------------------------------------------
void emplaced_gun_pain ( gentity_t * self , gentity_t * attacker , int damage )
{
if ( self - > health < = 0 )
{
// play pain effect?
}
else
{
// if ( self->paintarget )
// {
// G_UseTargets2( self, self->activator, self->paintarget );
// }
//Don't do script if dead
// G_ActivateBehavior( self, BSET_PAIN );
}
}
# define EMPLACED_GUN_HEALTH 800
//----------------------------------------------------------
void emplaced_gun_update ( gentity_t * self )
{
vec3_t smokeOrg , puffAngle ;
int oldWeap ;
float ownLen = 0 ;
if ( self - > health < 1 & & ! self - > bolt_Head )
{
if ( self - > spawnflags & EMPLACED_CANRESPAWN )
{
self - > bolt_Head = level . time + 4000 + self - > count ;
}
}
else if ( self - > health < 1 & & self - > bolt_Head < level . time )
{
self - > s . time = 0 ;
self - > boltpoint4 = 0 ;
self - > boltpoint3 = 0 ;
self - > health = EMPLACED_GUN_HEALTH * 0.4 ;
}
if ( self - > boltpoint4 & & self - > boltpoint4 < 2 & & self - > s . time < level . time )
{
vec3_t explOrg ;
VectorSet ( puffAngle , 0 , 0 , 1 ) ;
VectorCopy ( self - > r . currentOrigin , explOrg ) ;
explOrg [ 2 ] + = 16 ;
//G_PlayEffect(EFFECT_EXPLOSION, explOrg, /*self->r.currentAngles*/puffAngle);
G_PlayEffect ( EFFECT_EXPLOSION_DETPACK , explOrg , /*self->r.currentAngles*/ puffAngle ) ;
self - > boltpoint3 = level . time + Q_irand ( 2500 , 3500 ) ;
G_RadiusDamage ( self - > r . currentOrigin , self , self - > splashDamage , self - > splashRadius , self , MOD_UNKNOWN ) ;
self - > s . time = - 1 ;
self - > boltpoint4 = 2 ;
}
if ( self - > boltpoint3 > level . time )
{
if ( self - > boltpoint2 < level . time )
{
VectorSet ( puffAngle , 0 , 0 , 1 ) ;
VectorCopy ( self - > r . currentOrigin , smokeOrg ) ;
smokeOrg [ 2 ] + = 60 ;
//What.. was I thinking?
G_PlayEffect ( EFFECT_SMOKE , smokeOrg , puffAngle ) ;
self - > boltpoint2 = level . time + Q_irand ( 250 , 400 ) ;
//This would be much better if we checked a value on the entity on the client
//and then spawned smoke there instead of sending over a bunch of events. But
//this will do for now, an event every 250-400ms isn't too bad.
}
}
if ( self - > activator & & self - > activator - > client & & self - > activator - > inuse )
{
vec3_t vLen ;
VectorSubtract ( self - > s . origin , self - > activator - > client - > ps . origin , vLen ) ;
ownLen = VectorLength ( vLen ) ;
if ( ! ( self - > activator - > client - > pers . cmd . buttons & BUTTON_USE ) & & self - > boltpoint1 )
{
self - > boltpoint1 = 0 ;
}
if ( ( self - > activator - > client - > pers . cmd . buttons & BUTTON_USE ) & & ! self - > boltpoint1 )
{
self - > activator - > client - > ps . emplacedIndex = 0 ;
self - > nextthink = level . time + 50 ;
return ;
}
}
if ( ( self - > activator & & self - > activator - > client ) & &
( ! self - > activator - > inuse | | self - > activator - > client - > ps . emplacedIndex ! = self - > s . number | | self - > boltpoint4 | | ownLen > 64 ) )
{
if ( self - > activator - > client - > ps . stats [ STAT_WEAPONS ] & ( 1 < < WP_EMPLACED_GUN ) )
{
self - > activator - > client - > ps . stats [ STAT_WEAPONS ] - = ( 1 < < WP_EMPLACED_GUN ) ;
}
//VectorCopy(self->s.origin2, self->activator->client->ps.origin);
oldWeap = self - > activator - > client - > ps . weapon ;
self - > activator - > client - > ps . weapon = self - > s . weapon ;
self - > s . weapon = oldWeap ;
self - > activator - > r . ownerNum = ENTITYNUM_NONE ;
self - > activator - > client - > ps . emplacedTime = level . time + 1000 ;
self - > activator - > client - > ps . emplacedIndex = 0 ;
self - > activator = NULL ;
self - > s . activeForcePass = 0 ;
}
else if ( self - > activator & & self - > activator - > client )
{
self - > activator - > client - > ps . weapon = WP_EMPLACED_GUN ;
self - > activator - > client - > ps . weaponstate = WEAPON_READY ;
}
self - > nextthink = level . time + 50 ;
}
//----------------------------------------------------------
void emplaced_gun_die ( gentity_t * self , gentity_t * inflictor , gentity_t * attacker , int damage , int mod )
{
if ( self - > boltpoint4 )
{
return ;
}
self - > boltpoint4 = 1 ;
self - > s . time = level . time + 3000 ;
self - > bolt_Head = 0 ;
}
void SP_emplaced_gun ( gentity_t * ent )
{
//char name[] = "models/map_objects/imp_mine/turret_chair.glm";
char name [ ] = " models/map_objects/mp/turret_chair.glm " ;
vec3_t down ;
trace_t tr ;
RegisterItem ( BG_FindItemForWeapon ( WP_BLASTER ) ) ;
//Emplaced gun uses many of the same assets as the blaster, so just precache it
ent - > r . contents = CONTENTS_SOLID ;
ent - > s . solid = SOLID_BBOX ;
ent - > bolt_Head = 0 ;
VectorSet ( ent - > r . mins , - 30 , - 20 , 8 ) ;
VectorSet ( ent - > r . maxs , 30 , 20 , 60 ) ;
VectorCopy ( ent - > s . origin , down ) ;
down [ 2 ] - = 1024 ;
trap_Trace ( & tr , ent - > s . origin , ent - > r . mins , ent - > r . maxs , down , ent - > s . number , MASK_SOLID ) ;
if ( tr . fraction ! = 1 & & ! tr . allsolid & & ! tr . startsolid )
{
VectorCopy ( tr . endpos , ent - > s . origin ) ;
}
ent - > spawnflags | = 4 ; // deadsolid
ent - > health = EMPLACED_GUN_HEALTH ;
if ( ent - > spawnflags & EMPLACED_CANRESPAWN )
{ //make it somewhat easier to kill if it can respawn
ent - > health * = 0.4 ;
}
ent - > boltpoint4 = 0 ;
ent - > takedamage = qtrue ;
ent - > pain = emplaced_gun_pain ;
ent - > die = emplaced_gun_die ;
// being caught in this thing when it blows would be really bad.
ent - > splashDamage = 80 ;
ent - > splashRadius = 128 ;
// G_EffectIndex( "emplaced/explode" );
// G_EffectIndex( "emplaced/dead_smoke" );
// amount of ammo that this little poochie has
G_SpawnInt ( " count " , " 600 " , & ent - > count ) ;
ent - > s . modelindex = G_ModelIndex ( name ) ;
ent - > s . modelGhoul2 = 1 ;
ent - > s . g2radius = 110 ;
//trap_G2API_InitGhoul2Model( ent->s.ghoul2, name, ent->s.modelindex );
//g2r trap_G2API_InitGhoul2Model( &ent->s, name, ent->s.modelindex, 0, 0, 0, 0 );
// Activate our tags and bones
// ent->headBolt = gi.G2API_AddBolt( &ent->s.ghoul2[0], "*seat" );
// ent->handLBolt = gi.G2API_AddBolt( &ent->s.ghoul2[0], "*flash01" );
// ent->handRBolt = gi.G2API_AddBolt( &ent->s.ghoul2[0], "*flash02" );
// gi.G2API_SetBoneAngles( &ent->s.ghoul2[0], "swivel_bone", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL);
// RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN ));
ent - > s . weapon = WP_EMPLACED_GUN ;
// SnapVector(ent->s.origin);
G_SetOrigin ( ent , ent - > s . origin ) ;
//G_SetAngles( ent, ent->s.angles );
// store base angles for later
VectorCopy ( ent - > s . angles , ent - > pos1 ) ;
VectorCopy ( ent - > s . angles , ent - > r . currentAngles ) ;
VectorCopy ( ent - > s . angles , ent - > s . apos . trBase ) ;
ent - > think = emplaced_gun_update ;
ent - > nextthink = level . time + 50 ;
// ent->e_UseFunc = useF_emplaced_gun_use;
ent - > use = emplaced_gun_realuse ;
//ent->touch = emplaced_gun_use;
ent - > r . svFlags | = SVF_PLAYER_USABLE ;
ent - > s . pos . trType = TR_STATIONARY ;
ent - > s . owner = MAX_CLIENTS + 1 ;
ent - > s . shouldtarget = qtrue ;
ent - > s . teamowner = 0 ;
/*
angswiv [ ROLL ] = 0 ;
angswiv [ PITCH ] = 0 ;
angswiv [ YAW ] = 70 ;
trap_G2API_SetBoneAngles ( ent - > s . ghoul2 , 0 , " swivel_bone " , angswiv , BONE_ANGLES_REPLACE , POSITIVE_Z , NEGATIVE_X , NEGATIVE_Y , NULL , 0 , level . time ) ;
*/
//g2r ent->s.trickedentindex = trap_G2API_AddBolt(ent->s.ghoul2, 0, "*seat");
//g2r ent->s.bolt1 = trap_G2API_AddBolt(ent->s.ghoul2, 0, "*flash01");
//g2r ent->s.bolt2 = trap_G2API_AddBolt(ent->s.ghoul2, 0, "*flash02");
trap_LinkEntity ( ent ) ;
}