From fb6006e34c1fe83acfb7976e50cb2f498e9c70b6 Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Sun, 5 Jun 2005 22:16:54 +0000 Subject: * Added flashing alien icon if already at maximum class * Improved scanner render and refactored scanner code * Added animated projectiles * Grenade * Changed model names to be human name agnostic * Added sounds for lev1 grab and lev4 charge * Added sound for failed evolution * Added battery pack rendering code * Added functionality to particle system to allow attachment of particle systems to particles (for nice explosions) * Implemented CG_FileExists * Added some code to gracefully handle missing sounds (easier than making the sounds :D) * cg_drawBBOX now draws player BBOXen * Renamed the alien classes (now done in class override scripts) * Implemented Vector4Add * The usual assorted bug fixes --- src/cgame/cg_draw.c | 56 ++++++++++- src/cgame/cg_ents.c | 121 +++++++++-------------- src/cgame/cg_event.c | 92 +++++++++++++---- src/cgame/cg_local.h | 41 +++++++- src/cgame/cg_main.c | 38 ++++++- src/cgame/cg_particles.c | 251 ++++++++++++++++++++++++++++++++++++++++++++--- src/cgame/cg_players.c | 57 ++++++++++- src/cgame/cg_scanner.c | 177 +++++++++++++++++++++++++++------ src/cgame/cg_view.c | 24 ++--- src/cgame/cg_weapons.c | 32 +++++- 10 files changed, 723 insertions(+), 166 deletions(-) (limited to 'src/cgame') diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c index 88e1ffc0..a2b2186f 100644 --- a/src/cgame/cg_draw.c +++ b/src/cgame/cg_draw.c @@ -533,6 +533,35 @@ void CG_SetPrintString( int type, const char *p ) } } +/* +=============== +CG_AtHighestClass + +Is the local client at the highest class possible? +=============== +*/ +static qboolean CG_AtHighestClass( void ) +{ + int i; + qboolean superiorClasses = qfalse; + + for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ ) + { + if( BG_ClassCanEvolveFromTo( + cg.predictedPlayerState.stats[ STAT_PCLASS ], i, + ALIEN_MAX_KILLS, 0 ) >= 0 && + BG_FindStagesForClass( i, cgs.alienStage ) ) + { + superiorClasses = qtrue; + break; + } + } + + return !superiorClasses; +} + +#define NO_CREDITS_TIME 2000 + static void CG_DrawPlayerCreditsValue( rectDef_t *rect, vec4_t color, qboolean padding ) { int value; @@ -550,6 +579,16 @@ static void CG_DrawPlayerCreditsValue( rectDef_t *rect, vec4_t color, qboolean p value = ps->persistant[ PERS_CREDIT ]; if( value > -1 ) { + if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS && + !CG_AtHighestClass( ) ) + { + if( cg.time - cg.lastEvolveAttempt <= NO_CREDITS_TIME ) + { + if( ( ( cg.time - cg.lastEvolveAttempt ) / 300 ) % 2 ) + color[ 3 ] = 0.0f; + } + } + trap_R_SetColor( color ); if( padding ) @@ -975,10 +1014,10 @@ static void CG_DrawAlienSense( rectDef_t *rect ) CG_DrawHumanScanner ============== */ -static void CG_DrawHumanScanner( rectDef_t *rect, qhandle_t shader ) +static void CG_DrawHumanScanner( rectDef_t *rect, qhandle_t shader, vec4_t color ) { if( BG_InventoryContainsUpgrade( UP_HELMET, cg.snap->ps.stats ) ) - CG_Scanner( rect, shader ); + CG_Scanner( rect, shader, color ); } @@ -1065,7 +1104,7 @@ static void CG_DrawPlayerBuildTimer( rectDef_t *rect, vec4_t color ) if( cg.time - cg.lastBuildAttempt <= BUILD_DELAY_TIME ) { - if( ( cg.time / 300 ) % 2 ) + if( ( ( cg.time - cg.lastBuildAttempt ) / 300 ) % 2 ) { color[ 0 ] = 1.0f; color[ 1 ] = color[ 2 ] = 0.0f; @@ -2192,6 +2231,15 @@ void CG_DrawWeaponIcon( rectDef_t *rect, vec4_t color ) } } + if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS && CG_AtHighestClass( ) ) + { + if( cg.time - cg.lastEvolveAttempt <= NO_CREDITS_TIME ) + { + if( ( ( cg.time - cg.lastEvolveAttempt ) / 300 ) % 2 ) + color[ 3 ] = 0.0f; + } + } + trap_R_SetColor( color ); CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_weapons[ cent->currentState.weapon ].weaponIcon ); trap_R_SetColor( NULL ); @@ -2426,7 +2474,7 @@ void CG_OwnerDraw( float x, float y, float w, float h, float text_x, CG_DrawAlienSense( &rect ); break; case CG_PLAYER_HUMAN_SCANNER: - CG_DrawHumanScanner( &rect, shader ); + CG_DrawHumanScanner( &rect, shader, color ); break; case CG_PLAYER_USABLE_BUILDABLE: CG_DrawUsableBuildable( &rect, shader, color ); diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c index 01314df0..1b4a1639 100644 --- a/src/cgame/cg_ents.c +++ b/src/cgame/cg_ents.c @@ -347,14 +347,15 @@ CG_Missile */ static void CG_Missile( centity_t *cent ) { - refEntity_t ent; - entityState_t *es; - const weaponInfo_t *wi; - vec3_t up; - float fraction; - int index; - weapon_t weapon; - weaponMode_t weaponMode; + refEntity_t ent; + entityState_t *es; + const weaponInfo_t *wi; + vec3_t up; + float fraction; + int index; + weapon_t weapon; + weaponMode_t weaponMode; + const weaponInfoMode_t *wim; es = ¢->currentState; @@ -365,26 +366,28 @@ static void CG_Missile( centity_t *cent ) wi = &cg_weapons[ weapon ]; weaponMode = es->generic1; + wim = &wi->wim[ weaponMode ]; + // calculate the axis VectorCopy( es->angles, cent->lerpAngles ); // add dynamic light - if( wi->wim[ weaponMode ].missileDlight ) + if( wim->missileDlight ) { - trap_R_AddLightToScene( cent->lerpOrigin, wi->wim[ weaponMode ].missileDlight, - wi->wim[ weaponMode ].missileDlightColor[ 0 ], - wi->wim[ weaponMode ].missileDlightColor[ 1 ], - wi->wim[ weaponMode ].missileDlightColor[ 2 ] ); + trap_R_AddLightToScene( cent->lerpOrigin, wim->missileDlight, + wim->missileDlightColor[ 0 ], + wim->missileDlightColor[ 1 ], + wim->missileDlightColor[ 2 ] ); } // add missile sound - if( wi->wim[ weaponMode ].missileSound ) + if( wim->missileSound ) { vec3_t velocity; BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.time, velocity ); - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, wi->wim[ weaponMode ].missileSound ); + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, wim->missileSound ); } // create the render entity @@ -392,12 +395,12 @@ static void CG_Missile( centity_t *cent ) VectorCopy( cent->lerpOrigin, ent.origin ); VectorCopy( cent->lerpOrigin, ent.oldorigin ); - if( wi->wim[ weaponMode ].usesSpriteMissle ) + if( wim->usesSpriteMissle ) { ent.reType = RT_SPRITE; - ent.radius = wi->wim[ weaponMode ].missileSpriteSize; + ent.radius = wim->missileSpriteSize; ent.rotation = 0; - ent.customShader = wi->wim[ weaponMode ].missileSprite; + ent.customShader = wim->missileSprite; ent.shaderRGBA[ 0 ] = 0xFF; ent.shaderRGBA[ 1 ] = 0xFF; ent.shaderRGBA[ 2 ] = 0xFF; @@ -405,22 +408,42 @@ static void CG_Missile( centity_t *cent ) } else { - ent.hModel = wi->wim[ weaponMode ].missileModel; - ent.renderfx = wi->wim[ weaponMode ].missileRenderfx | RF_NOSHADOW; + ent.hModel = wim->missileModel; + ent.renderfx = wim->missileRenderfx | RF_NOSHADOW; // convert direction of travel into axis if( VectorNormalize2( es->pos.trDelta, ent.axis[ 0 ] ) == 0 ) ent.axis[ 0 ][ 2 ] = 1; // spin as it moves - if( es->pos.trType != TR_STATIONARY && wi->wim[ weaponMode ].missileRotates ) + if( es->pos.trType != TR_STATIONARY && wim->missileRotates ) RotateAroundDirection( ent.axis, cg.time / 4 ); else RotateAroundDirection( ent.axis, es->time ); + + if( wim->missileAnimates ) + { + int timeSinceStart = cg.time - es->time; + + if( wim->missileAnimLooping ) + { + ent.frame = wim->missileAnimStartFrame + + (int)( ( timeSinceStart / 1000.0f ) * wim->missileAnimFrameRate ) % + wim->missileAnimNumFrames; + } + else + { + ent.frame = wim->missileAnimStartFrame + + (int)( ( timeSinceStart / 1000.0f ) * wim->missileAnimFrameRate ); + + if( ent.frame > ( wim->missileAnimStartFrame + wim->missileAnimNumFrames ) ) + ent.frame = wim->missileAnimStartFrame + wim->missileAnimNumFrames; + } + } } //only refresh if there is something to display - if( wi->wim[ weaponMode ].missileSprite || wi->wim[ weaponMode ].missileModel ) + if( wim->missileSprite || wim->missileModel ) trap_R_AddRefEntityToScene( &ent ); } @@ -1045,57 +1068,8 @@ void CG_AddPacketEntities( void ) // lerp the non-predicted value for lightning gun origins CG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] ); - //TA: "empty" item position arrays - cg.ep.numAlienBuildables = 0; - cg.ep.numHumanBuildables = 0; - cg.ep.numAlienClients = 0; - cg.ep.numHumanClients = 0; - - for( num = 0; num < cg.snap->numEntities; num++ ) - { - cent = &cg_entities[ cg.snap->entities[ num ].number ]; - - if( cent->currentState.eType == ET_BUILDABLE ) - { - //TA: add to list of item positions (for creep) - if( cent->currentState.modelindex2 == BIT_ALIENS ) - { - VectorCopy( cent->lerpOrigin, cg.ep.alienBuildablePos[ cg.ep.numAlienBuildables ] ); - cg.ep.alienBuildableTimes[ cg.ep.numAlienBuildables ] = cent->miscTime; - - if( cg.ep.numAlienBuildables < MAX_GENTITIES ) - cg.ep.numAlienBuildables++; - } - else if( cent->currentState.modelindex2 == BIT_HUMANS ) - { - VectorCopy( cent->lerpOrigin, cg.ep.humanBuildablePos[ cg.ep.numHumanBuildables ] ); - - if( cg.ep.numHumanBuildables < MAX_GENTITIES ) - cg.ep.numHumanBuildables++; - } - } - else if( cent->currentState.eType == ET_PLAYER ) - { - int team = cent->currentState.powerups & 0x00FF; - - if( team == PTE_ALIENS ) - { - VectorCopy( cent->lerpOrigin, cg.ep.alienClientPos[ cg.ep.numAlienClients ] ); - - if( cg.ep.numAlienClients < MAX_CLIENTS ) - cg.ep.numAlienClients++; - } - else if( team == PTE_HUMANS ) - { - VectorCopy( cent->lerpOrigin, cg.ep.humanClientPos[ cg.ep.numHumanClients ] ); - - if( cg.ep.numHumanClients < MAX_CLIENTS ) - cg.ep.numHumanClients++; - } - } - } - - //Com_Printf( "%d %d\n", cgIP.numAlienClients, cgIP.numHumanClients ); + // scanner + CG_UpdateEntityPositions( ); for( num = 0; num < MAX_GENTITIES; num++ ) cg_entities[ num ].valid = qfalse; @@ -1140,7 +1114,6 @@ void CG_AddPacketEntities( void ) switch( es->eType ) { - case ET_PLAYER: case ET_BUILDABLE: case ET_MISSILE: case ET_CORPSE: diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c index 9b60df70..3a1138e6 100644 --- a/src/cgame/cg_event.c +++ b/src/cgame/cg_event.c @@ -32,6 +32,7 @@ static void CG_Obituary( entityState_t *ent ) const char *attackerInfo; char targetName[ 32 ]; char attackerName[ 32 ]; + char className[ 64 ]; gender_t gender; clientInfo_t *ci; @@ -57,7 +58,7 @@ static void CG_Obituary( entityState_t *ent ) if( !targetInfo ) return; - Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof( targetName ) - 2); + Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof( targetName ) - 2 ); strcat( targetName, S_COLOR_WHITE ); message2 = ""; @@ -145,6 +146,15 @@ static void CG_Obituary( entityState_t *ent ) message = "irradiated himself"; break; + case MOD_GRENADE: + if( gender == GENDER_FEMALE ) + message = "blew herself up"; + else if( gender == GENDER_NEUTER ) + message = "blew itself up"; + else + message = "blew himself up"; + break; + default: if( gender == GENDER_FEMALE ) message = "killed herself"; @@ -221,50 +231,70 @@ static void CG_Obituary( entityState_t *ent ) message = "was caught in the fallout of"; message2 = "'s lucifer cannon"; break; + case MOD_GRENADE: + message = "couldn't escape"; + message2 = "'s grenade"; + break; case MOD_ABUILDER_CLAW: message = "should leave"; message2 = "'s buildings alone"; break; - case MOD_SOLDIER_BITE: + case MOD_LEVEL0_BITE: message = "was bitten by"; break; - case MOD_HYDRA_CLAW: + case MOD_LEVEL1_CLAW: message = "was swiped by"; - message2 = "'s hydra"; + Com_sprintf( className, 64, "'s %s", + BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL1 ) ); + message2 = className; break; - case MOD_DRAGOON_CLAW: + case MOD_LEVEL3_CLAW: message = "was clawed by"; - message2 = "'s dragoon"; + Com_sprintf( className, 64, "'s %s", + BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL3 ) ); + message2 = className; break; - case MOD_DRAGOON_POUNCE: + case MOD_LEVEL3_POUNCE: message = "was pounced upon by"; - message2 = "'s dragoon"; + Com_sprintf( className, 64, "'s %s", + BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL3 ) ); + message2 = className; break; - case MOD_CHIMERA_CLAW: + case MOD_LEVEL2_CLAW: message = "was clawed by"; - message2 = "'s chimera"; + Com_sprintf( className, 64, "'s %s", + BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL3 ) ); + message2 = className; break; - case MOD_CHIMERA_ZAP: + case MOD_LEVEL2_ZAP: message = "was zapped by"; - message2 = "'s chimera"; + Com_sprintf( className, 64, "'s %s", + BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL3 ) ); + message2 = className; break; - case MOD_BMOFO_CLAW: + case MOD_LEVEL4_CLAW: message = "was mauled by"; - message2 = "'s big mofo"; + Com_sprintf( className, 64, "'s %s", + BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL4 ) ); + message2 = className; break; - case MOD_BMOFO_CHARGE: + case MOD_LEVEL4_CHARGE: message = "should have gotten out of the way of"; - message2 = "'s big mofo"; + Com_sprintf( className, 64, "'s %s", + BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL4 ) ); + message2 = className; break; case MOD_POISON: message = "should have used antitox against"; message2 = "'s poison"; break; - case MOD_HYDRA_PCLOUD: + case MOD_LEVEL1_PCLOUD: message = "was gassed by"; - message2 = "'s hydra"; + Com_sprintf( className, 64, "'s %s", + BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL1 ) ); + message2 = className; break; @@ -580,6 +610,22 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) break; + case EV_LEV1_GRAB: + DEBUGNAME( "EV_LEV1_GRAB" ); + trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL1Grab ); + break; + + case EV_LEV4_CHARGE_PREPARE: + DEBUGNAME( "EV_LEV4_CHARGE_PREPARE" ); + trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargePrepare ); + break; + + case EV_LEV4_CHARGE_START: + DEBUGNAME( "EV_LEV4_CHARGE_START" ); + //FIXME: stop cgs.media.alienL4ChargePrepare playing here + trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargeStart ); + break; + case EV_TAUNT: DEBUGNAME( "EV_TAUNT" ); trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) ); @@ -882,6 +928,16 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) cg.spawnTime = cg.time; break; + case EV_ALIEN_EVOLVE_FAILED: + DEBUGNAME( "EV_ALIEN_EVOLVE_FAILED" ); + if( clientNum == cg.predictedPlayerState.clientNum ) + { + //FIXME: change to "negative" sound + trap_S_StartLocalSound( cgs.media.buildableRepairedSound, CHAN_LOCAL_SOUND ); + cg.lastEvolveAttempt = cg.time; + } + break; + case EV_ALIEN_ACIDTUBE: DEBUGNAME( "EV_ALIEN_ACIDTUBE" ); { diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index 1d22e308..6b93f142 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -219,6 +219,12 @@ typedef struct baseParticle_s pLerpValues_t alpha; pLerpValues_t rotation; + char childSystemName[ MAX_QPATH ]; + qhandle_t childSystemHandle; + + char onDeathSystemName[ MAX_QPATH ]; + qhandle_t onDeathSystemHandle; + //particle invariant stuff char shaderNames[ MAX_QPATH ][ MAX_SHADER_FRAMES ]; qhandle_t shaders[ MAX_SHADER_FRAMES ]; @@ -267,7 +273,8 @@ typedef enum { PSA_STATIC, PSA_TAG, - PSA_CENT_ORIGIN + PSA_CENT_ORIGIN, + PSA_PARTICLE } psAttachmentType_t; @@ -277,6 +284,7 @@ typedef struct psAttachment_s qboolean tagValid; qboolean centValid; qboolean normalValid; + qboolean particleValid; //PMT_STATIC vec3_t origin; @@ -342,6 +350,8 @@ typedef struct particle_s int lastEvalTime; + int nextChildTime; + pLerpValues_t radius; pLerpValues_t alpha; pLerpValues_t rotation; @@ -349,6 +359,8 @@ typedef struct particle_s qboolean valid; int sortKey; + + particleSystem_t *childSystem; } particle_t; @@ -692,6 +704,11 @@ typedef struct weaponInfoMode_s int missileSpriteSize; qhandle_t missileParticleSystem; qboolean missileRotates; + qboolean missileAnimates; + int missileAnimStartFrame; + int missileAnimNumFrames; + int missileAnimFrameRate; + int missileAnimLooping; sfxHandle_t firingSound; qboolean loopFireSound; @@ -785,6 +802,10 @@ typedef struct vec3_t humanClientPos[ MAX_CLIENTS ]; int numHumanClients; + + int lastUpdateTime; + vec3_t origin; + vec3_t vangles; } entityPos_t; typedef struct @@ -1013,9 +1034,8 @@ typedef struct float mediaFraction; float buildablesFraction; - entityPos_t ep; - int lastBuildAttempt; + int lastEvolveAttempt; char consoleText[ MAX_CONSOLE_TEXT ]; consoleLine_t consoleLines[ MAX_CONSOLE_LINES ]; @@ -1194,6 +1214,10 @@ typedef struct sfxHandle_t humanBuildablePrebuild; sfxHandle_t humanBuildableDamage[ 4 ]; + sfxHandle_t alienL1Grab; + sfxHandle_t alienL4ChargePrepare; + sfxHandle_t alienL4ChargeStart; + qhandle_t cursor; qhandle_t selectCursor; qhandle_t sizeCursor; @@ -1210,6 +1234,7 @@ typedef struct qhandle_t jetpackModel; qhandle_t jetpackFlashModel; + qhandle_t battpackModel; sfxHandle_t repeaterUseSound; @@ -1443,6 +1468,7 @@ extern vmCvar_t cg_lightFlare; extern vmCvar_t cg_debugParticles; extern vmCvar_t cg_debugPVS; extern vmCvar_t cg_disableBuildWarnings; +extern vmCvar_t cg_disableScannerPlane; //TA: hack to get class an carriage through to UI module extern vmCvar_t ui_currentClass; @@ -1479,6 +1505,8 @@ void CG_EventHandling( int type ); void CG_SetScoreSelection( void *menu ); void CG_BuildSpectatorString( ); +qboolean CG_FileExists( char *filename ); + // // cg_view.c @@ -1656,7 +1684,8 @@ void CG_DrawItemSelectText( rectDef_t *rect, float scale, int textStyle ) // // cg_scanner.c // -void CG_Scanner( rectDef_t *rect, qhandle_t shader ); +void CG_UpdateEntityPositions( void ); +void CG_Scanner( rectDef_t *rect, qhandle_t shader, vec4_t color ); void CG_AlienSense( rectDef_t *rect ); // @@ -1781,8 +1810,10 @@ 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_AttachParticleSystemToOrigin( particleSystem_t *ps ); void CG_SetParticleSystemNormal( particleSystem_t *ps, vec3_t normal ); +void CG_AttachParticleSystemToParticle( particleSystem_t *ps ); +void CG_SetParticleSystemParentParticle( particleSystem_t *ps, particle_t *p ); void CG_AddParticles( void ); diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index 782db516..1ca58707 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -201,6 +201,7 @@ vmCvar_t cg_lightFlare; vmCvar_t cg_debugParticles; vmCvar_t cg_debugPVS; vmCvar_t cg_disableBuildWarnings; +vmCvar_t cg_disableScannerPlane; //TA: hack to get class and carriage through to UI module vmCvar_t ui_currentClass; @@ -305,6 +306,7 @@ static cvarTable_t cvarTable[ ] = { &cg_debugParticles, "cg_debugParticles", "0", CVAR_CHEAT }, { &cg_debugPVS, "cg_debugPVS", "0", CVAR_CHEAT }, { &cg_disableBuildWarnings, "cg_disableBuildWarnings", "0", CVAR_ARCHIVE }, + { &cg_disableScannerPlane, "cg_disableScannerPlane", "0", CVAR_ARCHIVE }, { &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE}, { &ui_currentClass, "ui_currentClass", "0", 0 }, @@ -567,6 +569,28 @@ const char *CG_Argv( int arg ) //======================================================================== +/* +================= +CG_FileExists + +Test if a specific file exists or not +================= +*/ +qboolean CG_FileExists( char *filename ) +{ + fileHandle_t f; + + if( trap_FS_FOpenFile( filename, &f, FS_READ ) > 0 ) + { + //file exists so close it + trap_FS_FCloseFile( f ); + + return qtrue; + } + else + return qfalse; +} + /* ================= CG_RegisterSounds @@ -587,6 +611,10 @@ static void CG_RegisterSounds( void ) cgs.media.alienOvermindDying = trap_S_RegisterSound( "sound/announcements/overminddying.wav", qtrue ); cgs.media.alienOvermindSpawns = trap_S_RegisterSound( "sound/announcements/overmindspawns.wav", qtrue ); + cgs.media.alienL1Grab = trap_S_RegisterSound( "sound/player/level1/grab.wav", qtrue ); + cgs.media.alienL4ChargePrepare = trap_S_RegisterSound( "sound/player/level4/charge_prepare.wav", qtrue ); + cgs.media.alienL4ChargeStart = trap_S_RegisterSound( "sound/player/level4/charge_start.wav", qtrue ); + cgs.media.tracerSound = trap_S_RegisterSound( "sound/weapons/machinegun/buletby1.wav", qfalse ); cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse ); cgs.media.wearOffSound = trap_S_RegisterSound( "sound/items/wearoff.wav", qfalse ); @@ -749,8 +777,7 @@ static void CG_RegisterGraphics( void ) cgs.media.creepShader = trap_R_RegisterShader( "creep" ); cgs.media.scannerBlipShader = trap_R_RegisterShader( "gfx/2d/blip" ); - cgs.media.scannerLineShader = trap_R_RegisterShader( "white" ); - /*cgs.media.scannerShader = trap_R_RegisterShader( "gfx/2d/scanner" );*/ + cgs.media.scannerLineShader = trap_R_RegisterShader( "gfx/2d/stalk" ); cgs.media.waterBubbleShader = trap_R_RegisterShader( "waterBubble" ); @@ -958,12 +985,13 @@ static void CG_RegisterClients( void ) trap_UpdateScreen( ); } - cgs.media.larmourHeadSkin = trap_R_RegisterSkin( "models/players/trooper/head_light.skin" ); - cgs.media.larmourLegsSkin = trap_R_RegisterSkin( "models/players/trooper/lower_light.skin" ); - cgs.media.larmourTorsoSkin = trap_R_RegisterSkin( "models/players/trooper/upper_light.skin" ); + cgs.media.larmourHeadSkin = trap_R_RegisterSkin( "models/players/human_base/head_light.skin" ); + cgs.media.larmourLegsSkin = trap_R_RegisterSkin( "models/players/human_base/lower_light.skin" ); + cgs.media.larmourTorsoSkin = trap_R_RegisterSkin( "models/players/human_base/upper_light.skin" ); cgs.media.jetpackModel = trap_R_RegisterModel( "models/players/human_base/jetpack.md3" ); cgs.media.jetpackFlashModel = trap_R_RegisterModel( "models/players/human_base/jetpack_flash.md3" ); + cgs.media.battpackModel = trap_R_RegisterModel( "models/players/human_base/battpack.md3" ); cg.charModelFraction = 1.0f; trap_UpdateScreen( ); diff --git a/src/cgame/cg_particles.c b/src/cgame/cg_particles.c index 9b37382a..7f4ac64c 100644 --- a/src/cgame/cg_particles.c +++ b/src/cgame/cg_particles.c @@ -78,6 +78,33 @@ static void CG_SpreadVector( vec3_t v, float spread ) VectorCopy( r2, v ); } +/* +=============== +CG_DestroyParticle + +Destroy an individual particle +=============== +*/ +static void CG_DestroyParticle( particle_t *p ) +{ + //this particle has an onDeath particle system attached + if( p->class->onDeathSystemName[ 0 ] != '\0' ) + { + particleSystem_t *ps; + + ps = CG_SpawnNewParticleSystem( p->class->childSystemHandle ); + + if( CG_IsParticleSystemValid( &ps ) ) + { + CG_SetParticleSystemOrigin( ps, p->origin ); + CG_SetParticleSystemNormal( ps, p->velocity ); + CG_AttachParticleSystemToOrigin( ps ); + } + } + + p->valid = qfalse; +} + /* =============== CG_SpawnNewParticle @@ -146,6 +173,32 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p VectorCopy( cent->lerpOrigin, p->origin ); break; + + case PSA_PARTICLE: + if( !ps->attachment.particleValid ) + return NULL; + + //find a particle which has ps as a child + for( j = 0; j < MAX_PARTICLES; j++ ) + { + particle_t *parentParticle = &particles[ j ]; + + if( parentParticle->valid && parentParticle->childSystem == ps ) + { + VectorCopy( parentParticle->origin, p->origin ); + break; + } + } + + if( j == MAX_PARTICLES ) + { + //didn't find the parent, so it's probably died already + + //prevent further (expensive) attempts at particle creation + ps->attachment.particleValid = qfalse; + return NULL; + } + break; } VectorAdd( p->origin, bp->displacement, p->origin ); @@ -191,18 +244,18 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p break; - case PMT_NORMAL: - - if( !ps->attachment.normalValid ) - return NULL; - - VectorCopy( ps->attachment.normal, p->velocity ); + case PMT_NORMAL: + + if( !ps->attachment.normalValid ) + return NULL; + + VectorCopy( ps->attachment.normal, p->velocity ); - //normal displacement - VectorNormalize( p->velocity ); - VectorMA( p->origin, bp->normalDisplacement, p->velocity, p->origin ); - - break; + //normal displacement + VectorNormalize( p->velocity ); + VectorMA( p->origin, bp->normalDisplacement, p->velocity, p->origin ); + + break; } VectorNormalize( p->velocity ); @@ -222,6 +275,21 @@ static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *p p->valid = qtrue; + //this particle has a child particle system attached + if( bp->childSystemName[ 0 ] != '\0' ) + { + particleSystem_t *ps; + + ps = CG_SpawnNewParticleSystem( bp->childSystemHandle ); + + if( CG_IsParticleSystemValid( &ps ) ) + { + CG_SetParticleSystemParentParticle( ps, p ); + CG_SetParticleSystemNormal( ps, p->velocity ); + CG_AttachParticleSystemToParticle( ps ); + } + } + break; } } @@ -418,6 +486,10 @@ qhandle_t CG_RegisterParticleSystem( char *name ) if( !strcmp( bps->name, name ) ) { + //already registered + if( bps->registered ) + return i + 1; + for( j = 0; j < bps->numEjectors; j++ ) { bpe = bps->ejectors[ j ]; @@ -428,6 +500,21 @@ qhandle_t CG_RegisterParticleSystem( char *name ) for( k = 0; k < bp->numFrames; k++ ) bp->shaders[ k ] = trap_R_RegisterShader( bp->shaderNames[ k ] ); + + //recursively register any children + if( bp->childSystemName[ 0 ] != '\0' ) + { + //don't care about a handle for children since + //the system deals with it + CG_RegisterParticleSystem( bp->childSystemName ); + } + + if( bp->onDeathSystemName[ 0 ] != '\0' ) + { + //don't care about a handle for children since + //the system deals with it + CG_RegisterParticleSystem( bp->onDeathSystemName ); + } } } @@ -980,6 +1067,26 @@ static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p ) continue; } + else if( !Q_stricmp( token, "childSystem" ) ) + { + token = COM_Parse( text_p ); + if( !token ) + break; + + Q_strncpyz( bp->childSystemName, token, MAX_QPATH ); + + continue; + } + else if( !Q_stricmp( token, "onDeathSystem" ) ) + { + token = COM_Parse( text_p ); + if( !token ) + break; + + Q_strncpyz( bp->onDeathSystemName, token, MAX_QPATH ); + + continue; + } else if( !Q_stricmp( token, "}" ) ) return qtrue; //reached the end of this particle else @@ -1306,13 +1413,34 @@ Load particle systems from .particle files */ void CG_LoadParticleSystems( void ) { - int i; + int i, j; const char *s[ MAX_PARTICLE_FILES ]; + //clear out the old numBaseParticleSystems = 0; numBaseParticleEjectors = 0; numBaseParticles = 0; + for( i = 0; i < MAX_BASEPARTICLE_SYSTEMS; i++ ) + { + baseParticleSystem_t *bps = &baseParticleSystems[ i ]; + memset( bps, 0, sizeof( baseParticleSystem_t ) ); + } + + for( i = 0; i < MAX_BASEPARTICLE_EJECTORS; i++ ) + { + baseParticleEjector_t *bpe = &baseParticleEjectors[ i ]; + memset( bpe, 0, sizeof( baseParticleEjector_t ) ); + } + + for( i = 0; i < MAX_BASEPARTICLES; i++ ) + { + baseParticle_t *bp = &baseParticles[ i ]; + memset( bp, 0, sizeof( baseParticle_t ) ); + } + + + //and bring in the new for( i = 0; i < MAX_PARTICLE_FILES; i++ ) { s[ i ] = CG_ConfigString( CS_PARTICLE_FILES + i ); @@ -1325,6 +1453,62 @@ void CG_LoadParticleSystems( void ) else break; } + + //connect any child systems to their psHandle + for( i = 0; i < numBaseParticles; i++ ) + { + baseParticle_t *bp = &baseParticles[ i ]; + + if( bp->childSystemName[ 0 ] ) + { + //particle class has a child, resolve the name + for( j = 0; j < numBaseParticleSystems; j++ ) + { + baseParticleSystem_t *bps = &baseParticleSystems[ j ]; + + if( !Q_stricmp( bps->name, bp->childSystemName ) ) + { + //FIXME: add checks for cycles and infinite children + + bp->childSystemHandle = j + 1; + + break; + } + } + + if( j == numBaseParticleSystems ) + { + //couldn't find named particle system + CG_Printf( S_COLOR_YELLOW "WARNING: failed to find child %s\n", bp->childSystemName ); + bp->childSystemName[ 0 ] = '\0'; + } + } + + if( bp->onDeathSystemName[ 0 ] ) + { + //particle class has a child, resolve the name + for( j = 0; j < numBaseParticleSystems; j++ ) + { + baseParticleSystem_t *bps = &baseParticleSystems[ j ]; + + if( !Q_stricmp( bps->name, bp->onDeathSystemName ) ) + { + //FIXME: add checks for cycles and infinite children + + bp->onDeathSystemHandle = j + 1; + + break; + } + } + + if( j == numBaseParticleSystems ) + { + //couldn't find named particle system + CG_Printf( S_COLOR_YELLOW "WARNING: failed to find onDeath system %s\n", bp->onDeathSystemName ); + bp->onDeathSystemName[ 0 ] = '\0'; + } + } + } } @@ -1445,6 +1629,44 @@ void CG_SetParticleSystemOrigin( particleSystem_t *ps, vec3_t origin ) VectorCopy( origin, ps->attachment.origin ); } +/* +=============== +CG_AttachParticleSystemToParticle + +Attach a particle system to a particle +=============== +*/ +void CG_AttachParticleSystemToParticle( particleSystem_t *ps ) +{ + if( ps == NULL || !ps->valid ) + { + CG_Printf( S_COLOR_YELLOW "WARNING: tried to modify a NULL particle system\n" ); + return; + } + + ps->attachType = PSA_PARTICLE; + ps->attached = qtrue; +} + +/* +=============== +CG_SetParticleSystemParentParticle + +Set a particle system attachment means +=============== +*/ +void CG_SetParticleSystemParentParticle( particleSystem_t *ps, particle_t *p ) +{ + if( ps == NULL || !ps->valid ) + { + CG_Printf( S_COLOR_YELLOW "WARNING: tried to modify a NULL particle system\n" ); + return; + } + + ps->attachment.particleValid = qtrue; + p->childSystem = ps; +} + /* =============== CG_SetParticleSystemNormal @@ -1462,6 +1684,7 @@ void CG_SetParticleSystemNormal( particleSystem_t *ps, vec3_t normal ) ps->attachment.normalValid = qtrue; VectorCopy( normal, ps->attachment.normal ); + VectorNormalize( ps->attachment.normal ); } @@ -1760,7 +1983,7 @@ static void CG_EvaluateParticlePhysics( particle_t *p ) if( ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) || ( bp->cullOnStartSolid && trace.startsolid ) || bp->bounceCull ) { - p->valid = qfalse; + CG_DestroyParticle( p ); return; } @@ -1979,7 +2202,7 @@ void CG_AddParticles( void ) CG_RenderParticle( p ); } else - p->valid = qfalse; + CG_DestroyParticle( p ); } } diff --git a/src/cgame/cg_players.c b/src/cgame/cg_players.c index 2a1ca0f4..0dadbb8f 100644 --- a/src/cgame/cg_players.c +++ b/src/cgame/cg_players.c @@ -557,9 +557,33 @@ static void CG_LoadClientInfo( clientInfo_t *ci ) if( !s ) break; - ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", dir, s + 1 ), qfalse ); - if( !ci->sounds[ i ] ) - ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", fallback, s + 1 ), qfalse ); + // fanny about a bit with sounds that are missing + if( !CG_FileExists( va( "sound/player/%s/%s", dir, s + 1 ) ) ) + { + //file doesn't exist + + if( i == 11 || i == 8 ) //fall or falling + { + ci->sounds[ i ] = trap_S_RegisterSound( "sound/null.wav", qfalse ); + } + else + { + if( i == 9 ) //gasp + s = cg_customSoundNames[ 7 ]; //pain100_1 + else if( i == 10 ) //drown + s = cg_customSoundNames[ 0 ]; //death1 + + ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", dir, s + 1 ), qfalse ); + if( !ci->sounds[ i ] ) + ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", fallback, s + 1 ), qfalse ); + } + } + else + { + ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", dir, s + 1 ), qfalse ); + if( !ci->sounds[ i ] ) + ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", fallback, s + 1 ), qfalse ); + } } if( ci->footsteps == FOOTSTEP_CUSTOM ) @@ -1526,6 +1550,7 @@ static void CG_PlayerUpgrades( centity_t *cent, refEntity_t *torso ) { int held, active; refEntity_t jetpack; + refEntity_t battpack; refEntity_t flash; entityState_t *es = ¢->currentState; @@ -1627,6 +1652,24 @@ static void CG_PlayerUpgrades( centity_t *cent, refEntity_t *torso ) cent->jetPackState = JPS_OFF; } + if( held & ( 1 << UP_BATTPACK ) ) + { + memset( &battpack, 0, sizeof( battpack ) ); + VectorCopy( torso->lightingOrigin, battpack.lightingOrigin ); + battpack.shadowPlane = torso->shadowPlane; + battpack.renderfx = torso->renderfx; + + battpack.hModel = cgs.media.battpackModel; + + //identity matrix + AxisCopy( axisDefault, battpack.axis ); + + //FIXME: change to tag_back when it exists + CG_PositionRotatedEntityOnTag( &battpack, torso, torso->hModel, "tag_head" ); + + trap_R_AddRefEntityToScene( &battpack ); + } + if( es->eFlags & EF_BLOBLOCKED ) { vec3_t temp, origin, up = { 0.0f, 0.0f, 1.0f }; @@ -2044,6 +2087,14 @@ void CG_Player( centity_t *cent ) return; } + if( cg_drawBBOX.integer ) + { + vec3_t mins, maxs; + + BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL ); + CG_DrawBoundingBox( cent->lerpOrigin, mins, maxs ); + } + memset( &legs, 0, sizeof( legs ) ); memset( &torso, 0, sizeof( torso ) ); memset( &head, 0, sizeof( head ) ); diff --git a/src/cgame/cg_scanner.c b/src/cgame/cg_scanner.c index 2c410f20..16e79a51 100644 --- a/src/cgame/cg_scanner.c +++ b/src/cgame/cg_scanner.c @@ -13,20 +13,121 @@ #include "cg_local.h" +static entityPos_t entityPositions; + +#define HUMAN_SCANNER_UPDATE_PERIOD 300 + +/* +============= +CG_UpdateEntityPositions + +Update this client's perception of entity positions +============= +*/ +void CG_UpdateEntityPositions( void ) +{ + centity_t *cent = NULL; + int i; + + if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS ) + { + if( entityPositions.lastUpdateTime + HUMAN_SCANNER_UPDATE_PERIOD > cg.time ) + return; + } + + VectorCopy( cg.refdef.vieworg, entityPositions.origin ); + VectorCopy( cg.refdefViewAngles, entityPositions.vangles ); + entityPositions.lastUpdateTime = cg.time; + + entityPositions.numAlienBuildables = 0; + entityPositions.numHumanBuildables = 0; + entityPositions.numAlienClients = 0; + entityPositions.numHumanClients = 0; + + for( i = 0; i < cg.snap->numEntities; i++ ) + { + cent = &cg_entities[ cg.snap->entities[ i ].number ]; + + if( cent->currentState.eType == ET_BUILDABLE ) + { + //TA: add to list of item positions (for creep) + if( cent->currentState.modelindex2 == BIT_ALIENS ) + { + VectorCopy( cent->lerpOrigin, entityPositions.alienBuildablePos[ + entityPositions.numAlienBuildables ] ); + entityPositions.alienBuildableTimes[ + entityPositions.numAlienBuildables ] = cent->miscTime; + + if( entityPositions.numAlienBuildables < MAX_GENTITIES ) + entityPositions.numAlienBuildables++; + } + else if( cent->currentState.modelindex2 == BIT_HUMANS ) + { + VectorCopy( cent->lerpOrigin, entityPositions.humanBuildablePos[ + entityPositions.numHumanBuildables ] ); + + if( entityPositions.numHumanBuildables < MAX_GENTITIES ) + entityPositions.numHumanBuildables++; + } + } + else if( cent->currentState.eType == ET_PLAYER ) + { + int team = cent->currentState.powerups & 0x00FF; + + if( team == PTE_ALIENS ) + { + VectorCopy( cent->lerpOrigin, entityPositions.alienClientPos[ + entityPositions.numAlienClients ] ); + + if( entityPositions.numAlienClients < MAX_CLIENTS ) + entityPositions.numAlienClients++; + } + else if( team == PTE_HUMANS ) + { + VectorCopy( cent->lerpOrigin, entityPositions.humanClientPos[ + entityPositions.numHumanClients ] ); + + if( entityPositions.numHumanClients < MAX_CLIENTS ) + entityPositions.numHumanClients++; + } + } + } +} + #define STALKWIDTH 2.0f #define BLIPX 16.0f #define BLIPY 8.0f +#define FAR_ALPHA 0.8f +#define NEAR_ALPHA 1.2f + +/* +============= +CG_DrawBlips +Draw blips and stalks for the human scanner +============= +*/ static void CG_DrawBlips( rectDef_t *rect, vec3_t origin, vec4_t colour ) { vec3_t drawOrigin; vec3_t up = { 0, 0, 1 }; + float alphaMod = 1.0f; - RotatePointAroundVector( drawOrigin, up, origin, -cg.refdefViewAngles[ 1 ] - 90 ); + RotatePointAroundVector( drawOrigin, up, origin, -entityPositions.vangles[ 1 ] - 90 ); drawOrigin[ 0 ] /= ( 2 * HELMET_RANGE / rect->w ); drawOrigin[ 1 ] /= ( 2 * HELMET_RANGE / rect->h ); drawOrigin[ 2 ] /= ( 2 * HELMET_RANGE / rect->w ); + alphaMod = FAR_ALPHA + + ( ( drawOrigin[ 1 ] + ( rect->h / 2.0f ) ) / rect->h ) * ( NEAR_ALPHA - FAR_ALPHA ); + + colour[ 3 ] *= alphaMod; + + if( colour[ 3 ] > 1.0f ) + colour[ 3 ] = 1.0f; + else if( colour[ 3 ] < 0.0f ) + colour[ 3 ] = 0.0f; + trap_R_SetColor( colour ); if( drawOrigin[ 2 ] > 0 ) @@ -47,6 +148,13 @@ static void CG_DrawBlips( rectDef_t *rect, vec3_t origin, vec4_t colour ) #define BLIPX2 24.0f #define BLIPY2 24.0f +/* +============= +CG_DrawDir + +Draw dot marking the direction to an enemy +============= +*/ static void CG_DrawDir( rectDef_t *rect, vec3_t origin, vec4_t colour ) { vec3_t drawOrigin; @@ -68,7 +176,7 @@ static void CG_DrawDir( rectDef_t *rect, vec3_t origin, vec4_t colour ) else VectorSet( normal, 0.0f, 0.0f, 1.0f ); - AngleVectors( cg.refdefViewAngles, view, NULL, NULL ); + AngleVectors( entityPositions.vangles, view, NULL, NULL ); ProjectPointOnPlane( noZOrigin, origin, normal ); ProjectPointOnPlane( noZview, view, normal ); @@ -107,23 +215,23 @@ void CG_AlienSense( rectDef_t *rect ) vec4_t buildable = { 1.0f, 0.0f, 0.0f, 0.7f }; vec4_t client = { 0.0f, 0.0f, 1.0f, 0.7f }; - VectorCopy( cg.refdef.vieworg, origin ); + VectorCopy( entityPositions.origin, origin ); //draw human buildables - for( i = 0; i < cg.ep.numHumanBuildables; i++ ) + for( i = 0; i < entityPositions.numHumanBuildables; i++ ) { VectorClear( relOrigin ); - VectorSubtract( cg.ep.humanBuildablePos[ i ], origin, relOrigin ); + VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin ); if( VectorLength( relOrigin ) < ALIENSENSE_RANGE ) CG_DrawDir( rect, relOrigin, buildable ); } //draw human clients - for( i = 0; i < cg.ep.numHumanClients; i++ ) + for( i = 0; i < entityPositions.numHumanClients; i++ ) { VectorClear( relOrigin ); - VectorSubtract( cg.ep.humanClientPos[ i ], origin, relOrigin ); + VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin ); if( VectorLength( relOrigin ) < ALIENSENSE_RANGE ) CG_DrawDir( rect, relOrigin, client ); @@ -135,95 +243,104 @@ void CG_AlienSense( rectDef_t *rect ) CG_Scanner ============= */ -void CG_Scanner( rectDef_t *rect, qhandle_t shader ) +void CG_Scanner( rectDef_t *rect, qhandle_t shader, vec4_t color ) { int i; vec3_t origin; vec3_t relOrigin; - vec4_t hIabove = { 0.0f, 1.0f, 0.0f, 1.0f }; - vec4_t hIbelow = { 0.0f, 0.5f, 0.0f, 1.0f }; - vec4_t aIabove = { 1.0f, 0.0f, 0.0f, 1.0f }; - vec4_t aIbelow = { 0.5f, 0.0f, 0.0f, 1.0f }; + vec4_t hIabove; + vec4_t hIbelow; + vec4_t aIabove = { 1.0f, 0.0f, 0.0f, 0.75f }; + vec4_t aIbelow = { 1.0f, 0.0f, 0.0f, 0.5f }; + + Vector4Copy( color, hIabove ); + hIabove[ 3 ] *= 1.5f; + Vector4Copy( color, hIbelow ); - VectorCopy( cg.refdef.vieworg, origin ); + VectorCopy( entityPositions.origin, origin ); //draw human buildables below scanner plane - for( i = 0; i < cg.ep.numHumanBuildables; i++ ) + for( i = 0; i < entityPositions.numHumanBuildables; i++ ) { VectorClear( relOrigin ); - VectorSubtract( cg.ep.humanBuildablePos[ i ], origin, relOrigin ); + VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin ); if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) ) CG_DrawBlips( rect, relOrigin, hIbelow ); } //draw alien buildables below scanner plane - for( i = 0; i < cg.ep.numAlienBuildables; i++ ) + for( i = 0; i < entityPositions.numAlienBuildables; i++ ) { VectorClear( relOrigin ); - VectorSubtract( cg.ep.alienBuildablePos[ i ], origin, relOrigin ); + VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin ); if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) ) CG_DrawBlips( rect, relOrigin, aIbelow ); } //draw human clients below scanner plane - for( i = 0; i < cg.ep.numHumanClients; i++ ) + for( i = 0; i < entityPositions.numHumanClients; i++ ) { VectorClear( relOrigin ); - VectorSubtract( cg.ep.humanClientPos[ i ], origin, relOrigin ); + VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin ); if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) ) CG_DrawBlips( rect, relOrigin, hIbelow ); } //draw alien buildables below scanner plane - for( i = 0; i < cg.ep.numAlienClients; i++ ) + for( i = 0; i < entityPositions.numAlienClients; i++ ) { VectorClear( relOrigin ); - VectorSubtract( cg.ep.alienClientPos[ i ], origin, relOrigin ); + VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin ); if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) ) CG_DrawBlips( rect, relOrigin, aIbelow ); } - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); + if( !cg_disableScannerPlane.integer ) + { + trap_R_SetColor( color ); + CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); + trap_R_SetColor( NULL ); + } //draw human buildables above scanner plane - for( i = 0; i < cg.ep.numHumanBuildables; i++ ) + for( i = 0; i < entityPositions.numHumanBuildables; i++ ) { VectorClear( relOrigin ); - VectorSubtract( cg.ep.humanBuildablePos[ i ], origin, relOrigin ); + VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin ); if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) ) CG_DrawBlips( rect, relOrigin, hIabove ); } //draw alien buildables above scanner plane - for( i = 0; i < cg.ep.numAlienBuildables; i++ ) + for( i = 0; i < entityPositions.numAlienBuildables; i++ ) { VectorClear( relOrigin ); - VectorSubtract( cg.ep.alienBuildablePos[ i ], origin, relOrigin ); + VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin ); if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) ) CG_DrawBlips( rect, relOrigin, aIabove ); } //draw human clients above scanner plane - for( i = 0; i < cg.ep.numHumanClients; i++ ) + for( i = 0; i < entityPositions.numHumanClients; i++ ) { VectorClear( relOrigin ); - VectorSubtract( cg.ep.humanClientPos[ i ], origin, relOrigin ); + VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin ); if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) ) CG_DrawBlips( rect, relOrigin, hIabove ); } //draw alien clients above scanner plane - for( i = 0; i < cg.ep.numAlienClients; i++ ) + for( i = 0; i < entityPositions.numAlienClients; i++ ) { VectorClear( relOrigin ); - VectorSubtract( cg.ep.alienClientPos[ i ], origin, relOrigin ); + VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin ); if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) ) CG_DrawBlips( rect, relOrigin, aIabove ); diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c index bb0816d9..d3173024 100644 --- a/src/cgame/cg_view.c +++ b/src/cgame/cg_view.c @@ -463,19 +463,19 @@ static void CG_OffsetFirstPersonView( void ) bob2 = BG_FindBobForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] ); -#define BMOFO_FEEDBACK 10.0f +#define LEVEL4_FEEDBACK 10.0f //give a charging player some feedback - if( ps->weapon == WP_BIGMOFO ) + if( ps->weapon == WP_ALEVEL4 ) { if( ps->stats[ STAT_MISC ] > 0 ) { - float fraction = (float)ps->stats[ STAT_MISC ] / (float)BMOFO_CHARGE_TIME; + float fraction = (float)ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME; if( fraction > 1.0f ) fraction = 1.0f; - bob2 *= ( 1.0f + fraction * BMOFO_FEEDBACK ); + bob2 *= ( 1.0f + fraction * LEVEL4_FEEDBACK ); } } @@ -499,11 +499,11 @@ static void CG_OffsetFirstPersonView( void ) angles[ ROLL ] += delta; } -#define DRAGOON_FEEDBACK 20.0f +#define LEVEL3_FEEDBACK 20.0f //provide some feedback for pouncing - if( cg.predictedPlayerState.weapon == WP_DRAGOON || - cg.predictedPlayerState.weapon == WP_DRAGOON_UPG ) + if( cg.predictedPlayerState.weapon == WP_ALEVEL3 || + cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG ) { if( cg.predictedPlayerState.stats[ STAT_MISC ] > 0 ) { @@ -513,14 +513,14 @@ static void CG_OffsetFirstPersonView( void ) AngleVectors( angles, forward, NULL, NULL ); VectorNormalize( forward ); - fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)DRAGOON_POUNCE_TIME; + fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)LEVEL3_POUNCE_TIME; if( fraction1 > 1.0f ) fraction1 = 1.0f; fraction2 = -sin( fraction1 * M_PI / 2 ); - VectorMA( origin, DRAGOON_FEEDBACK * fraction2, forward, origin ); + VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin ); } } @@ -583,8 +583,8 @@ static void CG_OffsetFirstPersonView( void ) float fraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 2 * PCLOUD_ROLL_FREQUENCY ); float pitchFraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 5 * PCLOUD_ROLL_FREQUENCY ); - fraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)HYDRA_PCLOUD_TIME ); - pitchFraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)HYDRA_PCLOUD_TIME ); + fraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); + pitchFraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); angles[ ROLL ] += fraction * PCLOUD_ROLL_AMPLITUDE; angles[ YAW ] += fraction * PCLOUD_ROLL_AMPLITUDE; @@ -795,7 +795,7 @@ static int CG_CalcFov( void ) { phase = cg.time / 1000.0 * PCLOUD_ZOOM_FREQUENCY * M_PI * 2; v = PCLOUD_ZOOM_AMPLITUDE * sin( phase ); - v *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)HYDRA_PCLOUD_TIME ); + v *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); fov_x += v; fov_y += v; } diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c index 02427daa..3c4e1d3e 100644 --- a/src/cgame/cg_weapons.c +++ b/src/cgame/cg_weapons.c @@ -210,7 +210,7 @@ void CG_AlienZap( vec3_t start, vec3_t end, int srcENum, int destENum ) le->destENum = destENum; le->vOffset = 6.0f; - le->maxRange = CHIMERA_AREAZAP_RANGE * M_ROOT3; + le->maxRange = LEVEL2_AREAZAP_RANGE * M_ROOT3; VectorCopy( start, re->origin ); VectorCopy( end, re->oldorigin ); @@ -338,6 +338,36 @@ static qboolean CG_ParseWeaponModeSection( weaponInfoMode_t *wim, char **text_p continue; } + else if( !Q_stricmp( token, "missileAnimates" ) ) + { + wim->missileAnimates = qtrue; + + token = COM_Parse( text_p ); + if( !token ) + break; + + wim->missileAnimStartFrame = atoi( token ); + + token = COM_Parse( text_p ); + if( !token ) + break; + + wim->missileAnimNumFrames = atoi( token ); + + token = COM_Parse( text_p ); + if( !token ) + break; + + wim->missileAnimFrameRate = atoi( token ); + + token = COM_Parse( text_p ); + if( !token ) + break; + + wim->missileAnimLooping = atoi( token ); + + continue; + } else if( !Q_stricmp( token, "missileParticleSystem" ) ) { token = COM_Parse( text_p ); -- cgit