diff options
-rw-r--r-- | scripts/mdriver.trail | 10 | ||||
-rw-r--r-- | scripts/weapons.particle | 47 | ||||
-rw-r--r-- | scripts/weapons.shader | 93 | ||||
-rw-r--r-- | src/cgame/cg_event.c | 7 | ||||
-rw-r--r-- | src/cgame/cg_local.h | 6 | ||||
-rw-r--r-- | src/cgame/cg_trails.c | 25 | ||||
-rw-r--r-- | src/cgame/cg_weapons.c | 23 | ||||
-rw-r--r-- | src/game/bg_public.h | 1 | ||||
-rw-r--r-- | src/game/g_buildable.c | 49 | ||||
-rw-r--r-- | src/game/g_client.c | 8 | ||||
-rw-r--r-- | src/game/g_weapon.c | 71 |
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( ); } |