2013-04-19 02:52:48 +00:00
// Copyright (C) 1999-2000 Id Software, Inc.
//
// cg_draw.c -- draw all of the graphical elements during
// active (after loading) gameplay
# include "cg_local.h"
# include "bg_saga.h"
# include "../ui/ui_shared.h"
# include "../ui/ui_public.h"
extern float CG_RadiusForCent ( centity_t * cent ) ;
qboolean CG_WorldCoordToScreenCoordFloat ( vec3_t worldCoord , float * x , float * y ) ;
qboolean CG_CalcMuzzlePoint ( int entityNum , vec3_t muzzle ) ;
static void CG_DrawSiegeTimer ( int timeRemaining , qboolean isMyTeam ) ;
static void CG_DrawSiegeDeathTimer ( int timeRemaining ) ;
// nmckenzie: DUEL_HEALTH
void CG_DrawDuelistHealth ( float x , float y , float w , float h , int duelist ) ;
// used for scoreboard
extern displayContextDef_t cgDC ;
menuDef_t * menuScoreboard = NULL ;
vec4_t bluehudtint = { 0.5 , 0.5 , 1.0 , 1.0 } ;
vec4_t redhudtint = { 1.0 , 0.5 , 0.5 , 1.0 } ;
float * hudTintColor ;
int sortedTeamPlayers [ TEAM_MAXOVERLAY ] ;
int numSortedTeamPlayers ;
int lastvalidlockdif ;
extern float zoomFov ; //this has to be global client-side
char systemChat [ 256 ] ;
char teamChat1 [ 256 ] ;
char teamChat2 [ 256 ] ;
// The time at which you died and the time it will take for you to rejoin game.
int cg_siegeDeathTime = 0 ;
# define MAX_HUD_TICS 4
const char * armorTicName [ MAX_HUD_TICS ] =
{
" armor_tic1 " ,
" armor_tic2 " ,
" armor_tic3 " ,
" armor_tic4 " ,
} ;
const char * healthTicName [ MAX_HUD_TICS ] =
{
" health_tic1 " ,
" health_tic2 " ,
" health_tic3 " ,
" health_tic4 " ,
} ;
const char * forceTicName [ MAX_HUD_TICS ] =
{
" force_tic1 " ,
" force_tic2 " ,
" force_tic3 " ,
" force_tic4 " ,
} ;
const char * ammoTicName [ MAX_HUD_TICS ] =
{
" ammo_tic1 " ,
" ammo_tic2 " ,
" ammo_tic3 " ,
" ammo_tic4 " ,
} ;
char * showPowersName [ ] =
{
" HEAL2 " , //FP_HEAL
" JUMP2 " , //FP_LEVITATION
" SPEED2 " , //FP_SPEED
" PUSH2 " , //FP_PUSH
" PULL2 " , //FP_PULL
" MINDTRICK2 " , //FP_TELEPTAHY
" GRIP2 " , //FP_GRIP
" LIGHTNING2 " , //FP_LIGHTNING
" DARK_RAGE2 " , //FP_RAGE
" PROTECT2 " , //FP_PROTECT
" ABSORB2 " , //FP_ABSORB
" TEAM_HEAL2 " , //FP_TEAM_HEAL
" TEAM_REPLENISH2 " , //FP_TEAM_FORCE
" DRAIN2 " , //FP_DRAIN
" SEEING2 " , //FP_SEE
" SABER_OFFENSE2 " , //FP_SABER_OFFENSE
" SABER_DEFENSE2 " , //FP_SABER_DEFENSE
" SABER_THROW2 " , //FP_SABERTHROW
NULL
} ;
//Called from UI shared code. For now we'll just redirect to the normal anim load function.
# include "../namespace_begin.h"
int UI_ParseAnimationFile ( const char * filename , animation_t * animset , qboolean isHumanoid )
{
return BG_ParseAnimationFile ( filename , animset , isHumanoid ) ;
}
int MenuFontToHandle ( int iMenuFont )
{
switch ( iMenuFont )
{
case FONT_SMALL : return cgDC . Assets . qhSmallFont ;
case FONT_SMALL2 : return cgDC . Assets . qhSmall2Font ;
case FONT_MEDIUM : return cgDC . Assets . qhMediumFont ;
case FONT_LARGE : return cgDC . Assets . qhMediumFont ; //cgDC.Assets.qhBigFont;
//fixme? Big fonr isn't registered...?
}
return cgDC . Assets . qhMediumFont ;
}
# include "../namespace_end.h"
int CG_Text_Width ( const char * text , float scale , int iMenuFont )
{
int iFontIndex = MenuFontToHandle ( iMenuFont ) ;
return trap_R_Font_StrLenPixels ( text , iFontIndex , scale ) ;
}
int CG_Text_Height ( const char * text , float scale , int iMenuFont )
{
int iFontIndex = MenuFontToHandle ( iMenuFont ) ;
return trap_R_Font_HeightPixels ( iFontIndex , scale ) ;
}
# include "../qcommon/qfiles.h" // for STYLE_BLINK etc
void CG_Text_Paint ( float x , float y , float scale , vec4_t color , const char * text , float adjust , int limit , int style , int iMenuFont )
{
int iStyleOR = 0 ;
int iFontIndex = MenuFontToHandle ( iMenuFont ) ;
switch ( style )
{
case ITEM_TEXTSTYLE_NORMAL : iStyleOR = 0 ; break ; // JK2 normal text
case ITEM_TEXTSTYLE_BLINK : iStyleOR = STYLE_BLINK ; break ; // JK2 fast blinking
case ITEM_TEXTSTYLE_PULSE : iStyleOR = STYLE_BLINK ; break ; // JK2 slow pulsing
case ITEM_TEXTSTYLE_SHADOWED : iStyleOR = ( int ) STYLE_DROPSHADOW ; break ; // JK2 drop shadow ( need a color for this )
case ITEM_TEXTSTYLE_OUTLINED : iStyleOR = ( int ) STYLE_DROPSHADOW ; break ; // JK2 drop shadow ( need a color for this )
case ITEM_TEXTSTYLE_OUTLINESHADOWED : iStyleOR = ( int ) STYLE_DROPSHADOW ; break ; // JK2 drop shadow ( need a color for this )
case ITEM_TEXTSTYLE_SHADOWEDMORE : iStyleOR = ( int ) STYLE_DROPSHADOW ; break ; // JK2 drop shadow ( need a color for this )
}
trap_R_Font_DrawString ( x , // int ox
y , // int oy
text , // const char *text
color , // paletteRGBA_c c
iStyleOR | iFontIndex , // const int iFontHandle
! limit ? - 1 : limit , // iCharLimit (-1 = none)
scale // const float scale = 1.0f
) ;
}
/*
qboolean CG_WorldCoordToScreenCoord ( vec3_t worldCoord , int * x , int * y )
Take any world coord and convert it to a 2 D virtual 640 x480 screen coord
*/
/*
qboolean CG_WorldCoordToScreenCoordFloat ( vec3_t worldCoord , float * x , float * y )
{
int xcenter , ycenter ;
vec3_t local , transformed ;
// xcenter = cg.refdef.width / 2;//gives screen coords adjusted for resolution
// ycenter = cg.refdef.height / 2;//gives screen coords adjusted for resolution
//NOTE: did it this way because most draw functions expect virtual 640x480 coords
// and adjust them for current resolution
xcenter = 640 / 2 ; //gives screen coords in virtual 640x480, to be adjusted when drawn
ycenter = 480 / 2 ; //gives screen coords in virtual 640x480, to be adjusted when drawn
VectorSubtract ( worldCoord , cg . refdef . vieworg , local ) ;
transformed [ 0 ] = DotProduct ( local , vright ) ;
transformed [ 1 ] = DotProduct ( local , vup ) ;
transformed [ 2 ] = DotProduct ( local , vfwd ) ;
// Make sure Z is not negative.
if ( transformed [ 2 ] < 0.01 )
{
return qfalse ;
}
// Simple convert to screen coords.
float xzi = xcenter / transformed [ 2 ] * ( 90.0 / cg . refdef . fov_x ) ;
float yzi = ycenter / transformed [ 2 ] * ( 90.0 / cg . refdef . fov_y ) ;
* x = xcenter + xzi * transformed [ 0 ] ;
* y = ycenter - yzi * transformed [ 1 ] ;
return qtrue ;
}
qboolean CG_WorldCoordToScreenCoord ( vec3_t worldCoord , int * x , int * y )
{
float xF , yF ;
qboolean retVal = CG_WorldCoordToScreenCoordFloat ( worldCoord , & xF , & yF ) ;
* x = ( int ) xF ;
* y = ( int ) yF ;
return retVal ;
}
*/
/*
= = = = = = = = = = = = = = = =
CG_DrawZoomMask
= = = = = = = = = = = = = = = =
*/
static void CG_DrawZoomMask ( void )
{
vec4_t color1 ;
float level ;
static qboolean flip = qtrue ;
// int ammo = cg_entities[0].gent->client->ps.ammo[weaponData[cent->currentState.weapon].ammoIndex];
float cx , cy ;
// int val[5];
float max , fi ;
// Check for Binocular specific zooming since we'll want to render different bits in each case
if ( cg . predictedPlayerState . zoomMode = = 2 )
{
int val , i ;
float off ;
// zoom level
level = ( float ) ( 80.0f - cg . predictedPlayerState . zoomFov ) / 80.0f ;
// ...so we'll clamp it
if ( level < 0.0f )
{
level = 0.0f ;
}
else if ( level > 1.0f )
{
level = 1.0f ;
}
// Using a magic number to convert the zoom level to scale amount
level * = 162.0f ;
// draw blue tinted distortion mask, trying to make it as small as is necessary to fill in the viewable area
trap_R_SetColor ( colorTable [ CT_WHITE ] ) ;
CG_DrawPic ( 34 , 48 , 570 , 362 , cgs . media . binocularStatic ) ;
// Black out the area behind the numbers
trap_R_SetColor ( colorTable [ CT_BLACK ] ) ;
CG_DrawPic ( 212 , 367 , 200 , 40 , cgs . media . whiteShader ) ;
// Numbers should be kind of greenish
color1 [ 0 ] = 0.2f ;
color1 [ 1 ] = 0.4f ;
color1 [ 2 ] = 0.2f ;
color1 [ 3 ] = 0.3f ;
trap_R_SetColor ( color1 ) ;
// Draw scrolling numbers, use intervals 10 units apart--sorry, this section of code is just kind of hacked
// up with a bunch of magic numbers.....
val = ( ( int ) ( ( cg . refdef . viewangles [ YAW ] + 180 ) / 10 ) ) * 10 ;
off = ( cg . refdef . viewangles [ YAW ] + 180 ) - val ;
for ( i = - 10 ; i < 30 ; i + = 10 )
{
val - = 10 ;
if ( val < 0 )
{
val + = 360 ;
}
// we only want to draw the very far left one some of the time, if it's too far to the left it will
// poke outside the mask.
if ( ( off > 3.0f & & i = = - 10 ) | | i > - 10 )
{
// draw the value, but add 200 just to bump the range up...arbitrary, so change it if you like
CG_DrawNumField ( 155 + i * 10 + off * 10 , 374 , 3 , val + 200 , 24 , 14 , NUM_FONT_CHUNKY , qtrue ) ;
CG_DrawPic ( 245 + ( i - 1 ) * 10 + off * 10 , 376 , 6 , 6 , cgs . media . whiteShader ) ;
}
}
CG_DrawPic ( 212 , 367 , 200 , 28 , cgs . media . binocularOverlay ) ;
color1 [ 0 ] = sin ( cg . time * 0.01f ) * 0.5f + 0.5f ;
color1 [ 0 ] = color1 [ 0 ] * color1 [ 0 ] ;
color1 [ 1 ] = color1 [ 0 ] ;
color1 [ 2 ] = color1 [ 0 ] ;
color1 [ 3 ] = 1.0f ;
trap_R_SetColor ( color1 ) ;
CG_DrawPic ( 82 , 94 , 16 , 16 , cgs . media . binocularCircle ) ;
// Flickery color
color1 [ 0 ] = 0.7f + crandom ( ) * 0.1f ;
color1 [ 1 ] = 0.8f + crandom ( ) * 0.1f ;
color1 [ 2 ] = 0.7f + crandom ( ) * 0.1f ;
color1 [ 3 ] = 1.0f ;
trap_R_SetColor ( color1 ) ;
CG_DrawPic ( 0 , 0 , 640 , 480 , cgs . media . binocularMask ) ;
CG_DrawPic ( 4 , 282 - level , 16 , 16 , cgs . media . binocularArrow ) ;
// The top triangle bit randomly flips
if ( flip )
{
CG_DrawPic ( 330 , 60 , - 26 , - 30 , cgs . media . binocularTri ) ;
}
else
{
CG_DrawPic ( 307 , 40 , 26 , 30 , cgs . media . binocularTri ) ;
}
if ( random ( ) > 0.98f & & ( cg . time & 1024 ) )
{
flip = ! flip ;
}
}
else if ( cg . predictedPlayerState . zoomMode )
{
// disruptor zoom mode
level = ( float ) ( 50.0f - zoomFov ) / 50.0f ; //(float)(80.0f - zoomFov) / 80.0f;
// ...so we'll clamp it
if ( level < 0.0f )
{
level = 0.0f ;
}
else if ( level > 1.0f )
{
level = 1.0f ;
}
// Using a magic number to convert the zoom level to a rotation amount that correlates more or less with the zoom artwork.
level * = 103.0f ;
// Draw target mask
trap_R_SetColor ( colorTable [ CT_WHITE ] ) ;
CG_DrawPic ( 0 , 0 , 640 , 480 , cgs . media . disruptorMask ) ;
// apparently 99.0f is the full zoom level
if ( level > = 99 )
{
// Fully zoomed, so make the rotating insert pulse
color1 [ 0 ] = 1.0f ;
color1 [ 1 ] = 1.0f ;
color1 [ 2 ] = 1.0f ;
color1 [ 3 ] = 0.7f + sin ( cg . time * 0.01f ) * 0.3f ;
trap_R_SetColor ( color1 ) ;
}
// Draw rotating insert
CG_DrawRotatePic2 ( 320 , 240 , 640 , 480 , - level , cgs . media . disruptorInsert ) ;
// Increase the light levels under the center of the target
// CG_DrawPic( 198, 118, 246, 246, cgs.media.disruptorLight );
// weirdness.....converting ammo to a base five number scale just to be geeky.
/* val[0] = ammo % 5;
val [ 1 ] = ( ammo / 5 ) % 5 ;
val [ 2 ] = ( ammo / 25 ) % 5 ;
val [ 3 ] = ( ammo / 125 ) % 5 ;
val [ 4 ] = ( ammo / 625 ) % 5 ;
color1 [ 0 ] = 0.2f ;
color1 [ 1 ] = 0.55f + crandom ( ) * 0.1f ;
color1 [ 2 ] = 0.5f + crandom ( ) * 0.1f ;
color1 [ 3 ] = 1.0f ;
trap_R_SetColor ( color1 ) ;
for ( int t = 0 ; t < 5 ; t + + )
{
cx = 320 + sin ( ( t * 10 + 45 ) / 57.296f ) * 192 ;
cy = 240 + cos ( ( t * 10 + 45 ) / 57.296f ) * 192 ;
CG_DrawRotatePic2 ( cx , cy , 24 , 38 , 45 - t * 10 , trap_R_RegisterShader ( va ( " gfx/2d/char%d " , val [ 4 - t ] ) ) ) ;
}
*/
//max = ( cg_entities[0].gent->health / 100.0f );
if ( ( cg . snap - > ps . eFlags & EF_DOUBLE_AMMO ) )
{
max = cg . snap - > ps . ammo [ weaponData [ WP_DISRUPTOR ] . ammoIndex ] / ( ( float ) ammoData [ weaponData [ WP_DISRUPTOR ] . ammoIndex ] . max * 2.0f ) ;
}
else
{
max = cg . snap - > ps . ammo [ weaponData [ WP_DISRUPTOR ] . ammoIndex ] / ( float ) ammoData [ weaponData [ WP_DISRUPTOR ] . ammoIndex ] . max ;
}
if ( max > 1.0f )
{
max = 1.0f ;
}
color1 [ 0 ] = ( 1.0f - max ) * 2.0f ;
color1 [ 1 ] = max * 1.5f ;
color1 [ 2 ] = 0.0f ;
color1 [ 3 ] = 1.0f ;
// If we are low on health, make us flash
if ( max < 0.15f & & ( cg . time & 512 ) )
{
VectorClear ( color1 ) ;
}
if ( color1 [ 0 ] > 1.0f )
{
color1 [ 0 ] = 1.0f ;
}
if ( color1 [ 1 ] > 1.0f )
{
color1 [ 1 ] = 1.0f ;
}
trap_R_SetColor ( color1 ) ;
max * = 58.0f ;
for ( fi = 18.5f ; fi < = 18.5f + max ; fi + = 3 ) // going from 15 to 45 degrees, with 5 degree increments
{
cx = 320 + sin ( ( fi + 90.0f ) / 57.296f ) * 190 ;
cy = 240 + cos ( ( fi + 90.0f ) / 57.296f ) * 190 ;
CG_DrawRotatePic2 ( cx , cy , 12 , 24 , 90 - fi , cgs . media . disruptorInsertTick ) ;
}
if ( cg . predictedPlayerState . weaponstate = = WEAPON_CHARGING_ALT )
{
trap_R_SetColor ( colorTable [ CT_WHITE ] ) ;
// draw the charge level
max = ( cg . time - cg . predictedPlayerState . weaponChargeTime ) / ( 50.0f * 30.0f ) ; // bad hardcodedness 50 is disruptor charge unit and 30 is max charge units allowed.
if ( max > 1.0f )
{
max = 1.0f ;
}
trap_R_DrawStretchPic ( 257 , 435 , 134 * max , 34 , 0 , 0 , max , 1 , cgs . media . disruptorChargeShader ) ;
}
// trap_R_SetColor( colorTable[CT_WHITE] );
// CG_DrawPic( 0, 0, 640, 480, cgs.media.disruptorMask );
}
}
/*
= = = = = = = = = = = = = = = =
CG_Draw3DModel
= = = = = = = = = = = = = = = =
*/
void CG_Draw3DModel ( float x , float y , float w , float h , qhandle_t model , void * ghoul2 , int g2radius , qhandle_t skin , vec3_t origin , vec3_t angles ) {
refdef_t refdef ;
refEntity_t ent ;
if ( ! cg_draw3dIcons . integer | | ! cg_drawIcons . integer ) {
return ;
}
memset ( & refdef , 0 , sizeof ( refdef ) ) ;
memset ( & ent , 0 , sizeof ( ent ) ) ;
AnglesToAxis ( angles , ent . axis ) ;
VectorCopy ( origin , ent . origin ) ;
ent . hModel = model ;
ent . ghoul2 = ghoul2 ;
ent . radius = g2radius ;
ent . customSkin = skin ;
ent . renderfx = RF_NOSHADOW ; // no stencil shadows
refdef . rdflags = RDF_NOWORLDMODEL ;
AxisClear ( refdef . viewaxis ) ;
refdef . fov_x = 30 ;
refdef . fov_y = 30 ;
refdef . x = x ;
refdef . y = y ;
refdef . width = w ;
refdef . height = h ;
refdef . time = cg . time ;
trap_R_ClearScene ( ) ;
trap_R_AddRefEntityToScene ( & ent ) ;
trap_R_RenderScene ( & refdef ) ;
}
/*
= = = = = = = = = = = = = = = =
CG_DrawHead
Used for both the status bar and the scoreboard
= = = = = = = = = = = = = = = =
*/
void CG_DrawHead ( float x , float y , float w , float h , int clientNum , vec3_t headAngles )
{
clientInfo_t * ci ;
if ( clientNum > = MAX_CLIENTS )
{ //npc?
return ;
}
ci = & cgs . clientinfo [ clientNum ] ;
CG_DrawPic ( x , y , w , h , ci - > modelIcon ) ;
// if they are deferred, draw a cross out
if ( ci - > deferred )
{
CG_DrawPic ( x , y , w , h , cgs . media . deferShader ) ;
}
}
/*
= = = = = = = = = = = = = = = =
CG_DrawFlagModel
Used for both the status bar and the scoreboard
= = = = = = = = = = = = = = = =
*/
void CG_DrawFlagModel ( float x , float y , float w , float h , int team , qboolean force2D ) {
qhandle_t cm ;
float len ;
vec3_t origin , angles ;
vec3_t mins , maxs ;
qhandle_t handle ;
if ( ! force2D & & cg_draw3dIcons . integer ) {
VectorClear ( angles ) ;
cm = cgs . media . redFlagModel ;
// offset the origin y and z to center the flag
trap_R_ModelBounds ( cm , mins , maxs ) ;
origin [ 2 ] = - 0.5 * ( mins [ 2 ] + maxs [ 2 ] ) ;
origin [ 1 ] = 0.5 * ( mins [ 1 ] + maxs [ 1 ] ) ;
// calculate distance so the flag nearly fills the box
// assume heads are taller than wide
len = 0.5 * ( maxs [ 2 ] - mins [ 2 ] ) ;
origin [ 0 ] = len / 0.268 ; // len / tan( fov/2 )
angles [ YAW ] = 60 * sin ( cg . time / 2000.0 ) ; ;
if ( team = = TEAM_RED ) {
handle = cgs . media . redFlagModel ;
} else if ( team = = TEAM_BLUE ) {
handle = cgs . media . blueFlagModel ;
} else if ( team = = TEAM_FREE ) {
handle = 0 ; //cgs.media.neutralFlagModel;
} else {
return ;
}
CG_Draw3DModel ( x , y , w , h , handle , NULL , 0 , 0 , origin , angles ) ;
} else if ( cg_drawIcons . integer ) {
gitem_t * item ;
if ( team = = TEAM_RED ) {
item = BG_FindItemForPowerup ( PW_REDFLAG ) ;
} else if ( team = = TEAM_BLUE ) {
item = BG_FindItemForPowerup ( PW_BLUEFLAG ) ;
} else if ( team = = TEAM_FREE ) {
item = BG_FindItemForPowerup ( PW_NEUTRALFLAG ) ;
} else {
return ;
}
if ( item ) {
CG_DrawPic ( x , y , w , h , cg_items [ ITEM_INDEX ( item ) ] . icon ) ;
}
}
}
/*
= = = = = = = = = = = = = = = =
DrawAmmo
= = = = = = = = = = = = = = = =
*/
void DrawAmmo ( )
{
int x , y ;
x = SCREEN_WIDTH - 80 ;
y = SCREEN_HEIGHT - 80 ;
}
/*
= = = = = = = = = = = = = = = =
CG_DrawHealth
= = = = = = = = = = = = = = = =
*/
void CG_DrawHealth ( menuDef_t * menuHUD )
{
vec4_t calcColor ;
playerState_t * ps ;
int healthAmt ;
int i , currValue , inc ;
itemDef_t * focusItem ;
float percent ;
// Can we find the menu?
if ( ! menuHUD )
{
return ;
}
ps = & cg . snap - > ps ;
// What's the health?
healthAmt = ps - > stats [ STAT_HEALTH ] ;
if ( healthAmt > ps - > stats [ STAT_MAX_HEALTH ] )
{
healthAmt = ps - > stats [ STAT_MAX_HEALTH ] ;
}
inc = ( float ) ps - > stats [ STAT_MAX_HEALTH ] / MAX_HUD_TICS ;
currValue = healthAmt ;
// Print the health tics, fading out the one which is partial health
for ( i = ( MAX_HUD_TICS - 1 ) ; i > = 0 ; i - - )
{
focusItem = Menu_FindItemByName ( menuHUD , healthTicName [ i ] ) ;
if ( ! focusItem ) // This is bad
{
continue ;
}
memcpy ( calcColor , hudTintColor , sizeof ( vec4_t ) ) ;
if ( currValue < = 0 ) // don't show tic
{
break ;
}
else if ( currValue < inc ) // partial tic (alpha it out)
{
percent = ( float ) currValue / inc ;
calcColor [ 3 ] * = percent ; // Fade it out
}
trap_R_SetColor ( calcColor ) ;
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
currValue - = inc ;
}
// Print the mueric amount
focusItem = Menu_FindItemByName ( menuHUD , " healthamount " ) ;
if ( focusItem )
{
// Print health amount
trap_R_SetColor ( focusItem - > window . foreColor ) ;
CG_DrawNumField (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
3 ,
ps - > stats [ STAT_HEALTH ] ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
NUM_FONT_SMALL ,
qfalse ) ;
}
}
/*
= = = = = = = = = = = = = = = =
CG_DrawArmor
= = = = = = = = = = = = = = = =
*/
void CG_DrawArmor ( menuDef_t * menuHUD )
{
vec4_t calcColor ;
playerState_t * ps ;
int armor , maxArmor ;
itemDef_t * focusItem ;
float percent , quarterArmor ;
int i , currValue , inc ;
//ps = &cg.snap->ps;
ps = & cg . predictedPlayerState ;
// Can we find the menu?
if ( ! menuHUD )
{
return ;
}
armor = ps - > stats [ STAT_ARMOR ] ;
maxArmor = ps - > stats [ STAT_MAX_HEALTH ] ;
if ( armor > maxArmor )
{
armor = maxArmor ;
}
currValue = armor ;
inc = ( float ) maxArmor / MAX_HUD_TICS ;
memcpy ( calcColor , hudTintColor , sizeof ( vec4_t ) ) ;
for ( i = ( MAX_HUD_TICS - 1 ) ; i > = 0 ; i - - )
{
focusItem = Menu_FindItemByName ( menuHUD , armorTicName [ i ] ) ;
if ( ! focusItem ) // This is bad
{
continue ;
}
memcpy ( calcColor , hudTintColor , sizeof ( vec4_t ) ) ;
if ( currValue < = 0 ) // don't show tic
{
break ;
}
else if ( currValue < inc ) // partial tic (alpha it out)
{
percent = ( float ) currValue / inc ;
calcColor [ 3 ] * = percent ;
}
trap_R_SetColor ( calcColor ) ;
if ( ( i = = ( MAX_HUD_TICS - 1 ) ) & & ( currValue < inc ) )
{
if ( cg . HUDArmorFlag )
{
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
}
}
else
{
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
}
currValue - = inc ;
}
focusItem = Menu_FindItemByName ( menuHUD , " armoramount " ) ;
if ( focusItem )
{
// Print armor amount
trap_R_SetColor ( focusItem - > window . foreColor ) ;
CG_DrawNumField (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
3 ,
armor ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
NUM_FONT_SMALL ,
qfalse ) ;
}
// If armor is low, flash a graphic to warn the player
if ( armor ) // Is there armor? Draw the HUD Armor TIC
{
quarterArmor = ( float ) ( ps - > stats [ STAT_MAX_HEALTH ] / 4.0f ) ;
// Make tic flash if armor is at 25% of full armor
if ( ps - > stats [ STAT_ARMOR ] < quarterArmor ) // Do whatever the flash timer says
{
if ( cg . HUDTickFlashTime < cg . time ) // Flip at the same time
{
cg . HUDTickFlashTime = cg . time + 400 ;
if ( cg . HUDArmorFlag )
{
cg . HUDArmorFlag = qfalse ;
}
else
{
cg . HUDArmorFlag = qtrue ;
}
}
}
else
{
cg . HUDArmorFlag = qtrue ;
}
}
else // No armor? Don't show it.
{
cg . HUDArmorFlag = qfalse ;
}
}
/*
= = = = = = = = = = = = = = = =
CG_DrawSaberStyle
If the weapon is a light saber ( which needs no ammo ) then draw a graphic showing
the saber style ( fast , medium , strong )
= = = = = = = = = = = = = = = =
*/
static void CG_DrawSaberStyle ( centity_t * cent , menuDef_t * menuHUD )
{
itemDef_t * focusItem ;
if ( ! cent - > currentState . weapon ) // We don't have a weapon right now
{
return ;
}
if ( cent - > currentState . weapon ! = WP_SABER )
{
return ;
}
// Can we find the menu?
if ( ! menuHUD )
{
return ;
}
// draw the current saber style in this window
switch ( cg . predictedPlayerState . fd . saberDrawAnimLevel )
{
case 1 : //FORCE_LEVEL_1:
case 5 : //FORCE_LEVEL_5://Tavion
focusItem = Menu_FindItemByName ( menuHUD , " saberstyle_fast " ) ;
if ( focusItem )
{
trap_R_SetColor ( hudTintColor ) ;
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
}
break ;
case 2 : //FORCE_LEVEL_2:
case 6 : //SS_DUAL
case 7 : //SS_STAFF
focusItem = Menu_FindItemByName ( menuHUD , " saberstyle_medium " ) ;
if ( focusItem )
{
trap_R_SetColor ( hudTintColor ) ;
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
}
break ;
case 3 : //FORCE_LEVEL_3:
case 4 : //FORCE_LEVEL_4://Desann
focusItem = Menu_FindItemByName ( menuHUD , " saberstyle_strong " ) ;
if ( focusItem )
{
trap_R_SetColor ( hudTintColor ) ;
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
}
break ;
}
}
/*
= = = = = = = = = = = = = = = =
CG_DrawAmmo
= = = = = = = = = = = = = = = =
*/
static void CG_DrawAmmo ( centity_t * cent , menuDef_t * menuHUD )
{
playerState_t * ps ;
int i ;
vec4_t calcColor ;
float value , inc = 0.0f , percent ;
itemDef_t * focusItem ;
ps = & cg . snap - > ps ;
// Can we find the menu?
if ( ! menuHUD )
{
return ;
}
if ( ! cent - > currentState . weapon ) // We don't have a weapon right now
{
return ;
}
value = ps - > ammo [ weaponData [ cent - > currentState . weapon ] . ammoIndex ] ;
if ( value < 0 ) // No ammo
{
return ;
}
focusItem = Menu_FindItemByName ( menuHUD , " ammoamount " ) ;
trap_R_SetColor ( hudTintColor ) ;
if ( weaponData [ cent - > currentState . weapon ] . energyPerShot = = 0 & &
weaponData [ cent - > currentState . weapon ] . altEnergyPerShot = = 0 )
{ //just draw "infinite"
inc = 8 / MAX_HUD_TICS ;
value = 8 ;
focusItem = Menu_FindItemByName ( menuHUD , " ammoinfinite " ) ;
trap_R_SetColor ( hudTintColor ) ;
if ( focusItem )
{
UI_DrawProportionalString ( focusItem - > window . rect . x , focusItem - > window . rect . y , " -- " , NUM_FONT_SMALL , focusItem - > window . foreColor ) ;
}
}
else
{
focusItem = Menu_FindItemByName ( menuHUD , " ammoamount " ) ;
trap_R_SetColor ( hudTintColor ) ;
if ( focusItem )
{
if ( ( cent - > currentState . eFlags & EF_DOUBLE_AMMO ) )
{
inc = ( float ) ( ammoData [ weaponData [ cent - > currentState . weapon ] . ammoIndex ] . max * 2.0f ) / MAX_HUD_TICS ;
}
else
{
inc = ( float ) ammoData [ weaponData [ cent - > currentState . weapon ] . ammoIndex ] . max / MAX_HUD_TICS ;
}
value = ps - > ammo [ weaponData [ cent - > currentState . weapon ] . ammoIndex ] ;
CG_DrawNumField (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
3 ,
value ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
NUM_FONT_SMALL ,
qfalse ) ;
}
}
// Draw tics
for ( i = MAX_HUD_TICS - 1 ; i > = 0 ; i - - )
{
focusItem = Menu_FindItemByName ( menuHUD , ammoTicName [ i ] ) ;
if ( ! focusItem )
{
continue ;
}
memcpy ( calcColor , hudTintColor , sizeof ( vec4_t ) ) ;
if ( value < = 0 ) // done
{
break ;
}
else if ( value < inc ) // partial tic
{
percent = value / inc ;
calcColor [ 3 ] = percent ;
}
trap_R_SetColor ( calcColor ) ;
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
value - = inc ;
}
}
/*
= = = = = = = = = = = = = = = =
CG_DrawForcePower
= = = = = = = = = = = = = = = =
*/
void CG_DrawForcePower ( menuDef_t * menuHUD )
{
int i ;
vec4_t calcColor ;
float value , inc , percent ;
itemDef_t * focusItem ;
const int maxForcePower = 100 ;
qboolean flash = qfalse ;
// Can we find the menu?
if ( ! menuHUD )
{
return ;
}
// Make the hud flash by setting forceHUDTotalFlashTime above cg.time
if ( cg . forceHUDTotalFlashTime > cg . time )
{
flash = qtrue ;
if ( cg . forceHUDNextFlashTime < cg . time )
{
cg . forceHUDNextFlashTime = cg . time + 400 ;
trap_S_StartSound ( NULL , 0 , CHAN_LOCAL , cgs . media . noforceSound ) ;
if ( cg . forceHUDActive )
{
cg . forceHUDActive = qfalse ;
}
else
{
cg . forceHUDActive = qtrue ;
}
}
}
else // turn HUD back on if it had just finished flashing time.
{
cg . forceHUDNextFlashTime = 0 ;
cg . forceHUDActive = qtrue ;
}
// if (!cg.forceHUDActive)
// {
// return;
// }
inc = ( float ) maxForcePower / MAX_HUD_TICS ;
value = cg . snap - > ps . fd . forcePower ;
for ( i = MAX_HUD_TICS - 1 ; i > = 0 ; i - - )
{
focusItem = Menu_FindItemByName ( menuHUD , forceTicName [ i ] ) ;
if ( ! focusItem )
{
continue ;
}
// memcpy(calcColor, hudTintColor, sizeof(vec4_t));
if ( value < = 0 ) // done
{
break ;
}
else if ( value < inc ) // partial tic
{
if ( flash )
{
memcpy ( calcColor , colorTable [ CT_RED ] , sizeof ( vec4_t ) ) ;
}
else
{
memcpy ( calcColor , colorTable [ CT_WHITE ] , sizeof ( vec4_t ) ) ;
}
percent = value / inc ;
calcColor [ 3 ] = percent ;
}
else
{
if ( flash )
{
memcpy ( calcColor , colorTable [ CT_RED ] , sizeof ( vec4_t ) ) ;
}
else
{
memcpy ( calcColor , colorTable [ CT_WHITE ] , sizeof ( vec4_t ) ) ;
}
}
trap_R_SetColor ( calcColor ) ;
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
value - = inc ;
}
focusItem = Menu_FindItemByName ( menuHUD , " forceamount " ) ;
if ( focusItem )
{
// Print force amount
trap_R_SetColor ( focusItem - > window . foreColor ) ;
CG_DrawNumField (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
3 ,
cg . snap - > ps . fd . forcePower ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
NUM_FONT_SMALL ,
qfalse ) ;
}
}
/*
= = = = = = = = = = = = = = = =
CG_DrawHUD
= = = = = = = = = = = = = = = =
*/
void CG_DrawHUD ( centity_t * cent )
{
menuDef_t * menuHUD = NULL ;
itemDef_t * focusItem = NULL ;
const char * scoreStr = NULL ;
int scoreBias ;
char scoreBiasStr [ 16 ] ;
if ( cg_hudFiles . integer )
{
int x = 0 ;
int y = SCREEN_HEIGHT - 80 ;
char ammoString [ 64 ] ;
int weapX = x ;
UI_DrawProportionalString ( x + 16 , y + 40 , va ( " %i " , cg . snap - > ps . stats [ STAT_HEALTH ] ) ,
UI_SMALLFONT | UI_DROPSHADOW , colorTable [ CT_HUD_RED ] ) ;
UI_DrawProportionalString ( x + 18 + 14 , y + 40 + 14 , va ( " %i " , cg . snap - > ps . stats [ STAT_ARMOR ] ) ,
UI_SMALLFONT | UI_DROPSHADOW , colorTable [ CT_HUD_GREEN ] ) ;
if ( cg . snap - > ps . weapon = = WP_SABER )
{
if ( cg . snap - > ps . fd . saberDrawAnimLevel = = SS_DUAL )
{
Com_sprintf ( ammoString , sizeof ( ammoString ) , " AKIMBO " ) ;
weapX + = 16 ;
}
else if ( cg . snap - > ps . fd . saberDrawAnimLevel = = SS_STAFF )
{
Com_sprintf ( ammoString , sizeof ( ammoString ) , " STAFF " ) ;
weapX + = 16 ;
}
else if ( cg . snap - > ps . fd . saberDrawAnimLevel = = FORCE_LEVEL_3 )
{
Com_sprintf ( ammoString , sizeof ( ammoString ) , " STRONG " ) ;
weapX + = 16 ;
}
else if ( cg . snap - > ps . fd . saberDrawAnimLevel = = FORCE_LEVEL_2 )
{
Com_sprintf ( ammoString , sizeof ( ammoString ) , " MEDIUM " ) ;
weapX + = 16 ;
}
else
{
Com_sprintf ( ammoString , sizeof ( ammoString ) , " FAST " ) ;
}
}
else
{
Com_sprintf ( ammoString , sizeof ( ammoString ) , " %i " , cg . snap - > ps . ammo [ weaponData [ cent - > currentState . weapon ] . ammoIndex ] ) ;
}
UI_DrawProportionalString ( SCREEN_WIDTH - ( weapX + 16 + 32 ) , y + 40 , va ( " %s " , ammoString ) ,
UI_SMALLFONT | UI_DROPSHADOW , colorTable [ CT_HUD_ORANGE ] ) ;
UI_DrawProportionalString ( SCREEN_WIDTH - ( x + 18 + 14 + 32 ) , y + 40 + 14 , va ( " %i " , cg . snap - > ps . fd . forcePower ) ,
UI_SMALLFONT | UI_DROPSHADOW , colorTable [ CT_ICON_BLUE ] ) ;
return ;
}
if ( cgs . gametype > = GT_TEAM & & cgs . gametype ! = GT_SIEGE )
{ // tint the hud items based on team
if ( cg . snap - > ps . persistant [ PERS_TEAM ] = = TEAM_RED )
hudTintColor = redhudtint ;
else if ( cg . snap - > ps . persistant [ PERS_TEAM ] = = TEAM_BLUE )
hudTintColor = bluehudtint ;
else // If we're not on a team for whatever reason, leave things as they are.
hudTintColor = colorTable [ CT_WHITE ] ;
}
else
{ // tint the hud items white (dont' tint)
hudTintColor = colorTable [ CT_WHITE ] ;
}
// Draw the left HUD
menuHUD = Menus_FindByName ( " lefthud " ) ;
if ( menuHUD )
{
itemDef_t * focusItem ;
// Print scanline
focusItem = Menu_FindItemByName ( menuHUD , " scanline " ) ;
if ( focusItem )
{
trap_R_SetColor ( hudTintColor ) ;
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
}
// Print frame
focusItem = Menu_FindItemByName ( menuHUD , " frame " ) ;
if ( focusItem )
{
trap_R_SetColor ( hudTintColor ) ;
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
}
if ( cg . predictedPlayerState . pm_type ! = PM_SPECTATOR )
{
CG_DrawArmor ( menuHUD ) ;
CG_DrawHealth ( menuHUD ) ;
}
}
else
{
//CG_Error("CG_ChatBox_ArrayInsert: unable to locate HUD menu file ");
}
//scoreStr = va("Score: %i", cgs.clientinfo[cg.snap->ps.clientNum].score);
if ( cgs . gametype = = GT_DUEL )
{ //A duel that requires more than one kill to knock the current enemy back to the queue
//show current kills out of how many needed
scoreStr = va ( " %s: %i/%i " , CG_GetStringEdString ( " MP_INGAME " , " SCORE " ) , cg . snap - > ps . persistant [ PERS_SCORE ] , cgs . fraglimit ) ;
}
else if ( 0 & & cgs . gametype < GT_TEAM )
{ // This is a teamless mode, draw the score bias.
scoreBias = cg . snap - > ps . persistant [ PERS_SCORE ] - cgs . scores1 ;
if ( scoreBias = = 0 )
{ // We are the leader!
if ( cgs . scores2 < = 0 )
{ // Nobody to be ahead of yet.
Com_sprintf ( scoreBiasStr , sizeof ( scoreBiasStr ) , " " ) ;
}
else
{
scoreBias = cg . snap - > ps . persistant [ PERS_SCORE ] - cgs . scores2 ;
if ( scoreBias = = 0 )
{
Com_sprintf ( scoreBiasStr , sizeof ( scoreBiasStr ) , " (Tie) " ) ;
}
else
{
Com_sprintf ( scoreBiasStr , sizeof ( scoreBiasStr ) , " (+%d) " , scoreBias ) ;
}
}
}
else // if (scoreBias < 0)
{ // We are behind!
Com_sprintf ( scoreBiasStr , sizeof ( scoreBiasStr ) , " (%d) " , scoreBias ) ;
}
scoreStr = va ( " %s: %i%s " , CG_GetStringEdString ( " MP_INGAME " , " SCORE " ) , cg . snap - > ps . persistant [ PERS_SCORE ] , scoreBiasStr ) ;
}
else
{ // Don't draw a bias.
scoreStr = va ( " %s: %i " , CG_GetStringEdString ( " MP_INGAME " , " SCORE " ) , cg . snap - > ps . persistant [ PERS_SCORE ] ) ;
}
menuHUD = Menus_FindByName ( " righthud " ) ;
if ( menuHUD )
{
if ( cgs . gametype ! = GT_POWERDUEL )
{
focusItem = Menu_FindItemByName ( menuHUD , " score_line " ) ;
if ( focusItem )
{
UI_DrawScaledProportionalString (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
scoreStr ,
UI_RIGHT | UI_DROPSHADOW ,
focusItem - > window . foreColor ,
0.7 ) ;
}
}
// Print scanline
focusItem = Menu_FindItemByName ( menuHUD , " scanline " ) ;
if ( focusItem )
{
trap_R_SetColor ( hudTintColor ) ;
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
}
focusItem = Menu_FindItemByName ( menuHUD , " frame " ) ;
if ( focusItem )
{
trap_R_SetColor ( hudTintColor ) ;
CG_DrawPic (
focusItem - > window . rect . x ,
focusItem - > window . rect . y ,
focusItem - > window . rect . w ,
focusItem - > window . rect . h ,
focusItem - > window . background
) ;
}
CG_DrawForcePower ( menuHUD ) ;
// Draw ammo tics or saber style
if ( cent - > currentState . weapon = = WP_SABER )
{
CG_DrawSaberStyle ( cent , menuHUD ) ;
}
else
{
CG_DrawAmmo ( cent , menuHUD ) ;
}
}
else
{
//CG_Error("CG_ChatBox_ArrayInsert: unable to locate HUD menu file ");
}
}
# define MAX_SHOWPOWERS NUM_FORCE_POWERS
qboolean ForcePower_Valid ( int i )
{
if ( i = = FP_LEVITATION | |
i = = FP_SABER_OFFENSE | |
i = = FP_SABER_DEFENSE | |
i = = FP_SABERTHROW )
{
return qfalse ;
}
if ( cg . snap - > ps . fd . forcePowersKnown & ( 1 < < i ) )
{
return qtrue ;
}
return qfalse ;
}
/*
= = = = = = = = = = = = = = = = = = =
CG_DrawForceSelect
= = = = = = = = = = = = = = = = = = =
*/
# ifdef _XBOX
extern bool CL_ExtendSelectTime ( void ) ;
# endif
void CG_DrawForceSelect ( void )
{
int i ;
int count ;
int smallIconSize , bigIconSize ;
int holdX , x , y , x2 , y2 , pad , length ;
int sideLeftIconCnt , sideRightIconCnt ;
int sideMax , holdCount , iconCnt ;
int yOffset = 0 ;
x2 = 0 ;
y2 = 0 ;
// don't display if dead
if ( cg . snap - > ps . stats [ STAT_HEALTH ] < = 0 )
{
return ;
}
if ( ( cg . forceSelectTime + WEAPON_SELECT_TIME ) < cg . time ) // Time is up for the HUD to display
{
cg . forceSelect = cg . snap - > ps . fd . forcePowerSelected ;
return ;
}
if ( ! cg . snap - > ps . fd . forcePowersKnown )
{
return ;
}
# ifdef _XBOX
if ( CL_ExtendSelectTime ( ) ) {
cg . forceSelectTime = cg . time ;
}
yOffset = - 50 ;
# endif
// count the number of powers owned
count = 0 ;
for ( i = 0 ; i < NUM_FORCE_POWERS ; + + i )
{
if ( ForcePower_Valid ( i ) )
{
count + + ;
}
}
if ( count = = 0 ) // If no force powers, don't display
{
return ;
}
sideMax = 3 ; // Max number of icons on the side
// Calculate how many icons will appear to either side of the center one
holdCount = count - 1 ; // -1 for the center icon
if ( holdCount = = 0 ) // No icons to either side
{
sideLeftIconCnt = 0 ;
sideRightIconCnt = 0 ;
}
else if ( count > ( 2 * sideMax ) ) // Go to the max on each side
{
sideLeftIconCnt = sideMax ;
sideRightIconCnt = sideMax ;
}
else // Less than max, so do the calc
{
sideLeftIconCnt = holdCount / 2 ;
sideRightIconCnt = holdCount - sideLeftIconCnt ;
}
smallIconSize = 30 ;
bigIconSize = 60 ;
pad = 12 ;
x = 320 ;
y = 425 ;
// Background
length = ( sideLeftIconCnt * smallIconSize ) + ( sideLeftIconCnt * pad ) +
bigIconSize + ( sideRightIconCnt * smallIconSize ) + ( sideRightIconCnt * pad ) + 12 ;
i = BG_ProperForceIndex ( cg . forceSelect ) - 1 ;
if ( i < 0 )
{
i = MAX_SHOWPOWERS ;
}
trap_R_SetColor ( NULL ) ;
// Work backwards from current icon
holdX = x - ( ( bigIconSize / 2 ) + pad + smallIconSize ) ;
for ( iconCnt = 1 ; iconCnt < ( sideLeftIconCnt + 1 ) ; i - - )
{
if ( i < 0 )
{
i = MAX_SHOWPOWERS ;
}
if ( ! ForcePower_Valid ( forcePowerSorted [ i ] ) ) // Does he have this power?
{
continue ;
}
+ + iconCnt ; // Good icon
if ( cgs . media . forcePowerIcons [ forcePowerSorted [ i ] ] )
{
CG_DrawPic ( holdX , y + yOffset , smallIconSize , smallIconSize , cgs . media . forcePowerIcons [ forcePowerSorted [ i ] ] ) ;
holdX - = ( smallIconSize + pad ) ;
}
}
if ( ForcePower_Valid ( cg . forceSelect ) )
{
// Current Center Icon
if ( cgs . media . forcePowerIcons [ cg . forceSelect ] )
{
CG_DrawPic ( x - ( bigIconSize / 2 ) , ( y - ( ( bigIconSize - smallIconSize ) / 2 ) ) + yOffset , bigIconSize , bigIconSize , cgs . media . forcePowerIcons [ cg . forceSelect ] ) ; //only cache the icon for display
}
}
i = BG_ProperForceIndex ( cg . forceSelect ) + 1 ;
if ( i > MAX_SHOWPOWERS )
{
i = 0 ;
}
// Work forwards from current icon
holdX = x + ( bigIconSize / 2 ) + pad ;
for ( iconCnt = 1 ; iconCnt < ( sideRightIconCnt + 1 ) ; i + + )
{
if ( i > MAX_SHOWPOWERS )
{
i = 0 ;
}
if ( ! ForcePower_Valid ( forcePowerSorted [ i ] ) ) // Does he have this power?
{
continue ;
}
+ + iconCnt ; // Good icon
if ( cgs . media . forcePowerIcons [ forcePowerSorted [ i ] ] )
{
CG_DrawPic ( holdX , y + yOffset , smallIconSize , smallIconSize , cgs . media . forcePowerIcons [ forcePowerSorted [ i ] ] ) ; //only cache the icon for display
holdX + = ( smallIconSize + pad ) ;
}
}
if ( showPowersName [ cg . forceSelect ] )
{
UI_DrawProportionalString ( 320 , y + 30 + yOffset , CG_GetStringEdString ( " SP_INGAME " , showPowersName [ cg . forceSelect ] ) , UI_CENTER | UI_SMALLFONT , colorTable [ CT_ICON_BLUE ] ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
CG_DrawInventorySelect
= = = = = = = = = = = = = = = = = = =
*/
void CG_DrawInvenSelect ( void )
{
int i ;
int sideMax , holdCount , iconCnt ;
int smallIconSize , bigIconSize ;
int sideLeftIconCnt , sideRightIconCnt ;
int count ;
int holdX , x , y , y2 , pad ;
int height ;
float addX ;
// don't display if dead
if ( cg . snap - > ps . stats [ STAT_HEALTH ] < = 0 )
{
return ;
}
if ( ( cg . invenSelectTime + WEAPON_SELECT_TIME ) < cg . time ) // Time is up for the HUD to display
{
return ;
}
if ( ! cg . snap - > ps . stats [ STAT_HOLDABLE_ITEM ] | | ! cg . snap - > ps . stats [ STAT_HOLDABLE_ITEMS ] )
{
return ;
}
# ifdef _XBOX
if ( CL_ExtendSelectTime ( ) ) {
cg . invenSelectTime = cg . time ;
}
# endif
if ( cg . itemSelect = = - 1 )
{
cg . itemSelect = bg_itemlist [ cg . snap - > ps . stats [ STAT_HOLDABLE_ITEM ] ] . giTag ;
}
//const int bits = cg.snap->ps.stats[ STAT_ITEMS ];
// count the number of items owned
count = 0 ;
for ( i = 0 ; i < HI_NUM_HOLDABLE ; i + + )
{
if ( /*CG_InventorySelectable(i) && inv_icons[i]*/
( cg . snap - > ps . stats [ STAT_HOLDABLE_ITEMS ] & ( 1 < < i ) ) )
{
count + + ;
}
}
if ( ! count )
{
y2 = 0 ; //err?
UI_DrawProportionalString ( 320 , y2 + 22 , " EMPTY INVENTORY " , UI_CENTER | UI_SMALLFONT , colorTable [ CT_ICON_BLUE ] ) ;
return ;
}
sideMax = 3 ; // Max number of icons on the side
// Calculate how many icons will appear to either side of the center one
holdCount = count - 1 ; // -1 for the center icon
if ( holdCount = = 0 ) // No icons to either side
{
sideLeftIconCnt = 0 ;
sideRightIconCnt = 0 ;
}
else if ( count > ( 2 * sideMax ) ) // Go to the max on each side
{
sideLeftIconCnt = sideMax ;
sideRightIconCnt = sideMax ;
}
else // Less than max, so do the calc
{
sideLeftIconCnt = holdCount / 2 ;
sideRightIconCnt = holdCount - sideLeftIconCnt ;
}
i = cg . itemSelect - 1 ;
if ( i < 0 )
{
i = HI_NUM_HOLDABLE - 1 ;
}
smallIconSize = 40 ;
bigIconSize = 80 ;
pad = 16 ;
x = 320 ;
y = 410 ;
// Left side ICONS
// Work backwards from current icon
holdX = x - ( ( bigIconSize / 2 ) + pad + smallIconSize ) ;
height = smallIconSize * cg . iconHUDPercent ;
addX = ( float ) smallIconSize * .75 ;
for ( iconCnt = 0 ; iconCnt < sideLeftIconCnt ; i - - )
{
if ( i < 0 )
{
i = HI_NUM_HOLDABLE - 1 ;
}
if ( ! ( cg . snap - > ps . stats [ STAT_HOLDABLE_ITEMS ] & ( 1 < < i ) ) | | i = = cg . itemSelect )
{
continue ;
}
+ + iconCnt ; // Good icon
if ( ! BG_IsItemSelectable ( & cg . predictedPlayerState , i ) )
{
continue ;
}
if ( cgs . media . invenIcons [ i ] )
{
trap_R_SetColor ( NULL ) ;
CG_DrawPic ( holdX , y + 10 , smallIconSize , smallIconSize , cgs . media . invenIcons [ i ] ) ;
trap_R_SetColor ( colorTable [ CT_ICON_BLUE ] ) ;
/*CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12,
NUM_FONT_SMALL , qfalse ) ;
*/
holdX - = ( smallIconSize + pad ) ;
}
}
// Current Center Icon
height = bigIconSize * cg . iconHUDPercent ;
if ( cgs . media . invenIcons [ cg . itemSelect ] & & BG_IsItemSelectable ( & cg . predictedPlayerState , cg . itemSelect ) )
{
int itemNdex ;
trap_R_SetColor ( NULL ) ;
CG_DrawPic ( x - ( bigIconSize / 2 ) , ( y - ( ( bigIconSize - smallIconSize ) / 2 ) ) + 10 , bigIconSize , bigIconSize , cgs . media . invenIcons [ cg . itemSelect ] ) ;
addX = ( float ) bigIconSize * .75 ;
trap_R_SetColor ( colorTable [ CT_ICON_BLUE ] ) ;
/*CG_DrawNumField ((x-(bigIconSize/2)) + addX, y, 2, cg.snap->ps.inventory[cg.inventorySelect], 6, 12,
NUM_FONT_SMALL , qfalse ) ; */
itemNdex = BG_GetItemIndexByTag ( cg . itemSelect , IT_HOLDABLE ) ;
if ( bg_itemlist [ itemNdex ] . classname )
{
vec4_t textColor = { .312f , .75f , .621f , 1.0f } ;
char text [ 1024 ] ;
char upperKey [ 1024 ] ;
strcpy ( upperKey , bg_itemlist [ itemNdex ] . classname ) ;
if ( trap_SP_GetStringTextString ( va ( " SP_INGAME_%s " , Q_strupr ( upperKey ) ) , text , sizeof ( text ) ) )
{
UI_DrawProportionalString ( 320 , y + 45 , text , UI_CENTER | UI_SMALLFONT , textColor ) ;
}
else
{
UI_DrawProportionalString ( 320 , y + 45 , bg_itemlist [ itemNdex ] . classname , UI_CENTER | UI_SMALLFONT , textColor ) ;
}
}
}
i = cg . itemSelect + 1 ;
if ( i > HI_NUM_HOLDABLE - 1 )
{
i = 0 ;
}
// Right side ICONS
// Work forwards from current icon
holdX = x + ( bigIconSize / 2 ) + pad ;
height = smallIconSize * cg . iconHUDPercent ;
addX = ( float ) smallIconSize * .75 ;
for ( iconCnt = 0 ; iconCnt < sideRightIconCnt ; i + + )
{
if ( i > HI_NUM_HOLDABLE - 1 )
{
i = 0 ;
}
if ( ! ( cg . snap - > ps . stats [ STAT_HOLDABLE_ITEMS ] & ( 1 < < i ) ) | | i = = cg . itemSelect )
{
continue ;
}
+ + iconCnt ; // Good icon
if ( ! BG_IsItemSelectable ( & cg . predictedPlayerState , i ) )
{
continue ;
}
if ( cgs . media . invenIcons [ i ] )
{
trap_R_SetColor ( NULL ) ;
CG_DrawPic ( holdX , y + 10 , smallIconSize , smallIconSize , cgs . media . invenIcons [ i ] ) ;
trap_R_SetColor ( colorTable [ CT_ICON_BLUE ] ) ;
/*CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12,
NUM_FONT_SMALL , qfalse ) ; */
holdX + = ( smallIconSize + pad ) ;
}
}
}
int cg_targVeh = ENTITYNUM_NONE ;
int cg_targVehLastTime = 0 ;
qboolean CG_CheckTargetVehicle ( centity_t * * pTargetVeh , float * alpha )
{
int targetNum = ENTITYNUM_NONE ;
centity_t * targetVeh = NULL ;
if ( ! pTargetVeh | | ! alpha )
{ //hey, where are my pointers?
return qfalse ;
}
* alpha = 1.0f ;
//FIXME: need to clear all of these when you die?
if ( cg . predictedPlayerState . rocketLockIndex < ENTITYNUM_WORLD )
{
targetNum = cg . predictedPlayerState . rocketLockIndex ;
}
else if ( cg . crosshairVehNum < ENTITYNUM_WORLD
& & cg . time - cg . crosshairVehTime < 3000 )
{ //crosshair was on a vehicle in the last 3 seconds
targetNum = cg . crosshairVehNum ;
}
else if ( cg . crosshairClientNum < ENTITYNUM_WORLD )
{
targetNum = cg . crosshairClientNum ;
}
if ( targetNum < MAX_CLIENTS )
{ //real client
if ( cg_entities [ targetNum ] . currentState . m_iVehicleNum > = MAX_CLIENTS )
{ //in a vehicle
targetNum = cg_entities [ targetNum ] . currentState . m_iVehicleNum ;
}
}
if ( targetNum < ENTITYNUM_WORLD
& & targetNum > = MAX_CLIENTS )
{
centity_t * targetVeh = & cg_entities [ targetNum ] ;
if ( targetVeh - > currentState . NPC_class = = CLASS_VEHICLE
& & targetVeh - > m_pVehicle
& & targetVeh - > m_pVehicle - > m_pVehicleInfo
& & targetVeh - > m_pVehicle - > m_pVehicleInfo - > type = = VH_FIGHTER )
{ //it's a vehicle
cg_targVeh = targetNum ;
cg_targVehLastTime = cg . time ;
* alpha = 1.0f ;
}
else
{
targetVeh = NULL ;
}
}
if ( ! targetVeh )
{
if ( cg_targVehLastTime & & cg . time - cg_targVehLastTime < 3000 )
{
targetVeh = & cg_entities [ cg_targVeh ] ; ;
if ( cg . time - cg_targVehLastTime < 1000 )
{ //stay at full alpha for 1 sec after lose them from crosshair
* alpha = 1.0f ;
}
else
{ //fade out over 2 secs
* alpha = 1.0f - ( ( cg . time - cg_targVehLastTime - 1000 ) / 2000.0f ) ;
}
}
}
if ( targetVeh )
{
* pTargetVeh = targetVeh ;
return qtrue ;
}
return qfalse ;
}
# define MAX_VHUD_SHIELD_TICS 12
# define MAX_VHUD_SPEED_TICS 5
# define MAX_VHUD_ARMOR_TICS 5
# define MAX_VHUD_AMMO_TICS 5
float CG_DrawVehicleShields ( const menuDef_t * menuHUD , const centity_t * veh )
{
int i ;
char itemName [ 64 ] ;
float inc , currValue , maxShields ;
vec4_t calcColor ;
itemDef_t * item ;
float percShields ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , " armorbackground " ) ;
if ( item )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
}
maxShields = veh - > m_pVehicle - > m_pVehicleInfo - > shields ;
currValue = cg . predictedVehicleState . stats [ STAT_ARMOR ] ;
percShields = ( float ) currValue / ( float ) maxShields ;
// Print all the tics of the shield graphic
// Look at the amount of health left and show only as much of the graphic as there is health.
// Use alpha to fade out partial section of health
inc = ( float ) maxShields / MAX_VHUD_ARMOR_TICS ;
for ( i = 1 ; i < = MAX_VHUD_ARMOR_TICS ; i + + )
{
sprintf ( itemName , " armor_tic%d " , i ) ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , itemName ) ;
if ( ! item )
{
continue ;
}
memcpy ( calcColor , item - > window . foreColor , sizeof ( vec4_t ) ) ;
if ( currValue < = 0 ) // don't show tic
{
break ;
}
else if ( currValue < inc ) // partial tic (alpha it out)
{
float percent = currValue / inc ;
calcColor [ 3 ] * = percent ; // Fade it out
}
trap_R_SetColor ( calcColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
currValue - = inc ;
}
return percShields ;
}
int cg_vehicleAmmoWarning = 0 ;
int cg_vehicleAmmoWarningTime = 0 ;
void CG_DrawVehicleAmmo ( const menuDef_t * menuHUD , const centity_t * veh )
{
int i ;
char itemName [ 64 ] ;
float inc , currValue , maxAmmo ;
vec4_t calcColor ;
itemDef_t * item ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , " ammobackground " ) ;
if ( item )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
}
maxAmmo = veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 0 ] . ammoMax ;
currValue = cg . predictedVehicleState . ammo [ 0 ] ;
inc = ( float ) maxAmmo / MAX_VHUD_AMMO_TICS ;
for ( i = 1 ; i < = MAX_VHUD_AMMO_TICS ; i + + )
{
sprintf ( itemName , " ammo_tic%d " , i ) ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , itemName ) ;
if ( ! item )
{
continue ;
}
if ( cg_vehicleAmmoWarningTime > cg . time
& & cg_vehicleAmmoWarning = = 0 )
{
memcpy ( calcColor , g_color_table [ ColorIndex ( COLOR_RED ) ] , sizeof ( vec4_t ) ) ;
calcColor [ 3 ] = sin ( cg . time * 0.005 ) * 0.5f + 0.5f ;
}
else
{
memcpy ( calcColor , item - > window . foreColor , sizeof ( vec4_t ) ) ;
if ( currValue < = 0 ) // don't show tic
{
break ;
}
else if ( currValue < inc ) // partial tic (alpha it out)
{
float percent = currValue / inc ;
calcColor [ 3 ] * = percent ; // Fade it out
}
}
trap_R_SetColor ( calcColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
currValue - = inc ;
}
}
void CG_DrawVehicleAmmoUpper ( const menuDef_t * menuHUD , const centity_t * veh )
{
int i ;
char itemName [ 64 ] ;
float inc , currValue , maxAmmo ;
vec4_t calcColor ;
itemDef_t * item ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , " ammoupperbackground " ) ;
if ( item )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
}
maxAmmo = veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 0 ] . ammoMax ;
currValue = cg . predictedVehicleState . ammo [ 0 ] ;
inc = ( float ) maxAmmo / MAX_VHUD_AMMO_TICS ;
for ( i = 1 ; i < MAX_VHUD_AMMO_TICS ; i + + )
{
sprintf ( itemName , " ammoupper_tic%d " , i ) ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , itemName ) ;
if ( ! item )
{
continue ;
}
if ( cg_vehicleAmmoWarningTime > cg . time
& & cg_vehicleAmmoWarning = = 0 )
{
memcpy ( calcColor , g_color_table [ ColorIndex ( COLOR_RED ) ] , sizeof ( vec4_t ) ) ;
calcColor [ 3 ] = sin ( cg . time * 0.005 ) * 0.5f + 0.5f ;
}
else
{
memcpy ( calcColor , item - > window . foreColor , sizeof ( vec4_t ) ) ;
if ( currValue < = 0 ) // don't show tic
{
break ;
}
else if ( currValue < inc ) // partial tic (alpha it out)
{
float percent = currValue / inc ;
calcColor [ 3 ] * = percent ; // Fade it out
}
}
trap_R_SetColor ( calcColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
currValue - = inc ;
}
}
void CG_DrawVehicleAmmoLower ( const menuDef_t * menuHUD , const centity_t * veh )
{
int i ;
char itemName [ 64 ] ;
float inc , currValue , maxAmmo ;
vec4_t calcColor ;
itemDef_t * item ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , " ammolowerbackground " ) ;
if ( item )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
}
maxAmmo = veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 1 ] . ammoMax ;
currValue = cg . predictedVehicleState . ammo [ 1 ] ;
inc = ( float ) maxAmmo / MAX_VHUD_AMMO_TICS ;
for ( i = 1 ; i < MAX_VHUD_AMMO_TICS ; i + + )
{
sprintf ( itemName , " ammolower_tic%d " , i ) ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , itemName ) ;
if ( ! item )
{
continue ;
}
if ( cg_vehicleAmmoWarningTime > cg . time
& & cg_vehicleAmmoWarning = = 1 )
{
memcpy ( calcColor , g_color_table [ ColorIndex ( COLOR_RED ) ] , sizeof ( vec4_t ) ) ;
calcColor [ 3 ] = sin ( cg . time * 0.005 ) * 0.5f + 0.5f ;
}
else
{
memcpy ( calcColor , item - > window . foreColor , sizeof ( vec4_t ) ) ;
if ( currValue < = 0 ) // don't show tic
{
break ;
}
else if ( currValue < inc ) // partial tic (alpha it out)
{
float percent = currValue / inc ;
calcColor [ 3 ] * = percent ; // Fade it out
}
}
trap_R_SetColor ( calcColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
currValue - = inc ;
}
}
// The HUD.menu file has the graphic print with a negative height, so it will print from the bottom up.
void CG_DrawVehicleTurboRecharge ( const menuDef_t * menuHUD , const centity_t * veh )
{
itemDef_t * item ;
int height ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , " turborecharge " ) ;
if ( item )
{
float percent = 0.0f ;
int diff = ( cg . time - veh - > m_pVehicle - > m_iTurboTime ) ;
height = item - > window . rect . h ;
if ( diff > veh - > m_pVehicle - > m_pVehicleInfo - > turboRecharge )
{
percent = 1.0f ;
trap_R_SetColor ( colorTable [ CT_GREEN ] ) ;
}
else
{
percent = ( float ) diff / veh - > m_pVehicle - > m_pVehicleInfo - > turboRecharge ;
if ( percent < 0.0f )
{
percent = 0.0f ;
}
trap_R_SetColor ( colorTable [ CT_RED ] ) ;
}
height * = percent ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
height ,
cgs . media . whiteShader ) ;
}
}
qboolean cg_drawLink = qfalse ;
void CG_DrawVehicleWeaponsLinked ( const menuDef_t * menuHUD , const centity_t * veh )
{
qboolean drawLink = qfalse ;
if ( veh - > m_pVehicle
& & veh - > m_pVehicle - > m_pVehicleInfo
& & ( veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 0 ] . linkable = = 2 | | veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 1 ] . linkable = = 2 ) )
{ //weapon is always linked
drawLink = qtrue ;
}
else
{
//MP way:
//must get sent over network
if ( cg . predictedVehicleState . vehWeaponsLinked )
{
drawLink = qtrue ;
}
//NOTE: below is SP way
/*
//just cheat it
if ( veh - > gent - > m_pVehicle - > weaponStatus [ 0 ] . linked
| | veh - > gent - > m_pVehicle - > weaponStatus [ 1 ] . linked )
{
drawLink = qtrue ;
}
*/
}
if ( cg_drawLink ! = drawLink )
{ //state changed, play sound
cg_drawLink = drawLink ;
trap_S_StartSound ( NULL , cg . predictedPlayerState . clientNum , CHAN_LOCAL , trap_S_RegisterSound ( " sound/vehicles/common/linkweaps.wav " ) ) ;
}
if ( drawLink )
{
itemDef_t * item ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , " weaponslinked " ) ;
if ( item )
{
trap_R_SetColor ( colorTable [ CT_CYAN ] ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
cgs . media . whiteShader ) ;
}
}
}
void CG_DrawVehicleSpeed ( const menuDef_t * menuHUD , const centity_t * veh )
{
int i ;
char itemName [ 64 ] ;
float inc , currValue , maxSpeed ;
vec4_t calcColor ;
itemDef_t * item ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , " speedbackground " ) ;
if ( item )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
}
maxSpeed = veh - > m_pVehicle - > m_pVehicleInfo - > speedMax ;
currValue = cg . predictedVehicleState . speed ;
// Print all the tics of the shield graphic
// Look at the amount of health left and show only as much of the graphic as there is health.
// Use alpha to fade out partial section of health
inc = ( float ) maxSpeed / MAX_VHUD_SPEED_TICS ;
for ( i = 1 ; i < = MAX_VHUD_SPEED_TICS ; i + + )
{
sprintf ( itemName , " speed_tic%d " , i ) ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , itemName ) ;
if ( ! item )
{
continue ;
}
if ( cg . time > veh - > m_pVehicle - > m_iTurboTime )
{
memcpy ( calcColor , item - > window . foreColor , sizeof ( vec4_t ) ) ;
}
else // In turbo mode
{
if ( cg . VHUDFlashTime < cg . time )
{
cg . VHUDFlashTime = cg . time + 200 ;
if ( cg . VHUDTurboFlag )
{
cg . VHUDTurboFlag = qfalse ;
}
else
{
cg . VHUDTurboFlag = qtrue ;
}
}
if ( cg . VHUDTurboFlag )
{
memcpy ( calcColor , colorTable [ CT_LTRED1 ] , sizeof ( vec4_t ) ) ;
}
else
{
memcpy ( calcColor , item - > window . foreColor , sizeof ( vec4_t ) ) ;
}
}
if ( currValue < = 0 ) // don't show tic
{
break ;
}
else if ( currValue < inc ) // partial tic (alpha it out)
{
float percent = currValue / inc ;
calcColor [ 3 ] * = percent ; // Fade it out
}
trap_R_SetColor ( calcColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
currValue - = inc ;
}
}
void CG_DrawVehicleArmor ( const menuDef_t * menuHUD , const centity_t * veh )
{
int i ;
vec4_t calcColor ;
char itemName [ 64 ] ;
float inc , currValue , maxArmor ;
itemDef_t * item ;
maxArmor = veh - > m_pVehicle - > m_pVehicleInfo - > armor ;
currValue = cg . predictedVehicleState . stats [ STAT_HEALTH ] ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , " shieldbackground " ) ;
if ( item )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
}
// Print all the tics of the shield graphic
// Look at the amount of health left and show only as much of the graphic as there is health.
// Use alpha to fade out partial section of health
inc = ( float ) maxArmor / MAX_VHUD_SHIELD_TICS ;
for ( i = 1 ; i < = MAX_VHUD_SHIELD_TICS ; i + + )
{
sprintf ( itemName , " shield_tic%d " , i ) ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , itemName ) ;
if ( ! item )
{
continue ;
}
memcpy ( calcColor , item - > window . foreColor , sizeof ( vec4_t ) ) ;
if ( currValue < = 0 ) // don't show tic
{
break ;
}
else if ( currValue < inc ) // partial tic (alpha it out)
{
float percent = currValue / inc ;
calcColor [ 3 ] * = percent ; // Fade it out
}
trap_R_SetColor ( calcColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
currValue - = inc ;
}
}
enum
{
VEH_DAMAGE_FRONT = 0 ,
VEH_DAMAGE_BACK ,
VEH_DAMAGE_LEFT ,
VEH_DAMAGE_RIGHT ,
} ;
typedef struct
{
char * itemName ;
short heavyDamage ;
short lightDamage ;
} veh_damage_t ;
veh_damage_t vehDamageData [ 4 ] =
{
" vehicle_front " , SHIPSURF_DAMAGE_FRONT_HEAVY , SHIPSURF_DAMAGE_FRONT_LIGHT ,
" vehicle_back " , SHIPSURF_DAMAGE_BACK_HEAVY , SHIPSURF_DAMAGE_BACK_LIGHT ,
" vehicle_left " , SHIPSURF_DAMAGE_LEFT_HEAVY , SHIPSURF_DAMAGE_LEFT_LIGHT ,
" vehicle_right " , SHIPSURF_DAMAGE_RIGHT_HEAVY , SHIPSURF_DAMAGE_RIGHT_LIGHT ,
} ;
// Draw health graphic for given part of vehicle
void CG_DrawVehicleDamage ( const centity_t * veh , int brokenLimbs , const menuDef_t * menuHUD , float alpha , int index )
{
itemDef_t * item ;
int colorI ;
vec4_t color ;
int graphicHandle = 0 ;
item = Menu_FindItemByName ( ( menuDef_t * ) menuHUD , vehDamageData [ index ] . itemName ) ;
if ( item )
{
if ( brokenLimbs & ( 1 < < vehDamageData [ index ] . heavyDamage ) )
{
colorI = CT_RED ;
if ( brokenLimbs & ( 1 < < vehDamageData [ index ] . lightDamage ) )
{
colorI = CT_DKGREY ;
}
}
else if ( brokenLimbs & ( 1 < < vehDamageData [ index ] . lightDamage ) )
{
colorI = CT_YELLOW ;
}
else
{
colorI = CT_GREEN ;
}
VectorCopy4 ( colorTable [ colorI ] , color ) ;
color [ 3 ] = alpha ;
trap_R_SetColor ( color ) ;
switch ( index )
{
case VEH_DAMAGE_FRONT :
graphicHandle = veh - > m_pVehicle - > m_pVehicleInfo - > iconFrontHandle ;
break ;
case VEH_DAMAGE_BACK :
graphicHandle = veh - > m_pVehicle - > m_pVehicleInfo - > iconBackHandle ;
break ;
case VEH_DAMAGE_LEFT :
graphicHandle = veh - > m_pVehicle - > m_pVehicleInfo - > iconLeftHandle ;
break ;
case VEH_DAMAGE_RIGHT :
graphicHandle = veh - > m_pVehicle - > m_pVehicleInfo - > iconRightHandle ;
break ;
}
if ( graphicHandle )
{
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
graphicHandle ) ;
}
}
}
// Used on both damage indicators : player vehicle and the vehicle the player is locked on
void CG_DrawVehicleDamageHUD ( const centity_t * veh , int brokenLimbs , float percShields , char * menuName , float alpha )
{
menuDef_t * menuHUD ;
itemDef_t * item ;
vec4_t color ;
menuHUD = Menus_FindByName ( menuName ) ;
if ( ! menuHUD )
{
return ;
}
item = Menu_FindItemByName ( menuHUD , " background " ) ;
if ( item )
{
if ( veh - > m_pVehicle - > m_pVehicleInfo - > dmgIndicBackgroundHandle )
{
if ( veh - > damageTime > cg . time )
{ //ship shields currently taking damage
//NOTE: cent->damageAngle can be accessed to get the direction from the ship origin to the impact point (in 3-D space)
float perc = 1.0f - ( ( veh - > damageTime - cg . time ) / 2000.0f /*MIN_SHIELD_TIME*/ ) ;
if ( perc < 0.0f )
{
perc = 0.0f ;
}
else if ( perc > 1.0f )
{
perc = 1.0f ;
}
color [ 0 ] = item - > window . foreColor [ 0 ] ; //flash red
color [ 1 ] = item - > window . foreColor [ 1 ] * perc ; //fade other colors back in over time
color [ 2 ] = item - > window . foreColor [ 2 ] * perc ; //fade other colors back in over time
color [ 3 ] = item - > window . foreColor [ 3 ] ; //always normal alpha
trap_R_SetColor ( color ) ;
}
else
{
trap_R_SetColor ( item - > window . foreColor ) ;
}
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
veh - > m_pVehicle - > m_pVehicleInfo - > dmgIndicBackgroundHandle ) ;
}
}
item = Menu_FindItemByName ( menuHUD , " outer_frame " ) ;
if ( item )
{
if ( veh - > m_pVehicle - > m_pVehicleInfo - > dmgIndicFrameHandle )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
veh - > m_pVehicle - > m_pVehicleInfo - > dmgIndicFrameHandle ) ;
}
}
item = Menu_FindItemByName ( menuHUD , " shields " ) ;
if ( item )
{
if ( veh - > m_pVehicle - > m_pVehicleInfo - > dmgIndicShieldHandle )
{
VectorCopy4 ( colorTable [ CT_HUD_GREEN ] , color ) ;
color [ 3 ] = percShields ;
trap_R_SetColor ( color ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
veh - > m_pVehicle - > m_pVehicleInfo - > dmgIndicShieldHandle ) ;
}
}
//TODO: if we check nextState.brokenLimbs & prevState.brokenLimbs, we can tell when a damage flag has been added and flash that part of the ship
//FIXME: when ship explodes, either stop drawing ship or draw all parts black
CG_DrawVehicleDamage ( veh , brokenLimbs , menuHUD , alpha , VEH_DAMAGE_FRONT ) ;
CG_DrawVehicleDamage ( veh , brokenLimbs , menuHUD , alpha , VEH_DAMAGE_BACK ) ;
CG_DrawVehicleDamage ( veh , brokenLimbs , menuHUD , alpha , VEH_DAMAGE_LEFT ) ;
CG_DrawVehicleDamage ( veh , brokenLimbs , menuHUD , alpha , VEH_DAMAGE_RIGHT ) ;
}
qboolean CG_DrawVehicleHud ( const centity_t * cent )
{
itemDef_t * item ;
menuDef_t * menuHUD ;
playerState_t * ps ;
centity_t * veh ;
float shieldPerc , alpha ;
menuHUD = Menus_FindByName ( " swoopvehiclehud " ) ;
if ( ! menuHUD )
{
return qtrue ; // Draw player HUD
}
ps = & cg . predictedPlayerState ;
if ( ! ps | | ! ( ps - > m_iVehicleNum ) )
{
return qtrue ; // Draw player HUD
}
veh = & cg_entities [ ps - > m_iVehicleNum ] ;
if ( ! veh )
{
return qtrue ; // Draw player HUD
}
CG_DrawVehicleTurboRecharge ( menuHUD , veh ) ;
CG_DrawVehicleWeaponsLinked ( menuHUD , veh ) ;
item = Menu_FindItemByName ( menuHUD , " leftframe " ) ;
// Draw frame
if ( item )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
}
item = Menu_FindItemByName ( menuHUD , " rightframe " ) ;
if ( item )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
}
CG_DrawVehicleArmor ( menuHUD , veh ) ;
// Get animal hud for speed
// if (veh->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
// {
// menuHUD = Menus_FindByName("tauntaunhud");
// }
CG_DrawVehicleSpeed ( menuHUD , veh ) ;
// Revert to swoophud
// if (veh->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
// {
// menuHUD = Menus_FindByName("swoopvehiclehud");
// }
// if (veh->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
// {
shieldPerc = CG_DrawVehicleShields ( menuHUD , veh ) ;
// }
if ( veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 0 ] . ID & & ! veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 1 ] . ID )
{
CG_DrawVehicleAmmo ( menuHUD , veh ) ;
}
else if ( veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 0 ] . ID & & veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 1 ] . ID )
{
CG_DrawVehicleAmmoUpper ( menuHUD , veh ) ;
CG_DrawVehicleAmmoLower ( menuHUD , veh ) ;
}
// If he's hidden, he must be in a vehicle
if ( veh - > m_pVehicle - > m_pVehicleInfo - > hideRider )
{
CG_DrawVehicleDamageHUD ( veh , cg . predictedVehicleState . brokenLimbs , shieldPerc , " vehicledamagehud " , 1.0f ) ;
// Has he targeted an enemy?
if ( CG_CheckTargetVehicle ( & veh , & alpha ) )
{
CG_DrawVehicleDamageHUD ( veh , veh - > currentState . brokenLimbs , ( ( float ) veh - > currentState . activeForcePass / 10.0f ) , " enemyvehicledamagehud " , alpha ) ;
}
return qfalse ; // Don't draw player HUD
}
return qtrue ; // Draw player HUD
}
/*
= = = = = = = = = = = = = = = =
CG_DrawStats
= = = = = = = = = = = = = = = =
*/
static void CG_DrawStats ( void )
{
centity_t * cent ;
playerState_t * ps ;
qboolean drawHUD = qtrue ;
/* playerState_t *ps;
vec3_t angles ;
// vec3_t origin;
if ( cg_drawStatus . integer = = 0 ) {
return ;
}
*/
cent = & cg_entities [ cg . snap - > ps . clientNum ] ;
/* ps = &cg.snap->ps;
VectorClear ( angles ) ;
// Do start
if ( ! cg . interfaceStartupDone )
{
CG_InterfaceStartup ( ) ;
}
cgi_UI_MenuPaintAll ( ) ; */
if ( cent )
{
ps = & cg . predictedPlayerState ;
if ( ( ps - > m_iVehicleNum ) ) // In a vehicle???
{
drawHUD = CG_DrawVehicleHud ( cent ) ;
}
}
if ( drawHUD )
{
CG_DrawHUD ( cent ) ;
}
/*CG_DrawArmor(cent);
CG_DrawHealth ( cent ) ;
CG_DrawAmmo ( cent ) ;
CG_DrawTalk ( cent ) ; */
}
/*
= = = = = = = = = = = = = = = = = = =
CG_DrawPickupItem
= = = = = = = = = = = = = = = = = = =
*/
static void CG_DrawPickupItem ( void ) {
int value ;
float * fadeColor ;
value = cg . itemPickup ;
if ( value & & cg_items [ value ] . icon ! = - 1 )
{
fadeColor = CG_FadeColor ( cg . itemPickupTime , 3000 ) ;
if ( fadeColor )
{
CG_RegisterItemVisuals ( value ) ;
trap_R_SetColor ( fadeColor ) ;
CG_DrawPic ( 573 , 320 , ICON_SIZE , ICON_SIZE , cg_items [ value ] . icon ) ;
trap_R_SetColor ( NULL ) ;
}
}
}
/*
= = = = = = = = = = = = = = = =
CG_DrawTeamBackground
= = = = = = = = = = = = = = = =
*/
void CG_DrawTeamBackground ( int x , int y , int w , int h , float alpha , int team )
{
vec4_t hcolor ;
hcolor [ 3 ] = alpha ;
if ( team = = TEAM_RED ) {
hcolor [ 0 ] = 1 ;
hcolor [ 1 ] = .2f ;
hcolor [ 2 ] = .2f ;
} else if ( team = = TEAM_BLUE ) {
hcolor [ 0 ] = .2f ;
hcolor [ 1 ] = .2f ;
hcolor [ 2 ] = 1 ;
} else {
return ;
}
// trap_R_SetColor( hcolor );
CG_FillRect ( x , y , w , h , hcolor ) ;
// CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
trap_R_SetColor ( NULL ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
UPPER RIGHT CORNER
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
CG_DrawMiniScoreboard
= = = = = = = = = = = = = = = =
*/
static float CG_DrawMiniScoreboard ( float y )
{
char temp [ MAX_QPATH ] ;
int xOffset = 0 ;
# ifdef _XBOX
xOffset = - 40 ;
# endif
if ( ! cg_drawScores . integer )
{
return y ;
}
if ( cgs . gametype = = GT_SIEGE )
{ //don't bother with this in siege
return y ;
}
if ( cgs . gametype > = GT_TEAM )
{
strcpy ( temp , va ( " %s: " , CG_GetStringEdString ( " MP_INGAME " , " RED " ) ) ) ;
Q_strcat ( temp , MAX_QPATH , cgs . scores1 = = SCORE_NOT_PRESENT ? " - " : ( va ( " %i " , cgs . scores1 ) ) ) ;
Q_strcat ( temp , MAX_QPATH , va ( " %s: " , CG_GetStringEdString ( " MP_INGAME " , " BLUE " ) ) ) ;
Q_strcat ( temp , MAX_QPATH , cgs . scores2 = = SCORE_NOT_PRESENT ? " - " : ( va ( " %i " , cgs . scores2 ) ) ) ;
CG_Text_Paint ( 630 - CG_Text_Width ( temp , 0.7f , FONT_MEDIUM ) + xOffset , y , 0.7f , colorWhite , temp , 0 , 0 , ITEM_TEXTSTYLE_SHADOWEDMORE , FONT_MEDIUM ) ;
y + = 15 ;
}
else
{
/*
strcpy ( temp , " 1st: " ) ;
Q_strcat ( temp , MAX_QPATH , cgs . scores1 = = SCORE_NOT_PRESENT ? " - " : ( va ( " %i " , cgs . scores1 ) ) ) ;
Q_strcat ( temp , MAX_QPATH , " 2nd: " ) ;
Q_strcat ( temp , MAX_QPATH , cgs . scores2 = = SCORE_NOT_PRESENT ? " - " : ( va ( " %i " , cgs . scores2 ) ) ) ;
CG_Text_Paint ( 630 - CG_Text_Width ( temp , 0.7f , FONT_SMALL ) , y , 0.7f , colorWhite , temp , 0 , 0 , ITEM_TEXTSTYLE_SHADOWEDMORE , FONT_MEDIUM ) ;
y + = 15 ;
*/
//rww - no longer doing this. Since the attacker now shows who is first, we print the score there.
}
return y ;
}
/*
= = = = = = = = = = = = = = = =
CG_DrawEnemyInfo
= = = = = = = = = = = = = = = =
*/
static float CG_DrawEnemyInfo ( float y )
{
float size ;
int clientNum ;
const char * title ;
clientInfo_t * ci ;
int xOffset = 0 ;
if ( ! cg . snap )
{
return y ;
}
# ifdef _XBOX
xOffset = - 40 ;
# endif
if ( ! cg_drawEnemyInfo . integer )
{
return y ;
}
if ( cg . predictedPlayerState . stats [ STAT_HEALTH ] < = 0 )
{
return y ;
}
if ( cgs . gametype = = GT_POWERDUEL )
{ //just get out of here then
return y ;
}
if ( cgs . gametype = = GT_JEDIMASTER )
{
//title = "Jedi Master";
title = CG_GetStringEdString ( " MP_INGAME " , " MASTERY7 " ) ;
clientNum = cgs . jediMaster ;
if ( clientNum < 0 )
{
//return y;
// title = "Get Saber!";
title = CG_GetStringEdString ( " MP_INGAME " , " GET_SABER " ) ;
size = ICON_SIZE * 1.25 ;
y + = 5 ;
CG_DrawPic ( 640 - size - 12 + xOffset , y , size , size , cgs . media . weaponIcons [ WP_SABER ] ) ;
y + = size ;
/*
CG_Text_Paint ( 630 - CG_Text_Width ( ci - > name , 0.7f , FONT_MEDIUM ) , y , 0.7f , colorWhite , ci - > name , 0 , 0 , 0 , FONT_MEDIUM ) ;
y + = 15 ;
*/
CG_Text_Paint ( 630 - CG_Text_Width ( title , 0.7f , FONT_MEDIUM ) + xOffset , y , 0.7f , colorWhite , title , 0 , 0 , 0 , FONT_MEDIUM ) ;
return y + BIGCHAR_HEIGHT + 2 ;
}
}
else if ( cg . snap - > ps . duelInProgress )
{
// title = "Dueling";
title = CG_GetStringEdString ( " MP_INGAME " , " DUELING " ) ;
clientNum = cg . snap - > ps . duelIndex ;
}
else if ( cgs . gametype = = GT_DUEL & & cgs . clientinfo [ cg . snap - > ps . clientNum ] . team ! = TEAM_SPECTATOR )
{
title = CG_GetStringEdString ( " MP_INGAME " , " DUELING " ) ;
if ( cg . snap - > ps . clientNum = = cgs . duelist1 )
{
clientNum = cgs . duelist2 ; //if power duel, should actually draw both duelists 2 and 3 I guess
}
else if ( cg . snap - > ps . clientNum = = cgs . duelist2 )
{
clientNum = cgs . duelist1 ;
}
else if ( cg . snap - > ps . clientNum = = cgs . duelist3 )
{
clientNum = cgs . duelist1 ;
}
else
{
return y ;
}
}
else
{
/*
title = " Attacker " ;
clientNum = cg . predictedPlayerState . persistant [ PERS_ATTACKER ] ;
if ( clientNum < 0 | | clientNum > = MAX_CLIENTS | | clientNum = = cg . snap - > ps . clientNum )
{
return y ;
}
if ( cg . time - cg . attackerTime > ATTACKER_HEAD_TIME )
{
cg . attackerTime = 0 ;
return y ;
}
*/
//As of current, we don't want to draw the attacker. Instead, draw whoever is in first place.
if ( cgs . duelWinner < 0 | | cgs . duelWinner > = MAX_CLIENTS )
{
return y ;
}
title = va ( " %s: %i " , CG_GetStringEdString ( " MP_INGAME " , " LEADER " ) , cgs . scores1 ) ;
/*
if ( cgs . scores1 = = 1 )
{
title = va ( " %i kill " , cgs . scores1 ) ;
}
else
{
title = va ( " %i kills " , cgs . scores1 ) ;
}
*/
clientNum = cgs . duelWinner ;
}
if ( clientNum > = MAX_CLIENTS | | ! ( & cgs . clientinfo [ clientNum ] ) )
{
return y ;
}
ci = & cgs . clientinfo [ clientNum ] ;
size = ICON_SIZE * 1.25 ;
y + = 5 ;
if ( ci - > modelIcon )
{
CG_DrawPic ( 640 - size - 5 + xOffset , y , size , size , ci - > modelIcon ) ;
}
y + = size ;
// CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.7f, FONT_MEDIUM ) + xOffset, y, 0.7f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM );
CG_Text_Paint ( 630 - CG_Text_Width ( ci - > name , 1.0f , FONT_SMALL2 ) + xOffset , y , 1.0f , colorWhite , ci - > name , 0 , 0 , 0 , FONT_SMALL2 ) ;
y + = 15 ;
// CG_Text_Paint( 630 - CG_Text_Width ( title, 0.7f, FONT_MEDIUM ) + xOffset, y, 0.7f, colorWhite, title, 0, 0, 0, FONT_MEDIUM );
CG_Text_Paint ( 630 - CG_Text_Width ( title , 1.0f , FONT_SMALL2 ) + xOffset , y , 1.0f , colorWhite , title , 0 , 0 , 0 , FONT_SMALL2 ) ;
if ( ( cgs . gametype = = GT_DUEL | | cgs . gametype = = GT_POWERDUEL ) & & cgs . clientinfo [ cg . snap - > ps . clientNum ] . team ! = TEAM_SPECTATOR )
{ //also print their score
char text [ 1024 ] ;
y + = 15 ;
Com_sprintf ( text , sizeof ( text ) , " %i/%i " , cgs . clientinfo [ clientNum ] . score , cgs . fraglimit ) ;
CG_Text_Paint ( 630 - CG_Text_Width ( text , 0.7f , FONT_MEDIUM ) + xOffset , y , 0.7f , colorWhite , text , 0 , 0 , 0 , FONT_MEDIUM ) ;
}
// nmckenzie: DUEL_HEALTH - fixme - need checks and such here. And this is coded to duelist 1 right now, which is wrongly.
if ( cgs . showDuelHealths > = 2 )
{
y + = 15 ;
if ( cgs . duelist1 = = clientNum )
{
CG_DrawDuelistHealth ( 640 - size - 5 + xOffset , y , 64 , 8 , 1 ) ;
}
else if ( cgs . duelist2 = = clientNum )
{
CG_DrawDuelistHealth ( 640 - size - 5 + xOffset , y , 64 , 8 , 2 ) ;
}
}
return y + BIGCHAR_HEIGHT + 2 ;
}
/*
= = = = = = = = = = = = = = = = = =
CG_DrawSnapshot
= = = = = = = = = = = = = = = = = =
*/
static float CG_DrawSnapshot ( float y ) {
char * s ;
int w ;
int xOffset = 0 ;
# ifdef _XBOX
xOffset = - 40 ;
# endif
s = va ( " time:%i snap:%i cmd:%i " , cg . snap - > serverTime ,
cg . latestSnapshotNum , cgs . serverCommandSequence ) ;
w = CG_DrawStrlen ( s ) * BIGCHAR_WIDTH ;
CG_DrawBigString ( 635 - w + xOffset , y + 2 , s , 1.0F ) ;
return y + BIGCHAR_HEIGHT + 4 ;
}
/*
= = = = = = = = = = = = = = = = = =
CG_DrawFPS
= = = = = = = = = = = = = = = = = =
*/
# define FPS_FRAMES 16
static float CG_DrawFPS ( float y ) {
char * s ;
int w ;
static unsigned short previousTimes [ FPS_FRAMES ] ;
static unsigned short index ;
static int previous , lastupdate ;
int t , i , fps , total ;
unsigned short frameTime ;
# ifdef _XBOX
const int xOffset = - 40 ;
# else
const int xOffset = 0 ;
# endif
// don't use serverTime, because that will be drifting to
// correct for internet lag changes, timescales, timedemos, etc
t = trap_Milliseconds ( ) ;
frameTime = t - previous ;
previous = t ;
if ( t - lastupdate > 50 ) //don't sample faster than this
{
lastupdate = t ;
previousTimes [ index % FPS_FRAMES ] = frameTime ;
index + + ;
}
// average multiple frames together to smooth changes out a bit
total = 0 ;
for ( i = 0 ; i < FPS_FRAMES ; i + + ) {
total + = previousTimes [ i ] ;
}
if ( ! total ) {
total = 1 ;
}
fps = 1000 * FPS_FRAMES / total ;
s = va ( " %ifps " , fps ) ;
w = CG_DrawStrlen ( s ) * BIGCHAR_WIDTH ;
CG_DrawBigString ( 635 - w + xOffset , y + 2 , s , 1.0F ) ;
return y + BIGCHAR_HEIGHT + 4 ;
}
// nmckenzie: DUEL_HEALTH
# define MAX_HEALTH_FOR_IFACE 100
void CG_DrawHealthBarRough ( float x , float y , int width , int height , float ratio , const float * color1 , const float * color2 )
{
float midpoint , remainder ;
float color3 [ 4 ] = { 1 , 0 , 0 , .7f } ;
midpoint = width * ratio - 1 ;
remainder = width - midpoint ;
color3 [ 0 ] = color1 [ 0 ] * 0.5f ;
assert ( ! ( height % 4 ) ) ; //this won't line up otherwise.
CG_DrawRect ( x + 1 , y + height / 2 - 1 , midpoint , 1 , height / 4 + 1 , color1 ) ; // creme-y filling.
CG_DrawRect ( x + midpoint , y + height / 2 - 1 , remainder , 1 , height / 4 + 1 , color3 ) ; // used-up-ness.
CG_DrawRect ( x , y , width , height , 1 , color2 ) ; // hard crispy shell
}
void CG_DrawDuelistHealth ( float x , float y , float w , float h , int duelist )
{
float duelHealthColor [ 4 ] = { 1 , 0 , 0 , 0.7f } ;
float healthSrc = 0.0f ;
float ratio ;
if ( duelist = = 1 )
{
healthSrc = cgs . duelist1health ;
}
else if ( duelist = = 2 )
{
healthSrc = cgs . duelist2health ;
}
ratio = healthSrc / MAX_HEALTH_FOR_IFACE ;
if ( ratio > 1.0f )
{
ratio = 1.0f ;
}
if ( ratio < 0.0f )
{
ratio = 0.0f ;
}
duelHealthColor [ 0 ] = ( ratio * 0.2f ) + 0.5f ;
CG_DrawHealthBarRough ( x , y , w , h , ratio , duelHealthColor , colorTable [ CT_WHITE ] ) ; // new art for this? I'm not crazy about how this looks.
}
/*
= = = = = = = = = = = = = = = = = = = = =
CG_DrawRadar
= = = = = = = = = = = = = = = = = = = = =
*/
//#define RADAR_RANGE 2500
float cg_radarRange = 2500.0f ;
# define RADAR_RADIUS 60
# define RADAR_X (580 - RADAR_RADIUS)
//#define RADAR_Y 10 //dynamic based on passed Y val
# define RADAR_CHAT_DURATION 6000
static int radarLockSoundDebounceTime = 0 ;
static int impactSoundDebounceTime = 0 ;
# define RADAR_MISSILE_RANGE 3000.0f
# define RADAR_ASTEROID_RANGE 10000.0f
# define RADAR_MIN_ASTEROID_SURF_WARN_DIST 1200.0f
float CG_DrawRadar ( float y )
{
vec4_t color ;
vec4_t teamColor ;
float arrow_w ;
float arrow_h ;
clientInfo_t * cl ;
clientInfo_t * local ;
int i ;
float arrowBaseScale ;
float zScale ;
int xOffset = 0 ;
if ( ! cg . snap )
{
return y ;
}
# ifdef _XBOX
xOffset = - 40 ;
# endif
// Make sure the radar should be showing
if ( cg . snap - > ps . stats [ STAT_HEALTH ] < = 0 )
{
return y ;
}
if ( ( cg . predictedPlayerState . pm_flags & PMF_FOLLOW ) | | cg . predictedPlayerState . persistant [ PERS_TEAM ] = = TEAM_SPECTATOR )
{
return y ;
}
local = & cgs . clientinfo [ cg . snap - > ps . clientNum ] ;
if ( ! local - > infoValid )
{
return y ;
}
// Draw the radar background image
color [ 0 ] = color [ 1 ] = color [ 2 ] = 1.0f ;
color [ 3 ] = 0.6f ;
trap_R_SetColor ( color ) ;
CG_DrawPic ( RADAR_X + xOffset , y , RADAR_RADIUS * 2 , RADAR_RADIUS * 2 , cgs . media . radarShader ) ;
//Always green for your own team.
VectorCopy ( g_color_table [ ColorIndex ( COLOR_GREEN ) ] , teamColor ) ;
teamColor [ 3 ] = 1.0f ;
// Draw all of the radar entities. Draw them backwards so players are drawn last
for ( i = cg . radarEntityCount - 1 ; i > = 0 ; i - - )
{
vec3_t dirLook ;
vec3_t dirPlayer ;
float angleLook ;
float anglePlayer ;
float angle ;
float distance , actualDist ;
centity_t * cent ;
cent = & cg_entities [ cg . radarEntities [ i ] ] ;
// Get the distances first
VectorSubtract ( cg . predictedPlayerState . origin , cent - > lerpOrigin , dirPlayer ) ;
dirPlayer [ 2 ] = 0 ;
actualDist = distance = VectorNormalize ( dirPlayer ) ;
if ( distance > cg_radarRange * 0.8f )
{
if ( ( cent - > currentState . eFlags & EF_RADAROBJECT ) //still want to draw the direction
| | ( cent - > currentState . eType = = ET_NPC //FIXME: draw last, with players...
& & cent - > currentState . NPC_class = = CLASS_VEHICLE
& & cent - > currentState . speed > 0 ) ) //always draw vehicles
{
distance = cg_radarRange * 0.8f ;
}
else
{
continue ;
}
}
distance = distance / cg_radarRange ;
distance * = RADAR_RADIUS ;
AngleVectors ( cg . predictedPlayerState . viewangles , dirLook , NULL , NULL ) ;
dirLook [ 2 ] = 0 ;
anglePlayer = atan2 ( dirPlayer [ 0 ] , dirPlayer [ 1 ] ) ;
VectorNormalize ( dirLook ) ;
angleLook = atan2 ( dirLook [ 0 ] , dirLook [ 1 ] ) ;
angle = angleLook - anglePlayer ;
switch ( cent - > currentState . eType )
{
default :
{
float x ;
float ly ;
qhandle_t shader ;
vec4_t color ;
x = ( float ) RADAR_X + ( float ) RADAR_RADIUS + ( float ) sin ( angle ) * distance ;
ly = y + ( float ) RADAR_RADIUS + ( float ) cos ( angle ) * distance ;
arrowBaseScale = 9.0f ;
shader = 0 ;
zScale = 1.0f ;
//we want to scale the thing up/down based on the relative Z (up/down) positioning
if ( cent - > lerpOrigin [ 2 ] > cg . predictedPlayerState . origin [ 2 ] )
{ //higher, scale up (between 16 and 24)
float dif = ( cent - > lerpOrigin [ 2 ] - cg . predictedPlayerState . origin [ 2 ] ) ;
//max out to 1.5x scale at 512 units above local player's height
dif / = 1024.0f ;
if ( dif > 0.5f )
{
dif = 0.5f ;
}
zScale + = dif ;
}
else if ( cent - > lerpOrigin [ 2 ] < cg . predictedPlayerState . origin [ 2 ] )
{ //lower, scale down (between 16 and 8)
float dif = ( cg . predictedPlayerState . origin [ 2 ] - cent - > lerpOrigin [ 2 ] ) ;
//half scale at 512 units below local player's height
dif / = 1024.0f ;
if ( dif > 0.5f )
{
dif = 0.5f ;
}
zScale - = dif ;
}
arrowBaseScale * = zScale ;
if ( cent - > currentState . brokenLimbs )
{ //slightly misleading to use this value, but don't want to add more to entstate.
//any ent with brokenLimbs non-0 and on radar is an objective ent.
//brokenLimbs is literal team value.
char objState [ 1024 ] ;
int complete ;
//we only want to draw it if the objective for it is not complete.
//frame represents objective num.
trap_Cvar_VariableStringBuffer ( va ( " team%i_objective%i " , cent - > currentState . brokenLimbs , cent - > currentState . frame ) , objState , 1024 ) ;
complete = atoi ( objState ) ;
if ( ! complete )
{
// generic enemy index specifies a shader to use for the radar entity.
if ( cent - > currentState . genericenemyindex )
{
color [ 0 ] = color [ 1 ] = color [ 2 ] = color [ 3 ] = 1.0f ;
shader = cgs . gameIcons [ cent - > currentState . genericenemyindex ] ;
}
else
{
if ( cg . snap & &
cent - > currentState . brokenLimbs = = cg . snap - > ps . persistant [ PERS_TEAM ] )
{
VectorCopy ( g_color_table [ ColorIndex ( COLOR_RED ) ] , color ) ;
}
else
{
VectorCopy ( g_color_table [ ColorIndex ( COLOR_GREEN ) ] , color ) ;
}
shader = cgs . media . siegeItemShader ;
}
}
}
else
{
color [ 0 ] = color [ 1 ] = color [ 2 ] = color [ 3 ] = 1.0f ;
// generic enemy index specifies a shader to use for the radar entity.
if ( cent - > currentState . genericenemyindex )
{
shader = cgs . gameIcons [ cent - > currentState . genericenemyindex ] ;
}
else
{
shader = cgs . media . siegeItemShader ;
}
}
if ( shader )
{
// Pulse the alpha if time2 is set. time2 gets set when the entity takes pain
if ( ( cent - > currentState . time2 & & cg . time - cent - > currentState . time2 < 5000 ) | |
( cent - > currentState . time2 = = 0xFFFFFFFF ) )
{
if ( ( cg . time / 200 ) & 1 )
{
color [ 3 ] = 0.1f + 0.9f * ( float ) ( cg . time % 200 ) / 200.0f ;
}
else
{
color [ 3 ] = 1.0f - 0.9f * ( float ) ( cg . time % 200 ) / 200.0f ;
}
}
trap_R_SetColor ( color ) ;
CG_DrawPic ( x - 4 + xOffset , ly - 4 , arrowBaseScale , arrowBaseScale , shader ) ;
}
}
break ;
case ET_NPC : //FIXME: draw last, with players...
if ( cent - > currentState . NPC_class = = CLASS_VEHICLE
& & cent - > currentState . speed > 0 )
{
if ( cent - > m_pVehicle & & cent - > m_pVehicle - > m_pVehicleInfo - > radarIconHandle )
{
float x ;
float ly ;
x = ( float ) RADAR_X + ( float ) RADAR_RADIUS + ( float ) sin ( angle ) * distance ;
ly = y + ( float ) RADAR_RADIUS + ( float ) cos ( angle ) * distance ;
arrowBaseScale = 9.0f ;
zScale = 1.0f ;
//we want to scale the thing up/down based on the relative Z (up/down) positioning
if ( cent - > lerpOrigin [ 2 ] > cg . predictedPlayerState . origin [ 2 ] )
{ //higher, scale up (between 16 and 24)
float dif = ( cent - > lerpOrigin [ 2 ] - cg . predictedPlayerState . origin [ 2 ] ) ;
//max out to 1.5x scale at 512 units above local player's height
dif / = 4096.0f ;
if ( dif > 0.5f )
{
dif = 0.5f ;
}
zScale + = dif ;
}
else if ( cent - > lerpOrigin [ 2 ] < cg . predictedPlayerState . origin [ 2 ] )
{ //lower, scale down (between 16 and 8)
float dif = ( cg . predictedPlayerState . origin [ 2 ] - cent - > lerpOrigin [ 2 ] ) ;
//half scale at 512 units below local player's height
dif / = 4096.0f ;
if ( dif > 0.5f )
{
dif = 0.5f ;
}
zScale - = dif ;
}
arrowBaseScale * = zScale ;
if ( cent - > currentState . m_iVehicleNum //vehicle has a driver
& & cgs . clientinfo [ cent - > currentState . m_iVehicleNum - 1 ] . infoValid )
{
if ( cgs . clientinfo [ cent - > currentState . m_iVehicleNum - 1 ] . team = = local - > team )
{
trap_R_SetColor ( teamColor ) ;
}
else
{
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_RED ) ] ) ;
}
}
else
{
trap_R_SetColor ( NULL ) ;
}
CG_DrawPic ( x - 4 + xOffset , ly - 4 , arrowBaseScale , arrowBaseScale , cent - > m_pVehicle - > m_pVehicleInfo - > radarIconHandle ) ;
}
}
break ; //maybe do something?
case ET_MOVER :
if ( cent - > currentState . speed //the mover's size, actually
& & actualDist < ( cent - > currentState . speed + RADAR_ASTEROID_RANGE )
& & cg . predictedPlayerState . m_iVehicleNum )
{ //a mover that's close to me and I'm in a vehicle
qboolean mayImpact = qfalse ;
float surfaceDist = ( actualDist - cent - > currentState . speed ) ;
if ( surfaceDist < 0.0f )
{
surfaceDist = 0.0f ;
}
if ( surfaceDist < RADAR_MIN_ASTEROID_SURF_WARN_DIST )
{ //always warn!
mayImpact = qtrue ;
}
else
{ //not close enough to always warn, yet, so check its direction
vec3_t asteroidPos , myPos , moveDir ;
int predictTime , timeStep = 500 ;
float newDist ;
for ( predictTime = timeStep ; predictTime < 5000 ; predictTime + = timeStep )
{
//asteroid dir, speed, size, + my dir & speed...
BG_EvaluateTrajectory ( & cent - > currentState . pos , cg . time + predictTime , asteroidPos ) ;
//FIXME: I don't think it's calcing "myPos" correctly
AngleVectors ( cg . predictedVehicleState . viewangles , moveDir , NULL , NULL ) ;
VectorMA ( cg . predictedVehicleState . origin , cg . predictedVehicleState . speed * predictTime / 1000.0f , moveDir , myPos ) ;
newDist = Distance ( myPos , asteroidPos ) ;
if ( ( newDist - cent - > currentState . speed ) < = RADAR_MIN_ASTEROID_SURF_WARN_DIST ) //200.0f )
{ //heading for an impact within the next 5 seconds
mayImpact = qtrue ;
break ;
}
}
}
if ( mayImpact )
{ //possible collision
vec4_t asteroidColor = { 0.5f , 0.5f , 0.5f , 1.0f } ;
float x ;
float ly ;
float asteroidScale = ( cent - > currentState . speed / 2000.0f ) ; //average asteroid radius?
if ( actualDist > RADAR_ASTEROID_RANGE )
{
actualDist = RADAR_ASTEROID_RANGE ;
}
distance = ( actualDist / RADAR_ASTEROID_RANGE ) * RADAR_RADIUS ;
x = ( float ) RADAR_X + ( float ) RADAR_RADIUS + ( float ) sin ( angle ) * distance ;
ly = y + ( float ) RADAR_RADIUS + ( float ) cos ( angle ) * distance ;
if ( asteroidScale > 3.0f )
{
asteroidScale = 3.0f ;
}
else if ( asteroidScale < 0.2f )
{
asteroidScale = 0.2f ;
}
arrowBaseScale = ( 9.0f * asteroidScale ) ;
if ( impactSoundDebounceTime < cg . time )
{
vec3_t soundOrg ;
if ( surfaceDist > RADAR_ASTEROID_RANGE * 0.66f )
{
impactSoundDebounceTime = cg . time + 1000 ;
}
else if ( surfaceDist > RADAR_ASTEROID_RANGE / 3.0f )
{
impactSoundDebounceTime = cg . time + 400 ;
}
else
{
impactSoundDebounceTime = cg . time + 100 ;
}
VectorMA ( cg . refdef . vieworg , - 500.0f * ( surfaceDist / RADAR_ASTEROID_RANGE ) , dirPlayer , soundOrg ) ;
trap_S_StartSound ( soundOrg , ENTITYNUM_WORLD , CHAN_AUTO , trap_S_RegisterSound ( " sound/vehicles/common/impactalarm.wav " ) ) ;
}
//brighten it the closer it is
if ( surfaceDist > RADAR_ASTEROID_RANGE * 0.66f )
{
asteroidColor [ 0 ] = asteroidColor [ 1 ] = asteroidColor [ 2 ] = 0.7f ;
}
else if ( surfaceDist > RADAR_ASTEROID_RANGE / 3.0f )
{
asteroidColor [ 0 ] = asteroidColor [ 1 ] = asteroidColor [ 2 ] = 0.85f ;
}
else
{
asteroidColor [ 0 ] = asteroidColor [ 1 ] = asteroidColor [ 2 ] = 1.0f ;
}
//alpha out the longer it's been since it was considered dangerous
if ( ( cg . time - impactSoundDebounceTime ) > 100 )
{
asteroidColor [ 3 ] = ( float ) ( ( cg . time - impactSoundDebounceTime ) - 100 ) / 900.0f ;
}
trap_R_SetColor ( asteroidColor ) ;
CG_DrawPic ( x - 4 + xOffset , ly - 4 , arrowBaseScale , arrowBaseScale , trap_R_RegisterShaderNoMip ( " gfx/menus/radar/asteroid " ) ) ;
}
}
break ;
case ET_MISSILE :
if ( //cent->currentState.weapon == WP_ROCKET_LAUNCHER &&//a rocket
cent - > currentState . owner > MAX_CLIENTS //belongs to an NPC
& & cg_entities [ cent - > currentState . owner ] . currentState . NPC_class = = CLASS_VEHICLE )
{ //a rocket belonging to an NPC, FIXME: only tracking rockets!
float x ;
float ly ;
x = ( float ) RADAR_X + ( float ) RADAR_RADIUS + ( float ) sin ( angle ) * distance ;
ly = y + ( float ) RADAR_RADIUS + ( float ) cos ( angle ) * distance ;
arrowBaseScale = 3.0f ;
if ( cg . predictedPlayerState . m_iVehicleNum )
{ //I'm in a vehicle
//if it's targetting me, then play an alarm sound if I'm in a vehicle
if ( cent - > currentState . otherEntityNum = = cg . predictedPlayerState . clientNum | | cent - > currentState . otherEntityNum = = cg . predictedPlayerState . m_iVehicleNum )
{
if ( radarLockSoundDebounceTime < cg . time )
{
vec3_t soundOrg ;
int alarmSound ;
if ( actualDist > RADAR_MISSILE_RANGE * 0.66f )
{
radarLockSoundDebounceTime = cg . time + 1000 ;
arrowBaseScale = 3.0f ;
alarmSound = trap_S_RegisterSound ( " sound/vehicles/common/lockalarm1.wav " ) ;
}
else if ( actualDist > RADAR_MISSILE_RANGE / 3.0f )
{
radarLockSoundDebounceTime = cg . time + 500 ;
arrowBaseScale = 6.0f ;
alarmSound = trap_S_RegisterSound ( " sound/vehicles/common/lockalarm2.wav " ) ;
}
else
{
radarLockSoundDebounceTime = cg . time + 250 ;
arrowBaseScale = 9.0f ;
alarmSound = trap_S_RegisterSound ( " sound/vehicles/common/lockalarm3.wav " ) ;
}
if ( actualDist > RADAR_MISSILE_RANGE )
{
actualDist = RADAR_MISSILE_RANGE ;
}
VectorMA ( cg . refdef . vieworg , - 500.0f * ( actualDist / RADAR_MISSILE_RANGE ) , dirPlayer , soundOrg ) ;
trap_S_StartSound ( soundOrg , ENTITYNUM_WORLD , CHAN_AUTO , alarmSound ) ;
}
}
}
zScale = 1.0f ;
//we want to scale the thing up/down based on the relative Z (up/down) positioning
if ( cent - > lerpOrigin [ 2 ] > cg . predictedPlayerState . origin [ 2 ] )
{ //higher, scale up (between 16 and 24)
float dif = ( cent - > lerpOrigin [ 2 ] - cg . predictedPlayerState . origin [ 2 ] ) ;
//max out to 1.5x scale at 512 units above local player's height
dif / = 1024.0f ;
if ( dif > 0.5f )
{
dif = 0.5f ;
}
zScale + = dif ;
}
else if ( cent - > lerpOrigin [ 2 ] < cg . predictedPlayerState . origin [ 2 ] )
{ //lower, scale down (between 16 and 8)
float dif = ( cg . predictedPlayerState . origin [ 2 ] - cent - > lerpOrigin [ 2 ] ) ;
//half scale at 512 units below local player's height
dif / = 1024.0f ;
if ( dif > 0.5f )
{
dif = 0.5f ;
}
zScale - = dif ;
}
arrowBaseScale * = zScale ;
if ( cent - > currentState . owner > = MAX_CLIENTS //missile owned by an NPC
& & cg_entities [ cent - > currentState . owner ] . currentState . NPC_class = = CLASS_VEHICLE //NPC is a vehicle
& & cg_entities [ cent - > currentState . owner ] . currentState . m_iVehicleNum < = MAX_CLIENTS //Vehicle has a player driver
& & cgs . clientinfo [ cg_entities [ cent - > currentState . owner ] . currentState . m_iVehicleNum - 1 ] . infoValid ) //player driver is valid
{
cl = & cgs . clientinfo [ cg_entities [ cent - > currentState . owner ] . currentState . m_iVehicleNum - 1 ] ;
if ( cl - > team = = local - > team )
{
trap_R_SetColor ( teamColor ) ;
}
else
{
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_RED ) ] ) ;
}
}
else
{
trap_R_SetColor ( NULL ) ;
}
CG_DrawPic ( x - 4 + xOffset , ly - 4 , arrowBaseScale , arrowBaseScale , cgs . media . mAutomapRocketIcon ) ;
}
break ;
case ET_PLAYER :
{
vec4_t color ;
cl = & cgs . clientinfo [ cent - > currentState . number ] ;
// not valid then dont draw it
if ( ! cl - > infoValid )
{
continue ;
}
VectorCopy4 ( teamColor , color ) ;
arrowBaseScale = 16.0f ;
zScale = 1.0f ;
// Pulse the radar icon after a voice message
if ( cent - > vChatTime + 2000 > cg . time )
{
float f = ( cent - > vChatTime + 2000 - cg . time ) / 3000.0f ;
arrowBaseScale = 16.0f + 4.0f * f ;
color [ 0 ] = teamColor [ 0 ] + ( 1.0f - teamColor [ 0 ] ) * f ;
color [ 1 ] = teamColor [ 1 ] + ( 1.0f - teamColor [ 1 ] ) * f ;
color [ 2 ] = teamColor [ 2 ] + ( 1.0f - teamColor [ 2 ] ) * f ;
}
trap_R_SetColor ( color ) ;
//we want to scale the thing up/down based on the relative Z (up/down) positioning
if ( cent - > lerpOrigin [ 2 ] > cg . predictedPlayerState . origin [ 2 ] )
{ //higher, scale up (between 16 and 32)
float dif = ( cent - > lerpOrigin [ 2 ] - cg . predictedPlayerState . origin [ 2 ] ) ;
//max out to 2x scale at 1024 units above local player's height
dif / = 1024.0f ;
if ( dif > 1.0f )
{
dif = 1.0f ;
}
zScale + = dif ;
}
else if ( cent - > lerpOrigin [ 2 ] < cg . predictedPlayerState . origin [ 2 ] )
{ //lower, scale down (between 16 and 8)
float dif = ( cg . predictedPlayerState . origin [ 2 ] - cent - > lerpOrigin [ 2 ] ) ;
//half scale at 512 units below local player's height
dif / = 1024.0f ;
if ( dif > 0.5f )
{
dif = 0.5f ;
}
zScale - = dif ;
}
arrowBaseScale * = zScale ;
arrow_w = arrowBaseScale * RADAR_RADIUS / 128 ;
arrow_h = arrowBaseScale * RADAR_RADIUS / 128 ;
CG_DrawRotatePic2 ( RADAR_X + RADAR_RADIUS + sin ( angle ) * distance + xOffset ,
y + RADAR_RADIUS + cos ( angle ) * distance ,
arrow_w , arrow_h ,
( 360 - cent - > lerpAngles [ YAW ] ) + cg . predictedPlayerState . viewangles [ YAW ] , cgs . media . mAutomapPlayerIcon ) ;
break ;
}
}
}
arrowBaseScale = 16.0f ;
arrow_w = arrowBaseScale * RADAR_RADIUS / 128 ;
arrow_h = arrowBaseScale * RADAR_RADIUS / 128 ;
trap_R_SetColor ( colorWhite ) ;
CG_DrawRotatePic2 ( RADAR_X + RADAR_RADIUS + xOffset , y + RADAR_RADIUS , arrow_w , arrow_h ,
0 , cgs . media . mAutomapPlayerIcon ) ;
return y + ( RADAR_RADIUS * 2 ) ;
}
/*
= = = = = = = = = = = = = = = = =
CG_DrawTimer
= = = = = = = = = = = = = = = = =
*/
static float CG_DrawTimer ( float y ) {
char * s ;
int w ;
int mins , seconds , tens ;
int msec ;
int xOffset = 0 ;
# ifdef _XBOX
xOffset = - 40 ;
# endif
msec = cg . time - cgs . levelStartTime ;
seconds = msec / 1000 ;
mins = seconds / 60 ;
seconds - = mins * 60 ;
tens = seconds / 10 ;
seconds - = tens * 10 ;
s = va ( " %i:%i%i " , mins , tens , seconds ) ;
w = CG_DrawStrlen ( s ) * BIGCHAR_WIDTH ;
CG_DrawBigString ( 635 - w + xOffset , y + 2 , s , 1.0F ) ;
return y + BIGCHAR_HEIGHT + 4 ;
}
/*
= = = = = = = = = = = = = = = = =
CG_DrawTeamOverlay
= = = = = = = = = = = = = = = = =
*/
extern const char * CG_GetLocationString ( const char * loc ) ; //cg_main.c
static float CG_DrawTeamOverlay ( float y , qboolean right , qboolean upper ) {
int x , w , h , xx ;
int i , j , len ;
const char * p ;
vec4_t hcolor ;
int pwidth , lwidth ;
int plyrs ;
char st [ 16 ] ;
clientInfo_t * ci ;
gitem_t * item ;
int ret_y , count ;
int xOffset = 0 ;
# ifdef _XBOX
xOffset = - 40 ;
# endif
if ( ! cg_drawTeamOverlay . integer ) {
return y ;
}
if ( cg . snap - > ps . persistant [ PERS_TEAM ] ! = TEAM_RED & & cg . snap - > ps . persistant [ PERS_TEAM ] ! = TEAM_BLUE ) {
return y ; // Not on any team
}
plyrs = 0 ;
// max player name width
pwidth = 0 ;
count = ( numSortedTeamPlayers > 8 ) ? 8 : numSortedTeamPlayers ;
for ( i = 0 ; i < count ; i + + ) {
ci = cgs . clientinfo + sortedTeamPlayers [ i ] ;
if ( ci - > infoValid & & ci - > team = = cg . snap - > ps . persistant [ PERS_TEAM ] ) {
plyrs + + ;
len = CG_DrawStrlen ( ci - > name ) ;
if ( len > pwidth )
pwidth = len ;
}
}
if ( ! plyrs )
return y ;
if ( pwidth > TEAM_OVERLAY_MAXNAME_WIDTH )
pwidth = TEAM_OVERLAY_MAXNAME_WIDTH ;
// max location name width
lwidth = 0 ;
for ( i = 1 ; i < MAX_LOCATIONS ; i + + ) {
p = CG_GetLocationString ( CG_ConfigString ( CS_LOCATIONS + i ) ) ;
if ( p & & * p ) {
len = CG_DrawStrlen ( p ) ;
if ( len > lwidth )
lwidth = len ;
}
}
if ( lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH )
lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH ;
w = ( pwidth + lwidth + 4 + 7 ) * TINYCHAR_WIDTH ;
if ( right )
x = 640 - w ;
else
x = 0 ;
h = plyrs * TINYCHAR_HEIGHT ;
if ( upper ) {
ret_y = y + h ;
} else {
y - = h ;
ret_y = y ;
}
if ( cg . snap - > ps . persistant [ PERS_TEAM ] = = TEAM_RED ) {
hcolor [ 0 ] = 1.0f ;
hcolor [ 1 ] = 0.0f ;
hcolor [ 2 ] = 0.0f ;
hcolor [ 3 ] = 0.33f ;
} else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )
hcolor [ 0 ] = 0.0f ;
hcolor [ 1 ] = 0.0f ;
hcolor [ 2 ] = 1.0f ;
hcolor [ 3 ] = 0.33f ;
}
trap_R_SetColor ( hcolor ) ;
CG_DrawPic ( x + xOffset , y , w , h , cgs . media . teamStatusBar ) ;
trap_R_SetColor ( NULL ) ;
for ( i = 0 ; i < count ; i + + ) {
ci = cgs . clientinfo + sortedTeamPlayers [ i ] ;
if ( ci - > infoValid & & ci - > team = = cg . snap - > ps . persistant [ PERS_TEAM ] ) {
hcolor [ 0 ] = hcolor [ 1 ] = hcolor [ 2 ] = hcolor [ 3 ] = 1.0 ;
xx = x + TINYCHAR_WIDTH ;
CG_DrawStringExt ( xx + xOffset , y ,
ci - > name , hcolor , qfalse , qfalse ,
TINYCHAR_WIDTH , TINYCHAR_HEIGHT , TEAM_OVERLAY_MAXNAME_WIDTH ) ;
if ( lwidth ) {
p = CG_GetLocationString ( CG_ConfigString ( CS_LOCATIONS + ci - > location ) ) ;
if ( ! p | | ! * p )
p = " unknown " ;
len = CG_DrawStrlen ( p ) ;
if ( len > lwidth )
len = lwidth ;
// xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth +
// ((lwidth/2 - len/2) * TINYCHAR_WIDTH);
xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth ;
CG_DrawStringExt ( xx + xOffset , y ,
p , hcolor , qfalse , qfalse , TINYCHAR_WIDTH , TINYCHAR_HEIGHT ,
TEAM_OVERLAY_MAXLOCATION_WIDTH ) ;
}
CG_GetColorForHealth ( ci - > health , ci - > armor , hcolor ) ;
Com_sprintf ( st , sizeof ( st ) , " %3i %3i " , ci - > health , ci - > armor ) ;
xx = x + TINYCHAR_WIDTH * 3 +
TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth ;
CG_DrawStringExt ( xx + xOffset , y ,
st , hcolor , qfalse , qfalse ,
TINYCHAR_WIDTH , TINYCHAR_HEIGHT , 0 ) ;
// draw weapon icon
xx + = TINYCHAR_WIDTH * 3 ;
if ( cg_weapons [ ci - > curWeapon ] . weaponIcon ) {
CG_DrawPic ( xx + xOffset , y , TINYCHAR_WIDTH , TINYCHAR_HEIGHT ,
cg_weapons [ ci - > curWeapon ] . weaponIcon ) ;
} else {
CG_DrawPic ( xx + xOffset , y , TINYCHAR_WIDTH , TINYCHAR_HEIGHT ,
cgs . media . deferShader ) ;
}
// Draw powerup icons
if ( right ) {
xx = x ;
} else {
xx = x + w - TINYCHAR_WIDTH ;
}
for ( j = 0 ; j < = PW_NUM_POWERUPS ; j + + ) {
if ( ci - > powerups & ( 1 < < j ) ) {
item = BG_FindItemForPowerup ( j ) ;
if ( item ) {
CG_DrawPic ( xx + xOffset , y , TINYCHAR_WIDTH , TINYCHAR_HEIGHT ,
trap_R_RegisterShader ( item - > icon ) ) ;
if ( right ) {
xx - = TINYCHAR_WIDTH ;
} else {
xx + = TINYCHAR_WIDTH ;
}
}
}
}
y + = TINYCHAR_HEIGHT ;
}
}
return ret_y ;
//#endif
}
static void CG_DrawPowerupIcons ( int y )
{
int j ;
int ico_size = 64 ;
//int y = ico_size/2;
int xOffset = 0 ;
gitem_t * item ;
# ifdef _XBOX
xOffset = - 40 ;
# endif
if ( ! cg . snap )
{
return ;
}
y + = 16 ;
for ( j = 0 ; j < = PW_NUM_POWERUPS ; j + + )
{
if ( cg . snap - > ps . powerups [ j ] > cg . time )
{
int secondsleft = ( cg . snap - > ps . powerups [ j ] - cg . time ) / 1000 ;
item = BG_FindItemForPowerup ( j ) ;
if ( item )
{
int icoShader = 0 ;
if ( cgs . gametype = = GT_CTY & & ( j = = PW_REDFLAG | | j = = PW_BLUEFLAG ) )
{
if ( j = = PW_REDFLAG )
{
icoShader = trap_R_RegisterShaderNoMip ( " gfx/hud/mpi_rflag_ys " ) ;
}
else
{
icoShader = trap_R_RegisterShaderNoMip ( " gfx/hud/mpi_bflag_ys " ) ;
}
}
else
{
icoShader = trap_R_RegisterShader ( item - > icon ) ;
}
CG_DrawPic ( ( 640 - ( ico_size * 1.1 ) ) + xOffset , y , ico_size , ico_size , icoShader ) ;
y + = ico_size ;
if ( j ! = PW_REDFLAG & & j ! = PW_BLUEFLAG & & secondsleft < 999 )
{
UI_DrawProportionalString ( ( 640 - ( ico_size * 1.1 ) ) + ( ico_size / 2 ) + xOffset , y - 8 , va ( " %i " , secondsleft ) , UI_CENTER | UI_BIGFONT | UI_DROPSHADOW , colorTable [ CT_WHITE ] ) ;
}
y + = ( ico_size / 3 ) ;
}
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = =
CG_DrawUpperRight
= = = = = = = = = = = = = = = = = = = = =
*/
static void CG_DrawUpperRight ( void ) {
float y ;
# ifdef _XBOX
y = 50 ;
# else
y = 0 ;
# endif
trap_R_SetColor ( colorTable [ CT_WHITE ] ) ;
if ( cgs . gametype > = GT_TEAM & & cg_drawTeamOverlay . integer = = 1 ) {
y = CG_DrawTeamOverlay ( y , qtrue , qtrue ) ;
}
if ( cg_drawSnapshot . integer ) {
y = CG_DrawSnapshot ( y ) ;
}
if ( cg_drawFPS . integer ) {
y = CG_DrawFPS ( y ) ;
}
if ( cg_drawTimer . integer ) {
y = CG_DrawTimer ( y ) ;
}
if ( ( cgs . gametype > = GT_TEAM | | cg . predictedPlayerState . m_iVehicleNum )
& & cg_drawRadar . integer )
{ //draw Radar in Siege mode or when in a vehicle of any kind
y = CG_DrawRadar ( y ) ;
}
y = CG_DrawEnemyInfo ( y ) ;
y = CG_DrawMiniScoreboard ( y ) ;
CG_DrawPowerupIcons ( y ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
CG_DrawReward
= = = = = = = = = = = = = = = = = = =
*/
# ifdef JK2AWARDS
static void CG_DrawReward ( void ) {
float * color ;
int i , count ;
float x , y ;
char buf [ 32 ] ;
if ( ! cg_drawRewards . integer ) {
return ;
}
color = CG_FadeColor ( cg . rewardTime , REWARD_TIME ) ;
if ( ! color ) {
if ( cg . rewardStack > 0 ) {
for ( i = 0 ; i < cg . rewardStack ; i + + ) {
cg . rewardSound [ i ] = cg . rewardSound [ i + 1 ] ;
cg . rewardShader [ i ] = cg . rewardShader [ i + 1 ] ;
cg . rewardCount [ i ] = cg . rewardCount [ i + 1 ] ;
}
cg . rewardTime = cg . time ;
cg . rewardStack - - ;
color = CG_FadeColor ( cg . rewardTime , REWARD_TIME ) ;
trap_S_StartLocalSound ( cg . rewardSound [ 0 ] , CHAN_ANNOUNCER ) ;
} else {
return ;
}
}
trap_R_SetColor ( color ) ;
/*
count = cg . rewardCount [ 0 ] / 10 ; // number of big rewards to draw
if ( count ) {
y = 4 ;
x = 320 - count * ICON_SIZE ;
for ( i = 0 ; i < count ; i + + ) {
CG_DrawPic ( x , y , ( ICON_SIZE * 2 ) - 4 , ( ICON_SIZE * 2 ) - 4 , cg . rewardShader [ 0 ] ) ;
x + = ( ICON_SIZE * 2 ) ;
}
}
count = cg . rewardCount [ 0 ] - count * 10 ; // number of small rewards to draw
*/
if ( cg . rewardCount [ 0 ] > = 10 ) {
y = 56 ;
x = 320 - ICON_SIZE / 2 ;
CG_DrawPic ( x , y , ICON_SIZE - 4 , ICON_SIZE - 4 , cg . rewardShader [ 0 ] ) ;
Com_sprintf ( buf , sizeof ( buf ) , " %d " , cg . rewardCount [ 0 ] ) ;
x = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen ( buf ) ) / 2 ;
CG_DrawStringExt ( x , y + ICON_SIZE , buf , color , qfalse , qtrue ,
SMALLCHAR_WIDTH , SMALLCHAR_HEIGHT , 0 ) ;
}
else {
count = cg . rewardCount [ 0 ] ;
y = 56 ;
x = 320 - count * ICON_SIZE / 2 ;
for ( i = 0 ; i < count ; i + + ) {
CG_DrawPic ( x , y , ICON_SIZE - 4 , ICON_SIZE - 4 , cg . rewardShader [ 0 ] ) ;
x + = ICON_SIZE ;
}
}
trap_R_SetColor ( NULL ) ;
}
# endif
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
LAGOMETER
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# define LAG_SAMPLES 128
typedef struct {
int frameSamples [ LAG_SAMPLES ] ;
int frameCount ;
int snapshotFlags [ LAG_SAMPLES ] ;
int snapshotSamples [ LAG_SAMPLES ] ;
int snapshotCount ;
} lagometer_t ;
lagometer_t lagometer ;
/*
= = = = = = = = = = = = = =
CG_AddLagometerFrameInfo
Adds the current interpolate / extrapolate bar for this frame
= = = = = = = = = = = = = =
*/
void CG_AddLagometerFrameInfo ( void ) {
int offset ;
offset = cg . time - cg . latestSnapshotTime ;
lagometer . frameSamples [ lagometer . frameCount & ( LAG_SAMPLES - 1 ) ] = offset ;
lagometer . frameCount + + ;
}
/*
= = = = = = = = = = = = = =
CG_AddLagometerSnapshotInfo
Each time a snapshot is received , log its ping time and
the number of snapshots that were dropped before it .
Pass NULL for a dropped packet .
= = = = = = = = = = = = = =
*/
void CG_AddLagometerSnapshotInfo ( snapshot_t * snap ) {
// dropped packet
if ( ! snap ) {
lagometer . snapshotSamples [ lagometer . snapshotCount & ( LAG_SAMPLES - 1 ) ] = - 1 ;
lagometer . snapshotCount + + ;
return ;
}
// add this snapshot's info
lagometer . snapshotSamples [ lagometer . snapshotCount & ( LAG_SAMPLES - 1 ) ] = snap - > ping ;
lagometer . snapshotFlags [ lagometer . snapshotCount & ( LAG_SAMPLES - 1 ) ] = snap - > snapFlags ;
lagometer . snapshotCount + + ;
}
/*
= = = = = = = = = = = = = =
CG_DrawDisconnect
Should we draw something differnet for long lag vs no packets ?
= = = = = = = = = = = = = =
*/
static void CG_DrawDisconnect ( void ) {
float x , y ;
int cmdNum ;
usercmd_t cmd ;
const char * s ;
int w ; // bk010215 - FIXME char message[1024];
if ( cg . mMapChange )
{
s = CG_GetStringEdString ( " MP_INGAME " , " SERVER_CHANGING_MAPS " ) ; // s = "Server Changing Maps";
w = CG_DrawStrlen ( s ) * BIGCHAR_WIDTH ;
CG_DrawBigString ( 320 - w / 2 , 100 , s , 1.0F ) ;
s = CG_GetStringEdString ( " MP_INGAME " , " PLEASE_WAIT " ) ; // s = "Please wait...";
w = CG_DrawStrlen ( s ) * BIGCHAR_WIDTH ;
CG_DrawBigString ( 320 - w / 2 , 200 , s , 1.0F ) ;
return ;
}
// draw the phone jack if we are completely past our buffers
cmdNum = trap_GetCurrentCmdNumber ( ) - CMD_BACKUP + 1 ;
trap_GetUserCmd ( cmdNum , & cmd ) ;
if ( cmd . serverTime < = cg . snap - > ps . commandTime
| | cmd . serverTime > cg . time ) { // special check for map_restart // bk 0102165 - FIXME
return ;
}
// also add text in center of screen
s = CG_GetStringEdString ( " MP_INGAME " , " CONNECTION_INTERRUPTED " ) ; // s = "Connection Interrupted"; // bk 010215 - FIXME
w = CG_DrawStrlen ( s ) * BIGCHAR_WIDTH ;
CG_DrawBigString ( 320 - w / 2 , 100 , s , 1.0F ) ;
// blink the icon
if ( ( cg . time > > 9 ) & 1 ) {
return ;
}
x = 640 - 48 ;
y = 480 - 48 ;
CG_DrawPic ( x , y , 48 , 48 , trap_R_RegisterShader ( " gfx/2d/net.tga " ) ) ;
}
# define MAX_LAGOMETER_PING 900
# define MAX_LAGOMETER_RANGE 300
/*
= = = = = = = = = = = = = =
CG_DrawLagometer
= = = = = = = = = = = = = =
*/
static void CG_DrawLagometer ( void ) {
int a , x , y , i ;
float v ;
float ax , ay , aw , ah , mid , range ;
int color ;
float vscale ;
if ( ! cg_lagometer . integer | | cgs . localServer ) {
CG_DrawDisconnect ( ) ;
return ;
}
//
// draw the graph
//
x = 640 - 48 ;
y = 480 - 144 ;
trap_R_SetColor ( NULL ) ;
CG_DrawPic ( x , y , 48 , 48 , cgs . media . lagometerShader ) ;
ax = x ;
ay = y ;
aw = 48 ;
ah = 48 ;
color = - 1 ;
range = ah / 3 ;
mid = ay + range ;
vscale = range / MAX_LAGOMETER_RANGE ;
// draw the frame interpoalte / extrapolate graph
for ( a = 0 ; a < aw ; a + + ) {
i = ( lagometer . frameCount - 1 - a ) & ( LAG_SAMPLES - 1 ) ;
v = lagometer . frameSamples [ i ] ;
v * = vscale ;
if ( v > 0 ) {
if ( color ! = 1 ) {
color = 1 ;
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_YELLOW ) ] ) ;
}
if ( v > range ) {
v = range ;
}
trap_R_DrawStretchPic ( ax + aw - a , mid - v , 1 , v , 0 , 0 , 0 , 0 , cgs . media . whiteShader ) ;
} else if ( v < 0 ) {
if ( color ! = 2 ) {
color = 2 ;
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_BLUE ) ] ) ;
}
v = - v ;
if ( v > range ) {
v = range ;
}
trap_R_DrawStretchPic ( ax + aw - a , mid , 1 , v , 0 , 0 , 0 , 0 , cgs . media . whiteShader ) ;
}
}
// draw the snapshot latency / drop graph
range = ah / 2 ;
vscale = range / MAX_LAGOMETER_PING ;
for ( a = 0 ; a < aw ; a + + ) {
i = ( lagometer . snapshotCount - 1 - a ) & ( LAG_SAMPLES - 1 ) ;
v = lagometer . snapshotSamples [ i ] ;
if ( v > 0 ) {
if ( lagometer . snapshotFlags [ i ] & SNAPFLAG_RATE_DELAYED ) {
if ( color ! = 5 ) {
color = 5 ; // YELLOW for rate delay
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_YELLOW ) ] ) ;
}
} else {
if ( color ! = 3 ) {
color = 3 ;
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_GREEN ) ] ) ;
}
}
v = v * vscale ;
if ( v > range ) {
v = range ;
}
trap_R_DrawStretchPic ( ax + aw - a , ay + ah - v , 1 , v , 0 , 0 , 0 , 0 , cgs . media . whiteShader ) ;
} else if ( v < 0 ) {
if ( color ! = 4 ) {
color = 4 ; // RED for dropped snapshots
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_RED ) ] ) ;
}
trap_R_DrawStretchPic ( ax + aw - a , ay + ah - range , 1 , range , 0 , 0 , 0 , 0 , cgs . media . whiteShader ) ;
}
}
trap_R_SetColor ( NULL ) ;
if ( cg_nopredict . integer | | cg_synchronousClients . integer ) {
CG_DrawBigString ( ax , ay , " snc " , 1.0 ) ;
}
CG_DrawDisconnect ( ) ;
}
void CG_DrawSiegeMessage ( const char * str , int objectiveScreen )
{
// if (!( trap_Key_GetCatcher() & KEYCATCH_UI ))
{
trap_OpenUIMenu ( UIMENU_CLOSEALL ) ;
trap_Cvar_Set ( " cg_siegeMessage " , str ) ;
if ( objectiveScreen )
{
trap_OpenUIMenu ( UIMENU_SIEGEOBJECTIVES ) ;
}
else
{
trap_OpenUIMenu ( UIMENU_SIEGEMESSAGE ) ;
}
}
}
void CG_DrawSiegeMessageNonMenu ( const char * str )
{
char text [ 1024 ] ;
if ( str [ 0 ] = = ' @ ' )
{
trap_SP_GetStringTextString ( str + 1 , text , sizeof ( text ) ) ;
str = text ;
}
CG_CenterPrint ( str , SCREEN_HEIGHT * 0.20 , BIGCHAR_WIDTH ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CENTER PRINTING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = =
CG_CenterPrint
Called for important messages that should stay in the center of the screen
for a few moments
= = = = = = = = = = = = = =
*/
void CG_CenterPrint ( const char * str , int y , int charWidth ) {
char * s ;
Q_strncpyz ( cg . centerPrint , str , sizeof ( cg . centerPrint ) ) ;
cg . centerPrintTime = cg . time ;
cg . centerPrintY = y ;
cg . centerPrintCharWidth = charWidth ;
// count the number of lines for centering
cg . centerPrintLines = 1 ;
s = cg . centerPrint ;
while ( * s ) {
if ( * s = = ' \n ' )
cg . centerPrintLines + + ;
s + + ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
CG_DrawCenterString
= = = = = = = = = = = = = = = = = = =
*/
static void CG_DrawCenterString ( void ) {
char * start ;
int l ;
int x , y , w ;
int h ;
float * color ;
const float scale = 1.0 ; //0.5
if ( ! cg . centerPrintTime ) {
return ;
}
color = CG_FadeColor ( cg . centerPrintTime , 1000 * cg_centertime . value ) ;
if ( ! color ) {
return ;
}
trap_R_SetColor ( color ) ;
start = cg . centerPrint ;
y = cg . centerPrintY - cg . centerPrintLines * BIGCHAR_HEIGHT / 2 ;
while ( 1 ) {
char linebuffer [ 1024 ] ;
for ( l = 0 ; l < 50 ; l + + ) {
if ( ! start [ l ] | | start [ l ] = = ' \n ' ) {
break ;
}
linebuffer [ l ] = start [ l ] ;
}
linebuffer [ l ] = 0 ;
w = CG_Text_Width ( linebuffer , scale , FONT_MEDIUM ) ;
h = CG_Text_Height ( linebuffer , scale , FONT_MEDIUM ) ;
x = ( SCREEN_WIDTH - w ) / 2 ;
CG_Text_Paint ( x , y + h , scale , color , linebuffer , 0 , 0 , ITEM_TEXTSTYLE_SHADOWEDMORE , FONT_MEDIUM ) ;
y + = h + 6 ;
while ( * start & & ( * start ! = ' \n ' ) ) {
start + + ;
}
if ( ! * start ) {
break ;
}
start + + ;
}
trap_R_SetColor ( NULL ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CROSSHAIR
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# define HEALTH_WIDTH 50.0f
# define HEALTH_HEIGHT 5.0f
//see if we can draw some extra info on this guy based on our class
void CG_DrawSiegeInfo ( centity_t * cent , float chX , float chY , float chW , float chH )
{
siegeExtended_t * se = & cg_siegeExtendedData [ cent - > currentState . number ] ;
clientInfo_t * ci ;
const char * configstring , * v ;
siegeClass_t * siegeClass ;
vec4_t aColor ;
vec4_t bColor ;
vec4_t cColor ;
float x ;
float y ;
float percent ;
int ammoMax ;
assert ( cent - > currentState . number < MAX_CLIENTS ) ;
if ( se - > lastUpdated > cg . time )
{ //strange, shouldn't happen
return ;
}
if ( ( cg . time - se - > lastUpdated ) > 10000 )
{ //if you haven't received a status update on this guy in 10 seconds, forget about it
return ;
}
if ( cent - > currentState . eFlags & EF_DEAD )
{ //he's dead, don't display info on him
return ;
}
if ( cent - > currentState . weapon ! = se - > weapon )
{ //data is invalidated until it syncs back again
return ;
}
ci = & cgs . clientinfo [ cent - > currentState . number ] ;
if ( ci - > team ! = cg . predictedPlayerState . persistant [ PERS_TEAM ] )
{ //not on the same team
return ;
}
configstring = CG_ConfigString ( cg . predictedPlayerState . clientNum + CS_PLAYERS ) ;
v = Info_ValueForKey ( configstring , " siegeclass " ) ;
if ( ! v | | ! v [ 0 ] )
{ //don't have siege class in info?
return ;
}
siegeClass = BG_SiegeFindClassByName ( v ) ;
if ( ! siegeClass )
{ //invalid
return ;
}
if ( ! ( siegeClass - > classflags & ( 1 < < CFL_STATVIEWER ) ) )
{ //doesn't really have the ability to see others' stats
return ;
}
x = chX + ( ( chW / 2 ) - ( HEALTH_WIDTH / 2 ) ) ;
y = ( chY + chH ) + 8.0f ;
percent = ( ( float ) se - > health / ( float ) se - > maxhealth ) * HEALTH_WIDTH ;
//color of the bar
aColor [ 0 ] = 0.0f ;
aColor [ 1 ] = 1.0f ;
aColor [ 2 ] = 0.0f ;
aColor [ 3 ] = 0.4f ;
//color of the border
bColor [ 0 ] = 0.0f ;
bColor [ 1 ] = 0.0f ;
bColor [ 2 ] = 0.0f ;
bColor [ 3 ] = 0.3f ;
//color of greyed out "missing health"
cColor [ 0 ] = 0.5f ;
cColor [ 1 ] = 0.5f ;
cColor [ 2 ] = 0.5f ;
cColor [ 3 ] = 0.4f ;
//draw the background (black)
CG_DrawRect ( x , y , HEALTH_WIDTH , HEALTH_HEIGHT , 1.0f , colorTable [ CT_BLACK ] ) ;
//now draw the part to show how much health there is in the color specified
CG_FillRect ( x + 1.0f , y + 1.0f , percent - 1.0f , HEALTH_HEIGHT - 1.0f , aColor ) ;
//then draw the other part greyed out
CG_FillRect ( x + percent , y + 1.0f , HEALTH_WIDTH - percent - 1.0f , HEALTH_HEIGHT - 1.0f , cColor ) ;
//now draw his ammo
ammoMax = ammoData [ weaponData [ cent - > currentState . weapon ] . ammoIndex ] . max ;
if ( ( cent - > currentState . eFlags & EF_DOUBLE_AMMO ) )
{
ammoMax * = 2 ;
}
x = chX + ( ( chW / 2 ) - ( HEALTH_WIDTH / 2 ) ) ;
y = ( chY + chH ) + HEALTH_HEIGHT + 10.0f ;
if ( ! weaponData [ cent - > currentState . weapon ] . energyPerShot & &
! weaponData [ cent - > currentState . weapon ] . altEnergyPerShot )
{ //a weapon that takes no ammo, so show full
percent = HEALTH_WIDTH ;
}
else
{
percent = ( ( float ) se - > ammo / ( float ) ammoMax ) * HEALTH_WIDTH ;
}
//color of the bar
aColor [ 0 ] = 1.0f ;
aColor [ 1 ] = 1.0f ;
aColor [ 2 ] = 0.0f ;
aColor [ 3 ] = 0.4f ;
//color of the border
bColor [ 0 ] = 0.0f ;
bColor [ 1 ] = 0.0f ;
bColor [ 2 ] = 0.0f ;
bColor [ 3 ] = 0.3f ;
//color of greyed out "missing health"
cColor [ 0 ] = 0.5f ;
cColor [ 1 ] = 0.5f ;
cColor [ 2 ] = 0.5f ;
cColor [ 3 ] = 0.4f ;
//draw the background (black)
CG_DrawRect ( x , y , HEALTH_WIDTH , HEALTH_HEIGHT , 1.0f , colorTable [ CT_BLACK ] ) ;
//now draw the part to show how much health there is in the color specified
CG_FillRect ( x + 1.0f , y + 1.0f , percent - 1.0f , HEALTH_HEIGHT - 1.0f , aColor ) ;
//then draw the other part greyed out
CG_FillRect ( x + percent , y + 1.0f , HEALTH_WIDTH - percent - 1.0f , HEALTH_HEIGHT - 1.0f , cColor ) ;
}
//draw the health bar based on current "health" and maxhealth
void CG_DrawHealthBar ( centity_t * cent , float chX , float chY , float chW , float chH )
{
vec4_t aColor ;
vec4_t bColor ;
vec4_t cColor ;
float x = chX + ( ( chW / 2 ) - ( HEALTH_WIDTH / 2 ) ) ;
float y = ( chY + chH ) + 8.0f ;
float percent = ( ( float ) cent - > currentState . health / ( float ) cent - > currentState . maxhealth ) * HEALTH_WIDTH ;
if ( percent < = 0 )
{
return ;
}
//color of the bar
if ( ! cent - > currentState . teamowner | | cgs . gametype < GT_TEAM )
{ //not owned by a team or teamplay
aColor [ 0 ] = 1.0f ;
aColor [ 1 ] = 1.0f ;
aColor [ 2 ] = 0.0f ;
aColor [ 3 ] = 0.4f ;
}
else if ( cent - > currentState . teamowner = = cg . predictedPlayerState . persistant [ PERS_TEAM ] )
{ //owned by my team
aColor [ 0 ] = 0.0f ;
aColor [ 1 ] = 1.0f ;
aColor [ 2 ] = 0.0f ;
aColor [ 3 ] = 0.4f ;
}
else
{ //hostile
aColor [ 0 ] = 1.0f ;
aColor [ 1 ] = 0.0f ;
aColor [ 2 ] = 0.0f ;
aColor [ 3 ] = 0.4f ;
}
//color of the border
bColor [ 0 ] = 0.0f ;
bColor [ 1 ] = 0.0f ;
bColor [ 2 ] = 0.0f ;
bColor [ 3 ] = 0.3f ;
//color of greyed out "missing health"
cColor [ 0 ] = 0.5f ;
cColor [ 1 ] = 0.5f ;
cColor [ 2 ] = 0.5f ;
cColor [ 3 ] = 0.4f ;
//draw the background (black)
CG_DrawRect ( x , y , HEALTH_WIDTH , HEALTH_HEIGHT , 1.0f , colorTable [ CT_BLACK ] ) ;
//now draw the part to show how much health there is in the color specified
CG_FillRect ( x + 1.0f , y + 1.0f , percent - 1.0f , HEALTH_HEIGHT - 1.0f , aColor ) ;
//then draw the other part greyed out
CG_FillRect ( x + percent , y + 1.0f , HEALTH_WIDTH - percent - 1.0f , HEALTH_HEIGHT - 1.0f , cColor ) ;
}
//same routine (at least for now), draw progress of a "hack" or whatever
void CG_DrawHaqrBar ( float chX , float chY , float chW , float chH )
{
vec4_t aColor ;
vec4_t bColor ;
vec4_t cColor ;
float x = chX + ( ( chW / 2 ) - ( HEALTH_WIDTH / 2 ) ) ;
float y = ( chY + chH ) + 8.0f ;
float percent = ( ( ( float ) cg . predictedPlayerState . hackingTime - ( float ) cg . time ) / ( float ) cg . predictedPlayerState . hackingBaseTime ) * HEALTH_WIDTH ;
if ( percent > HEALTH_WIDTH | |
percent < 1.0f )
{
return ;
}
//color of the bar
aColor [ 0 ] = 1.0f ;
aColor [ 1 ] = 1.0f ;
aColor [ 2 ] = 0.0f ;
aColor [ 3 ] = 0.4f ;
//color of the border
bColor [ 0 ] = 0.0f ;
bColor [ 1 ] = 0.0f ;
bColor [ 2 ] = 0.0f ;
bColor [ 3 ] = 0.3f ;
//color of greyed out done area
cColor [ 0 ] = 0.5f ;
cColor [ 1 ] = 0.5f ;
cColor [ 2 ] = 0.5f ;
cColor [ 3 ] = 0.1f ;
//draw the background (black)
CG_DrawRect ( x , y , HEALTH_WIDTH , HEALTH_HEIGHT , 1.0f , colorTable [ CT_BLACK ] ) ;
//now draw the part to show how much health there is in the color specified
CG_FillRect ( x + 1.0f , y + 1.0f , percent - 1.0f , HEALTH_HEIGHT - 1.0f , aColor ) ;
//then draw the other part greyed out
CG_FillRect ( x + percent , y + 1.0f , HEALTH_WIDTH - percent - 1.0f , HEALTH_HEIGHT - 1.0f , cColor ) ;
//draw the hacker icon
CG_DrawPic ( x , y - HEALTH_WIDTH , HEALTH_WIDTH , HEALTH_WIDTH , cgs . media . hackerIconShader ) ;
}
//generic timing bar
int cg_genericTimerBar = 0 ;
int cg_genericTimerDur = 0 ;
vec4_t cg_genericTimerColor ;
# define CGTIMERBAR_H 50.0f
# define CGTIMERBAR_W 10.0f
# define CGTIMERBAR_X (SCREEN_WIDTH-CGTIMERBAR_W-120.0f)
# define CGTIMERBAR_Y (SCREEN_HEIGHT-CGTIMERBAR_H-20.0f)
void CG_DrawGenericTimerBar ( void )
{
vec4_t aColor ;
vec4_t bColor ;
vec4_t cColor ;
float x = CGTIMERBAR_X ;
float y = CGTIMERBAR_Y ;
float percent = ( ( float ) ( cg_genericTimerBar - cg . time ) / ( float ) cg_genericTimerDur ) * CGTIMERBAR_H ;
if ( percent > CGTIMERBAR_H )
{
return ;
}
if ( percent < 0.1f )
{
percent = 0.1f ;
}
//color of the bar
aColor [ 0 ] = cg_genericTimerColor [ 0 ] ;
aColor [ 1 ] = cg_genericTimerColor [ 1 ] ;
aColor [ 2 ] = cg_genericTimerColor [ 2 ] ;
aColor [ 3 ] = cg_genericTimerColor [ 3 ] ;
//color of the border
bColor [ 0 ] = 0.0f ;
bColor [ 1 ] = 0.0f ;
bColor [ 2 ] = 0.0f ;
bColor [ 3 ] = 0.3f ;
//color of greyed out "missing fuel"
cColor [ 0 ] = 0.5f ;
cColor [ 1 ] = 0.5f ;
cColor [ 2 ] = 0.5f ;
cColor [ 3 ] = 0.1f ;
//draw the background (black)
CG_DrawRect ( x , y , CGTIMERBAR_W , CGTIMERBAR_H , 1.0f , colorTable [ CT_BLACK ] ) ;
//now draw the part to show how much health there is in the color specified
CG_FillRect ( x + 1.0f , y + 1.0f + ( CGTIMERBAR_H - percent ) , CGTIMERBAR_W - 2.0f , CGTIMERBAR_H - 1.0f - ( CGTIMERBAR_H - percent ) , aColor ) ;
//then draw the other part greyed out
CG_FillRect ( x + 1.0f , y + 1.0f , CGTIMERBAR_W - 2.0f , CGTIMERBAR_H - percent , cColor ) ;
}
/*
= = = = = = = = = = = = = = = = =
CG_DrawCrosshair
= = = = = = = = = = = = = = = = =
*/
# ifdef _XBOX
int cg_crossHairStatus = 0 ;
# endif
float cg_crosshairPrevPosX = 0 ;
float cg_crosshairPrevPosY = 0 ;
# define CRAZY_CROSSHAIR_MAX_ERROR_X (100.0f*640.0f / 480.0f)
# define CRAZY_CROSSHAIR_MAX_ERROR_Y (100.0f)
void CG_LerpCrosshairPos ( float * x , float * y )
{
if ( cg_crosshairPrevPosX )
{ //blend from old pos
float maxMove = 30.0f * ( ( float ) cg . frametime / 500.0f ) * 640.0f / 480.0f ;
float xDiff = ( * x - cg_crosshairPrevPosX ) ;
if ( fabs ( xDiff ) > CRAZY_CROSSHAIR_MAX_ERROR_X )
{
maxMove = CRAZY_CROSSHAIR_MAX_ERROR_X ;
}
if ( xDiff > maxMove )
{
* x = cg_crosshairPrevPosX + maxMove ;
}
else if ( xDiff < - maxMove )
{
* x = cg_crosshairPrevPosX - maxMove ;
}
}
cg_crosshairPrevPosX = * x ;
if ( cg_crosshairPrevPosY )
{ //blend from old pos
float maxMove = 30.0f * ( ( float ) cg . frametime / 500.0f ) ;
float yDiff = ( * y - cg_crosshairPrevPosY ) ;
if ( fabs ( yDiff ) > CRAZY_CROSSHAIR_MAX_ERROR_Y )
{
maxMove = CRAZY_CROSSHAIR_MAX_ERROR_X ;
}
if ( yDiff > maxMove )
{
* y = cg_crosshairPrevPosY + maxMove ;
}
else if ( yDiff < - maxMove )
{
* y = cg_crosshairPrevPosY - maxMove ;
}
}
cg_crosshairPrevPosY = * y ;
}
vec3_t cg_crosshairPos = { 0 , 0 , 0 } ;
static void CG_DrawCrosshair ( vec3_t worldPoint , int chEntValid ) {
float w , h ;
qhandle_t hShader = 0 ;
float f ;
float x , y ;
qboolean corona = qfalse ;
vec4_t ecolor = { 0 , 0 , 0 , 0 } ;
centity_t * crossEnt = NULL ;
float chX , chY ;
# ifdef _XBOX
cg_crossHairStatus = 0 ;
# endif
if ( worldPoint )
{
VectorCopy ( worldPoint , cg_crosshairPos ) ;
}
if ( ! cg_drawCrosshair . integer )
{
return ;
}
if ( cg . snap - > ps . fallingToDeath )
{
return ;
}
if ( cg . predictedPlayerState . zoomMode ! = 0 )
{ //not while scoped
return ;
}
/*
if ( cg_drawingRocketLockThisFrame
& & cg . snap - > ps . m_iVehicleNum )
{ //in vehicle, rocket lock-on replaces crosshair
return ;
}
*/
if ( cg_crosshairHealth . integer )
{
vec4_t hcolor ;
CG_ColorForHealth ( hcolor ) ;
trap_R_SetColor ( hcolor ) ;
}
else
{
//set color based on what kind of ent is under crosshair
if ( cg . crosshairClientNum > = ENTITYNUM_WORLD )
{
trap_R_SetColor ( NULL ) ;
}
//rwwFIXMEFIXME: Write this a different way, it's getting a bit too sloppy looking
else if ( chEntValid & &
( cg_entities [ cg . crosshairClientNum ] . currentState . number < MAX_CLIENTS | |
cg_entities [ cg . crosshairClientNum ] . currentState . eType = = ET_NPC | |
cg_entities [ cg . crosshairClientNum ] . currentState . shouldtarget | |
cg_entities [ cg . crosshairClientNum ] . currentState . health | | //always show ents with health data under crosshair
( cg_entities [ cg . crosshairClientNum ] . currentState . eType = = ET_MOVER & & cg_entities [ cg . crosshairClientNum ] . currentState . bolt1 & & cg . predictedPlayerState . weapon = = WP_SABER ) | |
( cg_entities [ cg . crosshairClientNum ] . currentState . eType = = ET_MOVER & & cg_entities [ cg . crosshairClientNum ] . currentState . teamowner ) ) )
{
crossEnt = & cg_entities [ cg . crosshairClientNum ] ;
if ( crossEnt - > currentState . powerups & ( 1 < < PW_CLOAKED ) )
{ //don't show up for cloaked guys
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 1.0 ; //B
}
else if ( crossEnt - > currentState . number < MAX_CLIENTS )
{
if ( cgs . gametype > = GT_TEAM & &
cgs . clientinfo [ crossEnt - > currentState . number ] . team = = cgs . clientinfo [ cg . snap - > ps . clientNum ] . team )
{
//Allies are green
ecolor [ 0 ] = 0.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
}
else
{
if ( cgs . gametype = = GT_POWERDUEL & &
cgs . clientinfo [ crossEnt - > currentState . number ] . duelTeam = = cgs . clientinfo [ cg . snap - > ps . clientNum ] . duelTeam )
{ //on the same duel team in powerduel, so he's a friend
ecolor [ 0 ] = 0.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
}
else
{ //Enemies are red
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 0.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
# ifdef _XBOX
cg_crossHairStatus = 1 ;
# endif
}
}
if ( cg . snap - > ps . duelInProgress )
{
if ( crossEnt - > currentState . number ! = cg . snap - > ps . duelIndex )
{ //grey out crosshair for everyone but your foe if you're in a duel
ecolor [ 0 ] = 0.4 ;
ecolor [ 1 ] = 0.4 ;
ecolor [ 2 ] = 0.4 ;
}
}
else if ( crossEnt - > currentState . bolt1 )
{ //this fellow is in a duel. We just checked if we were in a duel above, so
//this means we aren't and he is. Which of course means our crosshair greys out over him.
ecolor [ 0 ] = 0.4 ;
ecolor [ 1 ] = 0.4 ;
ecolor [ 2 ] = 0.4 ;
}
}
else if ( crossEnt - > currentState . shouldtarget | | crossEnt - > currentState . eType = = ET_NPC )
{
//VectorCopy( crossEnt->startRGBA, ecolor );
if ( ! ecolor [ 0 ] & & ! ecolor [ 1 ] & & ! ecolor [ 2 ] )
{
// We really don't want black, so set it to yellow
ecolor [ 0 ] = 1.0F ; //R
ecolor [ 1 ] = 0.8F ; //G
ecolor [ 2 ] = 0.3F ; //B
}
if ( crossEnt - > currentState . eType = = ET_NPC )
{
int plTeam ;
if ( cgs . gametype = = GT_SIEGE )
{
plTeam = cg . predictedPlayerState . persistant [ PERS_TEAM ] ;
}
else
{
plTeam = NPCTEAM_PLAYER ;
}
if ( crossEnt - > currentState . powerups & ( 1 < < PW_CLOAKED ) )
{
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 1.0 ; //B
}
else if ( ! crossEnt - > currentState . teamowner )
{ //not on a team
if ( ! crossEnt - > currentState . teamowner | |
crossEnt - > currentState . NPC_class = = CLASS_VEHICLE )
{ //neutral
if ( crossEnt - > currentState . owner < MAX_CLIENTS )
{ //base color on who is pilotting this thing
clientInfo_t * ci = & cgs . clientinfo [ crossEnt - > currentState . owner ] ;
if ( cgs . gametype > = GT_TEAM & & ci - > team = = cg . predictedPlayerState . persistant [ PERS_TEAM ] )
{ //friendly
ecolor [ 0 ] = 0.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
}
else
{ //hostile
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 0.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
# ifdef _XBOX
cg_crossHairStatus = 1 ;
# endif
}
}
else
{ //unmanned
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
}
}
else
{
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 0.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
# ifdef _XBOX
cg_crossHairStatus = 1 ;
# endif
}
}
else if ( crossEnt - > currentState . teamowner ! = plTeam )
{ // on enemy team
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 0.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
# ifdef _XBOX
cg_crossHairStatus = 1 ;
# endif
}
else
{ //a friend
ecolor [ 0 ] = 0.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
}
}
else if ( crossEnt - > currentState . teamowner = = TEAM_RED
| | crossEnt - > currentState . teamowner = = TEAM_BLUE )
{
if ( cgs . gametype < GT_TEAM )
{ //not teamplay, just neutral then
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
}
else if ( crossEnt - > currentState . teamowner ! = cgs . clientinfo [ cg . snap - > ps . clientNum ] . team )
{ //on the enemy team
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 0.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
# ifdef _XBOX
cg_crossHairStatus = 1 ;
# endif
}
else
{ //on my team
ecolor [ 0 ] = 0.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
}
}
else if ( crossEnt - > currentState . owner = = cg . snap - > ps . clientNum | |
( cgs . gametype > = GT_TEAM & & crossEnt - > currentState . teamowner = = cgs . clientinfo [ cg . snap - > ps . clientNum ] . team ) )
{
ecolor [ 0 ] = 0.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
}
else if ( crossEnt - > currentState . teamowner = = 16 | |
( cgs . gametype > = GT_TEAM & & crossEnt - > currentState . teamowner & & crossEnt - > currentState . teamowner ! = cgs . clientinfo [ cg . snap - > ps . clientNum ] . team ) )
{
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 0.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
# ifdef _XBOX
cg_crossHairStatus = 1 ;
# endif
}
}
else if ( crossEnt - > currentState . eType = = ET_MOVER & & crossEnt - > currentState . bolt1 & & cg . predictedPlayerState . weapon = = WP_SABER )
{ //can push/pull this mover. Only show it if we're using the saber.
ecolor [ 0 ] = 0.2f ;
ecolor [ 1 ] = 0.5f ;
ecolor [ 2 ] = 1.0f ;
corona = qtrue ;
}
else if ( crossEnt - > currentState . eType = = ET_MOVER & & crossEnt - > currentState . teamowner )
{ //a team owns this - if it's my team green, if not red, if not teamplay then yellow
if ( cgs . gametype < GT_TEAM )
{
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
}
else if ( cg . predictedPlayerState . persistant [ PERS_TEAM ] ! = crossEnt - > currentState . teamowner )
{ //not my team
ecolor [ 0 ] = 1.0 ; //R
ecolor [ 1 ] = 0.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
# ifdef _XBOX
cg_crossHairStatus = 1 ;
# endif
}
else
{ //my team
ecolor [ 0 ] = 0.0 ; //R
ecolor [ 1 ] = 1.0 ; //G
ecolor [ 2 ] = 0.0 ; //B
}
}
else if ( crossEnt - > currentState . health )
{
if ( ! crossEnt - > currentState . teamowner | | cgs . gametype < GT_TEAM )
{ //not owned by a team or teamplay
ecolor [ 0 ] = 1.0f ;
ecolor [ 1 ] = 1.0f ;
ecolor [ 2 ] = 0.0f ;
}
else if ( crossEnt - > currentState . teamowner = = cg . predictedPlayerState . persistant [ PERS_TEAM ] )
{ //owned by my team
ecolor [ 0 ] = 0.0f ;
ecolor [ 1 ] = 1.0f ;
ecolor [ 2 ] = 0.0f ;
}
else
{ //hostile
ecolor [ 0 ] = 1.0f ;
ecolor [ 1 ] = 0.0f ;
ecolor [ 2 ] = 0.0f ;
# ifdef _XBOX
cg_crossHairStatus = 1 ;
# endif
}
}
ecolor [ 3 ] = 1.0 ;
trap_R_SetColor ( ecolor ) ;
}
}
if ( cg . predictedPlayerState . m_iVehicleNum )
{ //I'm in a vehicle
centity_t * vehCent = & cg_entities [ cg . predictedPlayerState . m_iVehicleNum ] ;
if ( vehCent
& & vehCent - > m_pVehicle
& & vehCent - > m_pVehicle - > m_pVehicleInfo
& & vehCent - > m_pVehicle - > m_pVehicleInfo - > crosshairShaderHandle )
{
hShader = vehCent - > m_pVehicle - > m_pVehicleInfo - > crosshairShaderHandle ;
}
//bigger by default
w = cg_crosshairSize . value * 2.0f ;
h = w ;
}
else
{
w = h = cg_crosshairSize . value ;
}
// pulse the size of the crosshair when picking up items
f = cg . time - cg . itemPickupBlendTime ;
if ( f > 0 & & f < ITEM_BLOB_TIME ) {
f / = ITEM_BLOB_TIME ;
w * = ( 1 + f ) ;
h * = ( 1 + f ) ;
}
if ( worldPoint & & VectorLength ( worldPoint ) )
{
if ( ! CG_WorldCoordToScreenCoordFloat ( worldPoint , & x , & y ) )
{ //off screen, don't draw it
return ;
}
//CG_LerpCrosshairPos( &x, &y );
x - = 320 ;
y - = 240 ;
}
else
{
x = cg_crosshairX . integer ;
y = cg_crosshairY . integer ;
}
if ( ! hShader )
{
hShader = cgs . media . crosshairShader [ cg_drawCrosshair . integer % NUM_CROSSHAIRS ] ;
}
chX = x + cg . refdef . x + 0.5 * ( 640 - w ) ;
chY = y + cg . refdef . y + 0.5 * ( 480 - h ) ;
trap_R_DrawStretchPic ( chX , chY , w , h , 0 , 0 , 1 , 1 , hShader ) ;
//draw a health bar directly under the crosshair if we're looking at something
//that takes damage
if ( crossEnt & &
crossEnt - > currentState . maxhealth )
{
CG_DrawHealthBar ( crossEnt , chX , chY , w , h ) ;
chY + = HEALTH_HEIGHT * 2 ;
}
else if ( crossEnt & & crossEnt - > currentState . number < MAX_CLIENTS )
{
if ( cgs . gametype = = GT_SIEGE )
{
CG_DrawSiegeInfo ( crossEnt , chX , chY , w , h ) ;
chY + = HEALTH_HEIGHT * 4 ;
}
if ( cg . crosshairVehNum & & cg . time = = cg . crosshairVehTime )
{ //it was in the crosshair this frame
centity_t * hisVeh = & cg_entities [ cg . crosshairVehNum ] ;
if ( hisVeh - > currentState . eType = = ET_NPC & &
hisVeh - > currentState . NPC_class = = CLASS_VEHICLE & &
hisVeh - > currentState . maxhealth & &
hisVeh - > m_pVehicle )
{ //draw the health for this vehicle
CG_DrawHealthBar ( hisVeh , chX , chY , w , h ) ;
chY + = HEALTH_HEIGHT * 2 ;
}
}
}
if ( cg . predictedPlayerState . hackingTime )
{ //hacking something
CG_DrawHaqrBar ( chX , chY , w , h ) ;
}
if ( cg_genericTimerBar > cg . time )
{ //draw generic timing bar, can be used for whatever
CG_DrawGenericTimerBar ( ) ;
}
if ( corona ) // drawing extra bits
{
ecolor [ 3 ] = 0.5f ;
ecolor [ 0 ] = ecolor [ 1 ] = ecolor [ 2 ] = ( 1 - ecolor [ 3 ] ) * ( sin ( cg . time * 0.001f ) * 0.08f + 0.35f ) ; // don't draw full color
ecolor [ 3 ] = 1.0f ;
trap_R_SetColor ( ecolor ) ;
w * = 2.0f ;
h * = 2.0f ;
trap_R_DrawStretchPic ( x + cg . refdef . x + 0.5 * ( 640 - w ) ,
y + cg . refdef . y + 0.5 * ( 480 - h ) ,
w , h , 0 , 0 , 1 , 1 , cgs . media . forceCoronaShader ) ;
}
}
qboolean CG_WorldCoordToScreenCoordFloat ( vec3_t worldCoord , float * x , float * y )
{
float xcenter , ycenter ;
vec3_t local , transformed ;
vec3_t vfwd ;
vec3_t vright ;
vec3_t vup ;
float xzi ;
float yzi ;
// xcenter = cg.refdef.width / 2;//gives screen coords adjusted for resolution
// ycenter = cg.refdef.height / 2;//gives screen coords adjusted for resolution
//NOTE: did it this way because most draw functions expect virtual 640x480 coords
// and adjust them for current resolution
xcenter = 640.0f / 2.0f ; //gives screen coords in virtual 640x480, to be adjusted when drawn
ycenter = 480.0f / 2.0f ; //gives screen coords in virtual 640x480, to be adjusted when drawn
AngleVectors ( cg . refdef . viewangles , vfwd , vright , vup ) ;
VectorSubtract ( worldCoord , cg . refdef . vieworg , local ) ;
transformed [ 0 ] = DotProduct ( local , vright ) ;
transformed [ 1 ] = DotProduct ( local , vup ) ;
transformed [ 2 ] = DotProduct ( local , vfwd ) ;
// Make sure Z is not negative.
if ( transformed [ 2 ] < 0.01f )
{
return qfalse ;
}
xzi = xcenter / transformed [ 2 ] * ( 96.0f / cg . refdef . fov_x ) ;
yzi = ycenter / transformed [ 2 ] * ( 102.0f / cg . refdef . fov_y ) ;
* x = xcenter + xzi * transformed [ 0 ] ;
* y = ycenter - yzi * transformed [ 1 ] ;
return qtrue ;
}
qboolean CG_WorldCoordToScreenCoord ( vec3_t worldCoord , int * x , int * y )
{
float xF , yF ;
qboolean retVal = CG_WorldCoordToScreenCoordFloat ( worldCoord , & xF , & yF ) ;
* x = ( int ) xF ;
* y = ( int ) yF ;
return retVal ;
}
/*
= = = = = = = = = = = = = = = = = = = =
CG_SaberClashFlare
= = = = = = = = = = = = = = = = = = = =
*/
int cg_saberFlashTime = 0 ;
vec3_t cg_saberFlashPos = { 0 , 0 , 0 } ;
void CG_SaberClashFlare ( void )
{
int t , maxTime = 150 ;
vec3_t dif ;
vec3_t color ;
int x , y ;
float v , len ;
trace_t tr ;
t = cg . time - cg_saberFlashTime ;
if ( t < = 0 | | t > = maxTime )
{
return ;
}
// Don't do clashes for things that are behind us
VectorSubtract ( cg_saberFlashPos , cg . refdef . vieworg , dif ) ;
if ( DotProduct ( dif , cg . refdef . viewaxis [ 0 ] ) < 0.2 )
{
return ;
}
CG_Trace ( & tr , cg . refdef . vieworg , NULL , NULL , cg_saberFlashPos , - 1 , CONTENTS_SOLID ) ;
if ( tr . fraction < 1.0f )
{
return ;
}
len = VectorNormalize ( dif ) ;
// clamp to a known range
/*
if ( len > 800 )
{
len = 800 ;
}
*/
if ( len > 1200 )
{
return ;
}
v = ( 1.0f - ( ( float ) t / maxTime ) ) * ( ( 1.0f - ( len / 800.0f ) ) * 2.0f + 0.35f ) ;
if ( v < 0.001f )
{
v = 0.001f ;
}
CG_WorldCoordToScreenCoord ( cg_saberFlashPos , & x , & y ) ;
VectorSet ( color , 0.8f , 0.8f , 0.8f ) ;
trap_R_SetColor ( color ) ;
CG_DrawPic ( x - ( v * 300 ) , y - ( v * 300 ) ,
v * 600 , v * 600 ,
trap_R_RegisterShader ( " gfx/effects/saberFlare " ) ) ;
}
void CG_DottedLine ( float x1 , float y1 , float x2 , float y2 , float dotSize , int numDots , vec4_t color , float alpha )
{
float x , y , xDiff , yDiff , xStep , yStep ;
vec4_t colorRGBA ;
int dotNum = 0 ;
VectorCopy4 ( color , colorRGBA ) ;
colorRGBA [ 3 ] = alpha ;
trap_R_SetColor ( colorRGBA ) ;
xDiff = x2 - x1 ;
yDiff = y2 - y1 ;
xStep = xDiff / ( float ) numDots ;
yStep = yDiff / ( float ) numDots ;
for ( dotNum = 0 ; dotNum < numDots ; dotNum + + )
{
x = x1 + ( xStep * dotNum ) - ( dotSize * 0.5f ) ;
y = y1 + ( yStep * dotNum ) - ( dotSize * 0.5f ) ;
CG_DrawPic ( x , y , dotSize , dotSize , cgs . media . whiteShader ) ;
}
}
void CG_BracketEntity ( centity_t * cent , float radius )
{
trace_t tr ;
vec3_t dif ;
float len , size , lineLength , lineWidth ;
float x , y ;
clientInfo_t * local ;
qboolean isEnemy = qfalse ;
VectorSubtract ( cent - > lerpOrigin , cg . refdef . vieworg , dif ) ;
len = VectorNormalize ( dif ) ;
if ( cg . crosshairClientNum ! = cent - > currentState . clientNum
& & ( ! cg . snap | | cg . snap - > ps . rocketLockIndex ! = cent - > currentState . clientNum ) )
{ //if they're the entity you're locking onto or under your crosshair, always draw bracket
//Hmm... for now, if they're closer than 2000, don't bracket?
if ( len < 2000.0f )
{
return ;
}
CG_Trace ( & tr , cg . refdef . vieworg , NULL , NULL , cent - > lerpOrigin , - 1 , CONTENTS_OPAQUE ) ;
//don't bracket if can't see them
if ( tr . fraction < 1.0f )
{
return ;
}
}
if ( ! CG_WorldCoordToScreenCoordFloat ( cent - > lerpOrigin , & x , & y ) )
{ //off-screen, don't draw it
return ;
}
//just to see if it's centered
//CG_DrawPic( x-2, y-2, 4, 4, cgs.media.whiteShader );
local = & cgs . clientinfo [ cg . snap - > ps . clientNum ] ;
if ( cent - > currentState . m_iVehicleNum //vehicle has a driver
& & cgs . clientinfo [ cent - > currentState . m_iVehicleNum - 1 ] . infoValid )
{
if ( cgs . gametype < GT_TEAM )
{ //ffa?
isEnemy = qtrue ;
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_RED ) ] ) ;
}
else if ( cgs . clientinfo [ cent - > currentState . m_iVehicleNum - 1 ] . team = = local - > team )
{
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_GREEN ) ] ) ;
}
else
{
isEnemy = qtrue ;
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_RED ) ] ) ;
}
}
else if ( cent - > currentState . teamowner )
{
if ( cgs . gametype < GT_TEAM )
{ //ffa?
isEnemy = qtrue ;
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_RED ) ] ) ;
}
else if ( cent - > currentState . teamowner ! = cg . predictedPlayerState . persistant [ PERS_TEAM ] )
{ // on enemy team
isEnemy = qtrue ;
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_RED ) ] ) ;
}
else
{ //a friend
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_GREEN ) ] ) ;
}
}
else
{ //FIXME: if we want to ever bracket anything besides vehicles (like siege objectives we want to blow up), we should handle the coloring here
trap_R_SetColor ( NULL ) ;
}
if ( len < = 1.0f )
{ //super-close, max out at 400 times radius (which is HUGE)
size = radius * 400.0f ;
}
else
{ //scale by dist
size = radius * ( 400.0f / len ) ;
}
if ( size < 1.0f )
{
size = 1.0f ;
}
//length scales with dist
lineLength = ( size * 0.1f ) ;
if ( lineLength < 0.5f )
{ //always visible
lineLength = 0.5f ;
}
//always visible width
lineWidth = 1.0f ;
x - = ( size * 0.5f ) ;
y - = ( size * 0.5f ) ;
/*
if ( x > = 0 & & x < = 640
& & y > = 0 & & y < = 480 )
*/
{ //brackets would be drawn on the screen, so draw them
//upper left corner
//horz
CG_DrawPic ( x , y , lineLength , lineWidth , cgs . media . whiteShader ) ;
//vert
CG_DrawPic ( x , y , lineWidth , lineLength , cgs . media . whiteShader ) ;
//upper right corner
//horz
CG_DrawPic ( x + size - lineLength , y , lineLength , lineWidth , cgs . media . whiteShader ) ;
//vert
CG_DrawPic ( x + size - lineWidth , y , lineWidth , lineLength , cgs . media . whiteShader ) ;
//lower left corner
//horz
CG_DrawPic ( x , y + size - lineWidth , lineLength , lineWidth , cgs . media . whiteShader ) ;
//vert
CG_DrawPic ( x , y + size - lineLength , lineWidth , lineLength , cgs . media . whiteShader ) ;
//lower right corner
//horz
CG_DrawPic ( x + size - lineLength , y + size - lineWidth , lineLength , lineWidth , cgs . media . whiteShader ) ;
//vert
CG_DrawPic ( x + size - lineWidth , y + size - lineLength , lineWidth , lineLength , cgs . media . whiteShader ) ;
}
//Lead Indicator...
if ( cg_drawVehLeadIndicator . integer )
{ //draw the lead indicator
if ( isEnemy )
{ //an enemy object
if ( cent - > currentState . NPC_class = = CLASS_VEHICLE )
{ //enemy vehicle
if ( ! VectorCompare ( cent - > currentState . pos . trDelta , vec3_origin ) )
{ //enemy vehicle is moving
if ( cg . predictedPlayerState . m_iVehicleNum )
{ //I'm in a vehicle
centity_t * veh = & cg_entities [ cg . predictedPlayerState . m_iVehicleNum ] ;
if ( veh //vehicle cent
& & veh - > m_pVehicle //vehicle
& & veh - > m_pVehicle - > m_pVehicleInfo //vehicle stats
& & veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 0 ] . ID > VEH_WEAPON_BASE ) //valid vehicle weapon
{
vehWeaponInfo_t * vehWeapon = & g_vehWeaponInfo [ veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 0 ] . ID ] ;
if ( vehWeapon
& & vehWeapon - > bIsProjectile //primary weapon's shot is a projectile
& & ! vehWeapon - > bHasGravity //primary weapon's shot is not affected by gravity
& & ! vehWeapon - > fHoming //primary weapon's shot is not homing
& & vehWeapon - > fSpeed ) //primary weapon's shot has speed
{ //our primary weapon's projectile has a speed
vec3_t vehDiff , vehLeadPos ;
float vehDist , eta ;
float leadX , leadY ;
VectorSubtract ( cent - > lerpOrigin , cg . predictedVehicleState . origin , vehDiff ) ;
vehDist = VectorNormalize ( vehDiff ) ;
eta = ( vehDist / vehWeapon - > fSpeed ) ; //how many seconds it would take for my primary weapon's projectile to get from my ship to theirs
//now extrapolate their position that number of seconds into the future based on their velocity
VectorMA ( cent - > lerpOrigin , eta , cent - > currentState . pos . trDelta , vehLeadPos ) ;
//now we have where we should be aiming at, project that onto the screen at a 2D co-ord
if ( ! CG_WorldCoordToScreenCoordFloat ( cent - > lerpOrigin , & x , & y ) )
{ //off-screen, don't draw it
return ;
}
if ( ! CG_WorldCoordToScreenCoordFloat ( vehLeadPos , & leadX , & leadY ) )
{ //off-screen, don't draw it
//just draw the line
CG_DottedLine ( x , y , leadX , leadY , 1 , 10 , g_color_table [ ColorIndex ( COLOR_RED ) ] , 0.5f ) ;
return ;
}
//draw a line from the ship's cur pos to the lead pos
CG_DottedLine ( x , y , leadX , leadY , 1 , 10 , g_color_table [ ColorIndex ( COLOR_RED ) ] , 0.5f ) ;
//now draw the lead indicator
trap_R_SetColor ( g_color_table [ ColorIndex ( COLOR_RED ) ] ) ;
CG_DrawPic ( leadX - 8 , leadY - 8 , 16 , 16 , trap_R_RegisterShader ( " gfx/menus/radar/lead " ) ) ;
}
}
}
}
}
}
}
}
qboolean CG_InFighter ( void )
{
if ( cg . predictedPlayerState . m_iVehicleNum )
{ //I'm in a vehicle
centity_t * vehCent = & cg_entities [ cg . predictedPlayerState . m_iVehicleNum ] ;
if ( vehCent
& & vehCent - > m_pVehicle
& & vehCent - > m_pVehicle - > m_pVehicleInfo
& & vehCent - > m_pVehicle - > m_pVehicleInfo - > type = = VH_FIGHTER )
{ //I'm in a fighter
return qtrue ;
}
}
return qfalse ;
}
qboolean CG_InATST ( void )
{
if ( cg . predictedPlayerState . m_iVehicleNum )
{ //I'm in a vehicle
centity_t * vehCent = & cg_entities [ cg . predictedPlayerState . m_iVehicleNum ] ;
if ( vehCent
& & vehCent - > m_pVehicle
& & vehCent - > m_pVehicle - > m_pVehicleInfo
& & vehCent - > m_pVehicle - > m_pVehicleInfo - > type = = VH_WALKER )
{ //I'm in an atst
return qtrue ;
}
}
return qfalse ;
}
void CG_DrawBracketedEntities ( void )
{
int i ;
for ( i = 0 ; i < cg . bracketedEntityCount ; i + + )
{
centity_t * cent = & cg_entities [ cg . bracketedEntities [ i ] ] ;
CG_BracketEntity ( cent , CG_RadiusForCent ( cent ) ) ;
}
}
//--------------------------------------------------------------
static void CG_DrawHolocronIcons ( void )
//--------------------------------------------------------------
{
int icon_size = 40 ;
int i = 0 ;
int startx = 10 ;
int starty = 10 ; //SCREEN_HEIGHT - icon_size*3;
int endx = icon_size ;
int endy = icon_size ;
if ( cg . snap - > ps . zoomMode )
{ //don't display over zoom mask
return ;
}
if ( cgs . clientinfo [ cg . snap - > ps . clientNum ] . team = = TEAM_SPECTATOR )
{
return ;
}
while ( i < NUM_FORCE_POWERS )
{
if ( cg . snap - > ps . holocronBits & ( 1 < < forcePowerSorted [ i ] ) )
{
CG_DrawPic ( startx , starty , endx , endy , cgs . media . forcePowerIcons [ forcePowerSorted [ i ] ] ) ;
starty + = ( icon_size + 2 ) ; //+2 for spacing
if ( ( starty + icon_size ) > = SCREEN_HEIGHT - 80 )
{
starty = 10 ; //SCREEN_HEIGHT - icon_size*3;
startx + = ( icon_size + 2 ) ;
}
}
i + + ;
}
}
static qboolean CG_IsDurationPower ( int power )
{
if ( power = = FP_HEAL | |
power = = FP_SPEED | |
power = = FP_TELEPATHY | |
power = = FP_RAGE | |
power = = FP_PROTECT | |
power = = FP_ABSORB | |
power = = FP_SEE )
{
return qtrue ;
}
return qfalse ;
}
//--------------------------------------------------------------
static void CG_DrawActivePowers ( void )
//--------------------------------------------------------------
{
int icon_size = 40 ;
int i = 0 ;
int startx = icon_size * 2 + 16 ;
int starty = SCREEN_HEIGHT - icon_size * 2 ;
int endx = icon_size ;
int endy = icon_size ;
if ( cg . snap - > ps . zoomMode )
{ //don't display over zoom mask
return ;
}
if ( cgs . clientinfo [ cg . snap - > ps . clientNum ] . team = = TEAM_SPECTATOR )
{
return ;
}
while ( i < NUM_FORCE_POWERS )
{
if ( ( cg . snap - > ps . fd . forcePowersActive & ( 1 < < forcePowerSorted [ i ] ) ) & &
CG_IsDurationPower ( forcePowerSorted [ i ] ) )
{
CG_DrawPic ( startx , starty , endx , endy , cgs . media . forcePowerIcons [ forcePowerSorted [ i ] ] ) ;
startx + = ( icon_size + 2 ) ; //+2 for spacing
if ( ( startx + icon_size ) > = SCREEN_WIDTH - 80 )
{
startx = icon_size * 2 + 16 ;
starty + = ( icon_size + 2 ) ;
}
}
i + + ;
}
//additionally, draw an icon force force rage recovery
if ( cg . snap - > ps . fd . forceRageRecoveryTime > cg . time )
{
CG_DrawPic ( startx , starty , endx , endy , cgs . media . rageRecShader ) ;
}
}
//static qboolean cg_drawingRocketLockThisFrame = qfalse;
//--------------------------------------------------------------
static void CG_DrawRocketLocking ( int lockEntNum , int lockTime )
//--------------------------------------------------------------
{
int cx , cy ;
vec3_t org ;
static int oldDif = 0 ;
centity_t * cent = & cg_entities [ lockEntNum ] ;
vec4_t color = { 0.0f , 0.0f , 0.0f , 0.0f } ;
float lockTimeInterval = ( ( cgs . gametype = = GT_SIEGE ) ? 2400.0f : 1200.0f ) / 16.0f ;
//FIXME: if in a vehicle, use the vehicle's lockOnTime...
int dif = ( cg . time - cg . snap - > ps . rocketLockTime ) / lockTimeInterval ;
int i ;
// cg_drawingRocketLockThisFrame = qfalse;
if ( ! cg . snap - > ps . rocketLockTime )
{
return ;
}
if ( cgs . clientinfo [ cg . snap - > ps . clientNum ] . team = = TEAM_SPECTATOR )
{
return ;
}
if ( cg . snap - > ps . m_iVehicleNum )
{ //driving a vehicle
centity_t * veh = & cg_entities [ cg . snap - > ps . m_iVehicleNum ] ;
if ( veh - > m_pVehicle )
{
vehWeaponInfo_t * vehWeapon = NULL ;
if ( cg . predictedVehicleState . weaponstate = = WEAPON_CHARGING_ALT )
{
if ( veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 1 ] . ID > VEH_WEAPON_BASE
& & veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 1 ] . ID < MAX_VEH_WEAPONS )
{
vehWeapon = & g_vehWeaponInfo [ veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 1 ] . ID ] ;
}
}
else
{
if ( veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 0 ] . ID > VEH_WEAPON_BASE
& & veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 0 ] . ID < MAX_VEH_WEAPONS )
{
vehWeapon = & g_vehWeaponInfo [ veh - > m_pVehicle - > m_pVehicleInfo - > weapon [ 0 ] . ID ] ;
}
}
if ( vehWeapon ! = NULL )
{ //we are trying to lock on with a valid vehicle weapon, so use *its* locktime, not the hard-coded one
if ( ! vehWeapon - > iLockOnTime )
{ //instant lock-on
dif = 10.0f ;
}
else
{ //use the custom vehicle lockOnTime
lockTimeInterval = ( vehWeapon - > iLockOnTime / 16.0f ) ;
dif = ( cg . time - cg . snap - > ps . rocketLockTime ) / lockTimeInterval ;
}
}
}
}
//We can't check to see in pmove if players are on the same team, so we resort
//to just not drawing the lock if a teammate is the locked on ent
if ( cg . snap - > ps . rocketLockIndex > = 0 & &
cg . snap - > ps . rocketLockIndex < ENTITYNUM_NONE )
{
clientInfo_t * ci = NULL ;
if ( cg . snap - > ps . rocketLockIndex < MAX_CLIENTS )
{
ci = & cgs . clientinfo [ cg . snap - > ps . rocketLockIndex ] ;
}
else
{
ci = cg_entities [ cg . snap - > ps . rocketLockIndex ] . npcClient ;
}
if ( ci )
{
if ( ci - > team = = cgs . clientinfo [ cg . snap - > ps . clientNum ] . team )
{
if ( cgs . gametype > = GT_TEAM )
{
return ;
}
}
else if ( cgs . gametype > = GT_TEAM )
{
centity_t * hitEnt = & cg_entities [ cg . snap - > ps . rocketLockIndex ] ;
if ( hitEnt - > currentState . eType = = ET_NPC & &
hitEnt - > currentState . NPC_class = = CLASS_VEHICLE & &
hitEnt - > currentState . owner < ENTITYNUM_WORLD )
{ //this is a vehicle, if it has a pilot and that pilot is on my team, then...
if ( hitEnt - > currentState . owner < MAX_CLIENTS )
{
ci = & cgs . clientinfo [ hitEnt - > currentState . owner ] ;
}
else
{
ci = cg_entities [ hitEnt - > currentState . owner ] . npcClient ;
}
if ( ci & & ci - > team = = cgs . clientinfo [ cg . snap - > ps . clientNum ] . team )
{
return ;
}
}
}
}
}
if ( cg . snap - > ps . rocketLockTime ! = - 1 )
{
lastvalidlockdif = dif ;
}
else
{
dif = lastvalidlockdif ;
}
if ( ! cent )
{
return ;
}
VectorCopy ( cent - > lerpOrigin , org ) ;
if ( CG_WorldCoordToScreenCoord ( org , & cx , & cy ) )
{
// we care about distance from enemy to eye, so this is good enough
float sz = Distance ( cent - > lerpOrigin , cg . refdef . vieworg ) / 1024.0f ;
if ( sz > 1.0f )
{
sz = 1.0f ;
}
else if ( sz < 0.0f )
{
sz = 0.0f ;
}
sz = ( 1.0f - sz ) * ( 1.0f - sz ) * 32 + 6 ;
if ( cg . snap - > ps . m_iVehicleNum )
{
sz * = 2.0f ;
}
cy + = sz * 0.5f ;
if ( dif < 0 )
{
oldDif = 0 ;
return ;
}
else if ( dif > 8 )
{
dif = 8 ;
}
// do sounds
if ( oldDif ! = dif )
{
if ( dif = = 8 )
{
if ( cg . snap - > ps . m_iVehicleNum )
{
trap_S_StartSound ( org , 0 , CHAN_AUTO , trap_S_RegisterSound ( " sound/vehicles/weapons/common/lock.wav " ) ) ;
}
else
{
trap_S_StartSound ( org , 0 , CHAN_AUTO , trap_S_RegisterSound ( " sound/weapons/rocket/lock.wav " ) ) ;
}
}
else
{
if ( cg . snap - > ps . m_iVehicleNum )
{
trap_S_StartSound ( org , 0 , CHAN_AUTO , trap_S_RegisterSound ( " sound/vehicles/weapons/common/tick.wav " ) ) ;
}
else
{
trap_S_StartSound ( org , 0 , CHAN_AUTO , trap_S_RegisterSound ( " sound/weapons/rocket/tick.wav " ) ) ;
}
}
}
oldDif = dif ;
for ( i = 0 ; i < dif ; i + + )
{
color [ 0 ] = 1.0f ;
color [ 1 ] = 0.0f ;
color [ 2 ] = 0.0f ;
color [ 3 ] = 0.1f * i + 0.2f ;
trap_R_SetColor ( color ) ;
// our slices are offset by about 45 degrees.
CG_DrawRotatePic ( cx - sz , cy - sz , sz , sz , i * 45.0f , trap_R_RegisterShaderNoMip ( " gfx/2d/wedge " ) ) ;
}
// we are locked and loaded baby
if ( dif = = 8 )
{
color [ 0 ] = color [ 1 ] = color [ 2 ] = sin ( cg . time * 0.05f ) * 0.5f + 0.5f ;
color [ 3 ] = 1.0f ; // this art is additive, so the alpha value does nothing
trap_R_SetColor ( color ) ;
CG_DrawPic ( cx - sz , cy - sz * 2 , sz * 2 , sz * 2 , trap_R_RegisterShaderNoMip ( " gfx/2d/lock " ) ) ;
}
// cg_drawingRocketLockThisFrame = qtrue;
}
}
extern void CG_CalcVehMuzzle ( Vehicle_t * pVeh , centity_t * ent , int muzzleNum ) ;
qboolean CG_CalcVehicleMuzzlePoint ( int entityNum , vec3_t start , vec3_t d_f , vec3_t d_rt , vec3_t d_up )
{
centity_t * vehCent = & cg_entities [ entityNum ] ;
if ( vehCent - > m_pVehicle & & vehCent - > m_pVehicle - > m_pVehicleInfo - > type = = VH_WALKER )
{ //draw from barrels
VectorCopy ( vehCent - > lerpOrigin , start ) ;
start [ 2 ] + = vehCent - > m_pVehicle - > m_pVehicleInfo - > height - DEFAULT_MINS_2 - 48 ;
AngleVectors ( vehCent - > lerpAngles , d_f , d_rt , d_up ) ;
/*
mdxaBone_t boltMatrix ;
int bolt ;
vec3_t yawOnlyAngles ;
VectorSet ( yawOnlyAngles , 0 , vehCent - > lerpAngles [ YAW ] , 0 ) ;
bolt = trap_G2API_AddBolt ( vehCent - > ghoul2 , 0 , " *flash1 " ) ;
trap_G2API_GetBoltMatrix ( vehCent - > ghoul2 , 0 , bolt , & boltMatrix ,
yawOnlyAngles , vehCent - > lerpOrigin , cg . time ,
NULL , vehCent - > modelScale ) ;
// work the matrix axis stuff into the original axis and origins used.
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , start ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , POSITIVE_X , d_f ) ;
VectorClear ( d_rt ) ; //don't really need this, do we?
VectorClear ( d_up ) ; //don't really need this, do we?
*/
}
else
{
//check to see if we're a turret gunner on this vehicle
if ( cg . predictedPlayerState . generic1 ) //as a passenger
{ //passenger in a vehicle
if ( vehCent - > m_pVehicle
& & vehCent - > m_pVehicle - > m_pVehicleInfo
& & vehCent - > m_pVehicle - > m_pVehicleInfo - > maxPassengers )
{ //a vehicle capable of carrying passengers
int turretNum ;
for ( turretNum = 0 ; turretNum < MAX_VEHICLE_TURRETS ; turretNum + + )
{
if ( vehCent - > m_pVehicle - > m_pVehicleInfo - > turret [ turretNum ] . iAmmoMax )
{ // valid turret
if ( vehCent - > m_pVehicle - > m_pVehicleInfo - > turret [ turretNum ] . passengerNum = = cg . predictedPlayerState . generic1 )
{ //I control this turret
//Go through all muzzles, average their positions and directions and use the result for crosshair trace
int vehMuzzle , numMuzzles = 0 ;
vec3_t muzzlesAvgPos = { 0 } , muzzlesAvgDir = { 0 } ;
int i ;
for ( i = 0 ; i < MAX_VEHICLE_TURRET_MUZZLES ; i + + )
{
vehMuzzle = vehCent - > m_pVehicle - > m_pVehicleInfo - > turret [ turretNum ] . iMuzzle [ i ] ;
if ( vehMuzzle )
{
vehMuzzle - = 1 ;
CG_CalcVehMuzzle ( vehCent - > m_pVehicle , vehCent , vehMuzzle ) ;
VectorAdd ( muzzlesAvgPos , vehCent - > m_pVehicle - > m_vMuzzlePos [ vehMuzzle ] , muzzlesAvgPos ) ;
VectorAdd ( muzzlesAvgDir , vehCent - > m_pVehicle - > m_vMuzzleDir [ vehMuzzle ] , muzzlesAvgDir ) ;
numMuzzles + + ;
}
if ( numMuzzles )
{
VectorScale ( muzzlesAvgPos , 1.0f / ( float ) numMuzzles , start ) ;
VectorScale ( muzzlesAvgDir , 1.0f / ( float ) numMuzzles , d_f ) ;
VectorClear ( d_rt ) ;
VectorClear ( d_up ) ;
return qtrue ;
}
}
}
}
}
}
}
VectorCopy ( vehCent - > lerpOrigin , start ) ;
AngleVectors ( vehCent - > lerpAngles , d_f , d_rt , d_up ) ;
}
return qfalse ;
}
//calc the muzzle point from the e-web itself
void CG_CalcEWebMuzzlePoint ( centity_t * cent , vec3_t start , vec3_t d_f , vec3_t d_rt , vec3_t d_up )
{
int bolt = trap_G2API_AddBolt ( cent - > ghoul2 , 0 , " *cannonflash " ) ;
assert ( bolt ! = - 1 ) ;
if ( bolt ! = - 1 )
{
mdxaBone_t boltMatrix ;
trap_G2API_GetBoltMatrix_NoRecNoRot ( cent - > ghoul2 , 0 , bolt , & boltMatrix , cent - > lerpAngles , cent - > lerpOrigin , cg . time , NULL , cent - > modelScale ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , ORIGIN , start ) ;
BG_GiveMeVectorFromMatrix ( & boltMatrix , NEGATIVE_X , d_f ) ;
//these things start the shot a little inside the bbox to assure not starting in something solid
VectorMA ( start , - 16.0f , d_f , start ) ;
//I guess
VectorClear ( d_rt ) ; //don't really need this, do we?
VectorClear ( d_up ) ; //don't really need this, do we?
}
}
/*
= = = = = = = = = = = = = = = = =
CG_ ` Entity
= = = = = = = = = = = = = = = = =
*/
# define MAX_XHAIR_DIST_ACCURACY 20000.0f
static void CG_ScanForCrosshairEntity ( void ) {
trace_t trace ;
vec3_t start , end ;
int content ;
int ignore ;
qboolean bVehCheckTraceFromCamPos = qfalse ;
ignore = cg . predictedPlayerState . clientNum ;
if ( cg_dynamicCrosshair . integer )
{
vec3_t d_f , d_rt , d_up ;
/*
if ( cg . snap - > ps . weapon = = WP_NONE | |
cg . snap - > ps . weapon = = WP_SABER | |
cg . snap - > ps . weapon = = WP_STUN_BATON )
{
VectorCopy ( cg . refdef . vieworg , start ) ;
AngleVectors ( cg . refdef . viewangles , d_f , d_rt , d_up ) ;
}
else
*/
//For now we still want to draw the crosshair in relation to the player's world coordinates
//even if we have a melee weapon/no weapon.
if ( cg . predictedPlayerState . m_iVehicleNum & & ( cg . predictedPlayerState . eFlags & EF_NODRAW ) )
{ //we're *inside* a vehicle
//do the vehicle's crosshair instead
centity_t * veh = & cg_entities [ cg . predictedPlayerState . m_iVehicleNum ] ;
qboolean gunner = qfalse ;
//if (veh->currentState.owner == cg.predictedPlayerState.clientNum)
{ //the pilot
ignore = cg . predictedPlayerState . m_iVehicleNum ;
gunner = CG_CalcVehicleMuzzlePoint ( cg . predictedPlayerState . m_iVehicleNum , start , d_f , d_rt , d_up ) ;
}
/*
else
{ //a passenger
ignore = cg . predictedPlayerState . m_iVehicleNum ;
VectorCopy ( veh - > lerpOrigin , start ) ;
AngleVectors ( veh - > lerpAngles , d_f , d_rt , d_up ) ;
VectorMA ( start , 32.0f , d_f , start ) ; //super hack
}
*/
if ( veh - > m_pVehicle
& & veh - > m_pVehicle - > m_pVehicleInfo
& & veh - > m_pVehicle - > m_pVehicleInfo - > type = = VH_FIGHTER
& & cg . distanceCull > MAX_XHAIR_DIST_ACCURACY
& & ! gunner )
{
//NOTE: on huge maps, the crosshair gets inaccurate at close range,
// so we'll do an extra G2 trace from the cg.refdef.vieworg
// to see if we hit anything closer and auto-aim at it if so
bVehCheckTraceFromCamPos = qtrue ;
}
}
else if ( cg . snap & & cg . snap - > ps . weapon = = WP_EMPLACED_GUN & & cg . snap - > ps . emplacedIndex & &
cg_entities [ cg . snap - > ps . emplacedIndex ] . ghoul2 & & cg_entities [ cg . snap - > ps . emplacedIndex ] . currentState . weapon = = WP_NONE )
{ //locked into our e-web, calc the muzzle from it
CG_CalcEWebMuzzlePoint ( & cg_entities [ cg . snap - > ps . emplacedIndex ] , start , d_f , d_rt , d_up ) ;
}
else
{
if ( cg . snap & & cg . snap - > ps . weapon = = WP_EMPLACED_GUN & & cg . snap - > ps . emplacedIndex )
{
vec3_t pitchConstraint ;
ignore = cg . snap - > ps . emplacedIndex ;
VectorCopy ( cg . refdef . viewangles , pitchConstraint ) ;
if ( cg . renderingThirdPerson )
{
VectorCopy ( cg . predictedPlayerState . viewangles , pitchConstraint ) ;
}
else
{
VectorCopy ( cg . refdef . viewangles , pitchConstraint ) ;
}
if ( pitchConstraint [ PITCH ] > 40 )
{
pitchConstraint [ PITCH ] = 40 ;
}
AngleVectors ( pitchConstraint , d_f , d_rt , d_up ) ;
}
else
{
vec3_t pitchConstraint ;
if ( cg . renderingThirdPerson )
{
VectorCopy ( cg . predictedPlayerState . viewangles , pitchConstraint ) ;
}
else
{
VectorCopy ( cg . refdef . viewangles , pitchConstraint ) ;
}
AngleVectors ( pitchConstraint , d_f , d_rt , d_up ) ;
}
CG_CalcMuzzlePoint ( cg . snap - > ps . clientNum , start ) ;
}
VectorMA ( start , cg . distanceCull , d_f , end ) ;
}
else
{
VectorCopy ( cg . refdef . vieworg , start ) ;
VectorMA ( start , 131072 , cg . refdef . viewaxis [ 0 ] , end ) ;
}
if ( cg_dynamicCrosshair . integer & & cg_dynamicCrosshairPrecision . integer )
{ //then do a trace with ghoul2 models in mind
CG_G2Trace ( & trace , start , vec3_origin , vec3_origin , end ,
ignore , CONTENTS_SOLID | CONTENTS_BODY ) ;
if ( bVehCheckTraceFromCamPos )
{
//NOTE: this MUST stay up to date with the method used in WP_VehCheckTraceFromCamPos
centity_t * veh = & cg_entities [ cg . predictedPlayerState . m_iVehicleNum ] ;
trace_t extraTrace ;
vec3_t viewDir2End , extraEnd ;
float minAutoAimDist = Distance ( veh - > lerpOrigin , cg . refdef . vieworg ) + ( veh - > m_pVehicle - > m_pVehicleInfo - > length / 2.0f ) + 200.0f ;
VectorSubtract ( end , cg . refdef . vieworg , viewDir2End ) ;
VectorNormalize ( viewDir2End ) ;
VectorMA ( cg . refdef . vieworg , MAX_XHAIR_DIST_ACCURACY , viewDir2End , extraEnd ) ;
CG_G2Trace ( & extraTrace , cg . refdef . vieworg , vec3_origin , vec3_origin , extraEnd ,
ignore , CONTENTS_SOLID | CONTENTS_BODY ) ;
if ( ! extraTrace . allsolid
& & ! extraTrace . startsolid )
{
if ( extraTrace . fraction < 1.0f )
{
if ( ( extraTrace . fraction * MAX_XHAIR_DIST_ACCURACY ) > minAutoAimDist )
{
if ( ( ( extraTrace . fraction * MAX_XHAIR_DIST_ACCURACY ) - Distance ( veh - > lerpOrigin , cg . refdef . vieworg ) ) < ( trace . fraction * cg . distanceCull ) )
{ //this trace hit *something* that's closer than the thing the main trace hit, so use this result instead
memcpy ( & trace , & extraTrace , sizeof ( trace_t ) ) ;
}
}
}
}
}
}
else
{
CG_Trace ( & trace , start , vec3_origin , vec3_origin , end ,
ignore , CONTENTS_SOLID | CONTENTS_BODY ) ;
}
if ( trace . entityNum < MAX_CLIENTS )
{
if ( CG_IsMindTricked ( cg_entities [ trace . entityNum ] . currentState . trickedentindex ,
cg_entities [ trace . entityNum ] . currentState . trickedentindex2 ,
cg_entities [ trace . entityNum ] . currentState . trickedentindex3 ,
cg_entities [ trace . entityNum ] . currentState . trickedentindex4 ,
cg . snap - > ps . clientNum ) )
{
if ( cg . crosshairClientNum = = trace . entityNum )
{
cg . crosshairClientNum = ENTITYNUM_NONE ;
cg . crosshairClientTime = 0 ;
}
CG_DrawCrosshair ( trace . endpos , 0 ) ;
return ; //this entity is mind-tricking the current client, so don't render it
}
}
if ( cg . snap - > ps . persistant [ PERS_TEAM ] ! = TEAM_SPECTATOR )
{
if ( trace . entityNum < /*MAX_CLIENTS*/ ENTITYNUM_WORLD )
{
cg . crosshairClientNum = trace . entityNum ;
cg . crosshairClientTime = cg . time ;
if ( cg . crosshairClientNum < ENTITYNUM_WORLD )
{
centity_t * veh = & cg_entities [ cg . crosshairClientNum ] ;
if ( veh - > currentState . eType = = ET_NPC & &
veh - > currentState . NPC_class = = CLASS_VEHICLE & &
veh - > currentState . owner < MAX_CLIENTS )
{ //draw the name of the pilot then
cg . crosshairClientNum = veh - > currentState . owner ;
cg . crosshairVehNum = veh - > currentState . number ;
cg . crosshairVehTime = cg . time ;
}
}
CG_DrawCrosshair ( trace . endpos , 1 ) ;
}
else
{
CG_DrawCrosshair ( trace . endpos , 0 ) ;
}
}
// if ( trace.entityNum >= MAX_CLIENTS ) {
// return;
// }
// if the player is in fog, don't show it
content = trap_CM_PointContents ( trace . endpos , 0 ) ;
if ( content & CONTENTS_FOG ) {
return ;
}
// update the fade timer
cg . crosshairClientNum = trace . entityNum ;
cg . crosshairClientTime = cg . time ;
}
void CG_SanitizeString ( char * in , char * out )
{
int i = 0 ;
int r = 0 ;
while ( in [ i ] )
{
if ( i > = 128 - 1 )
{ //the ui truncates the name here..
break ;
}
if ( in [ i ] = = ' ^ ' )
{
if ( in [ i + 1 ] > = 48 & & //'0'
in [ i + 1 ] < = 57 ) //'9'
{ //only skip it if there's a number after it for the color
i + = 2 ;
continue ;
}
else
{ //just skip the ^
i + + ;
continue ;
}
}
if ( in [ i ] < 32 )
{
i + + ;
continue ;
}
out [ r ] = in [ i ] ;
r + + ;
i + + ;
}
out [ r ] = 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = =
CG_DrawCrosshairNames
= = = = = = = = = = = = = = = = = = = = =
*/
static void CG_DrawCrosshairNames ( void ) {
float * color ;
vec4_t tcolor ;
char * name ;
char sanitized [ 1024 ] ;
int baseColor ;
qboolean isVeh = qfalse ;
if ( ! cg_drawCrosshair . integer ) {
return ;
}
// scan the known entities to see if the crosshair is sighted on one
CG_ScanForCrosshairEntity ( ) ;
if ( ! cg_drawCrosshairNames . integer ) {
return ;
}
//rww - still do the trace, our dynamic crosshair depends on it
if ( cg . crosshairClientNum < ENTITYNUM_WORLD )
{
centity_t * veh = & cg_entities [ cg . crosshairClientNum ] ;
if ( veh - > currentState . eType = = ET_NPC & &
veh - > currentState . NPC_class = = CLASS_VEHICLE & &
veh - > currentState . owner < MAX_CLIENTS )
{ //draw the name of the pilot then
cg . crosshairClientNum = veh - > currentState . owner ;
cg . crosshairVehNum = veh - > currentState . number ;
cg . crosshairVehTime = cg . time ;
isVeh = qtrue ; //so we know we're drawing the pilot's name
}
}
if ( cg . crosshairClientNum > = MAX_CLIENTS )
{
return ;
}
if ( cg_entities [ cg . crosshairClientNum ] . currentState . powerups & ( 1 < < PW_CLOAKED ) )
{
return ;
}
// draw the name of the player being looked at
color = CG_FadeColor ( cg . crosshairClientTime , 1000 ) ;
if ( ! color ) {
trap_R_SetColor ( NULL ) ;
return ;
}
name = cgs . clientinfo [ cg . crosshairClientNum ] . name ;
if ( cgs . gametype > = GT_TEAM )
{
//if (cgs.gametype == GT_SIEGE)
if ( 1 )
{ //instead of team-based we'll make it oriented based on which team we're on
if ( cgs . clientinfo [ cg . crosshairClientNum ] . team = = cg . predictedPlayerState . persistant [ PERS_TEAM ] )
{
baseColor = CT_GREEN ;
}
else
{
baseColor = CT_RED ;
}
}
else
{
if ( cgs . clientinfo [ cg . crosshairClientNum ] . team = = TEAM_RED )
{
baseColor = CT_RED ;
}
else
{
baseColor = CT_BLUE ;
}
}
}
else
{
//baseColor = CT_WHITE;
if ( cgs . gametype = = GT_POWERDUEL & &
cgs . clientinfo [ cg . snap - > ps . clientNum ] . team ! = TEAM_SPECTATOR & &
cgs . clientinfo [ cg . crosshairClientNum ] . duelTeam = = cgs . clientinfo [ cg . predictedPlayerState . clientNum ] . duelTeam )
{ //on the same duel team in powerduel, so he's a friend
baseColor = CT_GREEN ;
}
else
{
baseColor = CT_RED ; //just make it red in nonteam modes since everyone is hostile and crosshair will be red on them too
}
}
if ( cg . snap - > ps . duelInProgress )
{
if ( cg . crosshairClientNum ! = cg . snap - > ps . duelIndex )
{ //grey out crosshair for everyone but your foe if you're in a duel
baseColor = CT_BLACK ;
}
}
else if ( cg_entities [ cg . crosshairClientNum ] . currentState . bolt1 )
{ //this fellow is in a duel. We just checked if we were in a duel above, so
//this means we aren't and he is. Which of course means our crosshair greys out over him.
baseColor = CT_BLACK ;
}
tcolor [ 0 ] = colorTable [ baseColor ] [ 0 ] ;
tcolor [ 1 ] = colorTable [ baseColor ] [ 1 ] ;
tcolor [ 2 ] = colorTable [ baseColor ] [ 2 ] ;
tcolor [ 3 ] = color [ 3 ] * 0.5f ;
CG_SanitizeString ( name , sanitized ) ;
if ( isVeh )
{
char str [ MAX_STRING_CHARS ] ;
Com_sprintf ( str , MAX_STRING_CHARS , " %s (pilot) " , sanitized ) ;
UI_DrawProportionalString ( 320 , 170 , str , UI_CENTER , tcolor ) ;
}
else
{
UI_DrawProportionalString ( 320 , 170 , sanitized , UI_CENTER , tcolor ) ;
}
trap_R_SetColor ( NULL ) ;
}
//==============================================================================
/*
= = = = = = = = = = = = = = = = =
CG_DrawSpectator
= = = = = = = = = = = = = = = = =
*/
static void CG_DrawSpectator ( void )
{
const char * s ;
s = CG_GetStringEdString ( " MP_INGAME " , " SPECTATOR " ) ;
if ( ( cgs . gametype = = GT_DUEL | | cgs . gametype = = GT_POWERDUEL ) & &
cgs . duelist1 ! = - 1 & &
cgs . duelist2 ! = - 1 )
{
char text [ 1024 ] ;
int size = 64 ;
if ( cgs . gametype = = GT_POWERDUEL & & cgs . duelist3 ! = - 1 )
{
Com_sprintf ( text , sizeof ( text ) , " %s^7 %s %s^7 %s %s " , cgs . clientinfo [ cgs . duelist1 ] . name , CG_GetStringEdString ( " MP_INGAME " , " SPECHUD_VERSUS " ) , cgs . clientinfo [ cgs . duelist2 ] . name , CG_GetStringEdString ( " MP_INGAME " , " AND " ) , cgs . clientinfo [ cgs . duelist3 ] . name ) ;
}
else
{
Com_sprintf ( text , sizeof ( text ) , " %s^7 %s %s " , cgs . clientinfo [ cgs . duelist1 ] . name , CG_GetStringEdString ( " MP_INGAME " , " SPECHUD_VERSUS " ) , cgs . clientinfo [ cgs . duelist2 ] . name ) ;
}
CG_Text_Paint ( 320 - CG_Text_Width ( text , 1.0f , 3 ) / 2 , 420 , 1.0f , colorWhite , text , 0 , 0 , 0 , 3 ) ;
trap_R_SetColor ( colorTable [ CT_WHITE ] ) ;
if ( cgs . clientinfo [ cgs . duelist1 ] . modelIcon )
{
CG_DrawPic ( 10 , SCREEN_HEIGHT - ( size * 1.5 ) , size , size , cgs . clientinfo [ cgs . duelist1 ] . modelIcon ) ;
}
if ( cgs . clientinfo [ cgs . duelist2 ] . modelIcon )
{
CG_DrawPic ( SCREEN_WIDTH - size - 10 , SCREEN_HEIGHT - ( size * 1.5 ) , size , size , cgs . clientinfo [ cgs . duelist2 ] . modelIcon ) ;
}
// nmckenzie: DUEL_HEALTH
if ( cgs . gametype = = GT_DUEL )
{
if ( cgs . showDuelHealths > = 1 )
{ // draw the healths on the two guys - how does this interact with power duel, though?
CG_DrawDuelistHealth ( 10 , SCREEN_HEIGHT - ( size * 1.5 ) - 12 , 64 , 8 , 1 ) ;
CG_DrawDuelistHealth ( SCREEN_WIDTH - size - 10 , SCREEN_HEIGHT - ( size * 1.5 ) - 12 , 64 , 8 , 2 ) ;
}
}
if ( cgs . gametype ! = GT_POWERDUEL )
{
Com_sprintf ( text , sizeof ( text ) , " %i/%i " , cgs . clientinfo [ cgs . duelist1 ] . score , cgs . fraglimit ) ;
CG_Text_Paint ( 42 - CG_Text_Width ( text , 1.0f , 2 ) / 2 , SCREEN_HEIGHT - ( size * 1.5 ) + 64 , 1.0f , colorWhite , text , 0 , 0 , 0 , 2 ) ;
Com_sprintf ( text , sizeof ( text ) , " %i/%i " , cgs . clientinfo [ cgs . duelist2 ] . score , cgs . fraglimit ) ;
CG_Text_Paint ( SCREEN_WIDTH - size + 22 - CG_Text_Width ( text , 1.0f , 2 ) / 2 , SCREEN_HEIGHT - ( size * 1.5 ) + 64 , 1.0f , colorWhite , text , 0 , 0 , 0 , 2 ) ;
}
if ( cgs . gametype = = GT_POWERDUEL & & cgs . duelist3 ! = - 1 )
{
if ( cgs . clientinfo [ cgs . duelist3 ] . modelIcon )
{
CG_DrawPic ( SCREEN_WIDTH - size - 10 , SCREEN_HEIGHT - ( size * 2.8 ) , size , size , cgs . clientinfo [ cgs . duelist3 ] . modelIcon ) ;
}
}
}
else
{
CG_Text_Paint ( 320 - CG_Text_Width ( s , 1.0f , 3 ) / 2 , 420 , 1.0f , colorWhite , s , 0 , 0 , 0 , 3 ) ;
}
if ( cgs . gametype = = GT_DUEL | | cgs . gametype = = GT_POWERDUEL )
{
s = CG_GetStringEdString ( " MP_INGAME " , " WAITING_TO_PLAY " ) ; // "waiting to play";
CG_Text_Paint ( 320 - CG_Text_Width ( s , 1.0f , 3 ) / 2 , 440 , 1.0f , colorWhite , s , 0 , 0 , 0 , 3 ) ;
}
else //if ( cgs.gametype >= GT_TEAM )
{
//s = "press ESC and use the JOIN menu to play";
s = CG_GetStringEdString ( " MP_INGAME " , " SPEC_CHOOSEJOIN " ) ;
CG_Text_Paint ( 320 - CG_Text_Width ( s , 1.0f , 3 ) / 2 , 440 , 1.0f , colorWhite , s , 0 , 0 , 0 , 3 ) ;
}
}
/*
= = = = = = = = = = = = = = = = =
CG_DrawVote
= = = = = = = = = = = = = = = = =
*/
static void CG_DrawVote ( void ) {
const char * s ;
int sec ;
char sYes [ 20 ] ;
char sNo [ 20 ] ;
char sVote [ 20 ] ;
char sCmd [ 100 ] ;
const char * sParm = 0 ;
if ( ! cgs . voteTime ) {
return ;
}
// play a talk beep whenever it is modified
if ( cgs . voteModified ) {
cgs . voteModified = qfalse ;
// trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
}
sec = ( VOTE_TIME - ( cg . time - cgs . voteTime ) ) / 1000 ;
if ( sec < 0 ) {
sec = 0 ;
}
if ( strncmp ( cgs . voteString , " map_restart " , 11 ) = = 0 )
{
trap_SP_GetStringTextString ( " MENUS_RESTART_MAP " , sCmd , sizeof ( sCmd ) ) ;
}
else if ( strncmp ( cgs . voteString , " vstr nextmap " , 12 ) = = 0 )
{
trap_SP_GetStringTextString ( " MENUS_NEXT_MAP " , sCmd , sizeof ( sCmd ) ) ;
}
else if ( strncmp ( cgs . voteString , " g_doWarmup " , 10 ) = = 0 )
{
trap_SP_GetStringTextString ( " MENUS_WARMUP " , sCmd , sizeof ( sCmd ) ) ;
}
else if ( strncmp ( cgs . voteString , " g_gametype " , 10 ) = = 0 )
{
trap_SP_GetStringTextString ( " MENUS_GAME_TYPE " , sCmd , sizeof ( sCmd ) ) ;
if ( stricmp ( " Free For All " , cgs . voteString + 11 ) = = 0 )
{
sParm = CG_GetStringEdString ( " MENUS " , " FREE_FOR_ALL " ) ;
}
else if ( stricmp ( " Duel " , cgs . voteString + 11 ) = = 0 )
{
sParm = CG_GetStringEdString ( " MENUS " , " DUEL " ) ;
}
else if ( stricmp ( " Holocron FFA " , cgs . voteString + 11 ) = = 0 )
{
sParm = CG_GetStringEdString ( " MENUS " , " HOLOCRON_FFA " ) ;
}
else if ( stricmp ( " Power Duel " , cgs . voteString + 11 ) = = 0 )
{
sParm = CG_GetStringEdString ( " MENUS " , " POWERDUEL " ) ;
}
else if ( stricmp ( " Team FFA " , cgs . voteString + 11 ) = = 0 )
{
sParm = CG_GetStringEdString ( " MENUS " , " TEAM_FFA " ) ;
}
else if ( stricmp ( " Siege " , cgs . voteString + 11 ) = = 0 )
{
sParm = CG_GetStringEdString ( " MENUS " , " SIEGE " ) ;
}
else if ( stricmp ( " Capture the Flag " , cgs . voteString + 11 ) = = 0 )
{
sParm = CG_GetStringEdString ( " MENUS " , " CAPTURE_THE_FLAG " ) ;
}
else if ( stricmp ( " Capture the Ysalamiri " , cgs . voteString + 11 ) = = 0 )
{
sParm = CG_GetStringEdString ( " MENUS " , " CAPTURE_THE_YSALIMARI " ) ;
}
}
else if ( strncmp ( cgs . voteString , " map " , 3 ) = = 0 )
{
trap_SP_GetStringTextString ( " MENUS_NEW_MAP " , sCmd , sizeof ( sCmd ) ) ;
sParm = cgs . voteString + 4 ;
}
else if ( strncmp ( cgs . voteString , " kick " , 4 ) = = 0 )
{
trap_SP_GetStringTextString ( " MENUS_KICK_PLAYER " , sCmd , sizeof ( sCmd ) ) ;
sParm = cgs . voteString + 5 ;
}
trap_SP_GetStringTextString ( " MENUS_VOTE " , sVote , sizeof ( sVote ) ) ;
trap_SP_GetStringTextString ( " MENUS_YES " , sYes , sizeof ( sYes ) ) ;
trap_SP_GetStringTextString ( " MENUS_NO " , sNo , sizeof ( sNo ) ) ;
if ( sParm & & sParm [ 0 ] )
{
s = va ( " %s(%i):<%s %s> %s:%i %s:%i " , sVote , sec , sCmd , sParm , sYes , cgs . voteYes , sNo , cgs . voteNo ) ;
}
else
{
s = va ( " %s(%i):<%s> %s:%i %s:%i " , sVote , sec , sCmd , sYes , cgs . voteYes , sNo , cgs . voteNo ) ;
}
CG_DrawSmallString ( 4 , 58 , s , 1.0F ) ;
s = CG_GetStringEdString ( " MP_INGAME " , " OR_PRESS_ESC_THEN_CLICK_VOTE " ) ; // s = "or press ESC then click Vote";
CG_DrawSmallString ( 4 , 58 + SMALLCHAR_HEIGHT + 2 , s , 1.0F ) ;
}
/*
= = = = = = = = = = = = = = = = =
CG_DrawTeamVote
= = = = = = = = = = = = = = = = =
*/
static void CG_DrawTeamVote ( void ) {
char * s ;
int sec , cs_offset ;
if ( cgs . clientinfo - > team = = TEAM_RED )
cs_offset = 0 ;
else if ( cgs . clientinfo - > team = = TEAM_BLUE )
cs_offset = 1 ;
else
return ;
if ( ! cgs . teamVoteTime [ cs_offset ] ) {
return ;
}
// play a talk beep whenever it is modified
if ( cgs . teamVoteModified [ cs_offset ] ) {
cgs . teamVoteModified [ cs_offset ] = qfalse ;
// trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
}
sec = ( VOTE_TIME - ( cg . time - cgs . teamVoteTime [ cs_offset ] ) ) / 1000 ;
if ( sec < 0 ) {
sec = 0 ;
}
if ( strstr ( cgs . teamVoteString [ cs_offset ] , " leader " ) )
{
int i = 0 ;
while ( cgs . teamVoteString [ cs_offset ] [ i ] & & cgs . teamVoteString [ cs_offset ] [ i ] ! = ' ' )
{
i + + ;
}
if ( cgs . teamVoteString [ cs_offset ] [ i ] = = ' ' )
{
int voteIndex = 0 ;
char voteIndexStr [ 256 ] ;
i + + ;
while ( cgs . teamVoteString [ cs_offset ] [ i ] )
{
voteIndexStr [ voteIndex ] = cgs . teamVoteString [ cs_offset ] [ i ] ;
voteIndex + + ;
i + + ;
}
voteIndexStr [ voteIndex ] = 0 ;
voteIndex = atoi ( voteIndexStr ) ;
s = va ( " TEAMVOTE(%i):(Make %s the new team leader) yes:%i no:%i " , sec , cgs . clientinfo [ voteIndex ] . name ,
cgs . teamVoteYes [ cs_offset ] , cgs . teamVoteNo [ cs_offset ] ) ;
}
else
{
s = va ( " TEAMVOTE(%i):%s yes:%i no:%i " , sec , cgs . teamVoteString [ cs_offset ] ,
cgs . teamVoteYes [ cs_offset ] , cgs . teamVoteNo [ cs_offset ] ) ;
}
}
else
{
s = va ( " TEAMVOTE(%i):%s yes:%i no:%i " , sec , cgs . teamVoteString [ cs_offset ] ,
cgs . teamVoteYes [ cs_offset ] , cgs . teamVoteNo [ cs_offset ] ) ;
}
CG_DrawSmallString ( 4 , 90 , s , 1.0F ) ;
}
static qboolean CG_DrawScoreboard ( ) {
return CG_DrawOldScoreboard ( ) ;
#if 0
static qboolean firstTime = qtrue ;
float fade , * fadeColor ;
if ( menuScoreboard ) {
menuScoreboard - > window . flags & = ~ WINDOW_FORCED ;
}
if ( cg_paused . integer ) {
cg . deferredPlayerLoading = 0 ;
firstTime = qtrue ;
return qfalse ;
}
// should never happen in Team Arena
if ( cgs . gametype = = GT_SINGLE_PLAYER & & cg . predictedPlayerState . pm_type = = PM_INTERMISSION ) {
cg . deferredPlayerLoading = 0 ;
firstTime = qtrue ;
return qfalse ;
}
// don't draw scoreboard during death while warmup up
if ( cg . warmup & & ! cg . showScores ) {
return qfalse ;
}
if ( cg . showScores | | cg . predictedPlayerState . pm_type = = PM_DEAD | | cg . predictedPlayerState . pm_type = = PM_INTERMISSION ) {
fade = 1.0 ;
fadeColor = colorWhite ;
} else {
fadeColor = CG_FadeColor ( cg . scoreFadeTime , FADE_TIME ) ;
if ( ! fadeColor ) {
// next time scoreboard comes up, don't print killer
cg . deferredPlayerLoading = 0 ;
cg . killerName [ 0 ] = 0 ;
firstTime = qtrue ;
return qfalse ;
}
fade = * fadeColor ;
}
if ( menuScoreboard = = NULL ) {
if ( cgs . gametype > = GT_TEAM ) {
menuScoreboard = Menus_FindByName ( " teamscore_menu " ) ;
} else {
menuScoreboard = Menus_FindByName ( " score_menu " ) ;
}
}
if ( menuScoreboard ) {
if ( firstTime ) {
CG_SetScoreSelection ( menuScoreboard ) ;
firstTime = qfalse ;
}
Menu_Paint ( menuScoreboard , qtrue ) ;
}
// load any models that have been deferred
if ( + + cg . deferredPlayerLoading > 10 ) {
CG_LoadDeferredPlayers ( ) ;
}
return qtrue ;
# endif
}
/*
= = = = = = = = = = = = = = = = =
CG_DrawIntermission
= = = = = = = = = = = = = = = = =
*/
static void CG_DrawIntermission ( void ) {
// int key;
//if (cg_singlePlayer.integer) {
// CG_DrawCenterString();
// return;
//}
cg . scoreFadeTime = cg . time ;
cg . scoreBoardShowing = CG_DrawScoreboard ( ) ;
}
/*
= = = = = = = = = = = = = = = = =
CG_DrawFollow
= = = = = = = = = = = = = = = = =
*/
static qboolean CG_DrawFollow ( void )
{
const char * s ;
if ( ! ( cg . snap - > ps . pm_flags & PMF_FOLLOW ) )
{
return qfalse ;
}
// s = "following";
if ( cgs . gametype = = GT_POWERDUEL )
{
clientInfo_t * ci = & cgs . clientinfo [ cg . snap - > ps . clientNum ] ;
if ( ci - > duelTeam = = DUELTEAM_LONE )
{
s = CG_GetStringEdString ( " MP_INGAME " , " FOLLOWINGLONE " ) ;
}
else if ( ci - > duelTeam = = DUELTEAM_DOUBLE )
{
s = CG_GetStringEdString ( " MP_INGAME " , " FOLLOWINGDOUBLE " ) ;
}
else
{
s = CG_GetStringEdString ( " MP_INGAME " , " FOLLOWING " ) ;
}
}
else
{
s = CG_GetStringEdString ( " MP_INGAME " , " FOLLOWING " ) ;
}
CG_Text_Paint ( 320 - CG_Text_Width ( s , 1.0f , FONT_MEDIUM ) / 2 , 60 , 1.0f , colorWhite , s , 0 , 0 , 0 , FONT_MEDIUM ) ;
s = cgs . clientinfo [ cg . snap - > ps . clientNum ] . name ;
CG_Text_Paint ( 320 - CG_Text_Width ( s , 2.0f , FONT_MEDIUM ) / 2 , 80 , 2.0f , colorWhite , s , 0 , 0 , 0 , FONT_MEDIUM ) ;
return qtrue ;
}
#if 0
static void CG_DrawTemporaryStats ( )
{ //placeholder for testing (draws ammo and force power)
char s [ 512 ] ;
if ( ! cg . snap )
{
return ;
}
sprintf ( s , " Force: %i " , cg . snap - > ps . fd . forcePower ) ;
CG_DrawBigString ( SCREEN_WIDTH - 164 , SCREEN_HEIGHT - dmgIndicSize , s , 1.0f ) ;
sprintf ( s , " Ammo: %i " , cg . snap - > ps . ammo [ weaponData [ cg . snap - > ps . weapon ] . ammoIndex ] ) ;
CG_DrawBigString ( SCREEN_WIDTH - 164 , SCREEN_HEIGHT - 112 , s , 1.0f ) ;
sprintf ( s , " Health: %i " , cg . snap - > ps . stats [ STAT_HEALTH ] ) ;
CG_DrawBigString ( 8 , SCREEN_HEIGHT - dmgIndicSize , s , 1.0f ) ;
sprintf ( s , " Armor: %i " , cg . snap - > ps . stats [ STAT_ARMOR ] ) ;
CG_DrawBigString ( 8 , SCREEN_HEIGHT - 112 , s , 1.0f ) ;
}
# endif
/*
= = = = = = = = = = = = = = = = =
CG_DrawAmmoWarning
= = = = = = = = = = = = = = = = =
*/
static void CG_DrawAmmoWarning ( void ) {
#if 0
const char * s ;
int w ;
if ( ! cg_drawStatus . integer )
{
return ;
}
if ( cg_drawAmmoWarning . integer = = 0 ) {
return ;
}
if ( ! cg . lowAmmoWarning ) {
return ;
}
if ( cg . lowAmmoWarning = = 2 ) {
s = " OUT OF AMMO " ;
} else {
s = " LOW AMMO WARNING " ;
}
w = CG_DrawStrlen ( s ) * BIGCHAR_WIDTH ;
CG_DrawBigString ( 320 - w / 2 , 64 , s , 1.0F ) ;
# endif
}
/*
= = = = = = = = = = = = = = = = =
CG_DrawWarmup
= = = = = = = = = = = = = = = = =
*/
static void CG_DrawWarmup ( void ) {
int w ;
int sec ;
int i ;
float scale ;
int cw ;
const char * s ;
sec = cg . warmup ;
if ( ! sec ) {
return ;
}
if ( sec < 0 ) {
// s = "Waiting for players";
s = CG_GetStringEdString ( " MP_INGAME " , " WAITING_FOR_PLAYERS " ) ;
w = CG_DrawStrlen ( s ) * BIGCHAR_WIDTH ;
CG_DrawBigString ( 320 - w / 2 , 24 , s , 1.0F ) ;
cg . warmupCount = 0 ;
return ;
}
if ( cgs . gametype = = GT_DUEL | | cgs . gametype = = GT_POWERDUEL )
{
// find the two active players
clientInfo_t * ci1 , * ci2 , * ci3 ;
ci1 = NULL ;
ci2 = NULL ;
ci3 = NULL ;
if ( cgs . gametype = = GT_POWERDUEL )
{
if ( cgs . duelist1 ! = - 1 )
{
ci1 = & cgs . clientinfo [ cgs . duelist1 ] ;
}
if ( cgs . duelist2 ! = - 1 )
{
ci2 = & cgs . clientinfo [ cgs . duelist2 ] ;
}
if ( cgs . duelist3 ! = - 1 )
{
ci3 = & cgs . clientinfo [ cgs . duelist3 ] ;
}
}
else
{
for ( i = 0 ; i < cgs . maxclients ; i + + ) {
if ( cgs . clientinfo [ i ] . infoValid & & cgs . clientinfo [ i ] . team = = TEAM_FREE ) {
if ( ! ci1 ) {
ci1 = & cgs . clientinfo [ i ] ;
} else {
ci2 = & cgs . clientinfo [ i ] ;
}
}
}
}
if ( ci1 & & ci2 )
{
if ( ci3 )
{
s = va ( " %s vs %s and %s " , ci1 - > name , ci2 - > name , ci3 - > name ) ;
}
else
{
s = va ( " %s vs %s " , ci1 - > name , ci2 - > name ) ;
}
w = CG_Text_Width ( s , 0.6f , FONT_MEDIUM ) ;
CG_Text_Paint ( 320 - w / 2 , 60 , 0.6f , colorWhite , s , 0 , 0 , ITEM_TEXTSTYLE_SHADOWEDMORE , FONT_MEDIUM ) ;
}
} else {
if ( cgs . gametype = = GT_FFA ) {
s = CG_GetStringEdString ( " MENUS " , " FREE_FOR_ALL " ) ; //"Free For All";
} else if ( cgs . gametype = = GT_HOLOCRON ) {
s = CG_GetStringEdString ( " MENUS " , " HOLOCRON_FFA " ) ; //"Holocron FFA";
} else if ( cgs . gametype = = GT_JEDIMASTER ) {
s = CG_GetStringEdString ( " MENUS " , " POWERDUEL " ) ; //"Jedi Master";??
} else if ( cgs . gametype = = GT_TEAM ) {
s = CG_GetStringEdString ( " MENUS " , " TEAM_FFA " ) ; //"Team FFA";
} else if ( cgs . gametype = = GT_SIEGE ) {
s = CG_GetStringEdString ( " MENUS " , " SIEGE " ) ; //"Siege";
} else if ( cgs . gametype = = GT_CTF ) {
s = CG_GetStringEdString ( " MENUS " , " CAPTURE_THE_FLAG " ) ; //"Capture the Flag";
} else if ( cgs . gametype = = GT_CTY ) {
s = CG_GetStringEdString ( " MENUS " , " CAPTURE_THE_YSALIMARI " ) ; //"Capture the Ysalamiri";
} else {
s = " " ;
}
w = CG_Text_Width ( s , 1.5f , FONT_MEDIUM ) ;
CG_Text_Paint ( 320 - w / 2 , 90 , 1.5f , colorWhite , s , 0 , 0 , ITEM_TEXTSTYLE_SHADOWEDMORE , FONT_MEDIUM ) ;
}
sec = ( sec - cg . time ) / 1000 ;
if ( sec < 0 ) {
cg . warmup = 0 ;
sec = 0 ;
}
// s = va( "Starts in: %i", sec + 1 );
s = va ( " %s: %i " , CG_GetStringEdString ( " MP_INGAME " , " STARTS_IN " ) , sec + 1 ) ;
if ( sec ! = cg . warmupCount ) {
cg . warmupCount = sec ;
if ( cgs . gametype ! = GT_SIEGE )
{
switch ( sec ) {
case 0 :
trap_S_StartLocalSound ( cgs . media . count1Sound , CHAN_ANNOUNCER ) ;
break ;
case 1 :
trap_S_StartLocalSound ( cgs . media . count2Sound , CHAN_ANNOUNCER ) ;
break ;
case 2 :
trap_S_StartLocalSound ( cgs . media . count3Sound , CHAN_ANNOUNCER ) ;
break ;
default :
break ;
}
}
}
scale = 0.45f ;
switch ( cg . warmupCount ) {
case 0 :
cw = 28 ;
scale = 1.25f ;
break ;
case 1 :
cw = 24 ;
scale = 1.15f ;
break ;
case 2 :
cw = 20 ;
scale = 1.05f ;
break ;
default :
cw = 16 ;
scale = 0.9f ;
break ;
}
w = CG_Text_Width ( s , scale , FONT_MEDIUM ) ;
CG_Text_Paint ( 320 - w / 2 , 125 , scale , colorWhite , s , 0 , 0 , ITEM_TEXTSTYLE_SHADOWEDMORE , FONT_MEDIUM ) ;
}
//==================================================================================
/*
= = = = = = = = = = = = = = = = =
CG_DrawTimedMenus
= = = = = = = = = = = = = = = = =
*/
void CG_DrawTimedMenus ( ) {
if ( cg . voiceTime ) {
int t = cg . time - cg . voiceTime ;
if ( t > 2500 ) {
Menus_CloseByName ( " voiceMenu " ) ;
trap_Cvar_Set ( " cl_conXOffset " , " 0 " ) ;
cg . voiceTime = 0 ;
}
}
}
void CG_DrawFlagStatus ( )
{
int myFlagTakenShader = 0 ;
int theirFlagShader = 0 ;
int team = 0 ;
int startDrawPos = 2 ;
int ico_size = 32 ;
if ( ! cg . snap )
{
return ;
}
if ( cgs . gametype ! = GT_CTF & & cgs . gametype ! = GT_CTY )
{
return ;
}
team = cg . snap - > ps . persistant [ PERS_TEAM ] ;
if ( cgs . gametype = = GT_CTY )
{
if ( team = = TEAM_RED )
{
myFlagTakenShader = trap_R_RegisterShaderNoMip ( " gfx/hud/mpi_rflag_x " ) ;
theirFlagShader = trap_R_RegisterShaderNoMip ( " gfx/hud/mpi_bflag_ys " ) ;
}
else
{
myFlagTakenShader = trap_R_RegisterShaderNoMip ( " gfx/hud/mpi_bflag_x " ) ;
theirFlagShader = trap_R_RegisterShaderNoMip ( " gfx/hud/mpi_rflag_ys " ) ;
}
}
else
{
if ( team = = TEAM_RED )
{
myFlagTakenShader = trap_R_RegisterShaderNoMip ( " gfx/hud/mpi_rflag_x " ) ;
theirFlagShader = trap_R_RegisterShaderNoMip ( " gfx/hud/mpi_bflag " ) ;
}
else
{
myFlagTakenShader = trap_R_RegisterShaderNoMip ( " gfx/hud/mpi_bflag_x " ) ;
theirFlagShader = trap_R_RegisterShaderNoMip ( " gfx/hud/mpi_rflag " ) ;
}
}
if ( CG_YourTeamHasFlag ( ) )
{
//CG_DrawPic( startDrawPos, 330, ico_size, ico_size, theirFlagShader );
CG_DrawPic ( 2 , 330 - startDrawPos , ico_size , ico_size , theirFlagShader ) ;
startDrawPos + = ico_size + 2 ;
}
if ( CG_OtherTeamHasFlag ( ) )
{
//CG_DrawPic( startDrawPos, 330, ico_size, ico_size, myFlagTakenShader );
CG_DrawPic ( 2 , 330 - startDrawPos , ico_size , ico_size , myFlagTakenShader ) ;
}
}
//draw meter showing jetpack fuel when it's not full
# define JPFUELBAR_H 100.0f
# define JPFUELBAR_W 20.0f
# define JPFUELBAR_X (SCREEN_WIDTH-JPFUELBAR_W-8.0f)
# define JPFUELBAR_Y 260.0f
void CG_DrawJetpackFuel ( void )
{
vec4_t aColor ;
vec4_t bColor ;
vec4_t cColor ;
float x = JPFUELBAR_X ;
float y = JPFUELBAR_Y ;
float percent = ( ( float ) cg . snap - > ps . jetpackFuel / 100.0f ) * JPFUELBAR_H ;
if ( percent > JPFUELBAR_H )
{
return ;
}
if ( percent < 0.1f )
{
percent = 0.1f ;
}
//color of the bar
aColor [ 0 ] = 0.5f ;
aColor [ 1 ] = 0.0f ;
aColor [ 2 ] = 0.0f ;
aColor [ 3 ] = 0.8f ;
//color of the border
bColor [ 0 ] = 0.0f ;
bColor [ 1 ] = 0.0f ;
bColor [ 2 ] = 0.0f ;
bColor [ 3 ] = 0.3f ;
//color of greyed out "missing fuel"
cColor [ 0 ] = 0.5f ;
cColor [ 1 ] = 0.5f ;
cColor [ 2 ] = 0.5f ;
cColor [ 3 ] = 0.1f ;
//draw the background (black)
CG_DrawRect ( x , y , JPFUELBAR_W , JPFUELBAR_H , 1.0f , colorTable [ CT_BLACK ] ) ;
//now draw the part to show how much health there is in the color specified
CG_FillRect ( x + 1.0f , y + 1.0f + ( JPFUELBAR_H - percent ) , JPFUELBAR_W - 1.0f , JPFUELBAR_H - 1.0f - ( JPFUELBAR_H - percent ) , aColor ) ;
//then draw the other part greyed out
CG_FillRect ( x + 1.0f , y + 1.0f , JPFUELBAR_W - 1.0f , JPFUELBAR_H - percent , cColor ) ;
}
//draw meter showing e-web health when it is in use
# define EWEBHEALTH_H 100.0f
# define EWEBHEALTH_W 20.0f
# define EWEBHEALTH_X (SCREEN_WIDTH-EWEBHEALTH_W-8.0f)
# define EWEBHEALTH_Y 290.0f
void CG_DrawEWebHealth ( void )
{
vec4_t aColor ;
vec4_t bColor ;
vec4_t cColor ;
float x = EWEBHEALTH_X ;
float y = EWEBHEALTH_Y ;
centity_t * eweb = & cg_entities [ cg . predictedPlayerState . emplacedIndex ] ;
float percent = ( ( float ) eweb - > currentState . health / eweb - > currentState . maxhealth ) * EWEBHEALTH_H ;
if ( percent > EWEBHEALTH_H )
{
return ;
}
if ( percent < 0.1f )
{
percent = 0.1f ;
}
//kind of hacky, need to pass a coordinate in here
if ( cg . snap - > ps . jetpackFuel < 100 )
{
x - = ( JPFUELBAR_W + 8.0f ) ;
}
if ( cg . snap - > ps . cloakFuel < 100 )
{
x - = ( JPFUELBAR_W + 8.0f ) ;
}
//color of the bar
aColor [ 0 ] = 0.5f ;
aColor [ 1 ] = 0.0f ;
aColor [ 2 ] = 0.0f ;
aColor [ 3 ] = 0.8f ;
//color of the border
bColor [ 0 ] = 0.0f ;
bColor [ 1 ] = 0.0f ;
bColor [ 2 ] = 0.0f ;
bColor [ 3 ] = 0.3f ;
//color of greyed out "missing fuel"
cColor [ 0 ] = 0.5f ;
cColor [ 1 ] = 0.5f ;
cColor [ 2 ] = 0.5f ;
cColor [ 3 ] = 0.1f ;
//draw the background (black)
CG_DrawRect ( x , y , EWEBHEALTH_W , EWEBHEALTH_H , 1.0f , colorTable [ CT_BLACK ] ) ;
//now draw the part to show how much health there is in the color specified
CG_FillRect ( x + 1.0f , y + 1.0f + ( EWEBHEALTH_H - percent ) , EWEBHEALTH_W - 1.0f , EWEBHEALTH_H - 1.0f - ( EWEBHEALTH_H - percent ) , aColor ) ;
//then draw the other part greyed out
CG_FillRect ( x + 1.0f , y + 1.0f , EWEBHEALTH_W - 1.0f , EWEBHEALTH_H - percent , cColor ) ;
}
//draw meter showing cloak fuel when it's not full
# define CLFUELBAR_H 100.0f
# define CLFUELBAR_W 20.0f
# define CLFUELBAR_X (SCREEN_WIDTH-CLFUELBAR_W-8.0f)
# define CLFUELBAR_Y 260.0f
void CG_DrawCloakFuel ( void )
{
vec4_t aColor ;
vec4_t bColor ;
vec4_t cColor ;
float x = CLFUELBAR_X ;
float y = CLFUELBAR_Y ;
float percent = ( ( float ) cg . snap - > ps . cloakFuel / 100.0f ) * CLFUELBAR_H ;
if ( percent > CLFUELBAR_H )
{
return ;
}
if ( cg . snap - > ps . jetpackFuel < 100 )
{ //if drawing jetpack fuel bar too, then move this over...?
x - = ( JPFUELBAR_W + 8.0f ) ;
}
if ( percent < 0.1f )
{
percent = 0.1f ;
}
//color of the bar
aColor [ 0 ] = 0.0f ;
aColor [ 1 ] = 0.0f ;
aColor [ 2 ] = 0.6f ;
aColor [ 3 ] = 0.8f ;
//color of the border
bColor [ 0 ] = 0.0f ;
bColor [ 1 ] = 0.0f ;
bColor [ 2 ] = 0.0f ;
bColor [ 3 ] = 0.3f ;
//color of greyed out "missing fuel"
cColor [ 0 ] = 0.1f ;
cColor [ 1 ] = 0.1f ;
cColor [ 2 ] = 0.3f ;
cColor [ 3 ] = 0.1f ;
//draw the background (black)
CG_DrawRect ( x , y , CLFUELBAR_W , CLFUELBAR_H , 1.0f , colorTable [ CT_BLACK ] ) ;
//now draw the part to show how much fuel there is in the color specified
CG_FillRect ( x + 1.0f , y + 1.0f + ( CLFUELBAR_H - percent ) , CLFUELBAR_W - 1.0f , CLFUELBAR_H - 1.0f - ( CLFUELBAR_H - percent ) , aColor ) ;
//then draw the other part greyed out
CG_FillRect ( x + 1.0f , y + 1.0f , CLFUELBAR_W - 1.0f , CLFUELBAR_H - percent , cColor ) ;
}
int cgRageTime = 0 ;
int cgRageFadeTime = 0 ;
float cgRageFadeVal = 0 ;
int cgRageRecTime = 0 ;
int cgRageRecFadeTime = 0 ;
float cgRageRecFadeVal = 0 ;
int cgAbsorbTime = 0 ;
int cgAbsorbFadeTime = 0 ;
float cgAbsorbFadeVal = 0 ;
int cgProtectTime = 0 ;
int cgProtectFadeTime = 0 ;
float cgProtectFadeVal = 0 ;
int cgYsalTime = 0 ;
int cgYsalFadeTime = 0 ;
float cgYsalFadeVal = 0 ;
qboolean gCGHasFallVector = qfalse ;
vec3_t gCGFallVector ;
/*
= = = = = = = = = = = = = = = = =
CG_Draw2D
= = = = = = = = = = = = = = = = =
*/
extern int cgSiegeRoundState ;
extern int cgSiegeRoundTime ;
extern int team1Timed ;
extern int team2Timed ;
int cg_beatingSiegeTime = 0 ;
int cgSiegeRoundBeganTime = 0 ;
int cgSiegeRoundCountTime = 0 ;
static void CG_DrawSiegeTimer ( int timeRemaining , qboolean isMyTeam )
{ //rwwFIXMEFIXME: Make someone make assets and use them.
//this function is pretty much totally placeholder.
// int x = 0;
// int y = SCREEN_HEIGHT-160;
int fColor = 0 ;
int minutes = 0 ;
int seconds = 0 ;
char timeStr [ 1024 ] ;
menuDef_t * menuHUD = NULL ;
itemDef_t * item = NULL ;
menuHUD = Menus_FindByName ( " mp_timer " ) ;
if ( ! menuHUD )
{
return ;
}
item = Menu_FindItemByName ( menuHUD , " frame " ) ;
if ( item )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
}
seconds = timeRemaining ;
while ( seconds > = 60 )
{
minutes + + ;
seconds - = 60 ;
}
strcpy ( timeStr , va ( " %i:%02i " , minutes , seconds ) ) ;
if ( isMyTeam )
{
fColor = CT_HUD_RED ;
}
else
{
fColor = CT_HUD_GREEN ;
}
// trap_Cvar_Set("ui_siegeTimer", timeStr);
// UI_DrawProportionalString( x+16, y+40, timeStr,
// UI_SMALLFONT|UI_DROPSHADOW, colorTable[fColor] );
item = Menu_FindItemByName ( menuHUD , " timer " ) ;
if ( item )
{
UI_DrawProportionalString (
item - > window . rect . x ,
item - > window . rect . y ,
timeStr ,
UI_SMALLFONT | UI_DROPSHADOW ,
colorTable [ fColor ] ) ;
}
}
static void CG_DrawSiegeDeathTimer ( int timeRemaining )
{
int minutes = 0 ;
int seconds = 0 ;
char timeStr [ 1024 ] ;
menuDef_t * menuHUD = NULL ;
itemDef_t * item = NULL ;
menuHUD = Menus_FindByName ( " mp_timer " ) ;
if ( ! menuHUD )
{
return ;
}
item = Menu_FindItemByName ( menuHUD , " frame " ) ;
if ( item )
{
trap_R_SetColor ( item - > window . foreColor ) ;
CG_DrawPic (
item - > window . rect . x ,
item - > window . rect . y ,
item - > window . rect . w ,
item - > window . rect . h ,
item - > window . background ) ;
}
seconds = timeRemaining ;
while ( seconds > = 60 )
{
minutes + + ;
seconds - = 60 ;
}
if ( seconds < 10 )
{
strcpy ( timeStr , va ( " %i:0%i " , minutes , seconds ) ) ;
}
else
{
strcpy ( timeStr , va ( " %i:%i " , minutes , seconds ) ) ;
}
item = Menu_FindItemByName ( menuHUD , " deathtimer " ) ;
if ( item )
{
UI_DrawProportionalString (
item - > window . rect . x ,
item - > window . rect . y ,
timeStr ,
UI_SMALLFONT | UI_DROPSHADOW ,
item - > window . foreColor ) ;
}
}
int cgSiegeEntityRender = 0 ;
static void CG_DrawSiegeHUDItem ( void )
{
void * g2 ;
qhandle_t handle ;
vec3_t origin , angles ;
vec3_t mins , maxs ;
float len ;
centity_t * cent = & cg_entities [ cgSiegeEntityRender ] ;
if ( cent - > ghoul2 )
{
g2 = cent - > ghoul2 ;
handle = 0 ;
}
else
{
handle = cgs . gameModels [ cent - > currentState . modelindex ] ;
g2 = NULL ;
}
if ( handle )
{
trap_R_ModelBounds ( handle , mins , maxs ) ;
}
else
{
VectorSet ( mins , - 16 , - 16 , - 20 ) ;
VectorSet ( maxs , 16 , 16 , 32 ) ;
}
origin [ 2 ] = - 0.5 * ( mins [ 2 ] + maxs [ 2 ] ) ;
origin [ 1 ] = 0.5 * ( mins [ 1 ] + maxs [ 1 ] ) ;
len = 0.5 * ( maxs [ 2 ] - mins [ 2 ] ) ;
origin [ 0 ] = len / 0.268 ;
VectorClear ( angles ) ;
angles [ YAW ] = cg . autoAngles [ YAW ] ;
CG_Draw3DModel ( 8 , 8 , 64 , 64 , handle , g2 , cent - > currentState . g2radius , 0 , origin , angles ) ;
cgSiegeEntityRender = 0 ; //reset for next frame
}
/*====================================
chatbox functionality - rww
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# define CHATBOX_CUTOFF_LEN 550
# define CHATBOX_FONT_HEIGHT 20
//utility func, insert a string into a string at the specified
//place (assuming this will not overflow the buffer)
void CG_ChatBox_StrInsert ( char * buffer , int place , char * str )
{
int insLen = strlen ( str ) ;
int i = strlen ( buffer ) ;
int k = 0 ;
buffer [ i + insLen + 1 ] = 0 ; //terminate the string at its new length
while ( i > = place )
{
buffer [ i + insLen ] = buffer [ i ] ;
i - - ;
}
i + + ;
while ( k < insLen )
{
buffer [ i ] = str [ k ] ;
i + + ;
k + + ;
}
}
//add chatbox string
void CG_ChatBox_AddString ( char * chatStr )
{
chatBoxItem_t * chat = & cg . chatItems [ cg . chatItemActive ] ;
float chatLen ;
if ( cg_chatBox . integer < = 0 )
{ //don't bother then.
return ;
}
memset ( chat , 0 , sizeof ( chatBoxItem_t ) ) ;
if ( strlen ( chatStr ) > sizeof ( chat - > string ) )
{ //too long, terminate at proper len.
chatStr [ sizeof ( chat - > string ) - 1 ] = 0 ;
}
strcpy ( chat - > string , chatStr ) ;
chat - > time = cg . time + cg_chatBox . integer ;
chat - > lines = 1 ;
chatLen = CG_Text_Width ( chat - > string , 1.0f , FONT_SMALL ) ;
if ( chatLen > CHATBOX_CUTOFF_LEN )
{ //we have to break it into segments...
int i = 0 ;
int lastLinePt = 0 ;
char s [ 2 ] ;
chatLen = 0 ;
while ( chat - > string [ i ] )
{
s [ 0 ] = chat - > string [ i ] ;
s [ 1 ] = 0 ;
chatLen + = CG_Text_Width ( s , 0.65f , FONT_SMALL ) ;
if ( chatLen > = CHATBOX_CUTOFF_LEN )
{
int j = i ;
while ( j > 0 & & j > lastLinePt )
{
if ( chat - > string [ j ] = = ' ' )
{
break ;
}
j - - ;
}
if ( chat - > string [ j ] = = ' ' )
{
i = j ;
}
chat - > lines + + ;
CG_ChatBox_StrInsert ( chat - > string , i , " \n " ) ;
i + + ;
chatLen = 0 ;
lastLinePt = i + 1 ;
}
i + + ;
}
}
cg . chatItemActive + + ;
if ( cg . chatItemActive > = MAX_CHATBOX_ITEMS )
{
cg . chatItemActive = 0 ;
}
}
//insert item into array (rearranging the array if necessary)
void CG_ChatBox_ArrayInsert ( chatBoxItem_t * * array , int insPoint , int maxNum , chatBoxItem_t * item )
{
if ( array [ insPoint ] )
{ //recursively call, to move everything up to the top
if ( insPoint + 1 > = maxNum )
{
CG_Error ( " CG_ChatBox_ArrayInsert: Exceeded array size " ) ;
}
CG_ChatBox_ArrayInsert ( array , insPoint + 1 , maxNum , array [ insPoint ] ) ;
}
//now that we have moved anything that would be in this slot up, insert what we want into the slot
array [ insPoint ] = item ;
}
//go through all the chat strings and draw them if they are not yet expired
static CGAME_INLINE void CG_ChatBox_DrawStrings ( void )
{
chatBoxItem_t * drawThese [ MAX_CHATBOX_ITEMS ] ;
int numToDraw = 0 ;
int linesToDraw = 0 ;
int i = 0 ;
int x = 30 ;
int y = cg . scoreBoardShowing ? 475 : cg_chatBoxHeight . integer ;
float fontScale = 0.65f ;
if ( ! cg_chatBox . integer )
{
return ;
}
memset ( drawThese , 0 , sizeof ( drawThese ) ) ;
while ( i < MAX_CHATBOX_ITEMS )
{
if ( cg . chatItems [ i ] . time > = cg . time )
{
int check = numToDraw ;
int insertionPoint = numToDraw ;
while ( check > = 0 )
{
if ( drawThese [ check ] & &
cg . chatItems [ i ] . time < drawThese [ check ] - > time )
{ //insert here
insertionPoint = check ;
}
check - - ;
}
CG_ChatBox_ArrayInsert ( drawThese , insertionPoint , MAX_CHATBOX_ITEMS , & cg . chatItems [ i ] ) ;
numToDraw + + ;
linesToDraw + = cg . chatItems [ i ] . lines ;
}
i + + ;
}
if ( ! numToDraw )
{ //nothing, then, just get out of here now.
return ;
}
//move initial point up so we draw bottom-up (visually)
y - = ( CHATBOX_FONT_HEIGHT * fontScale ) * linesToDraw ;
//we have the items we want to draw, just quickly loop through them now
i = 0 ;
while ( i < numToDraw )
{
CG_Text_Paint ( x , y , fontScale , colorWhite , drawThese [ i ] - > string , 0 , 0 , ITEM_TEXTSTYLE_OUTLINED , FONT_SMALL ) ;
y + = ( ( CHATBOX_FONT_HEIGHT * fontScale ) * drawThese [ i ] - > lines ) ;
i + + ;
}
}
static void CG_Draw2DScreenTints ( void )
{
float rageTime , rageRecTime , absorbTime , protectTime , ysalTime ;
vec4_t hcolor ;
if ( cgs . clientinfo [ cg . snap - > ps . clientNum ] . team ! = TEAM_SPECTATOR )
{
if ( cg . snap - > ps . fd . forcePowersActive & ( 1 < < FP_RAGE ) )
{
if ( ! cgRageTime )
{
cgRageTime = cg . time ;
}
rageTime = ( float ) ( cg . time - cgRageTime ) ;
rageTime / = 9000 ;
if ( rageTime < 0 )
{
rageTime = 0 ;
}
if ( rageTime > 0.15 )
{
rageTime = 0.15 ;
}
hcolor [ 3 ] = rageTime ;
hcolor [ 0 ] = 0.7 ;
hcolor [ 1 ] = 0 ;
hcolor [ 2 ] = 0 ;
if ( ! cg . renderingThirdPerson )
{
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
cgRageFadeTime = 0 ;
cgRageFadeVal = 0 ;
}
else if ( cgRageTime )
{
if ( ! cgRageFadeTime )
{
cgRageFadeTime = cg . time ;
cgRageFadeVal = 0.15 ;
}
rageTime = cgRageFadeVal ;
cgRageFadeVal - = ( cg . time - cgRageFadeTime ) * 0.000005 ;
if ( rageTime < 0 )
{
rageTime = 0 ;
}
if ( rageTime > 0.15 )
{
rageTime = 0.15 ;
}
if ( cg . snap - > ps . fd . forceRageRecoveryTime > cg . time )
{
float checkRageRecTime = rageTime ;
if ( checkRageRecTime < 0.15 )
{
checkRageRecTime = 0.15 ;
}
hcolor [ 3 ] = checkRageRecTime ;
hcolor [ 0 ] = rageTime * 4 ;
if ( hcolor [ 0 ] < 0.2 )
{
hcolor [ 0 ] = 0.2 ;
}
hcolor [ 1 ] = 0.2 ;
hcolor [ 2 ] = 0.2 ;
}
else
{
hcolor [ 3 ] = rageTime ;
hcolor [ 0 ] = 0.7 ;
hcolor [ 1 ] = 0 ;
hcolor [ 2 ] = 0 ;
}
if ( ! cg . renderingThirdPerson & & rageTime )
{
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
else
{
if ( cg . snap - > ps . fd . forceRageRecoveryTime > cg . time )
{
hcolor [ 3 ] = 0.15 ;
hcolor [ 0 ] = 0.2 ;
hcolor [ 1 ] = 0.2 ;
hcolor [ 2 ] = 0.2 ;
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
cgRageTime = 0 ;
}
}
else if ( cg . snap - > ps . fd . forceRageRecoveryTime > cg . time )
{
if ( ! cgRageRecTime )
{
cgRageRecTime = cg . time ;
}
rageRecTime = ( float ) ( cg . time - cgRageRecTime ) ;
rageRecTime / = 9000 ;
if ( rageRecTime < 0.15 ) //0)
{
rageRecTime = 0.15 ; //0;
}
if ( rageRecTime > 0.15 )
{
rageRecTime = 0.15 ;
}
hcolor [ 3 ] = rageRecTime ;
hcolor [ 0 ] = 0.2 ;
hcolor [ 1 ] = 0.2 ;
hcolor [ 2 ] = 0.2 ;
if ( ! cg . renderingThirdPerson )
{
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
cgRageRecFadeTime = 0 ;
cgRageRecFadeVal = 0 ;
}
else if ( cgRageRecTime )
{
if ( ! cgRageRecFadeTime )
{
cgRageRecFadeTime = cg . time ;
cgRageRecFadeVal = 0.15 ;
}
rageRecTime = cgRageRecFadeVal ;
cgRageRecFadeVal - = ( cg . time - cgRageRecFadeTime ) * 0.000005 ;
if ( rageRecTime < 0 )
{
rageRecTime = 0 ;
}
if ( rageRecTime > 0.15 )
{
rageRecTime = 0.15 ;
}
hcolor [ 3 ] = rageRecTime ;
hcolor [ 0 ] = 0.2 ;
hcolor [ 1 ] = 0.2 ;
hcolor [ 2 ] = 0.2 ;
if ( ! cg . renderingThirdPerson & & rageRecTime )
{
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
else
{
cgRageRecTime = 0 ;
}
}
if ( cg . snap - > ps . fd . forcePowersActive & ( 1 < < FP_ABSORB ) )
{
if ( ! cgAbsorbTime )
{
cgAbsorbTime = cg . time ;
}
absorbTime = ( float ) ( cg . time - cgAbsorbTime ) ;
absorbTime / = 9000 ;
if ( absorbTime < 0 )
{
absorbTime = 0 ;
}
if ( absorbTime > 0.15 )
{
absorbTime = 0.15 ;
}
hcolor [ 3 ] = absorbTime / 2 ;
hcolor [ 0 ] = 0 ;
hcolor [ 1 ] = 0 ;
hcolor [ 2 ] = 0.7 ;
if ( ! cg . renderingThirdPerson )
{
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
cgAbsorbFadeTime = 0 ;
cgAbsorbFadeVal = 0 ;
}
else if ( cgAbsorbTime )
{
if ( ! cgAbsorbFadeTime )
{
cgAbsorbFadeTime = cg . time ;
cgAbsorbFadeVal = 0.15 ;
}
absorbTime = cgAbsorbFadeVal ;
cgAbsorbFadeVal - = ( cg . time - cgAbsorbFadeTime ) * 0.000005 ;
if ( absorbTime < 0 )
{
absorbTime = 0 ;
}
if ( absorbTime > 0.15 )
{
absorbTime = 0.15 ;
}
hcolor [ 3 ] = absorbTime / 2 ;
hcolor [ 0 ] = 0 ;
hcolor [ 1 ] = 0 ;
hcolor [ 2 ] = 0.7 ;
if ( ! cg . renderingThirdPerson & & absorbTime )
{
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
else
{
cgAbsorbTime = 0 ;
}
}
if ( cg . snap - > ps . fd . forcePowersActive & ( 1 < < FP_PROTECT ) )
{
if ( ! cgProtectTime )
{
cgProtectTime = cg . time ;
}
protectTime = ( float ) ( cg . time - cgProtectTime ) ;
protectTime / = 9000 ;
if ( protectTime < 0 )
{
protectTime = 0 ;
}
if ( protectTime > 0.15 )
{
protectTime = 0.15 ;
}
hcolor [ 3 ] = protectTime / 2 ;
hcolor [ 0 ] = 0 ;
hcolor [ 1 ] = 0.7 ;
hcolor [ 2 ] = 0 ;
if ( ! cg . renderingThirdPerson )
{
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
cgProtectFadeTime = 0 ;
cgProtectFadeVal = 0 ;
}
else if ( cgProtectTime )
{
if ( ! cgProtectFadeTime )
{
cgProtectFadeTime = cg . time ;
cgProtectFadeVal = 0.15 ;
}
protectTime = cgProtectFadeVal ;
cgProtectFadeVal - = ( cg . time - cgProtectFadeTime ) * 0.000005 ;
if ( protectTime < 0 )
{
protectTime = 0 ;
}
if ( protectTime > 0.15 )
{
protectTime = 0.15 ;
}
hcolor [ 3 ] = protectTime / 2 ;
hcolor [ 0 ] = 0 ;
hcolor [ 1 ] = 0.7 ;
hcolor [ 2 ] = 0 ;
if ( ! cg . renderingThirdPerson & & protectTime )
{
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
else
{
cgProtectTime = 0 ;
}
}
if ( cg . snap - > ps . rocketLockIndex ! = ENTITYNUM_NONE & & ( cg . time - cg . snap - > ps . rocketLockTime ) > 0 )
{
CG_DrawRocketLocking ( cg . snap - > ps . rocketLockIndex , cg . snap - > ps . rocketLockTime ) ;
}
if ( BG_HasYsalamiri ( cgs . gametype , & cg . snap - > ps ) )
{
if ( ! cgYsalTime )
{
cgYsalTime = cg . time ;
}
ysalTime = ( float ) ( cg . time - cgYsalTime ) ;
ysalTime / = 9000 ;
if ( ysalTime < 0 )
{
ysalTime = 0 ;
}
if ( ysalTime > 0.15 )
{
ysalTime = 0.15 ;
}
hcolor [ 3 ] = ysalTime / 2 ;
hcolor [ 0 ] = 0.7 ;
hcolor [ 1 ] = 0.7 ;
hcolor [ 2 ] = 0 ;
if ( ! cg . renderingThirdPerson )
{
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
cgYsalFadeTime = 0 ;
cgYsalFadeVal = 0 ;
}
else if ( cgYsalTime )
{
if ( ! cgYsalFadeTime )
{
cgYsalFadeTime = cg . time ;
cgYsalFadeVal = 0.15 ;
}
ysalTime = cgYsalFadeVal ;
cgYsalFadeVal - = ( cg . time - cgYsalFadeTime ) * 0.000005 ;
if ( ysalTime < 0 )
{
ysalTime = 0 ;
}
if ( ysalTime > 0.15 )
{
ysalTime = 0.15 ;
}
hcolor [ 3 ] = ysalTime / 2 ;
hcolor [ 0 ] = 0.7 ;
hcolor [ 1 ] = 0.7 ;
hcolor [ 2 ] = 0 ;
if ( ! cg . renderingThirdPerson & & ysalTime )
{
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
else
{
cgYsalTime = 0 ;
}
}
}
if ( ( cg . refdef . viewContents & CONTENTS_LAVA ) )
{ //tint screen red
float phase = cg . time / 1000.0 * WAVE_FREQUENCY * M_PI * 2 ;
hcolor [ 3 ] = 0.5 + ( 0.15f * sin ( phase ) ) ;
hcolor [ 0 ] = 0.7f ;
hcolor [ 1 ] = 0 ;
hcolor [ 2 ] = 0 ;
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
else if ( ( cg . refdef . viewContents & CONTENTS_SLIME ) )
{ //tint screen green
float phase = cg . time / 1000.0 * WAVE_FREQUENCY * M_PI * 2 ;
hcolor [ 3 ] = 0.4 + ( 0.1f * sin ( phase ) ) ;
hcolor [ 0 ] = 0 ;
hcolor [ 1 ] = 0.7f ;
hcolor [ 2 ] = 0 ;
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
else if ( ( cg . refdef . viewContents & CONTENTS_WATER ) )
{ //tint screen light blue -- FIXME: don't do this if CONTENTS_FOG? (in case someone *does* make a water shader with fog in it?)
float phase = cg . time / 1000.0 * WAVE_FREQUENCY * M_PI * 2 ;
hcolor [ 3 ] = 0.3 + ( 0.05f * sin ( phase ) ) ;
hcolor [ 0 ] = 0 ;
hcolor [ 1 ] = 0.2f ;
hcolor [ 2 ] = 0.8 ;
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
}
}
static void CG_Draw2D ( void ) {
float inTime = cg . invenSelectTime + WEAPON_SELECT_TIME ;
float wpTime = cg . weaponSelectTime + WEAPON_SELECT_TIME ;
float fallTime ;
float bestTime ;
int drawSelect = 0 ;
// if we are taking a levelshot for the menu, don't draw anything
if ( cg . levelShot ) {
return ;
}
if ( cgs . clientinfo [ cg . snap - > ps . clientNum ] . team = = TEAM_SPECTATOR )
{
cgRageTime = 0 ;
cgRageFadeTime = 0 ;
cgRageFadeVal = 0 ;
cgRageRecTime = 0 ;
cgRageRecFadeTime = 0 ;
cgRageRecFadeVal = 0 ;
cgAbsorbTime = 0 ;
cgAbsorbFadeTime = 0 ;
cgAbsorbFadeVal = 0 ;
cgProtectTime = 0 ;
cgProtectFadeTime = 0 ;
cgProtectFadeVal = 0 ;
cgYsalTime = 0 ;
cgYsalFadeTime = 0 ;
cgYsalFadeVal = 0 ;
}
if ( cg_draw2D . integer = = 0 ) {
return ;
}
if ( cg . snap - > ps . pm_type = = PM_INTERMISSION ) {
CG_DrawIntermission ( ) ;
CG_ChatBox_DrawStrings ( ) ;
return ;
}
CG_Draw2DScreenTints ( ) ;
if ( cg . snap - > ps . rocketLockIndex ! = ENTITYNUM_NONE & & ( cg . time - cg . snap - > ps . rocketLockTime ) > 0 )
{
CG_DrawRocketLocking ( cg . snap - > ps . rocketLockIndex , cg . snap - > ps . rocketLockTime ) ;
}
if ( cg . snap - > ps . holocronBits )
{
CG_DrawHolocronIcons ( ) ;
}
if ( cg . snap - > ps . fd . forcePowersActive | | cg . snap - > ps . fd . forceRageRecoveryTime > cg . time )
{
CG_DrawActivePowers ( ) ;
}
if ( cg . snap - > ps . jetpackFuel < 100 )
{ //draw it as long as it isn't full
CG_DrawJetpackFuel ( ) ;
}
if ( cg . snap - > ps . cloakFuel < 100 )
{ //draw it as long as it isn't full
CG_DrawCloakFuel ( ) ;
}
if ( cg . predictedPlayerState . emplacedIndex > 0 )
{
centity_t * eweb = & cg_entities [ cg . predictedPlayerState . emplacedIndex ] ;
if ( eweb - > currentState . weapon = = WP_NONE )
{ //using an e-web, draw its health
CG_DrawEWebHealth ( ) ;
}
}
// Draw this before the text so that any text won't get clipped off
CG_DrawZoomMask ( ) ;
/*
if ( cg . cameraMode ) {
return ;
}
*/
if ( cg . snap - > ps . persistant [ PERS_TEAM ] = = TEAM_SPECTATOR ) {
CG_DrawSpectator ( ) ;
CG_DrawCrosshair ( NULL , 0 ) ;
CG_DrawCrosshairNames ( ) ;
CG_SaberClashFlare ( ) ;
} else {
// don't draw any status if dead or the scoreboard is being explicitly shown
if ( ! cg . showScores & & cg . snap - > ps . stats [ STAT_HEALTH ] > 0 ) {
if ( /*cg_drawStatus.integer*/ 0 ) {
//Reenable if stats are drawn with menu system again
Menu_PaintAll ( ) ;
CG_DrawTimedMenus ( ) ;
}
//CG_DrawTemporaryStats();
CG_DrawAmmoWarning ( ) ;
CG_DrawCrosshairNames ( ) ;
if ( cg_drawStatus . integer )
{
CG_DrawIconBackground ( ) ;
}
if ( inTime > wpTime )
{
drawSelect = 1 ;
bestTime = cg . invenSelectTime ;
}
else //only draw the most recent since they're drawn in the same place
{
drawSelect = 2 ;
bestTime = cg . weaponSelectTime ;
}
if ( cg . forceSelectTime > bestTime )
{
drawSelect = 3 ;
}
switch ( drawSelect )
{
case 1 :
CG_DrawInvenSelect ( ) ;
break ;
case 2 :
CG_DrawWeaponSelect ( ) ;
break ;
case 3 :
CG_DrawForceSelect ( ) ;
break ;
default :
break ;
}
if ( cg_drawStatus . integer )
{
//Powerups now done with upperright stuff
//CG_DrawPowerupIcons();
CG_DrawFlagStatus ( ) ;
}
CG_SaberClashFlare ( ) ;
if ( cg_drawStatus . integer )
{
CG_DrawStats ( ) ;
}
CG_DrawPickupItem ( ) ;
//Do we want to use this system again at some point?
//CG_DrawReward();
}
}
if ( cg . snap - > ps . fallingToDeath )
{
vec4_t hcolor ;
fallTime = ( float ) ( cg . time - cg . snap - > ps . fallingToDeath ) ;
fallTime / = ( FALL_FADE_TIME / 2 ) ;
if ( fallTime < 0 )
{
fallTime = 0 ;
}
if ( fallTime > 1 )
{
fallTime = 1 ;
}
hcolor [ 3 ] = fallTime ;
hcolor [ 0 ] = 0 ;
hcolor [ 1 ] = 0 ;
hcolor [ 2 ] = 0 ;
CG_DrawRect ( 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_WIDTH * SCREEN_HEIGHT , hcolor ) ;
if ( ! gCGHasFallVector )
{
VectorCopy ( cg . snap - > ps . origin , gCGFallVector ) ;
gCGHasFallVector = qtrue ;
}
}
else
{
if ( gCGHasFallVector )
{
gCGHasFallVector = qfalse ;
VectorClear ( gCGFallVector ) ;
}
}
CG_DrawVote ( ) ;
CG_DrawTeamVote ( ) ;
CG_DrawLagometer ( ) ;
if ( ! cg_paused . integer ) {
CG_DrawBracketedEntities ( ) ;
CG_DrawUpperRight ( ) ;
}
if ( ! CG_DrawFollow ( ) ) {
CG_DrawWarmup ( ) ;
}
if ( cgSiegeRoundState )
{
char pStr [ 1024 ] ;
int rTime = 0 ;
//cgSiegeRoundBeganTime = 0;
switch ( cgSiegeRoundState )
{
case 1 :
CG_CenterPrint ( CG_GetStringEdString ( " MP_INGAME " , " WAITING_FOR_PLAYERS " ) , SCREEN_HEIGHT * 0.30 , BIGCHAR_WIDTH ) ;
break ;
case 2 :
rTime = ( SIEGE_ROUND_BEGIN_TIME - ( cg . time - cgSiegeRoundTime ) ) ;
if ( rTime < 0 )
{
rTime = 0 ;
}
if ( rTime > SIEGE_ROUND_BEGIN_TIME )
{
rTime = SIEGE_ROUND_BEGIN_TIME ;
}
rTime / = 1000 ;
rTime + = 1 ;
if ( rTime < 1 )
{
rTime = 1 ;
}
if ( rTime < = 3 & & rTime ! = cgSiegeRoundCountTime )
{
cgSiegeRoundCountTime = rTime ;
switch ( rTime )
{
case 1 :
trap_S_StartLocalSound ( cgs . media . count1Sound , CHAN_ANNOUNCER ) ;
break ;
case 2 :
trap_S_StartLocalSound ( cgs . media . count2Sound , CHAN_ANNOUNCER ) ;
break ;
case 3 :
trap_S_StartLocalSound ( cgs . media . count3Sound , CHAN_ANNOUNCER ) ;
break ;
default :
break ;
}
}
strcpy ( pStr , va ( " %s %i... " , CG_GetStringEdString ( " MP_INGAME " , " ROUNDBEGINSIN " ) , rTime ) ) ;
CG_CenterPrint ( pStr , SCREEN_HEIGHT * 0.30 , BIGCHAR_WIDTH ) ;
//same
break ;
default :
break ;
}
cgSiegeEntityRender = 0 ;
}
else if ( cgSiegeRoundTime )
{
CG_CenterPrint ( " " , SCREEN_HEIGHT * 0.30 , BIGCHAR_WIDTH ) ;
cgSiegeRoundTime = 0 ;
//cgSiegeRoundBeganTime = cg.time;
cgSiegeEntityRender = 0 ;
}
else if ( cgSiegeRoundBeganTime )
{ //Draw how much time is left in the round based on local info.
int timedTeam = TEAM_FREE ;
int timedValue = 0 ;
if ( cgSiegeEntityRender )
{ //render the objective item model since this client has it
CG_DrawSiegeHUDItem ( ) ;
}
if ( team1Timed )
{
timedTeam = TEAM_RED ; //team 1
if ( cg_beatingSiegeTime )
{
timedValue = cg_beatingSiegeTime ;
}
else
{
timedValue = team1Timed ;
}
}
else if ( team2Timed )
{
timedTeam = TEAM_BLUE ; //team 2
if ( cg_beatingSiegeTime )
{
timedValue = cg_beatingSiegeTime ;
}
else
{
timedValue = team2Timed ;
}
}
if ( timedTeam ! = TEAM_FREE )
{ //one of the teams has a timer
int timeRemaining ;
qboolean isMyTeam = qfalse ;
if ( cgs . siegeTeamSwitch & & ! cg_beatingSiegeTime )
{ //in switchy mode but not beating a time, so count up.
timeRemaining = ( cg . time - cgSiegeRoundBeganTime ) ;
if ( timeRemaining < 0 )
{
timeRemaining = 0 ;
}
}
else
{
timeRemaining = ( ( ( cgSiegeRoundBeganTime ) + timedValue ) - cg . time ) ;
}
if ( timeRemaining > timedValue )
{
timeRemaining = timedValue ;
}
else if ( timeRemaining < 0 )
{
timeRemaining = 0 ;
}
if ( timeRemaining )
{
timeRemaining / = 1000 ;
}
if ( cg . predictedPlayerState . persistant [ PERS_TEAM ] = = timedTeam )
{ //the team that's timed is the one this client is on
isMyTeam = qtrue ;
}
CG_DrawSiegeTimer ( timeRemaining , isMyTeam ) ;
}
}
else
{
cgSiegeEntityRender = 0 ;
}
if ( cg_siegeDeathTime )
{
int timeRemaining = ( cg_siegeDeathTime - cg . time ) ;
if ( timeRemaining < 0 )
{
timeRemaining = 0 ;
cg_siegeDeathTime = 0 ;
}
if ( timeRemaining )
{
timeRemaining / = 1000 ;
}
CG_DrawSiegeDeathTimer ( timeRemaining ) ;
}
// don't draw center string if scoreboard is up
cg . scoreBoardShowing = CG_DrawScoreboard ( ) ;
if ( ! cg . scoreBoardShowing ) {
CG_DrawCenterString ( ) ;
}
// always draw chat
CG_ChatBox_DrawStrings ( ) ;
}
static void CG_DrawTourneyScoreboard ( ) {
}
/*
= = = = = = = = = = = = = = = = = = = = =
CG_DrawActive
Perform all drawing needed to completely fill the screen
= = = = = = = = = = = = = = = = = = = = =
*/
void CG_DrawActive ( stereoFrame_t stereoView ) {
float separation ;
vec3_t baseOrg ;
// optionally draw the info screen instead
if ( ! cg . snap ) {
CG_DrawInformation ( ) ;
return ;
}
// optionally draw the tournement scoreboard instead
if ( cg . snap - > ps . persistant [ PERS_TEAM ] = = TEAM_SPECTATOR & &
( cg . snap - > ps . pm_flags & PMF_SCOREBOARD ) ) {
CG_DrawTourneyScoreboard ( ) ;
return ;
}
switch ( stereoView ) {
case STEREO_CENTER :
separation = 0 ;
break ;
case STEREO_LEFT :
separation = - cg_stereoSeparation . value / 2 ;
break ;
case STEREO_RIGHT :
separation = cg_stereoSeparation . value / 2 ;
break ;
default :
separation = 0 ;
CG_Error ( " CG_DrawActive: Undefined stereoView " ) ;
}
// clear around the rendered view if sized down
CG_TileClear ( ) ;
// offset vieworg appropriately if we're doing stereo separation
VectorCopy ( cg . refdef . vieworg , baseOrg ) ;
if ( separation ! = 0 ) {
VectorMA ( cg . refdef . vieworg , - separation , cg . refdef . viewaxis [ 1 ] , cg . refdef . vieworg ) ;
}
cg . refdef . rdflags | = RDF_DRAWSKYBOX ;
// draw 3D view
trap_R_RenderScene ( & cg . refdef ) ;
// restore original viewpoint if running stereo
if ( separation ! = 0 ) {
VectorCopy ( baseOrg , cg . refdef . vieworg ) ;
}
// draw status bar and other floating elements
CG_Draw2D ( ) ;
}