mirror of
https://github.com/UberGames/RPG-X2.git
synced 2024-12-01 08:41:36 +00:00
caaa5786b1
Backup copy of the code in /old_code/g_weapon.c.
1128 lines
31 KiB
C
1128 lines
31 KiB
C
/*
|
|
----------------------------------------------
|
|
DREADNOUGHT
|
|
----------------------------------------------
|
|
*/
|
|
|
|
#define MAXRANGE_DREADNOUGHT 2048
|
|
|
|
//---------------------------------------------------------
|
|
void WP_FireDreadnoughtBeam( gentity_t *ent )
|
|
//---------------------------------------------------------
|
|
{
|
|
trace_t tr;
|
|
vec3_t end;
|
|
gentity_t *traceEnt;
|
|
vec3_t start;
|
|
qboolean bHit = qfalse;
|
|
|
|
// Trace once to the right...
|
|
VectorMA( muzzle, DREADNOUGHT_WIDTH, right, start);
|
|
VectorMA( start, MAXRANGE_DREADNOUGHT, forward, end );
|
|
|
|
// Find out who we've hit
|
|
trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
|
|
traceEnt = &g_entities[ tr.entityNum ];
|
|
|
|
if ( traceEnt->takedamage)
|
|
{
|
|
G_Damage( traceEnt, ent, ent, forward, tr.endpos, DREADNOUGHT_DAMAGE*s_quadFactor,
|
|
DAMAGE_NOT_ARMOR_PIERCING, MOD_DREADNOUGHT);
|
|
bHit = qtrue;
|
|
}
|
|
|
|
// Now trace once to the left...
|
|
VectorMA( muzzle, -DREADNOUGHT_WIDTH, right, start);
|
|
VectorMA( start, MAXRANGE_DREADNOUGHT, forward, end );
|
|
|
|
// Find out who we've hit
|
|
trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
|
|
traceEnt = &g_entities[ tr.entityNum ];
|
|
|
|
if ( traceEnt->takedamage)
|
|
{
|
|
G_Damage( traceEnt, ent, ent, forward, tr.endpos, DREADNOUGHT_DAMAGE*s_quadFactor,
|
|
DAMAGE_NOT_ARMOR_PIERCING, MOD_DREADNOUGHT);
|
|
bHit = qtrue;
|
|
}
|
|
if (bHit)
|
|
{
|
|
// log hit
|
|
/*if (ent->client)
|
|
{
|
|
ent->client->ps.persistant[PERS_ACCURACY_HITS]++;
|
|
}*/
|
|
}
|
|
}
|
|
|
|
|
|
//#define DN_SEARCH_DIST 512
|
|
//#define DN_SIDE_DIST 64
|
|
//#define DN_RAND_DEV 8
|
|
|
|
#define DN_SEARCH_DIST 256
|
|
#define DN_SIDE_DIST 128
|
|
#define DN_RAND_DEV 16
|
|
#define DN_ALT_THINK_TIME 100
|
|
#define DN_ALT_SIZE 12
|
|
void DreadnoughtBurstThink(gentity_t *ent)
|
|
{
|
|
vec3_t startpos, endpos, perp;
|
|
trace_t tr;
|
|
gentity_t *traceEnt, *tent;
|
|
int source;
|
|
vec3_t dest, mins={-DN_ALT_SIZE,-DN_ALT_SIZE,-1}, maxs={DN_ALT_SIZE,DN_ALT_SIZE,1};
|
|
float dot;
|
|
static qboolean recursion=qfalse;
|
|
|
|
VectorCopy(ent->s.origin, startpos);
|
|
|
|
// Search in a 3-way arc in front of it.
|
|
VectorMA(startpos, DN_SEARCH_DIST, ent->movedir, endpos);
|
|
endpos[0] += flrandom(-DN_RAND_DEV, DN_RAND_DEV);
|
|
endpos[1] += flrandom(-DN_RAND_DEV, DN_RAND_DEV);
|
|
endpos[2] += flrandom(-DN_RAND_DEV*0.5, DN_RAND_DEV*0.5);
|
|
|
|
// unlink this entity, so the next trace will go past it
|
|
trap_UnlinkEntity(ent);
|
|
|
|
// link back in any entities we unlinked
|
|
if (ent->target_ent)
|
|
{
|
|
source = ent->target_ent->s.number;
|
|
}
|
|
else if (ent->r.ownerNum)
|
|
{
|
|
source = ent->r.ownerNum;
|
|
}
|
|
else
|
|
{
|
|
source = ent->s.number;
|
|
}
|
|
|
|
trap_Trace (&tr, startpos, mins, maxs, endpos, source, MASK_SHOT );
|
|
traceEnt = &g_entities[ tr.entityNum ];
|
|
// did we hit the holdable shield?
|
|
if (traceEnt->classname && !Q_stricmp(traceEnt->classname, "holdable_shield"))
|
|
{
|
|
// Make sure you damage the surface first
|
|
G_Damage( traceEnt, ent, &g_entities[ent->r.ownerNum], forward, tr.endpos, ent->damage,
|
|
DAMAGE_NOT_ARMOR_PIERCING, MOD_DREADNOUGHT_ALT);
|
|
|
|
VectorCopy(ent->s.origin, ent->s.origin2);
|
|
VectorCopy(endpos, ent->s.origin);
|
|
SnapVector(ent->s.origin);
|
|
SnapVector(ent->s.origin2);
|
|
|
|
ent->nextthink = level.time + 100;
|
|
|
|
// yes. We are done.
|
|
ent->think = G_FreeEntity;
|
|
|
|
tent = G_TempEntity( tr.endpos, EV_DREADNOUGHT_MISS );
|
|
// Stash origins, etc. so that the effects can have access to them
|
|
VectorCopy( startpos, tent->s.origin2 );
|
|
SnapVector(tent->s.origin2);
|
|
tent->s.eventParm = DirToByte( tr.plane.normal );
|
|
|
|
return;
|
|
}
|
|
|
|
if (traceEnt->takedamage)
|
|
{
|
|
ent->target_ent = traceEnt;
|
|
VectorCopy(ent->s.origin, ent->s.origin2);
|
|
SnapVector(ent->s.origin);
|
|
SnapVector(ent->s.origin2);
|
|
VectorCopy(traceEnt->r.currentOrigin, ent->s.origin);
|
|
trap_LinkEntity(ent);
|
|
VectorNormalize(ent->movedir);
|
|
ent->nextthink = level.time + DN_ALT_THINK_TIME;
|
|
G_Damage( traceEnt, ent, &g_entities[ent->r.ownerNum], forward, tr.endpos, ent->damage,
|
|
DAMAGE_NOT_ARMOR_PIERCING, MOD_DREADNOUGHT_ALT);
|
|
// log hit
|
|
/*if (ent->client)
|
|
{
|
|
ent->client->ps.persistant[PERS_ACCURACY_HITS]++;
|
|
}*/
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (tr.fraction < 0.02)
|
|
{ // Hit a wall...
|
|
|
|
dot = DotProduct(ent->movedir, tr.plane.normal);
|
|
if (dot < -0.6 || dot == 0.0)
|
|
{ // Stop.
|
|
G_FreeEntity( ent );
|
|
|
|
tent = G_TempEntity( tr.endpos, EV_DREADNOUGHT_MISS );
|
|
|
|
// Stash origins, etc. so that the effects can have access to them
|
|
VectorCopy( startpos, tent->s.origin2 );
|
|
SnapVector(tent->s.origin2);
|
|
tent->s.eventParm = DirToByte( tr.plane.normal );
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
|
|
// Bounce off the surface just a little
|
|
VectorMA(ent->movedir, -1.25*dot, tr.plane.normal, ent->movedir);
|
|
VectorNormalize(ent->movedir);
|
|
|
|
// Make sure we store a next think time, else the effect could stick around forever...
|
|
ent->nextthink = level.time + DN_ALT_THINK_TIME;
|
|
|
|
if (!recursion)
|
|
{ // NOTE RECURSION HERE.
|
|
recursion=qtrue;
|
|
DreadnoughtBurstThink(ent);
|
|
recursion=qfalse;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
VectorCopy(tr.endpos, dest);
|
|
}
|
|
|
|
// Didn't hit anything forward. Try some side vectors.
|
|
|
|
// Get the perp vector (okay, only in 2D) to find a right or left (random)-pointing perpendicular vector to the facing.
|
|
if (irandom(0,1))
|
|
{ // Right vector
|
|
perp[0] = ent->movedir[1];
|
|
perp[1] = -ent->movedir[0];
|
|
perp[2] = ent->movedir[2];
|
|
}
|
|
else
|
|
{ // Left vector
|
|
perp[0] = -ent->movedir[1];
|
|
perp[1] = ent->movedir[0];
|
|
perp[2] = ent->movedir[2];
|
|
}
|
|
|
|
// Search a random interval from the side arc
|
|
VectorMA(endpos, DN_SIDE_DIST, perp, endpos);
|
|
endpos[0] += flrandom(-DN_RAND_DEV, DN_RAND_DEV);
|
|
endpos[1] += flrandom(-DN_RAND_DEV, DN_RAND_DEV);
|
|
endpos[2] += flrandom(-DN_RAND_DEV*0.5, DN_RAND_DEV*0.5);
|
|
|
|
trap_Trace (&tr, startpos, mins, maxs, endpos, source, MASK_SHOT );
|
|
traceEnt = &g_entities[ tr.entityNum ];
|
|
// did we hit the holdable shield?
|
|
if (traceEnt->classname && !Q_stricmp(traceEnt->classname, "holdable_shield"))
|
|
{
|
|
// yes. We are done.
|
|
VectorCopy(ent->s.origin, ent->s.origin2);
|
|
VectorCopy(endpos, ent->s.origin);
|
|
SnapVector(ent->s.origin);
|
|
SnapVector(ent->s.origin2);
|
|
|
|
ent->nextthink = level.time + 100;
|
|
|
|
ent->think = G_FreeEntity;
|
|
tent = G_TempEntity( tr.endpos, EV_DREADNOUGHT_MISS );
|
|
// Stash origins, etc. so that the effects can have access to them
|
|
VectorCopy( startpos, tent->s.origin2 );
|
|
SnapVector(tent->s.origin2);
|
|
tent->s.eventParm = DirToByte( tr.plane.normal );
|
|
|
|
return;
|
|
}
|
|
if (traceEnt->takedamage)
|
|
{
|
|
ent->target_ent = traceEnt;
|
|
VectorCopy(ent->s.origin, ent->s.origin2);
|
|
SnapVector(ent->s.origin);
|
|
SnapVector(ent->s.origin2);
|
|
VectorCopy(traceEnt->r.currentOrigin, ent->s.origin);
|
|
trap_LinkEntity(ent);
|
|
VectorNormalize(ent->movedir);
|
|
ent->nextthink = level.time + DN_ALT_THINK_TIME;
|
|
G_Damage( traceEnt, ent, &g_entities[ent->r.ownerNum], forward, tr.endpos, ent->damage,
|
|
DAMAGE_NOT_ARMOR_PIERCING, MOD_DREADNOUGHT_ALT);
|
|
|
|
// log hit
|
|
/*if (ent->client)
|
|
{
|
|
ent->client->ps.persistant[PERS_ACCURACY_HITS]++;
|
|
}*/
|
|
// NOTE Send this as a hit effect once we have one...
|
|
G_Sound( traceEnt, G_SoundIndex( SOUND_DIR "dreadnought/dn_althit.wav"));
|
|
|
|
return;
|
|
}
|
|
|
|
// Search a random interval in the opposite direction
|
|
VectorMA(endpos, -2.0*DN_SIDE_DIST, perp, endpos);
|
|
endpos[0] += flrandom(-DN_RAND_DEV, DN_RAND_DEV);
|
|
endpos[1] += flrandom(-DN_RAND_DEV, DN_RAND_DEV);
|
|
endpos[2] += flrandom(-DN_RAND_DEV*0.5, DN_RAND_DEV*0.5);
|
|
|
|
trap_Trace (&tr, startpos, mins, maxs, endpos, source, MASK_SHOT );
|
|
traceEnt = &g_entities[ tr.entityNum ];
|
|
// did we hit the holdable shield?
|
|
if (traceEnt->classname && !Q_stricmp(traceEnt->classname, "holdable_shield"))
|
|
{
|
|
VectorCopy(ent->s.origin, ent->s.origin2);
|
|
VectorCopy(endpos, ent->s.origin);
|
|
SnapVector(ent->s.origin);
|
|
SnapVector(ent->s.origin2);
|
|
|
|
ent->nextthink = level.time + 100;
|
|
|
|
// yes. We are done.
|
|
ent->think = G_FreeEntity;
|
|
|
|
tent = G_TempEntity( tr.endpos, EV_DREADNOUGHT_MISS );
|
|
// Stash origins, etc. so that the effects can have access to them
|
|
VectorCopy( startpos, tent->s.origin2 );
|
|
SnapVector(tent->s.origin2);
|
|
tent->s.eventParm = DirToByte( tr.plane.normal );
|
|
|
|
return;
|
|
}
|
|
if (traceEnt->takedamage)
|
|
{
|
|
ent->target_ent = traceEnt;
|
|
VectorCopy(ent->s.origin, ent->s.origin2);
|
|
SnapVector(ent->s.origin);
|
|
SnapVector(ent->s.origin2);
|
|
VectorCopy(traceEnt->r.currentOrigin, ent->s.origin);
|
|
trap_LinkEntity(ent);
|
|
VectorNormalize(ent->movedir);
|
|
ent->nextthink = level.time + DN_ALT_THINK_TIME;
|
|
G_Damage( traceEnt, ent, &g_entities[ent->r.ownerNum], forward, tr.endpos, ent->damage,
|
|
DAMAGE_NOT_ARMOR_PIERCING, MOD_DREADNOUGHT_ALT);
|
|
// log hit
|
|
/*if (ent->client)
|
|
{
|
|
ent->client->ps.persistant[PERS_ACCURACY_HITS]++;
|
|
}*/
|
|
return;
|
|
}
|
|
|
|
// We didn't find anything, so move the entity to the middle destination.
|
|
ent->target_ent = NULL;
|
|
VectorCopy(ent->s.origin, ent->s.origin2);
|
|
VectorCopy(dest, ent->s.origin);
|
|
VectorCopy(dest, ent->s.pos.trBase);
|
|
SnapVector(ent->s.origin2);
|
|
trap_LinkEntity(ent);
|
|
ent->nextthink = level.time + DN_ALT_THINK_TIME;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
void WP_FireDreadnoughtBurst( gentity_t *ent )
|
|
//---------------------------------------------------------
|
|
{
|
|
gentity_t *bolt;
|
|
vec3_t dir, start;
|
|
|
|
VectorCopy( forward, dir );
|
|
VectorCopy( muzzle, start );
|
|
|
|
bolt = G_Spawn();
|
|
bolt->classname = "dn_projectile";
|
|
|
|
bolt->nextthink = level.time + 200;
|
|
bolt->think = DreadnoughtBurstThink;
|
|
|
|
bolt->s.eType = ET_ALT_MISSILE;
|
|
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
|
|
bolt->s.weapon = WP_13;
|
|
bolt->r.ownerNum = ent->s.number;
|
|
bolt->parent = ent;
|
|
bolt->damage = DREADNOUGHT_ALTDAMAGE*DMG_VAR*s_quadFactor;
|
|
bolt->splashDamage = 0;
|
|
bolt->splashRadius = 0;
|
|
bolt->methodOfDeath = MOD_DREADNOUGHT_ALT;
|
|
bolt->clipmask = MASK_SHOT;
|
|
|
|
bolt->s.pos.trType = TR_LINEAR;
|
|
bolt->s.pos.trTime = level.time;
|
|
VectorCopy( start, bolt->s.pos.trBase );
|
|
VectorCopy( start, bolt->s.origin);
|
|
SnapVector(bolt->s.pos.trBase);
|
|
SnapVector(bolt->s.origin);
|
|
|
|
VectorCopy( forward, bolt->movedir);
|
|
|
|
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
|
|
VectorCopy( start, bolt->r.currentOrigin );
|
|
VectorCopy( start, bolt->pos1 );
|
|
VectorCopy( start, bolt->pos2 );
|
|
|
|
DreadnoughtBurstThink(bolt);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void WP_FireDreadnought( gentity_t *ent, qboolean alt_fire )
|
|
//---------------------------------------------------------
|
|
{
|
|
// This was moved out of the FireWeapon switch statement below to keep things more consistent
|
|
if ( alt_fire )
|
|
{
|
|
WP_FireDreadnoughtBurst( ent );
|
|
}
|
|
else
|
|
{
|
|
WP_FireDreadnoughtBeam( ent );
|
|
}
|
|
|
|
G_LogWeaponFire(ent->s.number, WP_13);
|
|
}
|
|
|
|
|
|
//======================================================================
|
|
|
|
#define BORG_PROJECTILE_SIZE 8
|
|
#define BORG_PROJ_VELOCITY 1000
|
|
|
|
void WP_FireBorgTaser( gentity_t *ent )
|
|
{
|
|
trace_t tr;
|
|
vec3_t end, d_dir;
|
|
gentity_t *tent = 0;
|
|
gentity_t *traceEnt = NULL;
|
|
|
|
VectorMA (muzzle, MAXRANGE_IMOD, forward, end);
|
|
|
|
trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
|
|
traceEnt = &g_entities[ tr.entityNum ];
|
|
|
|
if ( traceEnt->takedamage )
|
|
{
|
|
LogAccuracyHit( traceEnt, ent );
|
|
|
|
//For knockback - send them up in air
|
|
VectorCopy( forward, d_dir );
|
|
if ( d_dir[2] < 0.30f )
|
|
{
|
|
d_dir[2] = 0.30f;
|
|
}
|
|
VectorNormalize( d_dir );
|
|
|
|
G_Damage( traceEnt, ent, ent, forward, tr.endpos, BORG_TASER_DAMAGE * s_quadFactor, 0, MOD_BORG_ALT );
|
|
}
|
|
|
|
VectorMA (muzzle, 2, forward, muzzle);
|
|
tent = G_TempEntity( tr.endpos, EV_BORG_ALT_WEAPON );
|
|
|
|
// Stash origins, etc. so the effect can have access to them
|
|
VectorCopy( muzzle, tent->s.origin2 );
|
|
SnapVector( tent->s.origin2 ); // save net bandwidth
|
|
tent->s.eventParm = DirToByte( tr.plane.normal );
|
|
tent->s.weapon = ent->s.weapon;
|
|
}
|
|
|
|
|
|
void WP_FireBorgProjectile( gentity_t *ent, vec3_t start )
|
|
//---------------------------------------------------------
|
|
{
|
|
gentity_t *bolt;
|
|
|
|
bolt = G_Spawn();
|
|
|
|
bolt->classname = "borg_proj";
|
|
bolt->nextthink = level.time + 10000;
|
|
bolt->think = G_FreeEntity;
|
|
bolt->s.eType = ET_MISSILE;
|
|
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
|
|
bolt->s.weapon = WP_11;
|
|
bolt->r.ownerNum = ent->s.number;
|
|
bolt->parent = ent;
|
|
|
|
bolt->damage = BORG_PROJ_DAMAGE * DMG_VAR * s_quadFactor;
|
|
bolt->splashDamage = 0;
|
|
bolt->splashRadius = 0;
|
|
bolt->methodOfDeath = MOD_BORG;
|
|
bolt->clipmask = MASK_SHOT;
|
|
|
|
// Set the size of the missile up
|
|
VectorSet(bolt->r.maxs, BORG_PROJECTILE_SIZE, BORG_PROJECTILE_SIZE, BORG_PROJECTILE_SIZE);
|
|
VectorScale( bolt->r.maxs, -1, bolt->r.mins );
|
|
|
|
bolt->s.pos.trType = TR_LINEAR;
|
|
bolt->s.pos.trTime = level.time; // move a bit on the very first frame
|
|
VectorCopy( start, bolt->s.pos.trBase );
|
|
SnapVector( bolt->s.pos.trBase ); // save net bandwidth
|
|
VectorScale( forward, BORG_PROJ_VELOCITY, bolt->s.pos.trDelta );
|
|
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
|
|
VectorCopy( start, bolt->r.currentOrigin);
|
|
}
|
|
|
|
void WP_Assimilate( gentity_t *ent, qboolean alt_fire )
|
|
{//MCG: hacked this in for now for testing the rules
|
|
gentity_t *tr_ent;
|
|
trace_t tr;
|
|
vec3_t end;
|
|
float range;
|
|
|
|
if ( ent->s.number == borgQueenClientNum )
|
|
{
|
|
range = 32;
|
|
}
|
|
else
|
|
{
|
|
range = 64;
|
|
}
|
|
VectorMA( muzzle, range, forward, end );
|
|
|
|
trap_Trace ( &tr, muzzle, vec3_origin, vec3_origin, end, ent->s.number, MASK_SHOT );
|
|
|
|
if ( tr.entityNum >= ENTITYNUM_WORLD )
|
|
{
|
|
return;
|
|
}
|
|
|
|
tr_ent = &g_entities[tr.entityNum];
|
|
|
|
if ( tr_ent && tr_ent->client && tr_ent->health > 0 && ent->client && ent->client->sess.sessionTeam != tr_ent->client->sess.sessionTeam )
|
|
{
|
|
if ( ent->s.number == borgQueenClientNum )
|
|
{//Borg queen assimilates with one hit
|
|
tr_ent->health = 0;
|
|
player_die( tr_ent, ent, ent, 100, MOD_ASSIMILATE );
|
|
//G_Damage( tr_ent, ent, ent, forward, tr.endpos, 50, DAMAGE_NO_ARMOR|DAMAGE_NO_INVULNERABILITY, MOD_ASSIMILATE );
|
|
}
|
|
else
|
|
{
|
|
G_Damage( tr_ent, ent, ent, forward, tr.endpos, 10, DAMAGE_NO_ARMOR|DAMAGE_NO_INVULNERABILITY, MOD_ASSIMILATE );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
RPG-X Fire Engineer Tool
|
|
By: RedTechie
|
|
===============
|
|
*/
|
|
/*void WP_NEUTRINO_PROBE( gentity_t *ent, qboolean alt_fire ){
|
|
gentity_t *target; //Target entity
|
|
trace_t trace; //Used to trace target
|
|
vec3_t src, dest, vf; //Used to find target
|
|
|
|
if(!ent){
|
|
return;
|
|
}
|
|
//if(ent->parent->client->sess.sessionClass == PC_ADMIN){
|
|
if(alt_fire){
|
|
return;
|
|
}else{
|
|
//////////////////////////////////////
|
|
//All this code below finds the target entity
|
|
|
|
VectorCopy( ent->r.currentOrigin, src );
|
|
src[2] += ent->client->ps.viewheight;
|
|
|
|
AngleVectors( ent->client->ps.viewangles, vf, NULL, NULL );
|
|
|
|
//extend to find end of use trace
|
|
VectorMA( src, -6, vf, src );//in case we're inside something?
|
|
VectorMA( src, 1340, vf, dest );//128+6
|
|
|
|
//Trace ahead to find a valid target
|
|
trap_Trace( &trace, src, vec3_origin, vec3_origin, dest, ent->s.number, CONTENTS_TRIGGER );
|
|
|
|
if ( trace.fraction == 1.0f || trace.entityNum < 0 )
|
|
{
|
|
trap_SendConsoleCommand( EXEC_APPEND, va("echo No target in range to kick.") );
|
|
return;
|
|
}
|
|
|
|
target = &g_entities[trace.entityNum];
|
|
|
|
////////////////////////////////
|
|
|
|
//lets delete it
|
|
if(target){
|
|
G_FreeEntity( target );
|
|
}
|
|
}
|
|
//}
|
|
}*/
|
|
|
|
/*
|
|
----------------------------------------------
|
|
TETRION
|
|
----------------------------------------------
|
|
*/
|
|
|
|
#define TETRION_SPREAD 275
|
|
#define NUM_TETRION_SHOTS 3
|
|
|
|
#define TETRION_ALT_VELOCITY 500000 //RPG-X: J2J - increased velocity to 1/2 million units/second
|
|
#define TETRION_ALT_SIZE 6
|
|
|
|
#define MAXRANGE_TETRION 5000000 //RPG-X: J2J - increased range to 5 million units
|
|
|
|
typedef struct tetrionHit_s
|
|
{
|
|
gentity_t *ent;
|
|
vec3_t pos;
|
|
} tetrionHit_t;
|
|
|
|
// provide the center of the circle, a normal out from it (normalized, please), and the radius.
|
|
//out will then become a random position on the radius of the circle.
|
|
void fxRandCircumferencePos(vec3_t center, vec3_t normal, float radius, vec3_t out)
|
|
{
|
|
float rnd = flrandom(0, 2*M_PI);
|
|
float s = sin(rnd);
|
|
float c = cos(rnd);
|
|
vec3_t vTemp, radialX, radialY;
|
|
|
|
vTemp[0]=0;
|
|
vTemp[1]=0;
|
|
vTemp[2]=-1;
|
|
CrossProduct(normal, vTemp, radialX);
|
|
CrossProduct(normal, radialX, radialY);
|
|
VectorScale(radialX, radius, radialX);
|
|
VectorScale(radialY, radius, radialY);
|
|
VectorMA(center, s, radialX, out);
|
|
VectorMA(out, c, radialY, out);
|
|
}
|
|
#define NUM_TETRION_BULLETS 3
|
|
//---------------------------------------------------------
|
|
void FireTetrionBullet( gentity_t *ent, vec3_t start, vec3_t dir )
|
|
//---------------------------------------------------------
|
|
{
|
|
gentity_t *tent = NULL;
|
|
trace_t tr;
|
|
vec3_t end, lup = {0,0,1}, lright; // , zero = {0,0,0};
|
|
int i = 0, j = 0;
|
|
qboolean bHitAlready = qfalse;
|
|
int numHits = 0;
|
|
tetrionHit_t hitEnts[NUM_TETRION_BULLETS];
|
|
|
|
|
|
vec3_t new_start, radial, start2, spreadFwd;
|
|
float firingRadius = 6, minDeviation = 0.95, maxDeviation = 1.1;
|
|
|
|
for (i = 0; i < NUM_TETRION_BULLETS; i++)
|
|
{
|
|
hitEnts[i].ent = NULL;
|
|
}
|
|
// create our message-entity with the firing position for an origin
|
|
tent = G_TempEntity(muzzle, EV_TETRION);
|
|
// stash our firing direction in the message also
|
|
VectorCopy(forward, tent->s.angles2);
|
|
VectorShort(tent->s.angles2);
|
|
|
|
// now do the damage. we're going to fake three separate bullets here by doing three
|
|
//traces and splitting two or three hits worth of dmg between whatever the traces hit.
|
|
CrossProduct(forward, lup, lright);
|
|
CrossProduct(lright, forward, up); // get a "real" up
|
|
|
|
for (i = 0; i < NUM_TETRION_BULLETS; i++)
|
|
{
|
|
// determine new firing position
|
|
fxRandCircumferencePos(start, forward, firingRadius, new_start);
|
|
VectorSubtract(new_start, start, radial);
|
|
VectorMA(start, 10, forward, start2);
|
|
VectorMA(start2, flrandom(minDeviation, maxDeviation), radial, start2);
|
|
VectorSubtract(start2, new_start, spreadFwd);
|
|
VectorNormalize(spreadFwd);
|
|
// determine new end position for this bullet. give the endpoint some spread, too.
|
|
VectorMA(new_start, MAXRANGE_TETRION, spreadFwd, end);
|
|
trap_Trace ( &tr, new_start, NULL, NULL, end, ent->s.number, MASK_SHOT);
|
|
if ((tr.entityNum < MAX_GENTITIES) && (tr.entityNum != ENTITYNUM_WORLD))
|
|
{
|
|
bHitAlready = qfalse;
|
|
for (j = 0; j < numHits; j++)
|
|
{
|
|
if (hitEnts[j].ent == &g_entities[ tr.entityNum ])
|
|
{
|
|
// already hit this ent
|
|
bHitAlready = qtrue;
|
|
break;
|
|
}
|
|
}
|
|
if (!bHitAlready)
|
|
{
|
|
hitEnts[numHits].ent = &g_entities[ tr.entityNum ];
|
|
VectorCopy(tr.endpos, hitEnts[numHits].pos);
|
|
numHits++;
|
|
}
|
|
}
|
|
}
|
|
if (numHits)
|
|
{
|
|
// determine damage (2 or 3 bullets)
|
|
float totalDmg = (float)(irandom(2,3)*TETRION_DAMAGE*s_quadFactor), dmgPerHit = 0;
|
|
|
|
dmgPerHit = (int)(totalDmg/(float)numHits);
|
|
for (i = 0; i < numHits; i++)
|
|
{
|
|
if (hitEnts[i].ent->takedamage)
|
|
{
|
|
G_Damage( hitEnts[i].ent, ent, ent, forward, hitEnts[i].pos, dmgPerHit,
|
|
DAMAGE_ARMOR_PIERCING|DAMAGE_NO_KNOCKBACK, MOD_TETRION );
|
|
}
|
|
// log hit
|
|
/*if (ent->client)
|
|
{
|
|
ent->client->ps.persistant[PERS_ACCURACY_HITS]++;
|
|
}*/
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void FireTetrionProjectile( gentity_t *ent, vec3_t start, vec3_t dir )
|
|
//---------------------------------------------------------
|
|
{// Projectile that /*bouncesoff surfaces but does not have gravity
|
|
gentity_t *bolt;
|
|
|
|
bolt = G_Spawn();
|
|
bolt->classname = "tetrion_projectile";
|
|
bolt->nextthink = level.time + 2000;
|
|
bolt->think = G_FreeEntity;
|
|
|
|
bolt->s.eType = ET_ALT_MISSILE;
|
|
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
|
|
//bolt->s.eFlags |= EF_BOUNCE; //RPG-X: J2J - Dont bounce anymore
|
|
//bolt->count = random() > 0.75f ? 3 : 4; //RPG-X: J2J - Number of bounces
|
|
|
|
//RPG-X: J2J - Not sure about alt size, may need tweaking
|
|
VectorSet(bolt->r.mins, -TETRION_ALT_SIZE, -TETRION_ALT_SIZE, -TETRION_ALT_SIZE);
|
|
VectorSet(bolt->r.maxs, TETRION_ALT_SIZE, TETRION_ALT_SIZE, TETRION_ALT_SIZE);
|
|
|
|
bolt->s.weapon = WP_7;
|
|
bolt->r.ownerNum = ent->s.number;
|
|
bolt->parent = ent;
|
|
bolt->damage = 300; //RPG-X: RedTechie - Use to be TETRION_ALT_DAMAGE*DMG_VAR*s_quadFactor;
|
|
bolt->splashDamage = 0;
|
|
bolt->splashRadius = 0;
|
|
bolt->methodOfDeath = MOD_TETRION_ALT;
|
|
bolt->clipmask = CONTENTS_BODY; //MASK_SHOT; MASK_ONLYPLAYER //RPG-X: J2J - Goes through all objects except players and corpses
|
|
|
|
bolt->s.pos.trType = TR_LINEAR;
|
|
bolt->s.pos.trTime = level.time; // move a bit on the very first frame
|
|
VectorCopy( start, bolt->s.pos.trBase );
|
|
SnapVector( bolt->s.pos.trBase ); // save net bandwidth
|
|
VectorScale( dir, TETRION_ALT_VELOCITY, bolt->s.pos.trDelta );
|
|
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
|
|
VectorCopy (start, bolt->r.currentOrigin);
|
|
}
|
|
|
|
|
|
|
|
|
|
void WP_FireBorgWeapon( gentity_t *ent, qboolean alt_fire )
|
|
//---------------------------------------------------------
|
|
{
|
|
if ( alt_fire )
|
|
{
|
|
WP_FireBorgTaser( ent );
|
|
}
|
|
else
|
|
{
|
|
WP_FireBorgProjectile( ent, muzzle );
|
|
}
|
|
|
|
G_LogWeaponFire( ent->s.number, WP_11 );
|
|
}
|
|
|
|
//TiM
|
|
// Alt-fire...
|
|
//---------------------------------------------------------
|
|
/*void FireScavengerGrenade( gentity_t *ent, vec3_t start, vec3_t dir )
|
|
//---------------------------------------------------------
|
|
{
|
|
gentity_t *grenade;
|
|
|
|
grenade = G_Spawn();
|
|
|
|
grenade->classname = "scav_grenade";
|
|
grenade->nextthink = level.time + 9000;
|
|
grenade->think = G_FreeEntity;
|
|
grenade->s.eType = ET_ALT_MISSILE;
|
|
grenade->s.weapon = WP_4;
|
|
grenade->r.ownerNum = ent->s.number;
|
|
grenade->parent = ent;
|
|
grenade->damage = SCAV_ALT_DAMAGE*DMG_VAR*s_quadFactor;
|
|
grenade->splashDamage = SCAV_ALT_SPLASH_DAM*s_quadFactor;
|
|
grenade->splashRadius = SCAV_ALT_SPLASH_RAD;// *s_quadFactor;
|
|
grenade->methodOfDeath = MOD_SCAVENGER_ALT;
|
|
grenade->splashMethodOfDeath = MOD_SCAVENGER_ALT_SPLASH;
|
|
grenade->clipmask = MASK_SHOT;
|
|
grenade->s.eFlags |= EF_ALT_FIRING;
|
|
|
|
// Set the size of the missile up
|
|
VectorSet(grenade->r.maxs, SCAV_ALT_SIZE, SCAV_ALT_SIZE, SCAV_ALT_SIZE);
|
|
VectorSet(grenade->r.mins, -SCAV_ALT_SIZE, -SCAV_ALT_SIZE, -SCAV_ALT_SIZE);
|
|
|
|
grenade->s.pos.trType = TR_GRAVITY;
|
|
grenade->s.pos.trTime = level.time; // move a bit on the very first frame
|
|
|
|
VectorCopy( start, grenade->s.pos.trBase );
|
|
SnapVector( grenade->s.pos.trBase ); // save net bandwidth
|
|
VectorScale( dir, random() * 100 + SCAV_ALT_VELOCITY, grenade->s.pos.trDelta );
|
|
|
|
// Add a tad of upwards velocity to the shot.
|
|
grenade->s.pos.trDelta[2] += SCAV_ALT_UP_VELOCITY;
|
|
|
|
// Add in half the player's velocity to the shot.
|
|
VectorMA(grenade->s.pos.trDelta, 0.5, ent->s.pos.trDelta, grenade->s.pos.trDelta);
|
|
|
|
SnapVector( grenade->s.pos.trDelta ); // save net bandwidth
|
|
VectorCopy (start, grenade->r.currentOrigin);
|
|
VectorCopy (start, grenade->pos1);
|
|
VectorCopy (start, grenade->s.origin2);
|
|
SnapVector( grenade->s.origin2 ); // save net bandwidth
|
|
}*/
|
|
|
|
//TiM
|
|
//---------------------------------------------------------
|
|
/*void WP_FireScavenger( gentity_t *ent, qboolean alt_fire )
|
|
//---------------------------------------------------------
|
|
{
|
|
vec3_t dir, angles, temp_ang, temp_org;
|
|
vec3_t start;
|
|
float offset;
|
|
|
|
VectorCopy( forward, dir );
|
|
VectorCopy( muzzle, start );
|
|
|
|
if ( alt_fire )
|
|
{
|
|
FireScavengerGrenade( ent, start, dir );
|
|
}
|
|
else
|
|
{
|
|
vectoangles( dir, angles );
|
|
VectorSet( temp_ang, angles[0] + (crandom() * SCAV_SPREAD), angles[1] + (crandom() * SCAV_SPREAD), angles[2] );
|
|
AngleVectors( temp_ang, dir, NULL, NULL );
|
|
|
|
// try to make the shot alternate between barrels
|
|
offset = irandom(0, 1) * 2 + 1;
|
|
|
|
// FIXME: These offsets really don't work like they should
|
|
VectorMA( start, offset, right, temp_org );
|
|
VectorMA( temp_org, offset, up, temp_org );
|
|
FireScavengerBullet( ent, temp_org, dir );
|
|
}
|
|
|
|
G_LogWeaponFire(ent->s.number, WP_4);
|
|
}*/
|
|
|
|
void FireSeeker( gentity_t *owner, gentity_t *target, vec3_t origin)
|
|
{
|
|
vec3_t dir;
|
|
|
|
VectorSubtract( target->r.currentOrigin, origin, dir);
|
|
VectorNormalize(dir);
|
|
|
|
// for now I'm just using the scavenger bullet.
|
|
FireScavengerBullet( owner, origin, dir );
|
|
}
|
|
|
|
//TiM
|
|
//---------------------------------------------------------
|
|
void FireScavengerBullet( gentity_t *ent, vec3_t start, vec3_t dir )
|
|
//---------------------------------------------------------
|
|
{
|
|
gentity_t *bolt;
|
|
|
|
bolt = G_Spawn();
|
|
|
|
bolt->classname = "scav_proj";
|
|
bolt->nextthink = level.time + 10000;
|
|
bolt->think = G_FreeEntity;
|
|
bolt->s.eType = ET_MISSILE;
|
|
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
|
|
//bolt->s.weapon = WP_4;
|
|
bolt->s.weapon = WP_10; //TiM
|
|
bolt->r.ownerNum = ent->s.number;
|
|
bolt->parent = ent;
|
|
|
|
//fixme - remove
|
|
{
|
|
// Flags effect as being the full beefy version for the player
|
|
bolt->count = 0;
|
|
}
|
|
|
|
bolt->damage = SCAV_DAMAGE*DMG_VAR*s_quadFactor;
|
|
bolt->splashDamage = 0;
|
|
bolt->splashRadius = 0;
|
|
bolt->methodOfDeath = MOD_SCAVENGER;
|
|
bolt->clipmask = MASK_SHOT;
|
|
|
|
// Set the size of the missile up
|
|
VectorSet(bolt->r.maxs, SCAV_SIZE, SCAV_SIZE, SCAV_SIZE);
|
|
VectorSet(bolt->r.mins, -SCAV_SIZE, -SCAV_SIZE, -SCAV_SIZE);
|
|
|
|
bolt->s.pos.trType = TR_LINEAR;
|
|
bolt->s.pos.trTime = level.time - 10; // move a bit on the very first frame
|
|
VectorCopy( start, bolt->s.pos.trBase );
|
|
SnapVector( bolt->s.pos.trBase ); // save net bandwidth
|
|
VectorScale( dir, SCAV_VELOCITY, bolt->s.pos.trDelta );
|
|
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
|
|
VectorCopy( start, bolt->r.currentOrigin);
|
|
}
|
|
|
|
/*
|
|
----------------------------------------------
|
|
IMOD
|
|
----------------------------------------------
|
|
*/
|
|
|
|
#define MAXRANGE_IMOD 4096
|
|
#define MAX_RAIL_HITS 4
|
|
|
|
void IMODHit(qboolean alt_fire, gentity_t *traceEnt, gentity_t *ent, vec3_t d_dir, vec3_t endpos, vec3_t normal,
|
|
qboolean render_impact)
|
|
{
|
|
gentity_t *tent = NULL;
|
|
int damage = IMOD_ALT_DAMAGE*DMG_VAR;
|
|
|
|
if ( alt_fire )
|
|
{
|
|
// send beam impact
|
|
if ( traceEnt && traceEnt->takedamage )
|
|
{
|
|
G_Damage( traceEnt, ent, ent, d_dir, endpos, damage, DAMAGE_NO_ARMOR | DAMAGE_NO_INVULNERABILITY, MOD_IMOD_ALT);
|
|
if (render_impact)
|
|
{
|
|
tent = G_TempEntity( endpos, EV_IMOD_ALTFIRE_HIT );
|
|
}
|
|
// log hit
|
|
/*if (ent->client)
|
|
{
|
|
ent->client->ps.persistant[PERS_ACCURACY_HITS]++;
|
|
}*/
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// send beam impact
|
|
if ( traceEnt && traceEnt->takedamage && rpg_imoddmg.integer != 0)
|
|
{
|
|
G_Damage( traceEnt, ent, ent, d_dir, endpos, damage, DAMAGE_NO_ARMOR | DAMAGE_NO_INVULNERABILITY, MOD_IMOD);
|
|
if (render_impact)
|
|
{
|
|
tent = G_TempEntity( endpos, EV_IMOD_HIT );
|
|
}
|
|
// log hit
|
|
/*if (ent->client)
|
|
{
|
|
ent->client->ps.persistant[PERS_ACCURACY_HITS]++;
|
|
}*/
|
|
}
|
|
}
|
|
if (tent)
|
|
{
|
|
tent->s.eventParm = DirToByte( normal );
|
|
tent->s.weapon = ent->s.weapon;
|
|
VectorCopy( muzzle, tent->s.origin2 );
|
|
SnapVector(tent->s.origin2);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
/*void WP_FireIMOD ( gentity_t *ent, qboolean alt_fire )
|
|
//---------------------------------------------------------
|
|
{
|
|
int i = 0;
|
|
int hits = 0;
|
|
int unlinked = 0;
|
|
gentity_t *unlinkedEntities[MAX_RAIL_HITS];
|
|
|
|
trace_t tr;
|
|
vec3_t end, d_dir;
|
|
gentity_t *tent = 0;
|
|
gentity_t *traceEnt = NULL;
|
|
qboolean render_impact;
|
|
|
|
VectorMA (muzzle, MAXRANGE_IMOD, forward, end);
|
|
|
|
// trace only against the solids, so the railgun will go through people
|
|
do
|
|
{
|
|
trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
|
|
traceEnt = &g_entities[ tr.entityNum ];
|
|
if ( tr.surfaceFlags & SURF_NOIMPACT )
|
|
{ // If the beam hit the skybox, etc. it would look foolish to add in an explosion
|
|
render_impact = qfalse;
|
|
} else
|
|
{
|
|
render_impact = qtrue;
|
|
}
|
|
if ( traceEnt->takedamage )
|
|
{
|
|
if( LogAccuracyHit( traceEnt, ent ) )
|
|
{
|
|
hits++;
|
|
}
|
|
//For knockback - send them up in air
|
|
VectorCopy(forward, d_dir);
|
|
if(d_dir[2] < 0.30f)
|
|
{
|
|
d_dir[2] = 0.30f;
|
|
}
|
|
VectorNormalize(d_dir);
|
|
// do the damage and send an impact effect
|
|
IMODHit(alt_fire, traceEnt, ent, d_dir, tr.endpos, tr.plane.normal, qtrue);
|
|
|
|
// give the shooter a reward sound if they have made two sniper hits in a row
|
|
// check for "impressive" reward sound
|
|
// Note that hitting two people in a line warrants an "impressive" as well...
|
|
if (traceEnt->client)
|
|
{
|
|
if (((g_gametype.integer >= GT_TEAM) && (ent->client->ps.persistant[PERS_TEAM] != traceEnt->client->ps.persistant[PERS_TEAM]))
|
|
|| (g_gametype.integer < GT_TEAM))
|
|
{
|
|
if (alt_fire)
|
|
{
|
|
ent->client->accurateCount++;
|
|
if ( ent->client->accurateCount >= 2 )
|
|
{
|
|
ent->client->accurateCount -= 2;
|
|
ent->client->ps.persistant[PERS_REWARD_COUNT]++;
|
|
ent->client->ps.persistant[PERS_REWARD] = REWARD_IMPRESSIVE;
|
|
ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
|
|
// add the sprite over the player's head
|
|
ent->client->ps.eFlags &= ~EF_AWARD_MASK;
|
|
ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE;
|
|
ent->client->rewardTime = level.time + REWARD_SPRITE_TIME;
|
|
} // End of brace
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ // send an impact effect
|
|
IMODHit(alt_fire, traceEnt, ent, d_dir, tr.endpos, tr.plane.normal, render_impact);
|
|
}
|
|
if ( tr.contents & CONTENTS_SOLID )
|
|
{
|
|
break; // we hit something solid enough to stop the beam
|
|
}
|
|
// unlink this entity, so the next trace will go past it
|
|
trap_UnlinkEntity( traceEnt );
|
|
unlinkedEntities[unlinked] = traceEnt;
|
|
unlinked++;
|
|
} while ( unlinked < MAX_RAIL_HITS );
|
|
|
|
// link back in any entities we unlinked
|
|
for ( i = 0 ; i < unlinked ; i++ )
|
|
{
|
|
trap_LinkEntity( unlinkedEntities[i] );
|
|
}
|
|
|
|
// With endcapping on, the beam is actually longer than what the length parm in FX_AddLine for this
|
|
// effect specifies..so move it out so it doesn't clip into the gun so much
|
|
if ( alt_fire )
|
|
VectorMA (muzzle, 10, forward, muzzle);
|
|
else
|
|
VectorMA (muzzle, 2, forward, muzzle);
|
|
|
|
// Create the events that will add in the necessary effects
|
|
if ( alt_fire )
|
|
{
|
|
tent = G_TempEntity( tr.endpos, EV_IMOD_ALTFIRE );
|
|
}
|
|
else
|
|
{
|
|
tent = G_TempEntity( tr.endpos, EV_IMOD );
|
|
}
|
|
|
|
// Stash origins, etc. so the effect can have access to them
|
|
VectorCopy( muzzle, tent->s.origin2 );
|
|
SnapVector( tent->s.origin2 ); // save net bandwidth
|
|
if ( render_impact )
|
|
{
|
|
tent->s.eventParm = DirToByte( tr.plane.normal );
|
|
tent->s.weapon = ent->s.weapon;
|
|
}
|
|
|
|
G_LogWeaponFire(ent->s.number, WP_1);
|
|
//G_LogWeaponFire(ent->s.number, WP_1);
|
|
}*/
|
|
|
|
#define SEEKER_RADIUS 500
|
|
qboolean SeekerAcquiresTarget ( gentity_t *ent, vec3_t pos )
|
|
{
|
|
vec3_t seekerPos;
|
|
float angle;
|
|
int entityList[MAX_CLIENTS]; // targets within inital radius
|
|
int visibleTargets[MAX_CLIENTS]; // final filtered target list
|
|
int numListedEntities;
|
|
int i, e;
|
|
gentity_t *target;
|
|
vec3_t mins, maxs;
|
|
|
|
// if (!irandom(0,2)) for now, it'll shoot every second it finds a target
|
|
{
|
|
angle = level.time/100.0f;
|
|
seekerPos[0] = ent->r.currentOrigin[0] + 18 * cos(angle);
|
|
seekerPos[1] = ent->r.currentOrigin[1] + 18 * sin(angle);
|
|
seekerPos[2] = ent->r.currentOrigin[2] + ent->client->ps.viewheight + 8 + (3*cos(level.time/150.0f));
|
|
|
|
for ( i = 0 ; i < 3 ; i++ )
|
|
{
|
|
mins[i] = seekerPos[i] - SEEKER_RADIUS;
|
|
maxs[i] = seekerPos[i] + SEEKER_RADIUS;
|
|
}
|
|
|
|
// get potential targets within radius
|
|
numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
|
|
|
|
i = 0; // reset counter
|
|
|
|
for ( e = 0 ; e < numListedEntities ; e++ )
|
|
{
|
|
target = &g_entities[entityList[ e ]];
|
|
// seeker owner not a valid target
|
|
if (target == ent)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// only players are valid targets
|
|
if (!target->classname || strcmp(target->classname, "player"))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// teammates not valid targets
|
|
if (OnSameTeam(ent, target))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// don't shoot at dead things
|
|
if (target->health <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
//RPG-X: RedTechie - Need to take this out causes bad crashes with entity shooter, shouldent be needed anyway with newer code
|
|
//target->beingfiredby = ent;
|
|
if( CanDamage (target, seekerPos) ) // visible target, so add it to the list
|
|
{
|
|
visibleTargets[i++] = entityList[e];
|
|
}
|
|
}
|
|
|
|
if (i)
|
|
{
|
|
// ok, now we know there are i visible targets. Pick one as the seeker's target
|
|
ent->enemy = &g_entities[visibleTargets[irandom(0,i-1)]];
|
|
VectorCopy(seekerPos, pos);
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
return qfalse;
|
|
}
|