summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cgame/cg_ents.c175
-rw-r--r--src/cgame/cg_event.c41
-rw-r--r--src/cgame/cg_local.h477
-rw-r--r--src/cgame/cg_main.c4
-rw-r--r--src/cgame/cg_particles.c146
-rw-r--r--src/cgame/cg_players.c23
-rw-r--r--src/cgame/cg_weapons.c476
-rw-r--r--src/game/bg_public.h3
-rw-r--r--src/game/g_weapon.c22
9 files changed, 782 insertions, 585 deletions
diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c
index e7a8bd22..43897f4e 100644
--- a/src/cgame/cg_ents.c
+++ b/src/cgame/cg_ents.c
@@ -312,6 +312,31 @@ static void CG_Speaker( centity_t *cent )
/*
===============
+CG_LaunchMissile
+===============
+*/
+static void CG_LaunchMissile( centity_t *cent )
+{
+ entityState_t *es;
+ const weaponInfo_t *weapon;
+ particleSystem_t *ps;
+
+ es = &cent->currentState;
+ if( es->weapon > WP_NUM_WEAPONS )
+ es->weapon = 0;
+
+ weapon = &cg_weapons[ es->weapon ];
+
+ if( weapon->missileParticleSystem )
+ {
+ ps = CG_SpawnNewParticleSystem( weapon->missileParticleSystem );
+ CG_SetParticleSystemCent( ps, cent );
+ CG_AttachParticleSystemToCent( ps );
+ }
+}
+
+/*
+===============
CG_Missile
===============
*/
@@ -360,90 +385,35 @@ static void CG_Missile( centity_t *cent )
VectorCopy( cent->lerpOrigin, ent.origin );
VectorCopy( cent->lerpOrigin, ent.oldorigin );
- switch( cent->currentState.weapon )
+ if( weapon->usesSpriteMissle )
{
- case WP_BLASTER:
- ent.reType = RT_SPRITE;
- ent.radius = 4;
- ent.rotation = 0;
- ent.customShader = cgs.media.blasterShader;
- trap_R_AddRefEntityToScene( &ent );
- switchBugWorkaround = qtrue;
- break;
-
- case WP_PULSE_RIFLE:
- ent.reType = RT_SPRITE;
- ent.radius = 4;
- ent.rotation = 0;
- ent.customShader = cgs.media.plasmaBallShader;
- trap_R_AddRefEntityToScene( &ent );
- switchBugWorkaround = qtrue;
- break;
-
- case WP_LUCIFER_CANNON:
- ent.skinNum = cg.clientFrame & 1;
- ent.hModel = weapon->missileModel;
- ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
-
- // convert direction of travel into axis
- if( VectorNormalize2( s1->pos.trDelta, ent.axis[ 0 ] ) == 0 )
- ent.axis[ 0 ][ 2 ] = 1;
-
- RotateAroundDirection( ent.axis, cg.time / 4 );
-
- fraction = (float)s1->generic1 / (float)LCANNON_TOTAL_CHARGE;
- VectorScale( ent.axis[ 0 ], fraction, ent.axis[ 0 ] );
- VectorScale( ent.axis[ 1 ], fraction, ent.axis[ 1 ] );
- VectorScale( ent.axis[ 2 ], fraction, ent.axis[ 2 ] );
- ent.nonNormalizedAxes = qtrue;
-
- break;
-
- case WP_HIVE:
- //FIXME:
- ent.reType = RT_SPRITE;
- ent.radius = 4;
- ent.rotation = 0;
- ent.customShader = cgs.media.blasterShader;
- trap_R_AddRefEntityToScene( &ent );
- switchBugWorkaround = qtrue;
- break;
-
-/* case WP_LOCKBLOB_LAUNCHER:
- //FIXME:
- break;*/
-
-/* case WP_POUNCE_UPG:
- //FIXME:
- break;*/
-
- case WP_FLAMER:
- //TA: don't actually display the missile (use the particle engine)
- switchBugWorkaround = qtrue;
- break;
-
- default:
- // flicker between two skins
- ent.skinNum = cg.clientFrame & 1;
- ent.hModel = weapon->missileModel;
- ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
+ ent.reType = RT_SPRITE;
+ ent.radius = weapon->missileSpriteSize;
+ ent.rotation = 0;
+ ent.customShader = weapon->missileSprite;
+ }
+ else
+ {
+ ent.hModel = weapon->missileModel;
+ ent.renderfx = weapon->missileRenderfx | RF_NOSHADOW;
- // convert direction of travel into axis
- if( VectorNormalize2( s1->pos.trDelta, ent.axis[ 0 ] ) == 0 )
- ent.axis[ 0 ][ 2 ] = 1;
+ // convert direction of travel into axis
+ if( VectorNormalize2( s1->pos.trDelta, ent.axis[ 0 ] ) == 0 )
+ ent.axis[ 0 ][ 2 ] = 1;
+ if( weapon->missileRotates )
+ {
// spin as it moves
if( s1->pos.trType != TR_STATIONARY )
RotateAroundDirection( ent.axis, cg.time / 4 );
else
RotateAroundDirection( ent.axis, s1->time );
+ }
}
- if( switchBugWorkaround )
- return;
-
- // add to refresh list, possibly with quad glow
- CG_AddRefEntityWithPowerups( &ent, s1->powerups, TEAM_FREE );
+ //only refresh if there is something to display
+ if( weapon->missileSprite || weapon->missileModel )
+ trap_R_AddRefEntityToScene( &ent );
}
/*
@@ -877,6 +847,44 @@ static void CG_CalcEntityLerpPositions( centity_t *cent )
}
+/*
+===============
+CG_CEntityPVSEnter
+
+===============
+*/
+static void CG_CEntityPVSEnter( centity_t *cent )
+{
+ int i;
+
+ if( cg_debugPVS.integer )
+ CG_Printf( "Entity %d entered PVS\n", cent->currentState.number );
+
+ switch( cent->currentState.eType )
+ {
+ case ET_MISSILE:
+ CG_LaunchMissile( cent );
+ break;
+ }
+
+ //clear any particle systems from previous uses of this centity_t
+ cent->muzzlePS = NULL;
+ cent->muzzlePsTrigger = qfalse;
+}
+
+
+/*
+===============
+CG_CEntityPVSLeave
+
+===============
+*/
+static void CG_CEntityPVSLeave( centity_t *cent )
+{
+ if( cg_debugPVS.integer )
+ CG_Printf( "Entity %d left PVS\n", cent->currentState.number );
+}
+
/*
===============
@@ -1017,7 +1025,7 @@ void CG_AddPacketEntities( void )
cg.ep.numAlienClients = 0;
cg.ep.numHumanClients = 0;
- for( num = 0 ; num < cg.snap->numEntities ; num++ )
+ for( num = 0; num < cg.snap->numEntities; num++ )
{
cent = &cg_entities[ cg.snap->entities[ num ].number ];
@@ -1055,11 +1063,28 @@ void CG_AddPacketEntities( void )
//Com_Printf( "%d %d\n", cgIP.numAlienClients, cgIP.numHumanClients );
+ for( num = 0; num < MAX_GENTITIES; num++ )
+ cg_entities[ num ].valid = qfalse;
+
// add each entity sent over by the server
for( num = 0; num < cg.snap->numEntities; num++ )
{
cent = &cg_entities[ cg.snap->entities[ num ].number ];
+ cent->valid = qtrue;
CG_AddCEntity( cent );
}
+
+ for( num = 0; num < MAX_GENTITIES; num++ )
+ {
+ cent = &cg_entities[ num ];
+
+ if( cent->valid && !cent->oldValid )
+ CG_CEntityPVSEnter( cent );
+ else if( !cent->valid && cent->oldValid )
+ CG_CEntityPVSLeave( cent );
+
+ cent->oldValid = cent->valid;
+ }
+
}
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index 5907228a..9aa0028b 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -689,47 +689,6 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
break;
- case EV_LAS_HIT_WALL:
- DEBUGNAME( "EV_LAS_HIT_WALL" );
- ByteToDir( es->eventParm, dir );
- CG_LasGunHit( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
- break;
-
- case EV_LAS_HIT_FLESH:
- DEBUGNAME( "EV_LAS_HIT_FLESH" );
- CG_LasGunHit( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
- break;
-
-#define MASS_EJECTION_VEL 300
- case EV_MASS_DRIVER_HIT:
- DEBUGNAME( "EV_MASS_DRIVER_HIT" );
- for( i = 0; i <= 10; i++ )
- {
- qhandle_t spark;
- vec3_t velocity;
- vec3_t accel = { 0.0f, 0.0f, -DEFAULT_GRAVITY };
- vec3_t origin, normal;
-
- ByteToDir( es->eventParm, normal );
-
- VectorMA( es->pos.trBase, 10.0f, normal, origin );
-
- if( crandom( ) > 0.5f )
- spark = cgs.media.gibSpark1;
- else
- spark = cgs.media.gibSpark2;
-
- velocity[ 0 ] = ( 2 * random( ) - 1.0f ) * MASS_EJECTION_VEL;
- velocity[ 1 ] = ( 2 * random( ) - 1.0f ) * MASS_EJECTION_VEL;
- velocity[ 2 ] = ( 2 * random( ) - 1.0f ) * MASS_EJECTION_VEL;
-
- CG_LaunchSprite( origin, velocity, accel, 0.0f, 0.5f, 4.0f, 2.0f, 255, 0, rand( ) % 360,
- cg.time, cg.time, 5000 + ( crandom( ) * 3000 ),
- spark, qfalse, qfalse );
- }
-
- 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 281d732b..0e94e52c 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -115,6 +115,228 @@ typedef enum
} impactSound_t;
+//particle system stuff
+#define MAX_SHADER_FRAMES 64
+#define MAX_EJECTORS_PER_SYSTEM 4
+#define MAX_PARTICLES_PER_EJECTOR 4
+
+#define MAX_BASEPARTICLE_SYSTEMS 512
+#define MAX_BASEPARTICLE_EJECTORS MAX_BASEPARTICLE_SYSTEMS*MAX_EJECTORS_PER_SYSTEM
+#define MAX_BASEPARTICLES MAX_BASEPARTICLE_EJECTORS*MAX_PARTICLES_PER_EJECTOR
+
+#define MAX_PARTICLE_SYSTEMS 64
+#define MAX_PARTICLE_EJECTORS MAX_PARTICLE_SYSTEMS*MAX_EJECTORS_PER_SYSTEM
+#define MAX_PARTICLES MAX_PARTICLE_EJECTORS*8
+
+#define PARTICLES_INFINITE -1
+#define PARTICLES_SAME_AS_INITIAL -2
+
+/*
+===============
+
+COMPILE TIME STRUCTURES
+
+===============
+*/
+
+typedef enum
+{
+ PMT_STATIC,
+ PMT_TAG,
+ PMT_CENT_ANGLES,
+ PMT_NORMAL
+} pMoveType_t;
+
+typedef enum
+{
+ PMD_LINEAR,
+ PMD_POINT
+} pDirType_t;
+
+typedef struct pMoveValues_u
+{
+ pDirType_t dirType;
+
+ //PMD_LINEAR
+ vec3_t dir;
+ float dirRandAngle;
+
+ //PMD_POINT
+ vec3_t point;
+ float pointRandAngle;
+
+ float mag;
+ float magRandFrac;
+
+ float parentVelFrac;
+ float parentVelFracRandFrac;
+} pMoveValues_t;
+
+typedef struct pLerpValues_s
+{
+ int delay;
+ float delayRandFrac;
+
+ float initial;
+ float initialRandFrac;
+
+ float final;
+ float finalRandFrac;
+
+ float randFrac;
+} pLerpValues_t;
+
+//particle template
+typedef struct baseParticle_s
+{
+ float randDisplacement;
+
+ pMoveType_t velMoveType;
+ pMoveValues_t velMoveValues;
+
+ pMoveType_t accMoveType;
+ pMoveValues_t accMoveValues;
+
+ int lifeTime;
+ float lifeTimeRandFrac;
+
+ float bounceFrac;
+ float bounceFracRandFrac;
+
+ pLerpValues_t radius;
+ pLerpValues_t alpha;
+ pLerpValues_t rotation;
+
+ //particle invariant stuff
+ char shaderNames[ MAX_QPATH ][ MAX_SHADER_FRAMES ];
+ qhandle_t shaders[ MAX_SHADER_FRAMES ];
+ int numFrames;
+ float framerate;
+
+ qboolean overdrawProtection;
+ qboolean realLight;
+} baseParticle_t;
+
+
+//ejector template
+typedef struct baseParticleEjector_s
+{
+ baseParticle_t *particles[ MAX_PARTICLES_PER_EJECTOR ];
+ int numParticles;
+
+ pLerpValues_t eject; //zero period indicates creation of all particles at once
+
+ int totalParticles; //can be infinite
+ float totalParticlesRandFrac;
+} baseParticleEjector_t;
+
+
+//particle system template
+typedef struct baseParticleSystem_s
+{
+ char name[ MAX_QPATH ];
+ baseParticleEjector_t *ejectors[ MAX_EJECTORS_PER_SYSTEM ];
+ int numEjectors;
+
+ qboolean registered; //whether or not the assets for this particle have been loaded
+} baseParticleSystem_t;
+
+
+/*
+===============
+
+RUN TIME STRUCTURES
+
+===============
+*/
+
+typedef enum
+{
+ PSA_STATIC,
+ PSA_TAG,
+ PSA_CENT_ORIGIN
+} psAttachmentType_t;
+
+
+typedef struct psAttachment_s
+{
+ qboolean staticValid;
+ qboolean tagValid;
+ qboolean centValid;
+ qboolean normalValid;
+
+ //PMT_STATIC
+ vec3_t origin;
+
+ //PMT_TAG
+ refEntity_t re; //FIXME: should be pointers?
+ refEntity_t parent; //
+ qhandle_t model;
+ char tagName[ MAX_STRING_CHARS ];
+
+ //PMT_CENT_ANGLES
+ int centNum;
+
+ //PMT_NORMAL
+ vec3_t normal;
+} psAttachment_t;
+
+
+typedef struct particleSystem_s
+{
+ baseParticleSystem_t *class;
+
+ psAttachmentType_t attachType;
+ psAttachment_t attachment;
+ qboolean attached; //is the particle system attached to anything
+
+ qboolean enabled; //necessary?
+
+ qboolean valid;
+} particleSystem_t;
+
+
+typedef struct particleEjector_s
+{
+ baseParticleEjector_t *class;
+ particleSystem_t *parent;
+
+ pLerpValues_t ejectPeriod;
+
+ int count;
+ int totalParticles;
+
+ int nextEjectionTime;
+
+ qboolean valid;
+} particleEjector_t;
+
+
+//used for actual particle evaluation
+typedef struct particle_s
+{
+ baseParticle_t *class;
+ particleEjector_t *parent;
+
+ int birthTime;
+ int lifeTime;
+
+ vec3_t origin;
+ vec3_t velocity;
+
+ pMoveType_t accMoveType;
+ pMoveValues_t accMoveValues;
+
+ int lastEvalTime;
+
+ pLerpValues_t radius;
+ pLerpValues_t alpha;
+ pLerpValues_t rotation;
+
+ qboolean valid;
+} particle_t;
+
+
//=================================================
// player entities need to track more information
@@ -166,7 +388,7 @@ typedef struct
//=================================================
-
+#define MAX_CENTITY_PARTICLE_SYSTEMS 8
// centity_t have a direct corespondence with gentity_t in the game, but
// only the entityState_t is directly communicated to the cgame
@@ -225,6 +447,12 @@ typedef struct centity_s
qboolean flareStatus; //flare is visble?
qboolean doorState;
+
+ particleSystem_t *muzzlePS;
+ qboolean muzzlePsTrigger;
+
+ qboolean valid;
+ qboolean oldValid;
} centity_t;
@@ -432,6 +660,7 @@ typedef struct weaponInfo_s
float flashDlight;
vec3_t flashDlightColor;
sfxHandle_t flashSound[ 4 ]; // fast firing weapons randomly choose
+ qboolean continuousFlash;
qhandle_t weaponIcon;
qhandle_t ammoIcon;
@@ -445,6 +674,11 @@ typedef struct weaponInfo_s
float missileDlight;
vec3_t missileDlightColor;
int missileRenderfx;
+ qboolean usesSpriteMissle;
+ qhandle_t missileSprite;
+ int missileSpriteSize;
+ qhandle_t missileParticleSystem;
+ qboolean missileRotates;
void (*ejectBrassFunc)( centity_t * );
@@ -454,6 +688,18 @@ typedef struct weaponInfo_s
sfxHandle_t readySound;
sfxHandle_t firingSound;
qboolean loopFireSound;
+
+ qhandle_t muzzleParticleSystem;
+
+ qboolean alwaysImpact;
+ qhandle_t impactDish;
+ qhandle_t impactDishShader;
+ qhandle_t impactParticleSystem;
+ qhandle_t impactMark;
+ qhandle_t impactMarkSize;
+ sfxHandle_t impactSound[ 4 ]; //random impact sound
+ float impactDlight;
+ vec3_t impactDlightColor;
} weaponInfo_t;
typedef struct upgradeInfo_s
@@ -857,12 +1103,6 @@ typedef struct
qhandle_t lightningExplosionModel;
// weapon effect shaders
- qhandle_t railExplosionShader;
- qhandle_t plasmaExplosionShader;
- qhandle_t bulletExplosionShader;
- qhandle_t rocketExplosionShader;
- qhandle_t grenadeExplosionShader;
- qhandle_t bfgExplosionShader;
qhandle_t bloodExplosionShader;
// special effects models
@@ -875,7 +1115,6 @@ typedef struct
sfxHandle_t useNothingSound;
sfxHandle_t wearOffSound;
sfxHandle_t footsteps[ FOOTSTEP_TOTAL ][ 4 ];
- sfxHandle_t sfx_lghit;
sfxHandle_t sfx_ric1;
sfxHandle_t sfx_ric2;
sfxHandle_t sfx_ric3;
@@ -1154,6 +1393,8 @@ extern vmCvar_t cg_wwFollow;
extern vmCvar_t cg_zsortLEs;
extern vmCvar_t cg_consoleLatency;
extern vmCvar_t cg_lightFlare;
+extern vmCvar_t cg_debugParticles;
+extern vmCvar_t cg_debugPVS;
//TA: hack to get class an carriage through to UI module
extern vmCvar_t ui_currentClass;
@@ -1343,7 +1584,6 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t
void CG_Explosion( int clientNum, vec3_t origin, vec3_t dir );
void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum, int damage );
void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum );
-void CG_LasGunHit( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum );
void CG_TeslaTrail( vec3_t start, vec3_t end, int srcENum, int destENum );
void CG_AlienZap( vec3_t start, vec3_t end, int srcENum, int destENum );
@@ -1467,234 +1707,21 @@ qboolean S_decodeMP3( char *mp3File, char *wavFile );
//
// cg_particles.c
//
-
-#define MAX_SHADER_FRAMES 64
-#define MAX_EJECTORS_PER_SYSTEM 4
-#define MAX_PARTICLES_PER_EJECTOR 4
-
-#define MAX_BASEPARTICLE_SYSTEMS 512
-#define MAX_BASEPARTICLE_EJECTORS MAX_BASEPARTICLE_SYSTEMS*MAX_EJECTORS_PER_SYSTEM
-#define MAX_BASEPARTICLES MAX_BASEPARTICLE_EJECTORS*MAX_PARTICLES_PER_EJECTOR
-
-#define MAX_PARTICLE_SYSTEMS 16
-#define MAX_PARTICLE_EJECTORS MAX_PARTICLE_SYSTEMS*MAX_EJECTORS_PER_SYSTEM
-#define MAX_PARTICLES MAX_PARTICLE_EJECTORS*8
-
-#define PARTICLES_INFINITE -1
-#define PARTICLES_SAME_AS_INITIAL -2
-
-/*
-===============
-
-COMPILE TIME STRUCTURES
-
-===============
-*/
-
-typedef enum
-{
- PMT_STATIC,
- PMT_TAG,
- PMT_CENT_ANGLES
-} pMoveType_t;
-
-typedef enum
-{
- PMD_LINEAR,
- PMD_POINT
-} pDirType_t;
-
-typedef struct pMoveValues_u
-{
- pDirType_t dirType;
-
- //PMD_LINEAR
- vec3_t dir;
- float dirRandAngle;
-
- //PMD_POINT
- vec3_t point;
- float pointRandAngle;
-
- float mag;
- float magRandFrac;
-
- float parentVelFrac;
- float parentVelFracRandFrac;
-} pMoveValues_t;
-
-typedef struct pLerpValues_s
-{
- int delay;
- float delayRandFrac;
-
- float initial;
- float initialRandFrac;
-
- float final;
- float finalRandFrac;
-
- float randFrac;
-} pLerpValues_t;
-
-//particle template
-typedef struct baseParticle_s
-{
- float randDisplacement;
-
- pMoveType_t velMoveType;
- pMoveValues_t velMoveValues;
-
- pMoveType_t accMoveType;
- pMoveValues_t accMoveValues;
-
- int lifeTime;
- float lifeTimeRandFrac;
-
- float bounceFrac;
- float bounceFracRandFrac;
-
- pLerpValues_t radius;
- pLerpValues_t alpha;
- pLerpValues_t rotation;
-
- //particle invariant stuff
- char shaderNames[ MAX_QPATH ][ MAX_SHADER_FRAMES ];
- qhandle_t shaders[ MAX_SHADER_FRAMES ];
- int numFrames;
- float framerate;
-
- qboolean overdrawProtection;
- qboolean realLight;
-} baseParticle_t;
-
-
-//ejector template
-typedef struct baseParticleEjector_s
-{
- baseParticle_t *particles[ MAX_PARTICLES_PER_EJECTOR ];
- int numParticles;
-
- pLerpValues_t eject; //zero period indicates creation of all particles at once
-
- int totalParticles; //can be infinite
- float totalParticlesRandFrac;
-} baseParticleEjector_t;
-
-
-//particle system template
-typedef struct baseParticleSystem_s
-{
- char name[ MAX_QPATH ];
- baseParticleEjector_t *ejectors[ MAX_EJECTORS_PER_SYSTEM ];
- int numEjectors;
-
- qboolean registered; //whether or not the assets for this particle have been loaded
-} baseParticleSystem_t;
-
-
-/*
-===============
-
-RUN TIME STRUCTURES
-
-===============
-*/
-
-typedef enum
-{
- PSA_STATIC,
- PSA_TAG,
- PSA_CENT_ORIGIN
-} psAttachmentType_t;
-
-
-typedef struct psAttachment_s
-{
- qboolean staticValid;
- qboolean tagValid;
- qboolean centValid;
-
- //PMT_STATIC
- vec3_t origin;
-
- //PMT_TAG
- refEntity_t re;
- refEntity_t parent;
- qhandle_t model;
- char tagName[ MAX_STRING_CHARS ];
-
- //PMT_CENT_ANGLES
- centity_t *cent;
-} psAttachment_t;
-
-
-typedef struct particleSystem_s
-{
- baseParticleSystem_t *class;
-
- psAttachmentType_t attachType;
- psAttachment_t attachment;
- qboolean attached; //is the particle system attached to anything
-
- qboolean enabled; //necessary?
-
- qboolean valid;
-} particleSystem_t;
-
-
-typedef struct particleEjector_s
-{
- baseParticleEjector_t *class;
- particleSystem_t *parent;
-
- pLerpValues_t ejectPeriod;
-
- int count;
- int totalParticles;
-
- int nextEjectionTime;
-
- qboolean valid;
-} particleEjector_t;
-
-
-//used for actual particle evaluation
-typedef struct particle_s
-{
- baseParticle_t *class;
- particleEjector_t *parent;
-
- int birthTime;
- int lifeTime;
-
- vec3_t origin;
- vec3_t velocity;
-
- pMoveType_t accMoveType;
- pMoveValues_t accMoveValues;
-
- int lastEvalTime;
-
- pLerpValues_t radius;
- pLerpValues_t alpha;
- pLerpValues_t rotation;
-
- qboolean valid;
-} particle_t;
-
void CG_LoadParticleSystems( void );
qhandle_t CG_RegisterParticleSystem( char *name );
particleSystem_t *CG_SpawnNewParticleSystem( qhandle_t psHandle );
void CG_DestroyParticleSystem( particleSystem_t *ps );
+qboolean CG_IsParticleSystemInfinite( particleSystem_t *ps );
+
void CG_SetParticleSystemCent( particleSystem_t *ps, centity_t *cent );
void CG_AttachParticleSystemToCent( particleSystem_t *ps );
void CG_SetParticleSystemTag( particleSystem_t *ps, refEntity_t parent, qhandle_t model, char *tagName );
void CG_AttachParticleSystemToTag( particleSystem_t *ps );
void CG_SetParticleSystemOrigin( particleSystem_t *ps, vec3_t origin );
void CG_AttachParticleSystemOrigin( particleSystem_t *ps );
+void CG_SetParticleSystemNormal( particleSystem_t *ps, vec3_t normal );
void CG_AddParticles( void );
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index 01e8bedd..e42f1f50 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -196,6 +196,8 @@ vmCvar_t cg_wwFollow;
vmCvar_t cg_zsortLEs;
vmCvar_t cg_consoleLatency;
vmCvar_t cg_lightFlare;
+vmCvar_t cg_debugParticles;
+vmCvar_t cg_debugPVS;
//TA: hack to get class and carriage through to UI module
vmCvar_t ui_currentClass;
@@ -290,6 +292,8 @@ static cvarTable_t cvarTable[ ] =
{ &cg_zsortLEs, "cg_zsortLEs", "1", CVAR_ARCHIVE },
{ &cg_consoleLatency, "cg_consoleLatency", "3000", CVAR_ARCHIVE },
{ &cg_lightFlare, "cg_lightFlare", "3", CVAR_ARCHIVE },
+ { &cg_debugParticles, "cg_debugParticles", "0", CVAR_CHEAT },
+ { &cg_debugPVS, "cg_debugPVS", "0", CVAR_CHEAT },
{ &ui_currentClass, "ui_currentClass", "0", 0 },
{ &ui_carriage, "ui_carriage", "", 0 },
diff --git a/src/cgame/cg_particles.c b/src/cgame/cg_particles.c
index 99a9e352..75f3c4ab 100644
--- a/src/cgame/cg_particles.c
+++ b/src/cgame/cg_particles.c
@@ -1,3 +1,18 @@
+// cg_particles.c -- the particle system
+
+/*
+ * Portions Copyright (C) 2000-2001 Tim Angus
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the OSML - Open Source Modification License v1.0 as
+ * described in the file COPYING which is distributed with this source
+ * code.
+ *
+ * This program 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.
+ */
+
#include "cg_local.h"
static baseParticleSystem_t baseParticleSystems[ MAX_BASEPARTICLE_SYSTEMS ];
@@ -76,6 +91,7 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
particleEjector_t *pe = parent;
particleSystem_t *ps = parent->parent;
vec3_t forward;
+ centity_t *cent = &cg_entities[ ps->attachment.centNum ];
for( i = 0; i < MAX_PARTICLES; i++ )
{
@@ -124,7 +140,7 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
if( !ps->attachment.centValid )
return NULL;
- VectorCopy( ps->attachment.cent->lerpOrigin, p->origin );
+ VectorCopy( cent->lerpOrigin, p->origin );
break;
}
@@ -161,14 +177,23 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
return NULL;
if( bp->velMoveValues.dirType == PMD_POINT )
- VectorSubtract( ps->attachment.cent->lerpOrigin, p->origin, p->velocity );
+ VectorSubtract( cent->lerpOrigin, p->origin, p->velocity );
else if( bp->velMoveValues.dirType == PMD_LINEAR )
{
- AngleVectors( ps->attachment.cent->lerpAngles, forward, NULL, NULL );
+ AngleVectors( cent->lerpAngles, forward, NULL, NULL );
VectorCopy( forward, p->velocity );
}
break;
+
+ case PMT_NORMAL:
+
+ if( !ps->attachment.normalValid )
+ return NULL;
+
+ VectorCopy( ps->attachment.normal, p->velocity );
+
+ break;
}
VectorNormalize( p->velocity );
@@ -181,7 +206,7 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p
{
VectorMA( p->velocity,
CG_RandomiseValue( bp->velMoveValues.parentVelFrac, bp->velMoveValues.parentVelFracRandFrac ),
- ps->attachment.cent->currentState.pos.trDelta, p->velocity );
+ cent->currentState.pos.trDelta, p->velocity );
}
p->lastEvalTime = cg.time;
@@ -305,7 +330,7 @@ particleSystem_t *CG_SpawnNewParticleSystem( qhandle_t psHandle )
{
int i, j, start;
particleSystem_t *ps = NULL;
- baseParticleSystem_t *bps = &baseParticleSystems[ psHandle ];
+ baseParticleSystem_t *bps = &baseParticleSystems[ psHandle - 1 ];
if( !bps->registered )
{
@@ -327,6 +352,10 @@ particleSystem_t *CG_SpawnNewParticleSystem( qhandle_t psHandle )
CG_SpawnNewParticleEjector( bps->ejectors[ j ], ps );
ps->valid = qtrue;
+
+ if( cg_debugParticles.integer >= 1 )
+ CG_Printf( "PS %s created\n", bps->name );
+
break;
}
}
@@ -369,7 +398,8 @@ qhandle_t CG_RegisterParticleSystem( char *name )
bps->registered = qtrue;
- return i;
+ //avoid returning 0
+ return i + 1;
}
}
@@ -552,6 +582,8 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
bp->velMoveType = PMT_TAG;
else if( !Q_stricmp( token, "cent" ) )
bp->velMoveType = PMT_CENT_ANGLES;
+ else if( !Q_stricmp( token, "normal" ) )
+ bp->velMoveType = PMT_NORMAL;
continue;
}
@@ -667,6 +699,8 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p )
bp->accMoveType = PMT_TAG;
else if( !Q_stricmp( token, "cent" ) )
bp->accMoveType = PMT_CENT_ANGLES;
+ else if( !Q_stricmp( token, "normal" ) )
+ bp->accMoveType = PMT_NORMAL;
continue;
}
@@ -1280,7 +1314,7 @@ Set a particle system attachment means
void CG_SetParticleSystemCent( particleSystem_t *ps, centity_t *cent )
{
ps->attachment.centValid = qtrue;
- ps->attachment.cent = cent;
+ ps->attachment.centNum = cent->currentState.number;
}
/*
@@ -1338,6 +1372,19 @@ void CG_SetParticleSystemOrigin( particleSystem_t *ps, vec3_t origin )
VectorCopy( origin, ps->attachment.origin );
}
+/*
+===============
+CG_SetParticleSystemNormal
+
+Set a particle system attachment means
+===============
+*/
+void CG_SetParticleSystemNormal( particleSystem_t *ps, vec3_t normal )
+{
+ ps->attachment.normalValid = qtrue;
+ VectorCopy( normal, ps->attachment.normal );
+}
+
/*
===============
@@ -1348,11 +1395,45 @@ Destroy a particle system
*/
void CG_DestroyParticleSystem( particleSystem_t *ps )
{
+ if( cg_debugParticles.integer >= 1 )
+ CG_Printf( "PS destroyed\n" );
+
ps->valid = qfalse;
}
/*
===============
+CG_IsParticleSystemInfinite
+
+Test a particle system for 'count infinite' ejectors
+===============
+*/
+qboolean CG_IsParticleSystemInfinite( particleSystem_t *ps )
+{
+ int i;
+ particleEjector_t *pe;
+
+ //don't bother checking already invalid systems
+ if( !ps->valid )
+ return qfalse;
+
+ for( i = 0; i < MAX_PARTICLE_EJECTORS; i++ )
+ {
+ pe = &particleEjectors[ i ];
+
+ if( pe->valid && pe->parent == ps )
+ {
+ if( pe->totalParticles == PARTICLES_INFINITE )
+ return qtrue;
+ }
+ }
+
+ return qfalse;
+}
+
+
+/*
+===============
CG_GarbageCollectParticleSystems
Destroy inactive particle systems
@@ -1360,7 +1441,6 @@ Destroy inactive particle systems
*/
static void CG_GarbageCollectParticleSystems( void )
{
- //FIXME: test this and make sure it's efficient
int i, j, count;
particleSystem_t *ps;
particleEjector_t *pe;
@@ -1370,6 +1450,10 @@ static void CG_GarbageCollectParticleSystems( void )
ps = &particleSystems[ i ];
count = 0;
+ //don't bother checking already invalid systems
+ if( !ps->valid )
+ continue;
+
for( j = 0; j < MAX_PARTICLE_EJECTORS; j++ )
{
pe = &particleEjectors[ j ];
@@ -1380,6 +1464,16 @@ static void CG_GarbageCollectParticleSystems( void )
if( !count )
ps->valid = qfalse;
+
+ //check systems where the parent cent has left te PVS
+ if( ps->attachType == PSA_CENT_ORIGIN )
+ {
+ if( !cg_entities[ ps->attachment.centNum ].valid )
+ ps->valid = qfalse;
+ }
+
+ if( cg_debugParticles.integer >= 1 && !ps->valid )
+ CG_Printf( "PS garbage collected\n" );
}
}
@@ -1420,6 +1514,7 @@ static void CG_EvaluateParticlePhysics( particle_t *p )
vec3_t mins, maxs;
float deltaTime, bounce, radius, dot;
trace_t trace;
+ centity_t *cent;
switch( bp->accMoveType )
{
@@ -1449,15 +1544,26 @@ static void CG_EvaluateParticlePhysics( particle_t *p )
if( !ps->attachment.centValid )
return;
+ cent = &cg_entities[ ps->attachment.centNum ];
+
if( bp->accMoveValues.dirType == PMD_POINT )
- VectorSubtract( ps->attachment.cent->lerpOrigin, p->origin, acceleration );
+ VectorSubtract( cent->lerpOrigin, p->origin, acceleration );
else if( bp->accMoveValues.dirType == PMD_LINEAR )
{
- AngleVectors( ps->attachment.cent->lerpAngles, forward, NULL, NULL );
+ AngleVectors( cent->lerpAngles, forward, NULL, NULL );
VectorCopy( forward, acceleration );
}
break;
+
+ case PMT_NORMAL:
+
+ if( !ps->attachment.normalValid )
+ return;
+
+ VectorCopy( ps->attachment.normal, acceleration );
+
+ break;
}
#define MAX_ACC_RADIUS 1000.0f
@@ -1616,8 +1722,9 @@ void CG_AddParticles( void )
{
int i;
particle_t *p;
+ int numPS = 0, numPE = 0, numP = 0;
- /*CG_GarbageCollectParticleSystems( );*/
+ CG_GarbageCollectParticleSystems( );
//check each ejector and introduce any new particles
CG_SpawnNewParticles( );
@@ -1638,4 +1745,21 @@ void CG_AddParticles( void )
p->valid = qfalse;
}
}
+
+ if( cg_debugParticles.integer >= 2 )
+ {
+ for( i = 0; i < MAX_PARTICLE_SYSTEMS; i++ )
+ if( particleSystems[ i ].valid )
+ numPS++;
+
+ for( i = 0; i < MAX_PARTICLE_EJECTORS; i++ )
+ if( particleEjectors[ i ].valid )
+ numPE++;
+
+ for( i = 0; i < MAX_PARTICLES; i++ )
+ if( particles[ i ].valid )
+ numP++;
+
+ CG_Printf( "PS: %d PE: %d P: %d\n", numPS, numPE, numP );
+ }
}
diff --git a/src/cgame/cg_players.c b/src/cgame/cg_players.c
index bbb8569d..297fe0f9 100644
--- a/src/cgame/cg_players.c
+++ b/src/cgame/cg_players.c
@@ -1682,21 +1682,6 @@ static void CG_PlayerSplash( centity_t *cent )
}
-
-/*
-===============
-CG_AddRefEntityWithPowerups
-
-Adds a piece with modifications or duplications for powerups
-Also called by CG_Missile for quad rockets, but nobody can tell...
-===============
-*/
-void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, int team )
-{
- trap_R_AddRefEntityToScene( ent );
-}
-
-
/*
=================
CG_LightVerts
@@ -1850,15 +1835,7 @@ void CG_Player( centity_t *cent )
vec3_t angles;
int held = es->modelindex;
pTeam_t team = es->powerups & 0xFF;
- static particleSystem_t *partSystem = NULL;
- if( partSystem == NULL )
- {
- CG_Printf( S_COLOR_GREEN "particle system created\n" );
- partSystem = CG_SpawnNewParticleSystem( cgs.media.testParticleSystem );
- CG_SetParticleSystemCent( partSystem, cent );
- CG_AttachParticleSystemToCent( partSystem );
- }
// the client number is stored in clientNum. It can't be derived
// from the entity number, because a single client may have
// multiple corpses on the level using the same clientinfo
diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c
index 7fd3b627..5398ac34 100644
--- a/src/cgame/cg_weapons.c
+++ b/src/cgame/cg_weapons.c
@@ -290,6 +290,186 @@ static qboolean CG_ParseWeaponFile( const char *filename, weaponInfo_t *wi )
continue;
}
+ else if( !Q_stricmp( token, "missileSprite" ) )
+ {
+ int size = 0;
+
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ size = atoi( token );
+
+ if( size < 0 )
+ size = 0;
+
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ wi->missileSprite = trap_R_RegisterShader( token );
+ wi->missileSpriteSize = size;
+ wi->usesSpriteMissle = qtrue;
+
+ if( !wi->missileSprite )
+ CG_Printf( "Missile sprite not found %s: %s\n", filename, token );
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "missileRotates" ) )
+ {
+ wi->missileRotates = qtrue;
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "missileParticleSystem" ) )
+ {
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ wi->missileParticleSystem = CG_RegisterParticleSystem( token );
+
+ if( !wi->missileParticleSystem )
+ CG_Printf( "Missile particle system not found %s: %s\n", filename, token );
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "muzzleParticleSystem" ) )
+ {
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ wi->muzzleParticleSystem = CG_RegisterParticleSystem( token );
+
+ if( !wi->muzzleParticleSystem )
+ CG_Printf( "Muzzle particle system not found %s: %s\n", filename, token );
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "impactParticleSystem" ) )
+ {
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ wi->impactParticleSystem = CG_RegisterParticleSystem( token );
+
+ if( !wi->impactParticleSystem )
+ CG_Printf( "Impact particle system not found %s: %s\n", filename, token );
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "impactDish" ) )
+ {
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ wi->impactDish = trap_R_RegisterModel( token );
+
+ if( !wi->impactDish )
+ CG_Printf( "Impact dish model not found %s: %s\n", filename, token );
+
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ wi->impactDishShader = trap_R_RegisterShader( token );
+
+ if( !wi->impactDishShader )
+ CG_Printf( "Impact dish shader not found %s: %s\n", filename, token );
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "impactMark" ) )
+ {
+ int size = 0;
+
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ size = atoi( token );
+
+ if( size < 0 )
+ size = 0;
+
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ wi->impactMark = trap_R_RegisterShader( token );
+ wi->impactMarkSize = size;
+
+ if( !wi->impactMark )
+ CG_Printf( "Impact mark shader not found %s: %s\n", filename, token );
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "impactSound" ) )
+ {
+ int index = 0;
+
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ index = atoi( token );
+
+ if( index < 0 )
+ index = 0;
+ else if( index > 3 )
+ index = 3;
+
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ wi->impactSound[ index ] = trap_S_RegisterSound( token, qfalse );
+
+ if( !wi->impactSound[ index ] )
+ CG_Printf( "Weapon impact sound %d not found %s: %s\n", index, filename, token );
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "impactDlightColor" ) )
+ {
+ for( i = 0 ; i < 3 ; i++ )
+ {
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ wi->impactDlightColor[ i ] = atof( token );
+ }
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "impactDlight" ) )
+ {
+ int size = 0;
+
+ token = COM_Parse( &text_p );
+ if( !token )
+ break;
+
+ size = atoi( token );
+
+ if( size < 0 )
+ size = 0;
+
+ wi->impactDlight = size;
+
+ continue;
+ }
+ else if( !Q_stricmp( token, "alwaysImpact" ) )
+ {
+ wi->alwaysImpact = qtrue;
+
+ continue;
+ }
else if( !Q_stricmp( token, "flashDLightColor" ) )
{
for( i = 0 ; i < 3 ; i++ )
@@ -303,6 +483,12 @@ static qboolean CG_ParseWeaponFile( const char *filename, weaponInfo_t *wi )
continue;
}
+ else if( !Q_stricmp( token, "continuousFlash" ) )
+ {
+ wi->continuousFlash = qtrue;
+
+ continue;
+ }
else if( !Q_stricmp( token, "missileDlightColor" ) )
{
for( i = 0 ; i < 3 ; i++ )
@@ -511,12 +697,6 @@ void CG_InitWeapons( void )
cgs.media.lightningShader = trap_R_RegisterShader( "models/ammo/tesla/tesla_bolt");
cgs.media.lightningExplosionModel = trap_R_RegisterModel( "models/weaphits/crackle.md3" );
- cgs.media.sfx_lghit = trap_S_RegisterSound( "sound/weapons/lightning/lg_fire.wav", qfalse );
- cgs.media.lightningShader = trap_R_RegisterShader( "models/ammo/tesla/tesla_bolt");
- cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
- cgs.media.plasmaExplosionShader = trap_R_RegisterShader( "plasmaExplosion" );
- cgs.media.bulletExplosionShader = trap_R_RegisterShader( "bulletExplosion" );
- cgs.media.bfgExplosionShader = trap_R_RegisterShader( "bfgExplosion" );
}
@@ -987,13 +1167,23 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
CG_PoisonCloud( nonPredictedCent, cent->firstPoisonTime );
- // add the flash
- if( ( weaponNum == WP_TESLAGEN || weaponNum == WP_FLAMER ) &&
- ( nonPredictedCent->currentState.eFlags & EF_FIRING ) )
+ if( cent->muzzlePS )
{
- // continuous flash
+ if( ps || cg.renderingThirdPerson ||
+ cent->currentState.number != cg.predictedPlayerState.clientNum )
+ CG_SetParticleSystemTag( cent->muzzlePS, gun, weapon->weaponModel, "tag_flash" );
+
+ //if the PS is infinite disable it when not firing
+ if( !( cent->currentState.eFlags & EF_FIRING ) && CG_IsParticleSystemInfinite( cent->muzzlePS ) )
+ {
+ CG_DestroyParticleSystem( cent->muzzlePS );
+ cent->muzzlePS = NULL;
+ }
}
- else
+
+ // add the flash
+ if( !( weapon->continuousFlash &&
+ ( nonPredictedCent->currentState.eFlags & EF_FIRING ) ) )
{
// impulse flash
if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash )
@@ -1020,10 +1210,19 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
if( ps || cg.renderingThirdPerson ||
cent->currentState.number != cg.predictedPlayerState.clientNum )
{
+ if( weapon->muzzleParticleSystem && cent->muzzlePsTrigger )
+ {
+ cent->muzzlePS = CG_SpawnNewParticleSystem( weapon->muzzleParticleSystem );
+ CG_SetParticleSystemTag( cent->muzzlePS, gun, weapon->weaponModel, "tag_flash" );
+ CG_SetParticleSystemCent( cent->muzzlePS, cent );
+ CG_AttachParticleSystemToTag( cent->muzzlePS );
+ cent->muzzlePsTrigger = qfalse;
+ }
+
// add lightning bolt
CG_LightningBolt( nonPredictedCent, flash.origin );
- CG_FlameTrail( nonPredictedCent, flash.origin );
+ /*CG_FlameTrail( nonPredictedCent, flash.origin );*/
// make a dlight for the flash
if( weapon->flashDlightColor[ 0 ] || weapon->flashDlightColor[ 1 ] || weapon->flashDlightColor[ 2 ] )
@@ -1473,9 +1672,9 @@ Caused by an EV_FIRE_WEAPON event
*/
void CG_FireWeapon( centity_t *cent, int mode )
{
- entityState_t *ent;
- int c;
- weaponInfo_t *weap;
+ entityState_t *ent;
+ int c;
+ weaponInfo_t *weap;
ent = &cent->currentState;
if( ent->weapon == WP_NONE )
@@ -1496,6 +1695,12 @@ void CG_FireWeapon( centity_t *cent, int mode )
if( ent->weapon == WP_GRAB_CLAW_UPG && mode == 1 )
cent->firstPoisonTime = cg.time;
+ if( weap->muzzleParticleSystem )
+ {
+ if( !( cent->muzzlePS && CG_IsParticleSystemInfinite( cent->muzzlePS ) ) )
+ cent->muzzlePsTrigger = qtrue;
+ }
+
// lightning gun only does this this on initial press
if( ent->weapon == WP_TESLAGEN )
{
@@ -1543,158 +1748,65 @@ CG_MissileHitWall
Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
=================
*/
-void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType, int damage )
+void CG_MissileHitWall( int weaponNum, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType, int damage )
{
- qhandle_t mod;
- qhandle_t mark;
- qhandle_t shader;
- sfxHandle_t sfx;
- float radius;
- float light;
- vec3_t lightColor;
- localEntity_t *le;
- int r, i;
- qboolean alphaFade;
- qboolean isSprite;
- int duration;
- vec3_t sprOrg;
- vec3_t sprVel;
- qboolean switchBugWorkaround = qfalse;
-
- mark = 0;
- radius = 32;
- sfx = 0;
- mod = 0;
- shader = 0;
- light = 0;
- lightColor[ 0 ] = 1;
- lightColor[ 1 ] = 1;
- lightColor[ 2 ] = 0;
-
- // set defaults
- isSprite = qfalse;
- duration = 600;
-
- switch( weapon )
- {
- case WP_TESLAGEN:
- case WP_AREA_ZAP:
- case WP_DIRECT_ZAP:
- mod = cgs.media.lightningExplosionModel;
- shader = cgs.media.lightningShader;
- sfx = cgs.media.sfx_lghit;
- mark = cgs.media.energyMarkShader;
- radius = 24;
- break;
-
- case WP_LOCKBLOB_LAUNCHER:
- case WP_POUNCE_UPG:
- sfx = cgs.media.gibBounce1Sound;
- mark = cgs.media.greenBloodMarkShader;
- radius = 64;
- isSprite = qtrue;
- break;
-
- case WP_BLASTER:
- mark = cgs.media.burnMarkShader;
- radius = 4;
- break;
-
- case WP_FLAMER:
- sfx = cgs.media.sfx_flamerexp;
- mark = cgs.media.burnMarkShader;
- radius = 32;
- break;
-
- case WP_PULSE_RIFLE:
- mod = cgs.media.ringFlashModel;
- shader = cgs.media.plasmaExplosionShader;
- sfx = cgs.media.sfx_plasmaexp;
- mark = cgs.media.energyMarkShader;
- radius = 16;
- break;
-
- case WP_MASS_DRIVER:
- shader = cgs.media.bulletExplosionShader;
- mark = cgs.media.bulletMarkShader;
- radius = 8;
- break;
-
- case WP_MACHINEGUN:
- case WP_MGTURRET:
- case WP_CHAINGUN:
- case WP_LAS_GUN:
- mod = cgs.media.bulletFlashModel;
- shader = cgs.media.bulletExplosionShader;
- mark = cgs.media.bulletMarkShader;
-
- r = rand( ) & 3;
- if( r == 0 )
- sfx = cgs.media.sfx_ric1;
- else if( r == 1 )
- sfx = cgs.media.sfx_ric2;
- else
- sfx = cgs.media.sfx_ric3;
-
- radius = 8;
- break;
-
- #define LCANNON_EJECTION_VEL 300
-
- case WP_LUCIFER_CANNON:
- mod = cgs.media.dishFlashModel;
- shader = cgs.media.bfgExplosionShader;
- mark = cgs.media.bulletMarkShader;
- radius = 8;
- sfx = cgs.media.sfx_plasmaexp;
- isSprite = qtrue;
-
- for( i = 0; i <= damage / 20; i++ )
- {
- qhandle_t spark;
- vec3_t velocity;
- vec3_t accel = { 0.0f, 0.0f, -DEFAULT_GRAVITY };
-
- VectorMA( origin, 1.0f, dir, origin );
-
- if( random( ) > 0.5f )
- spark = cgs.media.gibSpark1;
- else
- spark = cgs.media.scannerBlipShader;
-
- velocity[ 0 ] = ( 2 * random( ) - 1.0f ) * LCANNON_EJECTION_VEL;
- velocity[ 1 ] = ( 2 * random( ) - 1.0f ) * LCANNON_EJECTION_VEL;
- velocity[ 2 ] = ( 2 * random( ) - 1.0f ) * LCANNON_EJECTION_VEL;
-
- CG_LaunchSprite( origin, velocity, accel, 0.0f,
- 0.9f, 1.0f, 40.0f, 255, 0, rand( ) % 360,
- cg.time, cg.time, 2000 + ( crandom( ) * 1000 ),
- spark, qfalse, qfalse );
- }
- break;
+ qhandle_t mod = 0;
+ qhandle_t mark = 0;
+ qhandle_t shader = 0;
+ qhandle_t ps = 0;
+ int c;
+ float radius = 1.0f;
+ float light = 0.0f;
+ vec3_t lightColor = { 0.0f, 0.0f, 0.0f };
+ localEntity_t *le;
+ weaponInfo_t *weapon;
+
+ weapon = &cg_weapons[ weaponNum ];
- case WP_HIVE:
- switchBugWorkaround = qtrue;
- break;
+ mark = weapon->impactMark;
+ radius = weapon->impactMarkSize;
+ mod = weapon->impactDish;
+ shader = weapon->impactDishShader;
+ light = weapon->impactDlight;
+ VectorCopy( weapon->impactDlightColor, lightColor );
+ ps = weapon->impactParticleSystem;
- default:
+ // play a sound
+ for( c = 0; c < 4; c++ )
+ {
+ if( !weapon->impactSound[ c ] )
break;
}
+
+ if( c > 0 )
+ {
+ c = rand( ) % c;
+ if( weapon->impactSound[ c ] )
+ trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, weapon->impactSound[ c ] );
+ }
- if( switchBugWorkaround )
- return;
-
- if( sfx )
- trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx );
+ //create impact particle system
+ if( ps )
+ {
+ vec3_t origin2;
+
+ particleSystem_t *partSystem = CG_SpawnNewParticleSystem( ps );
+ //move the origin out from the wall a bit
+ //so particles don't collide with it immediately
+ VectorMA( origin, 10.0f, dir, origin2 );
+ CG_SetParticleSystemOrigin( partSystem, origin2 );
+
+ CG_SetParticleSystemNormal( partSystem, dir );
+ CG_AttachParticleSystemToOrigin( partSystem );
+ }
+
//
// create the explosion
//
if( mod )
{
- le = CG_MakeExplosion( origin, dir,
- mod, shader,
- duration, isSprite );
+ le = CG_MakeExplosion( origin, dir, mod, shader, 600, qfalse );
le->light = light;
VectorCopy( lightColor, le->lightColor );
}
@@ -1702,11 +1814,8 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im
//
// impact mark
//
- // plasma fades alpha, all others fade color
- alphaFade = ( mark == cgs.media.energyMarkShader ||
- mark == cgs.media.greenBloodMarkShader );
-
- CG_ImpactMark( mark, origin, dir, random( ) * 360, 1, 1, 1, 1, alphaFade, radius, qfalse );
+ if( radius > 0.0f )
+ CG_ImpactMark( mark, origin, dir, random( ) * 360, 1, 1, 1, 1, qfalse, radius, qfalse );
}
@@ -1715,21 +1824,14 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im
CG_MissileHitPlayer
=================
*/
-void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum, int damage )
+void CG_MissileHitPlayer( int weaponNum, vec3_t origin, vec3_t dir, int entityNum, int damage )
{
+ weaponInfo_t *weapon = &cg_weapons[ weaponNum ];
+
CG_Bleed( origin, entityNum );
- // some weapons will make an explosion with the blood, while
- // others will just make the blood
- switch( weapon )
- {
- /* case WP_GRENADE_LAUNCHER:
- case WP_ROCKET_LAUNCHER:
- CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH );
- break;*/
- default:
- break;
- }
+ if( weapon->alwaysImpact )
+ CG_MissileHitWall( weaponNum, 0, origin, dir, IMPACTSOUND_FLESH, damage );
}
@@ -1863,36 +1965,6 @@ static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle )
}
-/*
-======================
-CG_LasGunHit
-
-Renders las gun effects.
-======================
-*/
-void CG_LasGunHit( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum )
-{
- trace_t trace;
- vec3_t start;
-
- // if the shooter is currently valid, calc a source point and possibly
- // do trail effects
- if( sourceEntityNum >= 0 && cg_tracerChance.value > 0 )
- {
- if( CG_CalcMuzzlePoint( sourceEntityNum, start ) )
- {
- // draw a tracer
- if( random() < cg_tracerChance.value )
- CG_Tracer( start, end );
- }
- }
-
- // impact splash and mark
- if( flesh )
- CG_Bleed( end, fleshEntityNum );
- else
- CG_MissileHitWall( WP_LAS_GUN, 0, end, normal, IMPACTSOUND_DEFAULT, 0 );
-}
/*
======================
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 920df33b..ad7404df 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -506,9 +506,6 @@ typedef enum
EV_BULLET_HIT_FLESH,
EV_BULLET_HIT_WALL,
- EV_LAS_HIT_FLESH,
- EV_LAS_HIT_WALL,
- EV_MASS_DRIVER_HIT,
EV_MISSILE_HIT,
EV_MISSILE_MISS,
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index fd44840c..1b1de4ab 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -182,8 +182,18 @@ void massDriverFire( gentity_t *ent )
SnapVectorTowards( tr.endpos, muzzle );
// send impact
- tent = G_TempEntity( tr.endpos, EV_MASS_DRIVER_HIT );
- tent->s.eventParm = DirToByte( tr.plane.normal );
+ 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;
+ }
+ else
+ {
+ tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
+ tent->s.eventParm = DirToByte( tr.plane.normal );
+ }
if( traceEnt->takedamage )
{
@@ -309,12 +319,14 @@ void lasGunFire( gentity_t *ent )
// send bullet impact
if( traceEnt->takedamage && traceEnt->client )
{
- tent = G_TempEntity( tr.endpos, EV_LAS_HIT_FLESH );
- tent->s.eventParm = traceEnt->s.number;
+ 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;
}
else
{
- tent = G_TempEntity( tr.endpos, EV_LAS_HIT_WALL );
+ tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
tent->s.eventParm = DirToByte( tr.plane.normal );
}
tent->s.otherEntityNum = ent->s.number;