summaryrefslogtreecommitdiff
path: root/src/cgame/cg_scanner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cgame/cg_scanner.c')
-rw-r--r--src/cgame/cg_scanner.c447
1 files changed, 447 insertions, 0 deletions
diff --git a/src/cgame/cg_scanner.c b/src/cgame/cg_scanner.c
new file mode 100644
index 0000000..f4c86de
--- /dev/null
+++ b/src/cgame/cg_scanner.c
@@ -0,0 +1,447 @@
+/*
+===========================================================================
+Copyright (C) 2000-2009 Darklegion Development
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+
+#include "cg_local.h"
+
+static entityPos_t entityPositions;
+
+#define HUMAN_SCANNER_UPDATE_PERIOD 25
+
+/*
+=============
+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_TEAM ] == TEAM_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 ];
+ //make adv basilisk invisble to human helmet if invisble
+ if( cent->currentState.eType == ET_BUILDABLE &&
+ !( cent->currentState.eFlags & EF_DEAD ))
+ {
+ // add to list of item positions (for creep)
+ if( cent->currentState.modelindex2 == TEAM_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 == TEAM_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.misc & 0x00FF;
+ //make adv basilisk invisble to radar if invisble
+ if( team == TEAM_ALIENS && !(cent->invisible ) )
+ {
+ VectorCopy( cent->lerpOrigin, entityPositions.alienClientPos[
+ entityPositions.numAlienClients ] );
+
+ if( entityPositions.numAlienClients < MAX_CLIENTS )
+ entityPositions.numAlienClients++;
+ }
+ else if( team == TEAM_HUMANS )
+ {
+ VectorCopy( cent->lerpOrigin, entityPositions.humanClientPos[
+ entityPositions.numHumanClients ] );
+
+ if( entityPositions.numHumanClients < MAX_CLIENTS )
+ entityPositions.numHumanClients++;
+ }
+ }
+ }
+}
+
+#define STALKWIDTH (2.0f * cgDC.aspectScale)
+#define BLIPX (14.0f * cgDC.aspectScale)
+#define BLIPY 6.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;
+ float timeFractionSinceRefresh = 1.0f -( (float)( cg.time - entityPositions.lastUpdateTime ) / (float)HUMAN_SCANNER_UPDATE_PERIOD );
+ vec4_t localColour;
+
+ Vector4Copy( colour, localColour );
+
+ 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 );
+
+ localColour[ 3 ] *= alphaMod;
+ localColour[ 3 ] *= ( 0.5f + ( timeFractionSinceRefresh * 0.5f ) );
+
+ if( localColour[ 3 ] > 1.0f )
+ localColour[ 3 ] = 1.0f;
+ else if( localColour[ 3 ] < 0.0f )
+ localColour[ 3 ] = 0.0f;
+
+ trap_R_SetColor( localColour );
+
+ if( drawOrigin[ 2 ] > 0 )
+ CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ],
+ rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ],
+ STALKWIDTH, drawOrigin[ 2 ], cgs.media.scannerLineShader );
+ else
+ CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ],
+ rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ],
+ STALKWIDTH, -drawOrigin[ 2 ], cgs.media.scannerLineShader );
+
+ CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX / 2 ) - drawOrigin[ 0 ],
+ rect->y + ( rect->h / 2 ) - ( BLIPY / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ],
+ BLIPX, BLIPY, cgs.media.scannerBlipShader );
+ trap_R_SetColor( NULL );
+}
+
+/*
+=============
+CG_DrawBlipsPlayer
+
+Draw blips and stalks for the human scanner
+=============
+*/
+static void CG_DrawBlipsPlayer( rectDef_t *rect, vec3_t origin, vec4_t colour )
+{
+ vec3_t drawOrigin;
+ vec3_t up = { 0, 0, 1 };
+ float alphaMod = 1.0f;
+ float timeFractionSinceRefresh = 1.0f -( (float)( cg.time - entityPositions.lastUpdateTime ) / (float)HUMAN_SCANNER_UPDATE_PERIOD );
+ vec4_t localColour;
+
+ Vector4Copy( colour, localColour );
+
+ 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 );
+
+ localColour[ 3 ] *= alphaMod;
+ localColour[ 3 ] *= ( 0.5f + ( timeFractionSinceRefresh * 0.5f ) );
+
+ if( localColour[ 3 ] > 1.0f )
+ localColour[ 3 ] = 1.0f;
+ else if( localColour[ 3 ] < 0.0f )
+ localColour[ 3 ] = 0.0f;
+
+ trap_R_SetColor( localColour );
+
+ if( drawOrigin[ 2 ] > 0 )
+ CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ],
+ rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ],
+ STALKWIDTH, drawOrigin[ 2 ], cgs.media.scannerLineShader );
+ else
+ CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ],
+ rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ],
+ STALKWIDTH, -drawOrigin[ 2 ], cgs.media.scannerLineShader );
+
+ CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX / 2 ) - drawOrigin[ 0 ],
+ rect->y + ( rect->h / 2 ) - ( BLIPY / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ],
+ BLIPX, BLIPY, cgs.media.scannerBlipShaderPlayer );
+ trap_R_SetColor( NULL );
+}
+
+#define BLIPX2 (24.0f * cgDC.aspectScale)
+#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;
+ vec3_t noZOrigin;
+ vec3_t normal, antinormal, normalDiff;
+ vec3_t view, noZview;
+ vec3_t up = { 0.0f, 0.0f, 1.0f };
+ vec3_t top = { 0.0f, -1.0f, 0.0f };
+ float angle;
+ playerState_t *ps = &cg.snap->ps;
+
+ BG_GetClientNormal( ps, normal );
+
+ AngleVectors( entityPositions.vangles, view, NULL, NULL );
+
+ ProjectPointOnPlane( noZOrigin, origin, normal );
+ ProjectPointOnPlane( noZview, view, normal );
+ VectorNormalize( noZOrigin );
+ VectorNormalize( noZview );
+
+ //calculate the angle between the images of the blip and the view
+ angle = RAD2DEG( acos( DotProduct( noZOrigin, noZview ) ) );
+ CrossProduct( noZOrigin, noZview, antinormal );
+ VectorNormalize( antinormal );
+
+ //decide which way to rotate
+ VectorSubtract( normal, antinormal, normalDiff );
+ if( VectorLength( normalDiff ) < 1.0f )
+ angle = 360.0f - angle;
+
+ RotatePointAroundVector( drawOrigin, up, top, angle );
+
+ trap_R_SetColor( colour );
+ CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX2 / 2 ) - drawOrigin[ 0 ] * ( rect->w / 2 ),
+ rect->y + ( rect->h / 2 ) - ( BLIPY2 / 2 ) + drawOrigin[ 1 ] * ( rect->h / 2 ),
+ BLIPX2, BLIPY2, cgs.media.scannerBlipShader );
+ trap_R_SetColor( NULL );
+}
+
+/*
+=============
+CG_DrawDirPlayer
+
+Draw dot marking the direction to an enemy
+=============
+*/
+static void CG_DrawDirPlayer( rectDef_t *rect, vec3_t origin, vec4_t colour )
+{
+ vec3_t drawOrigin;
+ vec3_t noZOrigin;
+ vec3_t normal, antinormal, normalDiff;
+ vec3_t view, noZview;
+ vec3_t up = { 0.0f, 0.0f, 1.0f };
+ vec3_t top = { 0.0f, -1.0f, 0.0f };
+ float angle;
+ playerState_t *ps = &cg.snap->ps;
+
+ BG_GetClientNormal( ps, normal );
+
+ AngleVectors( entityPositions.vangles, view, NULL, NULL );
+
+ ProjectPointOnPlane( noZOrigin, origin, normal );
+ ProjectPointOnPlane( noZview, view, normal );
+ VectorNormalize( noZOrigin );
+ VectorNormalize( noZview );
+
+ //calculate the angle between the images of the blip and the view
+ angle = RAD2DEG( acos( DotProduct( noZOrigin, noZview ) ) );
+ CrossProduct( noZOrigin, noZview, antinormal );
+ VectorNormalize( antinormal );
+
+ //decide which way to rotate
+ VectorSubtract( normal, antinormal, normalDiff );
+ if( VectorLength( normalDiff ) < 1.0f )
+ angle = 360.0f - angle;
+
+ RotatePointAroundVector( drawOrigin, up, top, angle );
+
+ trap_R_SetColor( colour );
+ CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX2 / 2 ) - drawOrigin[ 0 ] * ( rect->w / 2 ),
+ rect->y + ( rect->h / 2 ) - ( BLIPY2 / 2 ) + drawOrigin[ 1 ] * ( rect->h / 2 ),
+ BLIPX2, BLIPY2, cgs.media.scannerBlipShaderPlayer );
+ trap_R_SetColor( NULL );
+}
+
+/*
+=============
+CG_AlienSense
+=============
+*/
+void CG_AlienSense( rectDef_t *rect )
+{
+ int i;
+ vec3_t origin;
+ vec3_t relOrigin;
+ vec4_t buildableb = { 0.0f, 0.5f, 1.0f, 0.75f };
+ vec4_t client = { 0.0f, 0.9f, 1.0f, 0.75f };
+ VectorCopy( entityPositions.origin, origin );
+
+ //draw human buildables
+ for( i = 0; i < entityPositions.numHumanBuildables; i++ )
+ {
+ VectorClear( relOrigin );
+ VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < ALIENSENSE_RANGE )
+ CG_DrawDir( rect, relOrigin, buildableb );
+ }
+
+ //draw human clients
+ for( i = 0; i < entityPositions.numHumanClients; i++ )
+ {
+ VectorClear( relOrigin );
+ VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < ALIENSENSE_RANGE )
+ CG_DrawDirPlayer( rect, relOrigin, client );
+ }
+}
+
+/*
+=============
+CG_Scanner
+=============
+*/
+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, 1.0f, 0.75f };
+ vec4_t hIbelow = { 0.0f, 0.8f, 0.8f, 0.60f };
+ vec4_t aIabove = { 1.0f, 0.0f, 0.0f, 0.75f };
+ vec4_t aIbelow = { 0.8f, 0.0f, 0.0f, 0.60f };
+
+ VectorCopy( entityPositions.origin, origin );
+
+ //draw human buildables below scanner plane
+ for( i = 0; i < entityPositions.numHumanBuildables; i++ )
+ {
+ VectorClear( 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 < entityPositions.numAlienBuildables; i++ )
+ {
+ VectorClear( 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 < entityPositions.numHumanClients; i++ )
+ {
+ VectorClear( relOrigin );
+ VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
+ CG_DrawBlipsPlayer( rect, relOrigin, hIbelow );
+ }
+
+ //draw alien clients below scanner plane
+ for( i = 0; i < entityPositions.numAlienClients; i++ )
+ {
+ VectorClear( relOrigin );
+ VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) )
+ CG_DrawBlipsPlayer( rect, relOrigin, aIbelow );
+ }
+
+ 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 < entityPositions.numHumanBuildables; i++ )
+ {
+ VectorClear( 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 < entityPositions.numAlienBuildables; i++ )
+ {
+ VectorClear( 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 < entityPositions.numHumanClients; i++ )
+ {
+ VectorClear( relOrigin );
+ VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
+ CG_DrawBlipsPlayer( rect, relOrigin, hIabove );
+ }
+
+ //draw alien clients above scanner plane
+ for( i = 0; i < entityPositions.numAlienClients; i++ )
+ {
+ VectorClear( relOrigin );
+ VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin );
+
+ if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) )
+ CG_DrawBlipsPlayer( rect, relOrigin, aIabove );
+ }
+}