summaryrefslogtreecommitdiff
path: root/src/cgame
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2005-06-05 22:16:54 +0000
committerTim Angus <tim@ngus.net>2005-06-05 22:16:54 +0000
commitfb6006e34c1fe83acfb7976e50cb2f498e9c70b6 (patch)
treeb8b3f26b52c3b2e71b51d40ff84e86b5bfb9d52d /src/cgame
parent47221c9c78f4a027211a041eb2ad527339b4d54b (diff)
* 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
Diffstat (limited to 'src/cgame')
-rw-r--r--src/cgame/cg_draw.c56
-rw-r--r--src/cgame/cg_ents.c121
-rw-r--r--src/cgame/cg_event.c92
-rw-r--r--src/cgame/cg_local.h41
-rw-r--r--src/cgame/cg_main.c38
-rw-r--r--src/cgame/cg_particles.c251
-rw-r--r--src/cgame/cg_players.c57
-rw-r--r--src/cgame/cg_scanner.c177
-rw-r--r--src/cgame/cg_view.c24
-rw-r--r--src/cgame/cg_weapons.c32
10 files changed, 723 insertions, 166 deletions
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 = &cent->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( &cent->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 },
@@ -569,6 +571,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
called during a precache command
@@ -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
@@ -80,6 +80,33 @@ static void CG_SpreadVector( vec3_t v, float spread )
/*
===============
+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
Introduce a new particle into the world
@@ -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';
+ }
+ }
+ }
}
@@ -1447,6 +1631,44 @@ void CG_SetParticleSystemOrigin( particleSystem_t *ps, vec3_t 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
Set a particle system attachment means
@@ -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 = &cent->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 );