diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cgame/cg_ents.c | 175 | ||||
-rw-r--r-- | src/cgame/cg_event.c | 41 | ||||
-rw-r--r-- | src/cgame/cg_local.h | 477 | ||||
-rw-r--r-- | src/cgame/cg_main.c | 4 | ||||
-rw-r--r-- | src/cgame/cg_particles.c | 146 | ||||
-rw-r--r-- | src/cgame/cg_players.c | 23 | ||||
-rw-r--r-- | src/cgame/cg_weapons.c | 476 | ||||
-rw-r--r-- | src/game/bg_public.h | 3 | ||||
-rw-r--r-- | src/game/g_weapon.c | 22 |
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 = ¢->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 = ¢->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; |