summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scripts/mdriver.trail10
-rw-r--r--scripts/weapons.particle47
-rw-r--r--scripts/weapons.shader93
-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
11 files changed, 292 insertions, 48 deletions
diff --git a/scripts/mdriver.trail b/scripts/mdriver.trail
new file mode 100644
index 00000000..b1545e6b
--- /dev/null
+++ b/scripts/mdriver.trail
@@ -0,0 +1,10 @@
+models/weapons/mdriver/fireTS
+{
+ beam
+ {
+ shader gfx/mdriver/trail
+ width 3.0 3.0
+ textureType stretch 0.94 0.03
+ }
+ lifeTime 70
+}
diff --git a/scripts/weapons.particle b/scripts/weapons.particle
index 40971d49..c0b2ab24 100644
--- a/scripts/weapons.particle
+++ b/scripts/weapons.particle
@@ -417,36 +417,57 @@ models/weapons/mdriver/impactPS
{
particle
{
+ shader sync gfx/mdriver/green_particle
+
+ normalDisplacement 1.0
+
+ velocityType normal
+
+ radius 0 6.0 12.0
+ alpha 70 1.0 0.0
+ rotation 0 ~360 -
+
+ lifeTime 140
+ }
+
+ count 1
+ delay 0
+ period 0 - ~0%
+ }
+
+ ejector
+ {
+ particle
+ {
shader sync gfx/mdriver/green_particle
displacement 0 0 0 ~2.0
-
- normalDisplacement 10.0
+ normalDisplacement 7.0
velocityType normal
velocityDir linear
- velocityMagnitude 400
- velocity 0 0 0 ~80
+ velocityMagnitude 200
+ velocity 0 0 0 ~90
- accelerationType normal
+ accelerationType static
accelerationDir linear
- accelerationMagnitude 200
- acceleration 0 0 1 ~360
+ accelerationMagnitude 300
+ acceleration 0 0 -1 ~10
- radius 0 6.0 4.0
- alpha 0 1.0 0.0
+ radius 0 2.0~1.0 0.0
+ alpha 0 1.0 1.0
rotation 0 ~360 -
bounce 0.5
- lifeTime 1000
+ lifeTime 500
}
- count 10
+ count 3
delay 0
period 0 - ~0%
- }
+ }
}
-
+
models/weapons/lcannon/missilePS
{
ejector
diff --git a/scripts/weapons.shader b/scripts/weapons.shader
new file mode 100644
index 00000000..960aecb6
--- /dev/null
+++ b/scripts/weapons.shader
@@ -0,0 +1,93 @@
+gfx/blaster/orange_particle
+{
+ cull disable
+ {
+ map gfx/blaster/orange_particle.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ alphaGen vertex
+ rgbGen vertex
+ }
+}
+
+gfx/mdriver/green_particle
+{
+ cull disable
+ {
+ map gfx/mdriver/green_particle.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ rgbGen vertex
+ alphaGen vertex
+ }
+}
+
+gfx/mdriver/trail
+{
+ nomipmaps
+ cull disable
+ {
+ map gfx/mdriver/trail.tga
+ blendFunc blend
+ }
+}
+
+gfx/psaw/blue_particle
+{
+ cull disable
+ {
+ map gfx/psaw/blue_particle.jpg
+ blendFunc GL_ONE GL_ONE
+ alphaGen vertex
+ rgbGen vertex
+ }
+}
+
+gfx/rifle/verysmallrock
+{
+ cull disable
+ {
+ map gfx/rifle/verysmallrock.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ alphaGen vertex
+ rgbGen vertex
+ }
+}
+
+gfx/prifle/red_blob
+{
+ cull disable
+ {
+ map gfx/prifle/red_blob.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ alphaGen vertex
+ }
+}
+
+gfx/prifle/red_streak
+{
+ nomipmaps
+ cull disable
+ {
+ map gfx/prifle/red_streak.tga
+ blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ alphaGen vertex
+ }
+}
+
+gfx/lcannon/primary
+{
+ cull disable
+ {
+ animmap 24 gfx/lcannon/primary_1.jpg gfx/lcannon/primary_2.jpg gfx/lcannon/primary_3.jpg gfx/lcannon/primary_4.jpg
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
+gfx/lasgun/purple_particle
+{
+ cull disable
+ {
+ map gfx/lasgun/purple_particle.tga
+ blendFunc GL_ONE GL_ONE
+ }
+}
+
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( );
}