summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Levin <risujin@fastmail.fm>2009-10-03 11:17:25 +0000
committerTim Angus <tim@ngus.net>2013-01-03 00:14:50 +0000
commit6916f8fb5d3a19bf0bdfb84948b19445954306d9 (patch)
tree464c47a1e3655dae4cd2c6d307ece5d8ba2fef6b /src
parent2765a1c4a871cd9d34e5b6fce1e3c419a8e4dd6a (diff)
* I'm sick of entering \give 9999 every time I need to test something. Whenever cheats are enabled, players spawn with half-full credits.
* Reactor used to deal more damage to each Alien when multiple Aliens attacked it, fixed to ONE radius damage call. Extensive visual modifications to Mass Driver: * Added a short, briefly-displayed pseudo-trail * Impact system modified to have a large impact sprite and otherwise be more consistent with Lasgun * Added several files for the trail and shader * Firing code modified to generate visually correct trails and impact positions * Added a new event for Mass Driver trails, doubles as impact event to save bandwidth The Mass Driver trail extends from the gun rather than the muzzle to be more visually realistic. Shooting it from the muzzle prevents you from even seeing the trail and in 3rd person looks very wrong. The downside to the shifted origin is that the impact positions (multiple hits only) are not aligned with the beam. Had to add a good bit of complicated, mathy code to generate impact events in visually accurate locations. Looks damn good though.
Diffstat (limited to 'src')
-rw-r--r--src/cgame/cg_event.c7
-rw-r--r--src/cgame/cg_local.h6
-rw-r--r--src/cgame/cg_trails.c25
-rw-r--r--src/cgame/cg_weapons.c23
-rw-r--r--src/game/bg_public.h1
-rw-r--r--src/game/g_buildable.c49
-rw-r--r--src/game/g_client.c8
-rw-r--r--src/game/g_weapon.c71
8 files changed, 155 insertions, 35 deletions
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index 1caba1f5..763d8b77 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -874,6 +874,13 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
CG_ShotgunFire( es );
break;
+ case EV_MASS_DRIVER:
+ DEBUGNAME( "EV_MASS_DRIVER" );
+ ByteToDir( es->eventParm, dir );
+ CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_DEFAULT );
+ CG_MassDriverFire( es );
+ break;
+
case EV_GENERAL_SOUND:
DEBUGNAME( "EV_GENERAL_SOUND" );
if( cgs.gameSounds[ es->eventParm ] )
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index 50381ff2..00ddb519 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -459,7 +459,7 @@ typedef struct baseTrailBeam_s
// the time it takes for a beam to fade out (double attached only)
int fadeOutTime;
-
+
char shaderName[ MAX_QPATH ];
qhandle_t shader;
@@ -488,6 +488,7 @@ typedef struct baseTrailSystem_s
baseTrailBeam_t *beams[ MAX_BEAMS_PER_SYSTEM ];
int numBeams;
+ int lifeTime;
qboolean thirdPersonOnly;
qboolean registered; //whether or not the assets for this trail have been loaded
} baseTrailSystem_t;
@@ -499,6 +500,7 @@ typedef struct trailSystem_s
attachment_t frontAttachment;
attachment_t backAttachment;
+ int birthTime;
int destroyTime;
qboolean valid;
} trailSystem_t;
@@ -1252,6 +1254,7 @@ typedef struct
qhandle_t humanBleedPS;
qhandle_t teslaZapTS;
+ qhandle_t massDriverTS;
sfxHandle_t lCannonWarningSound;
@@ -1700,6 +1703,7 @@ void CG_MissileHitWall( weapon_t weapon, weaponMode_t weaponMode, int cli
void CG_MissileHitPlayer( weapon_t weapon, weaponMode_t weaponMode, vec3_t origin, vec3_t dir, int entityNum );
void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum );
void CG_ShotgunFire( entityState_t *es );
+void CG_MassDriverFire( entityState_t *es );
void CG_AddViewWeapon (playerState_t *ps);
void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent );
diff --git a/src/cgame/cg_trails.c b/src/cgame/cg_trails.c
index c8943ed8..ca610461 100644
--- a/src/cgame/cg_trails.c
+++ b/src/cgame/cg_trails.c
@@ -1009,6 +1009,15 @@ static qboolean CG_ParseTrailSystem( baseTrailSystem_t *bts, char **text_p, cons
}
else if( !Q_stricmp( token, "thirdPersonOnly" ) )
bts->thirdPersonOnly = qtrue;
+ else if( !Q_stricmp( token, "lifeTime" ) )
+ {
+ token = COM_Parse( text_p );
+ if( !Q_stricmp( token, "" ) )
+ break;
+
+ bts->lifeTime = atoi_neg( token, qfalse );
+ continue;
+ }
else if( !Q_stricmp( token, "beam" ) ) //acceptable text
continue;
else if( !Q_stricmp( token, "}" ) )
@@ -1291,7 +1300,8 @@ trailSystem_t *CG_SpawnNewTrailSystem( qhandle_t psHandle )
ts->valid = qtrue;
ts->destroyTime = -1;
-
+ ts->birthTime = cg.time;
+
for( j = 0; j < bts->numBeams; j++ )
CG_SpawnNewTrailBeam( bts->beams[ j ], ts );
@@ -1406,6 +1416,19 @@ static void CG_GarbageCollectTrailSystems( void )
CG_DestroyTrailSystem( &tempTS );
}
+ // lifetime expired
+ if( ts->destroyTime <= 0 && ts->class->lifeTime &&
+ ts->birthTime + ts->class->lifeTime < cg.time )
+ {
+ trailSystem_t *tempTS = ts;
+
+ CG_DestroyTrailSystem( &tempTS );
+ if( cg_debugTrails.integer >= 1 )
+ CG_Printf( "TS %s expired (born %d, lives %d, now %d)\n",
+ ts->class->name, ts->birthTime, ts->class->lifeTime,
+ cg.time );
+ }
+
if( cg_debugTrails.integer >= 1 && !ts->valid )
CG_Printf( "TS %s garbage collected\n", ts->class->name );
}
diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c
index a74a15f4..d5c91aa8 100644
--- a/src/cgame/cg_weapons.c
+++ b/src/cgame/cg_weapons.c
@@ -644,6 +644,7 @@ void CG_InitWeapons( void )
CG_RegisterWeapon( i );
cgs.media.level2ZapTS = CG_RegisterTrailSystem( "models/weapons/lev2zap/lightning" );
+ cgs.media.massDriverTS = CG_RegisterTrailSystem( "models/weapons/mdriver/fireTS" );
}
@@ -1614,6 +1615,28 @@ void CG_MissileHitPlayer( weapon_t weaponNum, weaponMode_t weaponMode,
CG_MissileHitWall( weaponNum, weaponMode, 0, origin, dir, IMPACTSOUND_FLESH );
}
+/*
+==============
+CG_MassDriverFire
+
+Draws the mass driver trail
+==============
+*/
+
+void CG_MassDriverFire( entityState_t *es )
+{
+ trailSystem_t *ts;
+
+ ts = CG_SpawnNewTrailSystem( cgs.media.massDriverTS );
+ if( CG_IsTrailSystemValid( &ts ) )
+ {
+ CG_SetAttachmentPoint( &ts->frontAttachment, es->origin2 );
+ CG_SetAttachmentPoint( &ts->backAttachment, es->pos.trBase );
+ CG_AttachToPoint( &ts->frontAttachment );
+ CG_AttachToPoint( &ts->backAttachment );
+ }
+}
+
/*
============================================================================
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 8cbeb64d..cc789c1f 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -516,6 +516,7 @@ typedef enum
EV_BULLET_HIT_WALL,
EV_SHOTGUN,
+ EV_MASS_DRIVER,
EV_MISSILE_HIT,
EV_MISSILE_MISS,
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 27168bbb..721e3fae 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -1840,35 +1840,38 @@ void HReactor_Think( gentity_t *self )
if( self->spawned && ( self->health > 0 ) )
{
- //do some damage
+ qboolean fired = qfalse;
+
+ // Creates a tesla trail for every target
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for( i = 0; i < num; i++ )
{
enemy = &g_entities[ entityList[ i ] ];
+ if( !enemy->client ||
+ enemy->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS )
+ continue;
- if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
- {
- self->timestamp = level.time;
- if( self->dcc )
- {
- G_SelectiveRadiusDamage( self->s.pos.trBase, self,
- REACTOR_ATTACK_DCC_DAMAGE, REACTOR_ATTACK_DCC_RANGE, self,
- MOD_REACTOR, PTE_HUMANS );
- }
- else
- {
- G_SelectiveRadiusDamage( self->s.pos.trBase, self,
- REACTOR_ATTACK_DAMAGE, REACTOR_ATTACK_RANGE, self,
- MOD_REACTOR, PTE_HUMANS );
- }
-
- tent = G_TempEntity( enemy->s.pos.trBase, EV_TESLATRAIL );
-
- VectorCopy( self->s.pos.trBase, tent->s.origin2 );
+ tent = G_TempEntity( enemy->s.pos.trBase, EV_TESLATRAIL );
+ tent->s.generic1 = self->s.number; //src
+ tent->s.clientNum = enemy->s.number; //dest
+ VectorCopy( self->s.pos.trBase, tent->s.origin2 );
+ fired = qtrue;
+ }
- tent->s.generic1 = self->s.number; //src
- tent->s.clientNum = enemy->s.number; //dest
- }
+ // Actual damage is done by radius
+ if( fired )
+ {
+ self->timestamp = level.time;
+ if( self->dcc )
+ G_SelectiveRadiusDamage( self->s.pos.trBase, self,
+ REACTOR_ATTACK_DCC_DAMAGE,
+ REACTOR_ATTACK_DCC_RANGE, self,
+ MOD_REACTOR, PTE_HUMANS );
+ else
+ G_SelectiveRadiusDamage( self->s.pos.trBase, self,
+ REACTOR_ATTACK_DAMAGE,
+ REACTOR_ATTACK_RANGE, self,
+ MOD_REACTOR, PTE_HUMANS );
}
}
diff --git a/src/game/g_client.c b/src/game/g_client.c
index 0e657f0a..b1b07df4 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -1590,6 +1590,14 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
trap_LinkEntity( ent );
+
+ // if this is devmap, give them some credits
+ if( g_cheats.integer && ent != spawn )
+ {
+ int credits = ent->client->pers.teamSelection == PTE_HUMANS ? 1000 : 5;
+
+ G_AddCreditToClient( ent->client, credits, qtrue );
+ }
}
// must do this here so the number of active clients is calculated
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index 7217bb1b..22d4dd74 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -438,19 +438,23 @@ MASS DRIVER
*/
#ifdef MDRIVER_SHOOT_THROUGH
+#define MDRIVER_MAX_HITS 16
void massDriverFire( gentity_t *ent )
{
trace_t tr;
- vec3_t end;
- gentity_t *tent, *traceEnt;
- int i, skipent;
+ vec3_t hitPoints[ MDRIVER_MAX_HITS ], hitNormals[ MDRIVER_MAX_HITS ],
+ origin, originToEnd, muzzleToOrigin, end;
+ gentity_t *traceEnts[ MDRIVER_MAX_HITS ], *traceEnt, *tent;
+ float length_offset;
+ int i, hits = 0, skipent;
- VectorMA( muzzle, 8192 * 16, forward, end );
+ // loop through all entities hit by a line trace
G_UnlaggedOn( muzzle, 8192 * 16 );
+ VectorMA( muzzle, 8192 * 16, forward, end );
VectorCopy( muzzle, tr.endpos );
skipent = ent->s.number;
- for( i = 0; i < 64 && skipent != ENTITYNUM_NONE; i++ )
+ for( i = 0; i < MDRIVER_MAX_HITS && skipent != ENTITYNUM_NONE; i++ )
{
trap_Trace( &tr, tr.endpos, NULL, NULL, end, skipent, MASK_SHOT );
if( tr.surfaceFlags & SURF_NOIMPACT )
@@ -473,24 +477,71 @@ void massDriverFire( gentity_t *ent )
!g_friendlyBuildableFire.integer )
skipent = ENTITYNUM_NONE;
- // snap the endpos to integers, but nudged towards the line
- SnapVectorTowards( tr.endpos, muzzle );
+ // save the hit entity, position, and normal
+ VectorCopy( tr.endpos, hitPoints[ hits ] );
+ VectorCopy( tr.plane.normal, hitNormals[ hits ] );
+ SnapVectorTowards( hitPoints[ hits ], muzzle );
+ traceEnts[ hits++ ] = traceEnt;
+ }
+ if( !hits )
+ return;
+
+ // originate trail line from the gun tip, not the head!
+ VectorCopy( muzzle, origin );
+ VectorMA( origin, -8, up, origin );
+ VectorMA( origin, 6, right, origin );
+ VectorMA( origin, 48, forward, origin );
+
+ // save the final position
+ VectorCopy( tr.endpos, end );
+ VectorSubtract( end, origin, originToEnd );
+ VectorNormalize( originToEnd );
+
+ // origin is further in front than muzzle, need to adjust length
+ VectorSubtract( origin, muzzle, muzzleToOrigin );
+ length_offset = VectorLength( muzzleToOrigin );
+
+ // now that the trace is finished, we know where we stopped and can generate
+ // visually correct impact locations
+ for( i = 0; i < hits; i++ )
+ {
+ vec3_t muzzleToPos;
+ float length;
+
+ // restore saved values
+ VectorCopy( hitPoints[ i ], tr.endpos );
+ VectorCopy( hitNormals[ i ], tr.plane.normal );
+ traceEnt = traceEnts[ i ];
+
+ // compute the visually correct impact point
+ VectorSubtract( tr.endpos, muzzle, muzzleToPos );
+ length = VectorLength( muzzleToPos ) - length_offset;
+ VectorMA( origin, length, originToEnd, tr.endpos );
// send impact
if( traceEnt->takedamage && traceEnt->client )
BloodSpurt( ent, traceEnt, &tr );
- else
+ else if( i < hits - 1 )
{
tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
tent->s.eventParm = DirToByte( tr.plane.normal );
tent->s.weapon = ent->s.weapon;
- tent->s.generic1 = ent->s.generic1; //weaponMode
+ tent->s.generic1 = ent->s.generic1; // weaponMode
}
-
+
if( traceEnt->takedamage )
G_Damage( traceEnt, ent, ent, forward, tr.endpos,
MDRIVER_DMG, 0, MOD_MDRIVER );
}
+
+ // create an event entity for the trail, doubles as an impact event
+ SnapVectorTowards( end, muzzle );
+ tent = G_TempEntity( end, EV_MASS_DRIVER );
+ tent->s.eventParm = DirToByte( tr.plane.normal );
+ tent->s.weapon = ent->s.weapon;
+ tent->s.generic1 = ent->s.generic1; // weaponMode
+ VectorCopy( origin, tent->s.origin2 );
+
G_UnlaggedOff( );
}