rpg-x2/old_code/g_weapon.c

1129 lines
31 KiB
C
Raw Normal View History

/*
----------------------------------------------
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;
}