diff options
| author | zakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-08-26 17:39:27 +0000 | 
|---|---|---|
| committer | zakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-08-26 17:39:27 +0000 | 
| commit | 6bf20c78f5b69d40bcc4931df93d29198435ab67 (patch) | |
| tree | e3eda937a05d7db42de725b7013bd0344b987f34 /code/game/g_weapon.c | |
| parent | 872d4d7f55af706737ffb361bb76ad13e7496770 (diff) | |
| download | ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.tar.gz ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.zip  | |
newlines fixed
git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/game/g_weapon.c')
| -rwxr-xr-x | code/game/g_weapon.c | 2290 | 
1 files changed, 1145 insertions, 1145 deletions
diff --git a/code/game/g_weapon.c b/code/game/g_weapon.c index 5a3fe5e..579a16c 100755 --- a/code/game/g_weapon.c +++ b/code/game/g_weapon.c @@ -1,1145 +1,1145 @@ -/*
 -===========================================================================
 -Copyright (C) 1999-2005 Id Software, Inc.
 -
 -This file is part of Quake III Arena source code.
 -
 -Quake III Arena 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.
 -
 -Quake III Arena 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 Foobar; 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;
 -static	vec3_t	forward, right, up;
 -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 );
 -
 -	VectorMA (muzzle, 32, forward, end);
 -
 -	trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT);
 -	if ( tr.surfaceFlags & SURF_NOIMPACT ) {
 -		return qfalse;
 -	}
 -
 -	traceEnt = &g_entities[ tr.entityNum ];
 -
 -	// 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
 -
 -	damage = 50 * s_quadFactor;
 -	G_Damage( traceEnt, ent, ent, forward, tr.endpos,
 -		damage, 0, MOD_GAUNTLET );
 -
 -	return qtrue;
 -}
 -
 -
 -/*
 -======================================================================
 -
 -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] = (int)v[i];
 -		} else {
 -			v[i] = (int)v[i] + 1;
 -		}
 -	}
 -}
 -
 -#ifdef MISSIONPACK
 -#define CHAINGUN_SPREAD		600
 -#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 ) {
 -	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++) {
 -
 -		trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT);
 -		if ( tr.surfaceFlags & SURF_NOIMPACT ) {
 -			return;
 -		}
 -
 -		traceEnt = &g_entities[ tr.entityNum ];
 -
 -		// 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, 0, MOD_MACHINEGUN);
 -#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;
 -
 -	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);
 -		traceEnt = &g_entities[ tr.entityNum ];
 -
 -		// 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;
 -			}
 -			else {
 -				G_Damage( traceEnt, ent, ent, forward, tr.endpos,
 -					damage, 0, MOD_SHOTGUN);
 -				if( LogAccuracyHit( traceEnt, ent ) ) {
 -					return qtrue;
 -				}
 -			}
 -#else
 -			G_Damage( traceEnt, ent, ent, forward, tr.endpos,	damage, 0, MOD_SHOTGUN);
 -				if( LogAccuracyHit( traceEnt, ent ) ) {
 -					return qtrue;
 -				}
 -#endif
 -		}
 -		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;
 -	int			oldScore;
 -	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 );
 -
 -	oldScore = ent->client->ps.persistant[PERS_SCORE];
 -
 -	// 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
 -
 -======================================================================
 -*/
 -
 -void weapon_grenadelauncher_fire (gentity_t *ent) {
 -	gentity_t	*m;
 -
 -	// extra vertical velocity
 -	forward[2] += 0.2f;
 -	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
 -}
 -
 -/*
 -======================================================================
 -
 -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;
 -
 -//	VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta );	// "real" physics
 -}
 -
 -
 -/*
 -======================================================================
 -
 -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
 -}
 -
 -/*
 -======================================================================
 -
 -RAILGUN
 -
 -======================================================================
 -*/
 -
 -
 -/*
 -=================
 -weapon_railgun_fire
 -=================
 -*/
 -#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 = 100 * s_quadFactor;
 -
 -	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;
 -		}
 -		traceEnt = &g_entities[ trace.entityNum ];
 -		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++;
 -				}
 -				G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
 -			}
 -#else
 -				if( LogAccuracyHit( traceEnt, ent ) ) {
 -					hits++;
 -				}
 -				G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
 -#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 >= 2 ) {
 -			ent->client->accurateCount -= 2;
 -			ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
 -			// add the sprite over the player's head
 -			ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
 -			ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE;
 -			ent->client->rewardTime = level.time + REWARD_SPRITE_TIME;
 -		}
 -		ent->client->accuracy_hits++;
 -	}
 -
 -}
 -
 -
 -/*
 -======================================================================
 -
 -GRAPPLING HOOK
 -
 -======================================================================
 -*/
 -
 -void Weapon_GrapplingHook_Fire (gentity_t *ent)
 -{
 -	if (!ent->client->fireHeld && !ent->client->hook)
 -		fire_grapple (ent, muzzle, forward);
 -
 -	ent->client->fireHeld = qtrue;
 -}
 -
 -void Weapon_HookFree (gentity_t *ent)
 -{
 -	ent->parent->client->hook = NULL;
 -	ent->parent->client->ps.pm_flags &= ~PMF_GRAPPLE_PULL;
 -	G_FreeEntity( ent );
 -}
 -
 -void Weapon_HookThink (gentity_t *ent)
 -{
 -	if (ent->enemy) {
 -		vec3_t v, oldorigin;
 -
 -		VectorCopy(ent->r.currentOrigin, oldorigin);
 -		v[0] = ent->enemy->r.currentOrigin[0] + (ent->enemy->r.mins[0] + ent->enemy->r.maxs[0]) * 0.5;
 -		v[1] = ent->enemy->r.currentOrigin[1] + (ent->enemy->r.mins[1] + ent->enemy->r.maxs[1]) * 0.5;
 -		v[2] = ent->enemy->r.currentOrigin[2] + (ent->enemy->r.mins[2] + ent->enemy->r.maxs[2]) * 0.5;
 -		SnapVectorTowards( v, oldorigin );	// save net bandwidth
 -
 -		G_SetOrigin( ent, v );
 -	}
 -
 -	VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
 -}
 -
 -/*
 -======================================================================
 -
 -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;
 -		}
 -
 -		traceEnt = &g_entities[ tr.entityNum ];
 -
 -		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;
 -			}
 -			else {
 -				G_Damage( traceEnt, ent, ent, forward, tr.endpos,
 -					damage, 0, MOD_LIGHTNING);
 -			}
 -#else
 -				G_Damage( traceEnt, ent, ent, forward, tr.endpos,
 -					damage, 0, MOD_LIGHTNING);
 -#endif
 -		}
 -
 -		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( LogAccuracyHit( traceEnt, ent ) ) {
 -				ent->client->accuracy_hits++;
 -			}
 -		} 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 );
 -	muzzlePoint[2] += ent->client->ps.viewheight;
 -	VectorMA( muzzlePoint, 14, forward, muzzlePoint );
 -	// snap to integer coordinates for more efficient network bandwidth usage
 -	SnapVector( muzzlePoint );
 -}
 -
 -/*
 -===============
 -CalcMuzzlePointOrigin
 -
 -set muzzle location relative to pivoting eye
 -===============
 -*/
 -void CalcMuzzlePointOrigin ( gentity_t *ent, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
 -	VectorCopy( ent->s.pos.trBase, muzzlePoint );
 -	muzzlePoint[2] += ent->client->ps.viewheight;
 -	VectorMA( muzzlePoint, 14, forward, muzzlePoint );
 -	// snap to integer coordinates for more efficient network bandwidth usage
 -	SnapVector( muzzlePoint );
 -}
 -
 -
 -
 -/*
 -===============
 -FireWeapon
 -===============
 -*/
 -void FireWeapon( gentity_t *ent ) {
 -	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
 -	if( ent->s.weapon != WP_GRAPPLING_HOOK && ent->s.weapon != WP_GAUNTLET ) {
 -#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 );
 -
 -	// 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 );
 -		} else {
 -			Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_TEAM_DAMAGE );
 -		}
 -		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;
 -	case WP_GRAPPLING_HOOK:
 -		Weapon_GrapplingHook_Fire( ent );
 -		break;
 -#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, MACHINEGUN_DAMAGE );
 -		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;
 -		}
 -
 -		// dont hit things we have already hit
 -		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 ]];
 -
 -		// dont hit things we have already hit
 -		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
 +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena 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. + +Quake III Arena 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 Foobar; 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; +static	vec3_t	forward, right, up; +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 ); + +	VectorMA (muzzle, 32, forward, end); + +	trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT); +	if ( tr.surfaceFlags & SURF_NOIMPACT ) { +		return qfalse; +	} + +	traceEnt = &g_entities[ tr.entityNum ]; + +	// 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 + +	damage = 50 * s_quadFactor; +	G_Damage( traceEnt, ent, ent, forward, tr.endpos, +		damage, 0, MOD_GAUNTLET ); + +	return qtrue; +} + + +/* +====================================================================== + +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] = (int)v[i]; +		} else { +			v[i] = (int)v[i] + 1; +		} +	} +} + +#ifdef MISSIONPACK +#define CHAINGUN_SPREAD		600 +#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 ) { +	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++) { + +		trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT); +		if ( tr.surfaceFlags & SURF_NOIMPACT ) { +			return; +		} + +		traceEnt = &g_entities[ tr.entityNum ]; + +		// 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, 0, MOD_MACHINEGUN); +#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; + +	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); +		traceEnt = &g_entities[ tr.entityNum ]; + +		// 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; +			} +			else { +				G_Damage( traceEnt, ent, ent, forward, tr.endpos, +					damage, 0, MOD_SHOTGUN); +				if( LogAccuracyHit( traceEnt, ent ) ) { +					return qtrue; +				} +			} +#else +			G_Damage( traceEnt, ent, ent, forward, tr.endpos,	damage, 0, MOD_SHOTGUN); +				if( LogAccuracyHit( traceEnt, ent ) ) { +					return qtrue; +				} +#endif +		} +		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; +	int			oldScore; +	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 ); + +	oldScore = ent->client->ps.persistant[PERS_SCORE]; + +	// 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 + +====================================================================== +*/ + +void weapon_grenadelauncher_fire (gentity_t *ent) { +	gentity_t	*m; + +	// extra vertical velocity +	forward[2] += 0.2f; +	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 +} + +/* +====================================================================== + +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; + +//	VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta );	// "real" physics +} + + +/* +====================================================================== + +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 +} + +/* +====================================================================== + +RAILGUN + +====================================================================== +*/ + + +/* +================= +weapon_railgun_fire +================= +*/ +#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 = 100 * s_quadFactor; + +	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; +		} +		traceEnt = &g_entities[ trace.entityNum ]; +		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++; +				} +				G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN); +			} +#else +				if( LogAccuracyHit( traceEnt, ent ) ) { +					hits++; +				} +				G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN); +#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 >= 2 ) { +			ent->client->accurateCount -= 2; +			ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++; +			// add the sprite over the player's head +			ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP ); +			ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE; +			ent->client->rewardTime = level.time + REWARD_SPRITE_TIME; +		} +		ent->client->accuracy_hits++; +	} + +} + + +/* +====================================================================== + +GRAPPLING HOOK + +====================================================================== +*/ + +void Weapon_GrapplingHook_Fire (gentity_t *ent) +{ +	if (!ent->client->fireHeld && !ent->client->hook) +		fire_grapple (ent, muzzle, forward); + +	ent->client->fireHeld = qtrue; +} + +void Weapon_HookFree (gentity_t *ent) +{ +	ent->parent->client->hook = NULL; +	ent->parent->client->ps.pm_flags &= ~PMF_GRAPPLE_PULL; +	G_FreeEntity( ent ); +} + +void Weapon_HookThink (gentity_t *ent) +{ +	if (ent->enemy) { +		vec3_t v, oldorigin; + +		VectorCopy(ent->r.currentOrigin, oldorigin); +		v[0] = ent->enemy->r.currentOrigin[0] + (ent->enemy->r.mins[0] + ent->enemy->r.maxs[0]) * 0.5; +		v[1] = ent->enemy->r.currentOrigin[1] + (ent->enemy->r.mins[1] + ent->enemy->r.maxs[1]) * 0.5; +		v[2] = ent->enemy->r.currentOrigin[2] + (ent->enemy->r.mins[2] + ent->enemy->r.maxs[2]) * 0.5; +		SnapVectorTowards( v, oldorigin );	// save net bandwidth + +		G_SetOrigin( ent, v ); +	} + +	VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint); +} + +/* +====================================================================== + +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; +		} + +		traceEnt = &g_entities[ tr.entityNum ]; + +		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; +			} +			else { +				G_Damage( traceEnt, ent, ent, forward, tr.endpos, +					damage, 0, MOD_LIGHTNING); +			} +#else +				G_Damage( traceEnt, ent, ent, forward, tr.endpos, +					damage, 0, MOD_LIGHTNING); +#endif +		} + +		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( LogAccuracyHit( traceEnt, ent ) ) { +				ent->client->accuracy_hits++; +			} +		} 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 ); +	muzzlePoint[2] += ent->client->ps.viewheight; +	VectorMA( muzzlePoint, 14, forward, muzzlePoint ); +	// snap to integer coordinates for more efficient network bandwidth usage +	SnapVector( muzzlePoint ); +} + +/* +=============== +CalcMuzzlePointOrigin + +set muzzle location relative to pivoting eye +=============== +*/ +void CalcMuzzlePointOrigin ( gentity_t *ent, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) { +	VectorCopy( ent->s.pos.trBase, muzzlePoint ); +	muzzlePoint[2] += ent->client->ps.viewheight; +	VectorMA( muzzlePoint, 14, forward, muzzlePoint ); +	// snap to integer coordinates for more efficient network bandwidth usage +	SnapVector( muzzlePoint ); +} + + + +/* +=============== +FireWeapon +=============== +*/ +void FireWeapon( gentity_t *ent ) { +	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 +	if( ent->s.weapon != WP_GRAPPLING_HOOK && ent->s.weapon != WP_GAUNTLET ) { +#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 ); + +	// 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 ); +		} else { +			Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_TEAM_DAMAGE ); +		} +		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; +	case WP_GRAPPLING_HOOK: +		Weapon_GrapplingHook_Fire( ent ); +		break; +#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, MACHINEGUN_DAMAGE ); +		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; +		} + +		// dont hit things we have already hit +		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 ]]; + +		// dont hit things we have already hit +		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  | 
