q3rally/engine/code/game/g_weapon.c

1586 lines
41 KiB
C
Raw Normal View History

2011-02-18 14:31:32 +00:00
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
2021-03-24 20:13:01 +00:00
Copyright (C) 2002-2021 Q3Rally Team (Per Thormann - q3rally@gmail.com)
2011-02-18 14:31:32 +00:00
This file is part of q3rally source code.
q3rally source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
q3rally source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with q3rally; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// g_weapon.c
// perform the server side effects of a weapon firing
#include "g_local.h"
static float s_quadFactor;
2011-02-18 14:31:32 +00:00
vec3_t forward, right, up;
2011-02-18 14:31:32 +00:00
static vec3_t muzzle;
#define NUM_NAILSHOTS 15
/*
================
G_BounceProjectile
================
*/
void G_BounceProjectile( vec3_t start, vec3_t impact, vec3_t dir, vec3_t endout ) {
vec3_t v, newv;
float dot;
VectorSubtract( impact, start, v );
dot = DotProduct( v, dir );
VectorMA( v, -2*dot, dir, newv );
VectorNormalize(newv);
VectorMA(impact, 8192, newv, endout);
}
/*
======================================================================
GAUNTLET
======================================================================
*/
void Weapon_Gauntlet( gentity_t *ent ) {
}
/*
===============
CheckGauntletAttack
===============
*/
qboolean CheckGauntletAttack( gentity_t *ent ) {
trace_t tr;
vec3_t end;
gentity_t *tent;
gentity_t *traceEnt;
int damage;
// set aiming directions
AngleVectors (ent->client->ps.viewangles, forward, right, up);
CalcMuzzlePoint ( ent, forward, right, up, muzzle );
2011-02-18 14:31:32 +00:00
VectorMA (muzzle, CAR_LENGTH/2, forward, end);
2011-02-18 14:31:32 +00:00
trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT);
if ( tr.surfaceFlags & SURF_NOIMPACT ) {
return qfalse;
}
if ( ent->client->noclip ) {
return qfalse;
}
2011-02-18 14:31:32 +00:00
if (g_entities[ tr.entityNum ].flags & FL_EXTRA_BBOX)
traceEnt = &g_entities[ g_entities[ tr.entityNum ].r.ownerNum ];
else
traceEnt = &g_entities[ tr.entityNum ];
2011-02-18 14:31:32 +00:00
// send blood impact
if ( traceEnt->takedamage && traceEnt->client ) {
tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
tent->s.otherEntityNum = traceEnt->s.number;
tent->s.eventParm = DirToByte( tr.plane.normal );
tent->s.weapon = ent->s.weapon;
}
if ( !traceEnt->takedamage) {
return qfalse;
}
if (ent->client->ps.powerups[PW_QUAD] ) {
G_AddEvent( ent, EV_POWERUP_QUAD, 0 );
s_quadFactor = g_quadfactor.value;
} else {
s_quadFactor = 1;
}
#ifdef MISSIONPACK
if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
s_quadFactor *= 2;
}
#endif
2023-03-02 20:44:38 +00:00
2011-02-18 14:31:32 +00:00
damage = 50 * s_quadFactor;
2023-03-02 20:44:38 +00:00
G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_WEAPON, MOD_GAUNTLET );
2011-02-18 14:31:32 +00:00
return qtrue;
}
//Q3Rally Code Start
/*
=======================================================================
FLAME THROWER
=======================================================================
*/
void Weapon_fire_flame (gentity_t *ent ) {
gentity_t *m;
m = fire_flame(ent, muzzle, forward);
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
}
/*
=======================================================================
FLAME THROWER SPREAD - Altfire
2011-02-18 14:31:32 +00:00
=======================================================================
*/
2011-02-18 14:31:32 +00:00
void Weapon_cluster_fire_flame (gentity_t *ent ) {
gentity_t *m, *n, *o;
vec3_t temp;
m = fire_cluster_flame(ent, muzzle, forward);
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
VectorAdd(forward, right, temp);
n = fire_cluster_flame(ent, muzzle, temp);
n->damage *= s_quadFactor;
n->splashDamage *= s_quadFactor;
VectorInverse(right);
VectorAdd(forward, right, temp);
o = fire_cluster_flame(ent, muzzle, temp);
o->damage *= s_quadFactor;
o->splashDamage *= s_quadFactor;
}
2011-02-18 14:31:32 +00:00
/*
======================================================================
MACHINEGUN
======================================================================
*/
/*
======================
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] = floor(v[i]);
2011-02-18 14:31:32 +00:00
} else {
v[i] = ceil(v[i]);
2011-02-18 14:31:32 +00:00
}
}
}
#ifdef MISSIONPACK
#define CHAINGUN_SPREAD 600
#define CHAINGUN_DAMAGE 7
2011-02-18 14:31:32 +00:00
#endif
#define MACHINEGUN_SPREAD 200
#define MACHINEGUN_DAMAGE 7
#define MACHINEGUN_TEAM_DAMAGE 5 // wimpier MG in teamplay
void Bullet_Fire (gentity_t *ent, float spread, int damage, int mod ) {
2011-02-18 14:31:32 +00:00
trace_t tr;
vec3_t end;
#ifdef MISSIONPACK
vec3_t impactpoint, bouncedir;
#endif
float r;
float u;
gentity_t *tent;
gentity_t *traceEnt;
int i, passent;
damage *= s_quadFactor;
r = random() * M_PI * 2.0f;
u = sin(r) * crandom() * spread * 16;
r = cos(r) * crandom() * spread * 16;
VectorMA (muzzle, 8192*16, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
passent = ent->s.number;
for (i = 0; i < 10; i++) {
2011-02-18 14:31:32 +00:00
trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT);
// trap_Trace (&tr, muzzle, NULL, NULL, end, ENTITYNUM_NONE, MASK_SHOT);
2011-02-18 14:31:32 +00:00
if ( tr.surfaceFlags & SURF_NOIMPACT ) {
return;
}
if (g_entities[ tr.entityNum ].flags & FL_EXTRA_BBOX)
2011-02-18 14:31:32 +00:00
traceEnt = &g_entities[ g_entities[ tr.entityNum ].r.ownerNum ];
else
2011-02-18 14:31:32 +00:00
traceEnt = &g_entities[ tr.entityNum ];
2011-02-18 14:31:32 +00:00
// snap the endpos to integers, but nudged towards the line
SnapVectorTowards( tr.endpos, muzzle );
// send bullet impact
if ( traceEnt->takedamage && traceEnt->client ) {
tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
tent->s.eventParm = traceEnt->s.number;
if( LogAccuracyHit( traceEnt, ent ) ) {
ent->client->accuracy_hits++;
}
} else {
tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );
tent->s.eventParm = DirToByte( tr.plane.normal );
}
tent->s.otherEntityNum = ent->s.number;
if ( traceEnt->takedamage) {
#ifdef MISSIONPACK
if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
VectorCopy( impactpoint, muzzle );
// the player can hit him/herself with the bounced rail
passent = ENTITYNUM_NONE;
}
else {
VectorCopy( tr.endpos, muzzle );
passent = traceEnt->s.number;
}
continue;
}
else {
#endif
G_Damage( traceEnt, ent, ent, forward, tr.endpos,
damage, DAMAGE_WEAPON, mod);
2011-02-18 14:31:32 +00:00
#ifdef MISSIONPACK
}
#endif
}
break;
}
}
/*
======================================================================
BFG
======================================================================
*/
void BFG_Fire ( gentity_t *ent ) {
gentity_t *m;
m = fire_bfg (ent, muzzle, forward);
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
}
/*
======================================================================
SHOTGUN
======================================================================
*/
// DEFAULT_SHOTGUN_SPREAD and DEFAULT_SHOTGUN_COUNT are in bg_public.h, because
// client predicts same spreads
#define DEFAULT_SHOTGUN_DAMAGE 10
qboolean ShotgunPellet( vec3_t start, vec3_t end, gentity_t *ent ) {
trace_t tr;
int damage, i, passent;
gentity_t *traceEnt;
#ifdef MISSIONPACK
vec3_t impactpoint, bouncedir;
#endif
vec3_t tr_start, tr_end;
ioquake3 resync to revision 3385 from 3347. Fix going to previous browser source in q3_ui Limit ui_smallFont/ui_bigFont/cg_noTaunt cvars to missionpack Fix team chat box for spectators Don't draw crosshair 0 in Team Arena setup menu Make client for Windows x86_64 use OpenAL64.dll by default Fix loading renderer DLLs on Windows x86 Add Windows application manifest Disable DPI scaling on Windows ignore window resize event on fullscreen Don't reload arenas.txt/*.arena files in Team Arena UI Fix crash when out of memory in Team Arena's String_Alloc Fix in_nograb not releasing the mouse cursor Update UI player animation handling to match CGame Fix specifying minimum mac os version in make-macosx.sh Fix listen server sending snapshots each client frame Statically link libgcc on Windows Fix hit accuracy stats for lightning gun and shotgun kills Don't link to libGL at compile time Add common OpenGL version parsing + OpenGL 3 fixes Support parsing OpenGL ES version strings Fix setting cflags/libs from sdl2-config Load OpenGL ES 1.1 function procs [qcommon] Use unsigned types where wrapping arithmetic is intended OpenGL2: Fix brightness when r_autoExposure is disabled OpenGL2: Fix MD3 surface with zero shaders dividing by zero [botlib/be_aas_def.h] Change array size from MAX_PATH to MAX_QPATH Don't redefine MAX_PATH in bot code Fix memory leak in (unused) AAS_FloodAreas() Fix compiling GLSL shaders under Windows. Only draw cm_patch/bot debug polygons in world scenes Fix reading crash log when log wraps around buffer Don't send team overlay info to bots Fix a race condition in the makedirs target Fix shader corruption on OpenBSD
2017-11-04 11:30:30 +00:00
qboolean hitClient = qfalse;
2011-02-18 14:31:32 +00:00
passent = ent->s.number;
VectorCopy( start, tr_start );
VectorCopy( end, tr_end );
for (i = 0; i < 10; i++) {
trap_Trace (&tr, tr_start, NULL, NULL, tr_end, passent, MASK_SHOT);
2011-02-18 14:31:32 +00:00
if (g_entities[ tr.entityNum ].flags & FL_EXTRA_BBOX)
traceEnt = &g_entities[ g_entities[ tr.entityNum ].r.ownerNum ];
else
traceEnt = &g_entities[ tr.entityNum ];
2011-02-18 14:31:32 +00:00
// send bullet impact
if ( tr.surfaceFlags & SURF_NOIMPACT ) {
return qfalse;
}
if ( traceEnt->takedamage) {
damage = DEFAULT_SHOTGUN_DAMAGE * s_quadFactor;
#ifdef MISSIONPACK
if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
G_BounceProjectile( tr_start, impactpoint, bouncedir, tr_end );
VectorCopy( impactpoint, tr_start );
// the player can hit him/herself with the bounced rail
passent = ENTITYNUM_NONE;
}
else {
VectorCopy( tr.endpos, tr_start );
passent = traceEnt->s.number;
}
continue;
}
ioquake3 resync to revision 3385 from 3347. Fix going to previous browser source in q3_ui Limit ui_smallFont/ui_bigFont/cg_noTaunt cvars to missionpack Fix team chat box for spectators Don't draw crosshair 0 in Team Arena setup menu Make client for Windows x86_64 use OpenAL64.dll by default Fix loading renderer DLLs on Windows x86 Add Windows application manifest Disable DPI scaling on Windows ignore window resize event on fullscreen Don't reload arenas.txt/*.arena files in Team Arena UI Fix crash when out of memory in Team Arena's String_Alloc Fix in_nograb not releasing the mouse cursor Update UI player animation handling to match CGame Fix specifying minimum mac os version in make-macosx.sh Fix listen server sending snapshots each client frame Statically link libgcc on Windows Fix hit accuracy stats for lightning gun and shotgun kills Don't link to libGL at compile time Add common OpenGL version parsing + OpenGL 3 fixes Support parsing OpenGL ES version strings Fix setting cflags/libs from sdl2-config Load OpenGL ES 1.1 function procs [qcommon] Use unsigned types where wrapping arithmetic is intended OpenGL2: Fix brightness when r_autoExposure is disabled OpenGL2: Fix MD3 surface with zero shaders dividing by zero [botlib/be_aas_def.h] Change array size from MAX_PATH to MAX_QPATH Don't redefine MAX_PATH in bot code Fix memory leak in (unused) AAS_FloodAreas() Fix compiling GLSL shaders under Windows. Only draw cm_patch/bot debug polygons in world scenes Fix reading crash log when log wraps around buffer Don't send team overlay info to bots Fix a race condition in the makedirs target Fix shader corruption on OpenBSD
2017-11-04 11:30:30 +00:00
#endif
if( LogAccuracyHit( traceEnt, ent ) ) {
hitClient = qtrue;
2011-02-18 14:31:32 +00:00
}
G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_WEAPON, MOD_SHOTGUN);
ioquake3 resync to revision 3385 from 3347. Fix going to previous browser source in q3_ui Limit ui_smallFont/ui_bigFont/cg_noTaunt cvars to missionpack Fix team chat box for spectators Don't draw crosshair 0 in Team Arena setup menu Make client for Windows x86_64 use OpenAL64.dll by default Fix loading renderer DLLs on Windows x86 Add Windows application manifest Disable DPI scaling on Windows ignore window resize event on fullscreen Don't reload arenas.txt/*.arena files in Team Arena UI Fix crash when out of memory in Team Arena's String_Alloc Fix in_nograb not releasing the mouse cursor Update UI player animation handling to match CGame Fix specifying minimum mac os version in make-macosx.sh Fix listen server sending snapshots each client frame Statically link libgcc on Windows Fix hit accuracy stats for lightning gun and shotgun kills Don't link to libGL at compile time Add common OpenGL version parsing + OpenGL 3 fixes Support parsing OpenGL ES version strings Fix setting cflags/libs from sdl2-config Load OpenGL ES 1.1 function procs [qcommon] Use unsigned types where wrapping arithmetic is intended OpenGL2: Fix brightness when r_autoExposure is disabled OpenGL2: Fix MD3 surface with zero shaders dividing by zero [botlib/be_aas_def.h] Change array size from MAX_PATH to MAX_QPATH Don't redefine MAX_PATH in bot code Fix memory leak in (unused) AAS_FloodAreas() Fix compiling GLSL shaders under Windows. Only draw cm_patch/bot debug polygons in world scenes Fix reading crash log when log wraps around buffer Don't send team overlay info to bots Fix a race condition in the makedirs target Fix shader corruption on OpenBSD
2017-11-04 11:30:30 +00:00
return hitClient;
2011-02-18 14:31:32 +00:00
}
return qfalse;
}
return qfalse;
}
// this should match CG_ShotgunPattern
void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) {
int i;
float r, u;
vec3_t end;
vec3_t forward, right, up;
qboolean hitClient = qfalse;
// derive the right and up vectors from the forward vector, because
// the client won't have any other information
VectorNormalize2( origin2, forward );
PerpendicularVector( right, forward );
CrossProduct( forward, right, up );
// generate the "random" spread pattern
for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
VectorMA( origin, 8192 * 16, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
if( ShotgunPellet( origin, end, ent ) && !hitClient ) {
hitClient = qtrue;
ent->client->accuracy_hits++;
}
}
}
void weapon_supershotgun_fire (gentity_t *ent) {
gentity_t *tent;
// send shotgun blast
tent = G_TempEntity( muzzle, EV_SHOTGUN );
VectorScale( forward, 4096, tent->s.origin2 );
SnapVector( tent->s.origin2 );
tent->s.eventParm = rand() & 255; // seed for spread pattern
tent->s.otherEntityNum = ent->s.number;
ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent );
}
/*
======================================================================
GRENADE LAUNCHER
2011-02-18 14:31:32 +00:00
======================================================================
*/
void weapon_grenadelauncher_fire (gentity_t *ent) {
gentity_t *m;
// extra vertical velocity
forward[2] += 0.2f;
2011-02-18 14:31:32 +00:00
VectorNormalize( forward );
m = fire_grenade (ent, muzzle, forward);
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
2011-02-18 14:31:32 +00:00
}
/*
======================================================================
CLUSTER GRENADE LAUNCHER - Altfire
2011-02-18 14:31:32 +00:00
======================================================================
*/
void weapon_cluster_grenadelauncher_fire (gentity_t *ent) {
gentity_t *m;
// extra vertical velocity
2021-02-19 22:13:57 +00:00
forward[2] += 0.15f;
2011-02-18 14:31:32 +00:00
VectorNormalize( forward );
m = fire_cluster_grenade (ent, muzzle, forward);
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
VectorScale(forward, 2000, m->s.pos.trDelta) ;
2023-03-02 20:44:38 +00:00
VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
2011-02-18 14:31:32 +00:00
}
/*
======================================================================
ROCKET
======================================================================
*/
void Weapon_RocketLauncher_Fire (gentity_t *ent) {
gentity_t *m;
m = fire_rocket (ent, muzzle, forward);
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
2023-03-02 20:44:38 +00:00
VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
2011-02-18 14:31:32 +00:00
}
/*
======================================================================
HOMING ROCKET - Altfire
2011-02-18 14:31:32 +00:00
======================================================================
*/
void Weapon_Homing_RocketLauncher_Fire (gentity_t *ent) {
gentity_t *m;
m = fire_homing_rocket (ent, muzzle, forward);
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
2023-03-02 20:44:38 +00:00
VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
2011-02-18 14:31:32 +00:00
}
/*
======================================================================
PLASMA GUN
======================================================================
*/
void Weapon_Plasmagun_Fire (gentity_t *ent) {
gentity_t *m;
m = fire_plasma (ent, muzzle, forward);
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
}
/*
======================================================================
PLASMA GUN - Altfire
2011-02-18 14:31:32 +00:00
======================================================================
*/
void Weapon_Plasmagun_Circular_Fire (gentity_t *ent) {
2011-03-08 09:07:05 +00:00
gentity_t *m;
// gentity_t *n;
// vec3_t temp, temp2;
2011-02-18 14:31:32 +00:00
//forward[0] += (float)sin( m->s.pos.trTime / m->s.pos.trDuration );
// temp[0] = (float) sin( level.time * 2 * 3.14 / 1000.0);
// temp[1] = 0; temp[2] = 0;
2011-02-18 14:31:32 +00:00
// temp2[0] = (float) cos( level.time * 2 * 3.14 / 1000.0);
// temp2[1] = 0; temp2[2] = 0;
2011-02-18 14:31:32 +00:00
// VectorAdd( forward, temp, temp);
// VectorAdd( right, temp2, temp2);
// VectorAdd( temp, temp2, temp2);
2011-02-18 14:31:32 +00:00
//VectorMA( m->s.pos.trBase, 100, forward, temp2);
m = fire_plasma_bounce(ent, muzzle, forward);
2011-02-18 14:31:32 +00:00
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
/*
//right[0] += (float)cos( n->s.pos.trTime / n->s.pos.trDuration );
//VectorMA(n->s.pos.trBase, 10, right, temp2);
n = fire_plasma_circular_def(ent, muzzle, temp2);
n->damage *= s_quadFactor;
n->splashDamage *= s_quadFactor;*/
//VectorCopy(forward, temp);
//temp[0] = forward[2];
//temp[2] = -forward[0];
//forward[2] -= 0.1f;
//VectorCopy(temp,forward);
//VectorNormalize(forward);
/*
m->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;
m->s.pos.trBase = 0;
m->s.pos.trDuration = 100; */
// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
}
/*
======================================================================
RAILGUN
2011-02-18 14:31:32 +00:00
======================================================================
*/
#define MAX_RAIL_HITS 4
void weapon_railgun_fire (gentity_t *ent) {
vec3_t end;
#ifdef MISSIONPACK
vec3_t impactpoint, bouncedir;
#endif
trace_t trace;
gentity_t *tent;
gentity_t *traceEnt;
int damage;
int i;
int hits;
int unlinked;
int passent;
gentity_t *unlinkedEntities[MAX_RAIL_HITS];
damage = 17 * s_quadFactor;
2011-02-18 14:31:32 +00:00
VectorMA (muzzle, 8192, forward, end);
// trace only against the solids, so the railgun will go through people
unlinked = 0;
hits = 0;
passent = ent->s.number;
do {
trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT );
if ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) {
break;
}
2011-02-18 14:31:32 +00:00
if (g_entities[ trace.entityNum ].flags & FL_EXTRA_BBOX)
traceEnt = &g_entities[ g_entities[ trace.entityNum ].r.ownerNum ];
else
traceEnt = &g_entities[ trace.entityNum ];
2011-02-18 14:31:32 +00:00
if ( traceEnt->takedamage ) {
#ifdef MISSIONPACK
if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
if ( G_InvulnerabilityEffect( traceEnt, forward, trace.endpos, impactpoint, bouncedir ) ) {
G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
// snap the endpos to integers to save net bandwidth, but nudged towards the line
SnapVectorTowards( trace.endpos, muzzle );
// send railgun beam effect
tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
// set player number for custom colors on the railtrail
tent->s.clientNum = ent->s.clientNum;
VectorCopy( muzzle, tent->s.origin2 );
// move origin a bit to come closer to the drawn gun muzzle
VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
tent->s.eventParm = 255; // don't make the explosion at the end
//
VectorCopy( impactpoint, muzzle );
// the player can hit him/herself with the bounced rail
passent = ENTITYNUM_NONE;
}
}
else {
if( LogAccuracyHit( traceEnt, ent ) ) {
hits++;
}
2011-02-18 14:31:32 +00:00
G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, DAMAGE_WEAPON, MOD_RAILGUN);
2011-02-18 14:31:32 +00:00
}
#else
if( LogAccuracyHit( traceEnt, ent ) ) {
hits++;
}
2011-02-18 14:31:32 +00:00
G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, DAMAGE_WEAPON, MOD_RAILGUN);
2011-02-18 14:31:32 +00:00
#endif
}
if ( trace.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] );
}
// the final trace endpos will be the terminal point of the rail trail
// snap the endpos to integers to save net bandwidth, but nudged towards the line
SnapVectorTowards( trace.endpos, muzzle );
// send railgun beam effect
tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
// set player number for custom colors on the railtrail
tent->s.clientNum = ent->s.clientNum;
VectorCopy( muzzle, tent->s.origin2 );
// move origin a bit to come closer to the drawn gun muzzle
VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
// no explosion at end if SURF_NOIMPACT, but still make the trail
if ( trace.surfaceFlags & SURF_NOIMPACT ) {
tent->s.eventParm = 255; // don't make the explosion at the end
} else {
tent->s.eventParm = DirToByte( trace.plane.normal );
}
tent->s.clientNum = ent->s.clientNum;
// give the shooter a reward sound if they have made two railgun hits in a row
if ( hits == 0 ) {
// complete miss
ent->client->accurateCount = 0;
} else {
// check for "impressive" reward sound
ent->client->accurateCount += hits;
if ( ent->client->accurateCount >= 6 ) {
ent->client->accurateCount -= 6;
2011-02-18 14:31:32 +00:00
ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
// add the sprite over the player's head
ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_IMPRESSIVETELEFRAG | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
2011-02-18 14:31:32 +00:00
ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE;
ent->client->rewardTime = level.time + REWARD_SPRITE_TIME;
}
ent->client->accuracy_hits++;
2011-02-18 14:31:32 +00:00
}
}
/*
======================================================================
TELEFRAG GUN - Altfire to Railgun
======================================================================
2011-02-18 14:31:32 +00:00
*/
void weapon_telefrag_fire (gentity_t *ent,vec3_t muzzle,vec3_t forward,vec3_t right,vec3_t up) {
vec3_t end;
2011-02-18 14:31:32 +00:00
trace_t trace;
gentity_t *tent;
gentity_t *traceEnt;
2022-02-14 18:19:42 +00:00
int damage = 50;
int hits = 0;
int passent = ent->s.number;
2011-02-18 14:31:32 +00:00
VectorMA (muzzle, 8192, forward, end);
// Trace the projectile
trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT );
2011-02-18 14:31:32 +00:00
// The entity is a valid entity
if ( trace.entityNum < ENTITYNUM_MAX_NORMAL ) {
2011-02-18 14:31:32 +00:00
// Who exactly is this entity (a reference to the entity structure)
if (g_entities[ trace.entityNum ].flags & FL_EXTRA_BBOX)
traceEnt = &g_entities[ g_entities[ trace.entityNum ].r.ownerNum ];
// Can this entity be damaged?
if ( traceEnt->takedamage )
{
if(LogAccuracyHit(traceEnt,ent))
{
2011-02-18 14:31:32 +00:00
hits++;
}
// It is important that all this checking is done. If you try and
// telefrag a door or a spectator, the game *will* crash.
// is the entity a client, alive and not a spectator
if((traceEnt->client) && (traceEnt->client->ps.pm_type != PM_DEAD) && (traceEnt->client->sess.sessionTeam != TEAM_SPECTATOR))
{
// if the attacker was on the same team and TF_NO_FRIENDLY_FIRE is set
// do not telefrag, just do a normal damage
if (OnSameTeam(traceEnt,ent) && (!g_friendlyFire.integer))
{
G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
// Not on same team, or on same team and can friendly fire
// Damage, then telefrag
}else{
G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
TelefragPlayer(ent, traceEnt->r.currentOrigin, traceEnt->r.currentAngles);
}
}else{
// Damage
G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
}
}
2011-02-18 14:31:32 +00:00
}
// snap the endpos to integers to save net bandwidth, but nudged towards the line
SnapVectorTowards( trace.endpos, muzzle );
// send railgun beam effect
tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
// set player number for custom colors on the railtrail
tent->s.clientNum = ent->s.clientNum;
VectorCopy( muzzle, tent->s.origin2 );
// move origin a bit to come closer to the drawn gun muzzle
VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
// no explosion at end if SURF_NOIMPACT, but still make the trail
if ( trace.surfaceFlags & SURF_NOIMPACT )
{
2011-02-18 14:31:32 +00:00
tent->s.eventParm = 255; // don't make the explosion at the end
} else {
tent->s.eventParm = DirToByte( trace.plane.normal );
}
tent->s.clientNum = ent->s.clientNum;
2022-02-14 18:19:42 +00:00
// give the shooter a reward sound if they have made two telefrag hits in a row
if ( hits == 0 )
{
2011-02-18 14:31:32 +00:00
// complete miss
ent->client->accurateCountTelefrag = 0;
2011-02-18 14:31:32 +00:00
} else {
// check for "telefragged" reward sound
ent->client->accurateCountTelefrag += hits;
if ( ent->client->accurateCountTelefrag >= 2 )
{
ent->client->accurateCountTelefrag -= 2;
ent->client->ps.persistant[PERS_IMPRESSIVETELEFRAG_COUNT]++;
2011-02-18 14:31:32 +00:00
// add the sprite over the player's head
ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_IMPRESSIVETELEFRAG | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVETELEFRAG;
2011-02-18 14:31:32 +00:00
ent->client->rewardTime = level.time + REWARD_SPRITE_TIME;
}
ent->client->accuracy_hits++;
}
}
/*
======================================================================
LIGHTNING GUN
======================================================================
*/
void Weapon_LightningFire( gentity_t *ent ) {
trace_t tr;
vec3_t end;
#ifdef MISSIONPACK
vec3_t impactpoint, bouncedir;
#endif
gentity_t *traceEnt, *tent;
int damage, i, passent;
damage = 8 * s_quadFactor;
passent = ent->s.number;
for (i = 0; i < 10; i++) {
VectorMA( muzzle, LIGHTNING_RANGE, forward, end );
trap_Trace( &tr, muzzle, NULL, NULL, end, passent, MASK_SHOT );
#ifdef MISSIONPACK
// if not the first trace (the lightning bounced of an invulnerability sphere)
if (i) {
// add bounced off lightning bolt temp entity
// the first lightning bolt is a cgame only visual
//
tent = G_TempEntity( muzzle, EV_LIGHTNINGBOLT );
VectorCopy( tr.endpos, end );
SnapVector( end );
VectorCopy( end, tent->s.origin2 );
}
#endif
if ( tr.entityNum == ENTITYNUM_NONE ) {
return;
}
// STONELANCE
// traceEnt = &g_entities[ tr.entityNum ];
if (g_entities[ tr.entityNum ].flags & FL_EXTRA_BBOX)
traceEnt = &g_entities[ g_entities[ tr.entityNum ].r.ownerNum ];
else
traceEnt = &g_entities[ tr.entityNum ];
// END
if ( traceEnt->takedamage) {
#ifdef MISSIONPACK
if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
VectorCopy( impactpoint, muzzle );
VectorSubtract( end, impactpoint, forward );
VectorNormalize(forward);
// the player can hit him/herself with the bounced lightning
passent = ENTITYNUM_NONE;
}
else {
VectorCopy( tr.endpos, muzzle );
passent = traceEnt->s.number;
}
continue;
}
ioquake3 resync to revision 3385 from 3347. Fix going to previous browser source in q3_ui Limit ui_smallFont/ui_bigFont/cg_noTaunt cvars to missionpack Fix team chat box for spectators Don't draw crosshair 0 in Team Arena setup menu Make client for Windows x86_64 use OpenAL64.dll by default Fix loading renderer DLLs on Windows x86 Add Windows application manifest Disable DPI scaling on Windows ignore window resize event on fullscreen Don't reload arenas.txt/*.arena files in Team Arena UI Fix crash when out of memory in Team Arena's String_Alloc Fix in_nograb not releasing the mouse cursor Update UI player animation handling to match CGame Fix specifying minimum mac os version in make-macosx.sh Fix listen server sending snapshots each client frame Statically link libgcc on Windows Fix hit accuracy stats for lightning gun and shotgun kills Don't link to libGL at compile time Add common OpenGL version parsing + OpenGL 3 fixes Support parsing OpenGL ES version strings Fix setting cflags/libs from sdl2-config Load OpenGL ES 1.1 function procs [qcommon] Use unsigned types where wrapping arithmetic is intended OpenGL2: Fix brightness when r_autoExposure is disabled OpenGL2: Fix MD3 surface with zero shaders dividing by zero [botlib/be_aas_def.h] Change array size from MAX_PATH to MAX_QPATH Don't redefine MAX_PATH in bot code Fix memory leak in (unused) AAS_FloodAreas() Fix compiling GLSL shaders under Windows. Only draw cm_patch/bot debug polygons in world scenes Fix reading crash log when log wraps around buffer Don't send team overlay info to bots Fix a race condition in the makedirs target Fix shader corruption on OpenBSD
2017-11-04 11:30:30 +00:00
#endif
if( LogAccuracyHit( traceEnt, ent ) ) {
ent->client->accuracy_hits++;
2011-02-18 14:31:32 +00:00
}
ioquake3 resync to revision 3385 from 3347. Fix going to previous browser source in q3_ui Limit ui_smallFont/ui_bigFont/cg_noTaunt cvars to missionpack Fix team chat box for spectators Don't draw crosshair 0 in Team Arena setup menu Make client for Windows x86_64 use OpenAL64.dll by default Fix loading renderer DLLs on Windows x86 Add Windows application manifest Disable DPI scaling on Windows ignore window resize event on fullscreen Don't reload arenas.txt/*.arena files in Team Arena UI Fix crash when out of memory in Team Arena's String_Alloc Fix in_nograb not releasing the mouse cursor Update UI player animation handling to match CGame Fix specifying minimum mac os version in make-macosx.sh Fix listen server sending snapshots each client frame Statically link libgcc on Windows Fix hit accuracy stats for lightning gun and shotgun kills Don't link to libGL at compile time Add common OpenGL version parsing + OpenGL 3 fixes Support parsing OpenGL ES version strings Fix setting cflags/libs from sdl2-config Load OpenGL ES 1.1 function procs [qcommon] Use unsigned types where wrapping arithmetic is intended OpenGL2: Fix brightness when r_autoExposure is disabled OpenGL2: Fix MD3 surface with zero shaders dividing by zero [botlib/be_aas_def.h] Change array size from MAX_PATH to MAX_QPATH Don't redefine MAX_PATH in bot code Fix memory leak in (unused) AAS_FloodAreas() Fix compiling GLSL shaders under Windows. Only draw cm_patch/bot debug polygons in world scenes Fix reading crash log when log wraps around buffer Don't send team overlay info to bots Fix a race condition in the makedirs target Fix shader corruption on OpenBSD
2017-11-04 11:30:30 +00:00
G_Damage( traceEnt, ent, ent, forward, tr.endpos,
2011-02-18 14:31:32 +00:00
// STONELANCE
// damage, 0, MOD_LIGHTNING);
damage, DAMAGE_WEAPON, MOD_LIGHTNING);
// END
}
if ( traceEnt->takedamage && traceEnt->client ) {
tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
tent->s.otherEntityNum = traceEnt->s.number;
tent->s.eventParm = DirToByte( tr.plane.normal );
tent->s.weapon = ent->s.weapon;
2023-03-02 20:44:38 +00:00
if( LogAccuracyHit( traceEnt, ent ) ) {
ent->client->accuracy_hits++;
}
2011-02-18 14:31:32 +00:00
} else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) {
tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
tent->s.eventParm = DirToByte( tr.plane.normal );
}
break;
}
}
#ifdef MISSIONPACK
/*
======================================================================
NAILGUN
======================================================================
*/
void Weapon_Nailgun_Fire (gentity_t *ent) {
gentity_t *m;
int count;
for( count = 0; count < NUM_NAILSHOTS; count++ ) {
m = fire_nail (ent, muzzle, forward, right, up );
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
}
// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
}
/*
======================================================================
PROXIMITY MINE LAUNCHER
======================================================================
*/
void weapon_proxlauncher_fire (gentity_t *ent) {
gentity_t *m;
// extra vertical velocity
forward[2] += 0.2f;
VectorNormalize( forward );
m = fire_prox (ent, muzzle, forward);
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
}
#endif
//======================================================================
/*
===============
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 ) {
VectorCopy( ent->s.pos.trBase, muzzlePoint );
// STONELANCE
// muzzlePoint[2] += ent->client->ps.viewheight;
// VectorMA( muzzlePoint, 14, forward, muzzlePoint );
VectorMA( muzzlePoint, CAR_HEIGHT/2, up, muzzlePoint );
VectorMA( muzzlePoint, 14, forward, muzzlePoint );
// END
// 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 );
// STONELANCE
// muzzlePoint[2] += ent->client->ps.viewheight;
VectorMA( muzzlePoint, CAR_HEIGHT/2, up, muzzlePoint );
// END
VectorMA( muzzlePoint, 14, forward, muzzlePoint );
// snap to integer coordinates for more efficient network bandwidth usage
SnapVector( muzzlePoint );
}
/*
===============
FireWeapon
===============
*/
void FireWeapon( gentity_t *ent ) {
// STONELANCE
vec3_t delta, angles, end, mins, maxs;
trace_t tr;
int entNumber;
gentity_t *traceEnt;
int count = 0;
// END
if (ent->client->ps.powerups[PW_QUAD] ) {
s_quadFactor = g_quadfactor.value;
} else {
s_quadFactor = 1;
}
#ifdef MISSIONPACK
if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
s_quadFactor *= 2;
}
#endif
// track shots taken for accuracy tracking. Grapple is not a weapon and gauntet is just not tracked
// STONELANCE
// if( ent->s.weapon != WP_GRAPPLING_HOOK && ent->s.weapon != WP_GAUNTLET ) {
if( ent->s.weapon != WP_GAUNTLET ) {
// END
#ifdef MISSIONPACK
if( ent->s.weapon == WP_NAILGUN ) {
ent->client->accuracy_shots += NUM_NAILSHOTS;
} else {
ent->client->accuracy_shots++;
}
#else
ent->client->accuracy_shots++;
#endif
}
// set aiming directions
AngleVectors (ent->client->ps.viewangles, forward, right, up);
CalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle );
// STONELANCE (vertical autoaim)
VectorSet(mins, -8, -8, -128);
VectorSet(maxs, 8, 8, 128);
VectorMA(muzzle, 8000, forward, end);
trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, CONTENTS_PLAYERCLIP | CONTENTS_BODY );
while ( tr.fraction < 1.0f && count < 10000 ){
if ( tr.fraction < 0.0001f )
break;
if ( tr.allsolid )
break;
count++;
// if ( g_entities[ tr.entityNum ].flags & FL_EXTRA_BBOX )
// entNumber = g_entities[ tr.entityNum ].r.ownerNum;
// else
entNumber = tr.entityNum;
traceEnt = &g_entities[ entNumber ];
if ( g_gametype.integer > GT_TEAM && traceEnt->client ){
// skip team members
if (ent->client->sess.sessionTeam == traceEnt->client->sess.sessionTeam)
continue;
}
if ( traceEnt->takedamage ){
VectorSubtract( traceEnt->r.currentOrigin, muzzle, delta );
vectoangles( delta, angles );
angles[YAW] = ent->client->ps.viewangles[YAW];
AngleVectors( angles, forward, right, up );
break;
}
trap_Trace( &tr, tr.endpos, mins, maxs, end, entNumber, CONTENTS_PLAYERCLIP | CONTENTS_BODY );
}
if ( count == 10000 ){
Com_Printf( "Detected long loop in verticle autoaiming\n" );
Com_Printf( "fraction %f, startsolid %i, contents %i, entityNum %i\n", tr.fraction, tr.startsolid, tr.contents, tr.entityNum );
}
// END
// fire the specific weapon
switch( ent->s.weapon ) {
case WP_GAUNTLET:
Weapon_Gauntlet( ent );
break;
case WP_LIGHTNING:
Weapon_LightningFire( ent );
break;
case WP_SHOTGUN:
weapon_supershotgun_fire( ent );
break;
case WP_MACHINEGUN:
if ( g_gametype.integer != GT_TEAM ) {
Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_DAMAGE, MOD_MACHINEGUN );
2011-02-18 14:31:32 +00:00
} else {
Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_TEAM_DAMAGE, MOD_MACHINEGUN );
2011-02-18 14:31:32 +00:00
}
break;
case WP_GRENADE_LAUNCHER:
weapon_grenadelauncher_fire( ent );
break;
case WP_ROCKET_LAUNCHER:
Weapon_RocketLauncher_Fire( ent );
break;
case WP_PLASMAGUN:
Weapon_Plasmagun_Fire( ent );
break;
case WP_RAILGUN:
weapon_railgun_fire( ent );
break;
case WP_BFG:
BFG_Fire( ent );
break;
2021-02-18 11:46:04 +00:00
case WP_FLAME_THROWER:
Weapon_fire_flame( ent );
break;
2011-02-18 14:31:32 +00:00
#ifdef MISSIONPACK
case WP_NAILGUN:
Weapon_Nailgun_Fire( ent );
break;
case WP_PROX_LAUNCHER:
weapon_proxlauncher_fire( ent );
break;
case WP_CHAINGUN:
Bullet_Fire( ent, CHAINGUN_SPREAD, CHAINGUN_DAMAGE, MOD_CHAINGUN );
2011-02-18 14:31:32 +00:00
break;
#endif
default:
// FIXME G_Error( "Bad ent->s.weapon" );
break;
}
}
/*
===============
FireAltWeapon
===============
*/
void FireAltWeapon( gentity_t *ent ) {
// STONELANCE
vec3_t delta, angles, end, mins, maxs;
trace_t tr;
int entNumber;
gentity_t *traceEnt;
int count = 0;
// END
if (ent->client->ps.powerups[PW_QUAD] ) {
s_quadFactor = g_quadfactor.value;
} else {
s_quadFactor = 1;
}
#ifdef MISSIONPACK
if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
s_quadFactor *= 2;
}
#endif
// track shots taken for accuracy tracking. Grapple is not a weapon and gauntet is just not tracked
// STONELANCE
// if( ent->s.weapon != WP_GRAPPLING_HOOK && ent->s.weapon != WP_GAUNTLET ) {
if( ent->s.weapon != WP_GAUNTLET ) {
// END
#ifdef MISSIONPACK
if( ent->s.weapon == WP_NAILGUN ) {
ent->client->accuracy_shots += NUM_NAILSHOTS;
} else {
ent->client->accuracy_shots++;
}
#else
ent->client->accuracy_shots++;
#endif
}
// set aiming directions
AngleVectors (ent->client->ps.viewangles, forward, right, up);
CalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle );
// STONELANCE (vertical autoaim)
VectorSet(mins, -8, -8, -128);
VectorSet(maxs, 8, 8, 128);
VectorMA(muzzle, 8000, forward, end);
trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, CONTENTS_PLAYERCLIP | CONTENTS_BODY );
while ( tr.fraction < 1.0f && count < 10000 ){
if ( tr.fraction < 0.0001f )
break;
if ( tr.allsolid )
break;
count++;
// if ( g_entities[ tr.entityNum ].flags & FL_EXTRA_BBOX )
// entNumber = g_entities[ tr.entityNum ].r.ownerNum;
// else
entNumber = tr.entityNum;
traceEnt = &g_entities[ entNumber ];
if ( g_gametype.integer > GT_TEAM && traceEnt->client ){
// skip team members
if (ent->client->sess.sessionTeam == traceEnt->client->sess.sessionTeam)
continue;
}
if ( traceEnt->takedamage ){
VectorSubtract( traceEnt->r.currentOrigin, muzzle, delta );
vectoangles( delta, angles );
angles[YAW] = ent->client->ps.viewangles[YAW];
AngleVectors( angles, forward, right, up );
break;
}
trap_Trace( &tr, tr.endpos, mins, maxs, end, entNumber, CONTENTS_PLAYERCLIP | CONTENTS_BODY );
}
if ( count == 10000 ){
Com_Printf( "Detected long loop in verticle autoaiming\n" );
Com_Printf( "fraction %f, startsolid %i, contents %i, entityNum %i\n", tr.fraction, tr.startsolid, tr.contents, tr.entityNum );
}
// END
// fire the specific weapon
switch( ent->s.weapon ) {
case WP_GAUNTLET:
Weapon_Gauntlet( ent );
break;
case WP_LIGHTNING:
Weapon_LightningFire( ent );
break;
case WP_SHOTGUN:
weapon_supershotgun_fire( ent );
break;
case WP_MACHINEGUN:
if ( g_gametype.integer != GT_TEAM ) {
Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_DAMAGE, MOD_MACHINEGUN );
2011-02-18 14:31:32 +00:00
} else {
Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_TEAM_DAMAGE, MOD_MACHINEGUN );
2011-02-18 14:31:32 +00:00
}
break;
case WP_GRENADE_LAUNCHER:
weapon_cluster_grenadelauncher_fire( ent );
break;
case WP_ROCKET_LAUNCHER:
Weapon_Homing_RocketLauncher_Fire( ent );
break;
case WP_PLASMAGUN:
Weapon_Plasmagun_Circular_Fire( ent );
break;
case WP_RAILGUN:
weapon_telefrag_fire( ent,muzzle,forward,right,up );
2011-02-18 14:31:32 +00:00
break;
case WP_BFG:
BFG_Fire( ent );
break;
case WP_FLAME_THROWER:
Weapon_cluster_fire_flame( ent );
break;
2011-02-18 14:31:32 +00:00
#ifdef MISSIONPACK
case WP_NAILGUN:
Weapon_Nailgun_Fire( ent );
break;
case WP_PROX_LAUNCHER:
weapon_proxlauncher_fire( ent );
break;
case WP_CHAINGUN:
Bullet_Fire( ent, CHAINGUN_SPREAD, CHAINGUN_DAMAGE, MOD_CHAINGUN );
2011-02-18 14:31:32 +00:00
break;
#endif
default:
// FIXME G_Error( "Bad ent->s.weapon" );
break;
}
}
#ifdef MISSIONPACK
/*
===============
KamikazeRadiusDamage
===============
*/
static void KamikazeRadiusDamage( vec3_t origin, gentity_t *attacker, float damage, float radius ) {
float dist;
gentity_t *ent;
int entityList[MAX_GENTITIES];
int numListedEntities;
vec3_t mins, maxs;
vec3_t v;
vec3_t dir;
int i, e;
if ( radius < 1 ) {
radius = 1;
}
for ( i = 0 ; i < 3 ; i++ ) {
mins[i] = origin[i] - radius;
maxs[i] = origin[i] + radius;
}
numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for ( e = 0 ; e < numListedEntities ; e++ ) {
ent = &g_entities[entityList[ e ]];
if (!ent->takedamage) {
continue;
}
// don't hit things we have already hit
2011-02-18 14:31:32 +00:00
if( ent->kamikazeTime > level.time ) {
continue;
}
// find the distance from the edge of the bounding box
for ( i = 0 ; i < 3 ; i++ ) {
if ( origin[i] < ent->r.absmin[i] ) {
v[i] = ent->r.absmin[i] - origin[i];
} else if ( origin[i] > ent->r.absmax[i] ) {
v[i] = origin[i] - ent->r.absmax[i];
} else {
v[i] = 0;
}
}
dist = VectorLength( v );
if ( dist >= radius ) {
continue;
}
// if( CanDamage (ent, origin) ) {
VectorSubtract (ent->r.currentOrigin, origin, dir);
// push the center of mass higher than the origin so players
// get knocked into the air more
dir[2] += 24;
G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
ent->kamikazeTime = level.time + 3000;
// }
}
}
/*
===============
KamikazeShockWave
===============
*/
static void KamikazeShockWave( vec3_t origin, gentity_t *attacker, float damage, float push, float radius ) {
float dist;
gentity_t *ent;
int entityList[MAX_GENTITIES];
int numListedEntities;
vec3_t mins, maxs;
vec3_t v;
vec3_t dir;
int i, e;
if ( radius < 1 )
radius = 1;
for ( i = 0 ; i < 3 ; i++ ) {
mins[i] = origin[i] - radius;
maxs[i] = origin[i] + radius;
}
numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for ( e = 0 ; e < numListedEntities ; e++ ) {
ent = &g_entities[entityList[ e ]];
// don't hit things we have already hit
2011-02-18 14:31:32 +00:00
if( ent->kamikazeShockTime > level.time ) {
continue;
}
// find the distance from the edge of the bounding box
for ( i = 0 ; i < 3 ; i++ ) {
if ( origin[i] < ent->r.absmin[i] ) {
v[i] = ent->r.absmin[i] - origin[i];
} else if ( origin[i] > ent->r.absmax[i] ) {
v[i] = origin[i] - ent->r.absmax[i];
} else {
v[i] = 0;
}
}
dist = VectorLength( v );
if ( dist >= radius ) {
continue;
}
// if( CanDamage (ent, origin) ) {
VectorSubtract (ent->r.currentOrigin, origin, dir);
dir[2] += 24;
G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
//
dir[2] = 0;
VectorNormalize(dir);
if ( ent->client ) {
ent->client->ps.velocity[0] = dir[0] * push;
ent->client->ps.velocity[1] = dir[1] * push;
ent->client->ps.velocity[2] = 100;
}
ent->kamikazeShockTime = level.time + 3000;
// }
}
}
/*
===============
KamikazeDamage
===============
*/
static void KamikazeDamage( gentity_t *self ) {
int i;
float t;
gentity_t *ent;
vec3_t newangles;
self->count += 100;
if (self->count >= KAMI_SHOCKWAVE_STARTTIME) {
// shockwave push back
t = self->count - KAMI_SHOCKWAVE_STARTTIME;
KamikazeShockWave(self->s.pos.trBase, self->activator, 25, 400, (int) (float) t * KAMI_SHOCKWAVE_MAXRADIUS / (KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME) );
}
//
if (self->count >= KAMI_EXPLODE_STARTTIME) {
// do our damage
t = self->count - KAMI_EXPLODE_STARTTIME;
KamikazeRadiusDamage( self->s.pos.trBase, self->activator, 400, (int) (float) t * KAMI_BOOMSPHERE_MAXRADIUS / (KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME) );
}
// either cycle or kill self
if( self->count >= KAMI_SHOCKWAVE_ENDTIME ) {
G_FreeEntity( self );
return;
}
self->nextthink = level.time + 100;
// add earth quake effect
newangles[0] = crandom() * 2;
newangles[1] = crandom() * 2;
newangles[2] = 0;
for (i = 0; i < MAX_CLIENTS; i++)
{
ent = &g_entities[i];
if (!ent->inuse)
continue;
if (!ent->client)
continue;
if (ent->client->ps.groundEntityNum != ENTITYNUM_NONE) {
ent->client->ps.velocity[0] += crandom() * 120;
ent->client->ps.velocity[1] += crandom() * 120;
ent->client->ps.velocity[2] = 30 + random() * 25;
}
ent->client->ps.delta_angles[0] += ANGLE2SHORT(newangles[0] - self->movedir[0]);
ent->client->ps.delta_angles[1] += ANGLE2SHORT(newangles[1] - self->movedir[1]);
ent->client->ps.delta_angles[2] += ANGLE2SHORT(newangles[2] - self->movedir[2]);
}
VectorCopy(newangles, self->movedir);
}
/*
===============
G_StartKamikaze
===============
*/
void G_StartKamikaze( gentity_t *ent ) {
gentity_t *explosion;
gentity_t *te;
vec3_t snapped;
// start up the explosion logic
explosion = G_Spawn();
explosion->s.eType = ET_EVENTS + EV_KAMIKAZE;
explosion->eventTime = level.time;
if ( ent->client ) {
VectorCopy( ent->s.pos.trBase, snapped );
}
else {
VectorCopy( ent->activator->s.pos.trBase, snapped );
}
SnapVector( snapped ); // save network bandwidth
G_SetOrigin( explosion, snapped );
explosion->classname = "kamikaze";
explosion->s.pos.trType = TR_STATIONARY;
explosion->kamikazeTime = level.time;
explosion->think = KamikazeDamage;
explosion->nextthink = level.time + 100;
explosion->count = 0;
VectorClear(explosion->movedir);
trap_LinkEntity( explosion );
if (ent->client) {
//
explosion->activator = ent;
//
ent->s.eFlags &= ~EF_KAMIKAZE;
// nuke the guy that used it
G_Damage( ent, ent, ent, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_KAMIKAZE );
}
else {
if ( !strcmp(ent->activator->classname, "bodyque") ) {
explosion->activator = &g_entities[ent->activator->r.ownerNum];
}
else {
explosion->activator = ent->activator;
}
}
// play global sound at all clients
te = G_TempEntity(snapped, EV_GLOBAL_TEAM_SOUND );
te->r.svFlags |= SVF_BROADCAST;
te->s.eventParm = GTS_KAMIKAZE;
}
#endif