1133 lines
29 KiB
C
1133 lines
29 KiB
C
// Copyright (C) 2001-2002 Raven Software.
|
|
//
|
|
// cg_newdraw.c --
|
|
|
|
#include "cg_local.h"
|
|
#include "../game/bg_public.h"
|
|
#include "../ui/ui_shared.h"
|
|
|
|
extern displayContextDef_t cgDC;
|
|
|
|
static float healthColors[4][4] =
|
|
{
|
|
{ 1.0f, 0.69f, 0.0f, 1.0f } , // normal
|
|
{ 1.0f, 0.2f, 0.2f, 1.0f }, // low health
|
|
{ 0.5f, 0.5f, 0.5f, 1.0f}, // weapon firing
|
|
{ 1.0f, 1.0f, 1.0f, 1.0f } // health > 100
|
|
};
|
|
|
|
static void CG_DrawPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle )
|
|
{
|
|
clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum];
|
|
const char *s;
|
|
|
|
if (!ci)
|
|
{
|
|
return;
|
|
}
|
|
|
|
s = CG_ConfigString(CS_LOCATIONS + ci->location);
|
|
|
|
if (!s || !*s)
|
|
{
|
|
s = "unknown";
|
|
}
|
|
|
|
CG_DrawText(rect->x, rect->y + rect->h, cgs.media.hudFont, scale, color, s, 0, 0 );
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerSniperBullet
|
|
//==============================================================================
|
|
static void CG_DrawPlayerSniperBullet ( rectDef_t* rect, qhandle_t shader, int bullet )
|
|
{
|
|
// Dont draw the bullet if the player doesnt have enough ammo
|
|
if ( bullet > cg.predictedPlayerState.clip[ATTACK_NORMAL][WP_MSG90A1] )
|
|
{
|
|
return;
|
|
}
|
|
|
|
CG_DrawStretchPic ( rect->x, rect->y, rect->w, rect->h, 0, 0, 1, 1, NULL, shader );
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerSniperMagnification
|
|
//==============================================================================
|
|
static void CG_DrawPlayerSniperMagnification ( rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
const char* mag;
|
|
|
|
switch ( cg.predictedPlayerState.zoomFov )
|
|
{
|
|
default:
|
|
case 20: mag = "5x"; break;
|
|
case 10: mag = "10x"; break;
|
|
case 5: mag = "20x"; break;
|
|
}
|
|
|
|
// Center the text
|
|
CG_DrawText (rect->x, rect->y, font, scale, color, mag, 0, 0 );
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerWeaponName
|
|
//==============================================================================
|
|
static void CG_DrawPlayerWeaponName ( rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
float width;
|
|
const char* name;
|
|
|
|
if( cg.weaponSelect > WP_NONE )
|
|
{
|
|
// Equipped weapon
|
|
name = weaponData[cg.weaponSelect].classname;
|
|
}
|
|
else
|
|
{
|
|
// No weapon equipped.
|
|
name = "NONE";
|
|
}
|
|
|
|
// Get the width of the text so we can center it
|
|
width = trap_R_GetTextWidth ( name, font, scale, 0 );
|
|
|
|
// Center the text
|
|
CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, name, 0, 0 );
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerWeaponName
|
|
//==============================================================================
|
|
static void CG_DrawPlayerAltWeaponName ( rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
float width;
|
|
const char* name;
|
|
|
|
if( cg.weaponSelect > WP_NONE )
|
|
{
|
|
// Equipped weapon
|
|
name = weaponData[cg.weaponSelect].attack[ATTACK_ALTERNATE].name;
|
|
}
|
|
else
|
|
{
|
|
// No weapon equipped.
|
|
name = "NONE";
|
|
}
|
|
|
|
// Get the width of the text so we can center it
|
|
width = trap_R_GetTextWidth ( name, font, scale, 0 );
|
|
|
|
// Center the text
|
|
CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, name, 0, 0 );
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerWeaponAmmo
|
|
//==============================================================================
|
|
static void CG_DrawPlayerWeaponAmmo(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
const char *ammo;
|
|
int value;
|
|
float width;
|
|
|
|
// If the client doenst have a selected weapon then dont draw the ammo
|
|
if ( cg.weaponSelect <= WP_NONE )
|
|
return;
|
|
|
|
// Retrieve the ammo value
|
|
value = cg.predictedPlayerState.ammo[weaponData[cg.weaponSelect].attack[ATTACK_NORMAL].ammoIndex];
|
|
|
|
// If the ammo value is crazy then dont display it
|
|
if ( value <= -1 )
|
|
return;
|
|
|
|
// Build the ammo string padded with zeros
|
|
ammo = va ( "%03d", value );
|
|
|
|
// Retrive the width of the ammo string so it can be centered
|
|
width = trap_R_GetTextWidth (ammo, font, scale, 0 );
|
|
|
|
// Draw the ammo string centered
|
|
CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, ammo, 0, 0 );
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerAltWeaponAmmo
|
|
//==============================================================================
|
|
static void CG_DrawPlayerAltWeaponAmmo(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
const char *ammo;
|
|
int value;
|
|
float width;
|
|
|
|
// If the client doenst have a selected weapon then dont draw the ammo
|
|
if ( cg.weaponSelect <= WP_NONE )
|
|
return;
|
|
|
|
// If the selected weapon doesn't have an altclip, don't draw.
|
|
if(weaponData[cg.weaponSelect].attack[ATTACK_ALTERNATE].clipSize<=0)
|
|
return;
|
|
|
|
// Retrieve the ammo value
|
|
value = cg.predictedPlayerState.ammo[weaponData[cg.weaponSelect].attack[ATTACK_ALTERNATE].ammoIndex];
|
|
value += cg.predictedPlayerState.clip[ATTACK_ALTERNATE][cg.weaponSelect];
|
|
|
|
// If the ammo value is crazy then dont display it
|
|
if ( value <= -1 )
|
|
return;
|
|
|
|
// Build the ammo string padded with zeros
|
|
ammo = va ( "%03d", value );
|
|
|
|
// Retrive the width of the ammo string so it can be centered
|
|
width = trap_R_GetTextWidth (ammo, font, scale, 0 );
|
|
|
|
// Draw the ammo string centered
|
|
CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, ammo, 0, 0 );
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerAltWeaponAmmoIcon
|
|
//==============================================================================
|
|
static void CG_DrawPlayerAltWeaponAmmoIcon(rectDef_t *rect, vec4_t color )
|
|
{
|
|
vec4_t fade;
|
|
|
|
// If the client doenst have a selected weapon then dont draw the ammo icon
|
|
if ( cg.weaponSelect <= WP_NONE )
|
|
return;
|
|
|
|
// If there is no loaded icon then dont draw it
|
|
if ( !cg_weapons[cg.weaponSelect].attack[ATTACK_ALTERNATE].ammoIcon )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Fade out the icon if there isnt anything in the alt clip
|
|
fade[0] = color[0];
|
|
fade[1] = color[1];
|
|
fade[2] = color[2];
|
|
fade[3] = color[3] * (cg.predictedPlayerState.clip[ATTACK_ALTERNATE][cg.weaponSelect]?1:0.20f);
|
|
|
|
trap_R_SetColor ( fade );
|
|
|
|
// Draw the icon
|
|
CG_DrawPic ( rect->x, rect->y, rect->w, rect->h, cg_weapons[cg.weaponSelect].attack[ATTACK_ALTERNATE].ammoIcon );
|
|
|
|
// Back to no color
|
|
trap_R_SetColor ( NULL );
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerWeaponClip
|
|
//==============================================================================
|
|
static void CG_DrawPlayerWeaponClip (rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
const char *clip;
|
|
int value;
|
|
float width;
|
|
|
|
// If the client doenst have a selected weapon then dont draw the ammo
|
|
if ( cg.weaponSelect <= WP_NONE )
|
|
return;
|
|
|
|
// Retrieve the ammo value
|
|
value = cg.predictedPlayerState.clip[ATTACK_NORMAL][cg.weaponSelect];
|
|
|
|
// If the ammo value is crazy then dont display it
|
|
if ( value <= -1 )
|
|
return;
|
|
|
|
// Build the clip string padded with zeros
|
|
clip = va ( "%02d", value );
|
|
|
|
// Retrive the width of the clip string so it can be centered
|
|
width = trap_R_GetTextWidth (clip, font, scale, 0 );
|
|
|
|
// Draw the clip string centered
|
|
CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, clip, 0, 0 );
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerWeaponMode
|
|
//==============================================================================
|
|
static void CG_DrawPlayerWeaponMode ( rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
float width;
|
|
const char* mode;
|
|
int curMode;
|
|
|
|
// Use the current fire mode for this weapon, if its undefined then find what it will
|
|
// be once its set
|
|
curMode = cg.predictedPlayerState.firemode[cg.weaponSelect];
|
|
if ( curMode == WP_FIREMODE_NONE )
|
|
{
|
|
curMode = BG_FindFireMode ( cg.weaponSelect, ATTACK_NORMAL, WP_FIREMODE_AUTO );
|
|
}
|
|
|
|
// TODO: Retrieve the real mode
|
|
switch ( curMode )
|
|
{
|
|
case WP_FIREMODE_NONE:
|
|
mode = "";
|
|
break;
|
|
case WP_FIREMODE_AUTO:
|
|
mode = "AUTO";
|
|
break;
|
|
case WP_FIREMODE_BURST:
|
|
mode = "BURST";
|
|
break;
|
|
case WP_FIREMODE_SINGLE:
|
|
mode = "SINGLE";
|
|
break;
|
|
default:
|
|
// This shouldn't happen.
|
|
assert(0);
|
|
mode = "";
|
|
}
|
|
|
|
// Get the width of the text so we can center it
|
|
width = trap_R_GetTextWidth ( mode, font, scale, 0 );
|
|
|
|
// Center the text
|
|
CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, mode, 0, 0 );
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawUseIcon
|
|
//==============================================================================
|
|
void CG_DrawUseIcon ( rectDef_t* rect )
|
|
{
|
|
// If not in a use zone then dont bother
|
|
if ( !(cg.predictedPlayerState.pm_flags & PMF_CAN_USE ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
CG_DrawStretchPic ( rect->x, rect->y, rect->w, rect->h,0, 0, 1, 1, NULL,
|
|
cgs.gameIcons [ cg.predictedPlayerState.stats[STAT_USEICON] ] );
|
|
|
|
if ( cg.predictedPlayerState.stats[STAT_USETIME] )
|
|
{
|
|
float w = 98.0f * (float)cg.predictedPlayerState.stats[STAT_USETIME] / (float)cg.predictedPlayerState.stats[STAT_USETIME_MAX];
|
|
CG_DrawRect ( rect->x + rect->h + 10, rect->y + 9, 100, rect->h - 18, 1, colorWhite );
|
|
CG_FillRect ( rect->x + rect->h + 11, rect->y + 10, w, rect->h - 20, colorRed );
|
|
CG_DrawRect ( rect->x + rect->h + 11, rect->y + 10, w, rect->h - 20, 1, colorBlack );
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerGametypeItems
|
|
//==============================================================================
|
|
void CG_DrawPlayerGametypeItems ( rectDef_t* rect )
|
|
{
|
|
float x;
|
|
int i;
|
|
|
|
// If not in a use zone then dont bother
|
|
if ( cg.predictedPlayerState.pm_flags & PMF_CAN_USE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
x = rect->x;
|
|
|
|
for ( i = 0; i < MAX_GAMETYPE_ITEMS; i ++ )
|
|
{
|
|
// Doesnt have this mission item
|
|
if ( !(cg.predictedPlayerState.stats[STAT_GAMETYPE_ITEMS] & (1<<i)) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( !cg_items[i+MODELINDEX_GAMETYPE_ITEM].icon )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
CG_DrawPic ( x, rect->y, rect->w, rect->h, cg_items[i+MODELINDEX_GAMETYPE_ITEM].icon );
|
|
|
|
x += 2;
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
// CG_DrawPlayerArmor
|
|
//==============================================================================
|
|
void CG_DrawPlayerArmor ( rectDef_t* rect )
|
|
{
|
|
float x;
|
|
float w;
|
|
|
|
// Draw the icon
|
|
trap_R_SetColor ( NULL );
|
|
|
|
w = rect->w;
|
|
x = rect->x;
|
|
|
|
for ( ; w >= rect->h; w -= rect->h, x += rect->h )
|
|
{
|
|
CG_DrawPic ( x, rect->y - rect->h, rect->h, rect->h, cgs.media.armorShader );
|
|
}
|
|
|
|
if ( w )
|
|
{
|
|
CG_DrawStretchPic ( x, rect->y - rect->h, w, rect->h,
|
|
0, 0, w/rect->h, 1.0f, NULL, cgs.media.armorShader );
|
|
}
|
|
}
|
|
|
|
|
|
static void CG_DrawPlayerScore( rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
const char* s;
|
|
|
|
s = va("%03d",cg.snap->ps.persistant[PERS_SCORE]);
|
|
|
|
CG_DrawText(rect->x + (rect->w - trap_R_GetTextWidth(s,font,scale,0)) / 2, rect->y + rect->h, font, scale, color, s, 0, 0 );
|
|
}
|
|
|
|
static void CG_DrawRedScore(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
int value;
|
|
char num[16];
|
|
|
|
if ( cgs.scores1 == SCORE_NOT_PRESENT )
|
|
{
|
|
Com_sprintf (num, sizeof(num), "-");
|
|
}
|
|
else
|
|
{
|
|
Com_sprintf (num, sizeof(num), "%i", cgs.scores1);
|
|
}
|
|
|
|
value = trap_R_GetTextWidth (num, font, scale, 0);
|
|
|
|
CG_DrawText (rect->x + rect->w - value, rect->y + rect->h, font, scale, color, num, 0, 0 );
|
|
}
|
|
|
|
static void CG_DrawBlueScore(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
int value;
|
|
char num[16];
|
|
|
|
if ( cgs.scores2 == SCORE_NOT_PRESENT )
|
|
{
|
|
Com_sprintf (num, sizeof(num), "-");
|
|
}
|
|
else
|
|
{
|
|
Com_sprintf (num, sizeof(num), "%i", cgs.scores2);
|
|
}
|
|
|
|
value = trap_R_GetTextWidth(num, font, scale, 0 );
|
|
CG_DrawText(rect->x + rect->w - value, rect->y + rect->h, font, scale, color, num, 0, 0 );
|
|
}
|
|
|
|
#define MSECS_PER_FRAME (1000.0 / 60.0)
|
|
#define HUD_FADE_SPEED 0.05
|
|
|
|
float TimeAdjustHUDVal(float mainVal, float dstVal, float factor)
|
|
{
|
|
mainVal = mainVal * (1.0 - factor) + dstVal * factor;
|
|
|
|
//once we get close enough, just finish up
|
|
if(fabs(mainVal - dstVal) < .01)
|
|
{ // if we don't have this, the last few pixels take FOREVER
|
|
mainVal = dstVal;
|
|
}
|
|
|
|
return mainVal;
|
|
}
|
|
|
|
void HandleHUDSegment(float *floorVal, float *ceilVal, float dstVal, float factor)
|
|
{
|
|
if(dstVal < *floorVal)
|
|
{
|
|
*floorVal = dstVal;
|
|
}
|
|
else if(dstVal > *floorVal)
|
|
{
|
|
*floorVal = TimeAdjustHUDVal(*floorVal, dstVal, factor);
|
|
}
|
|
|
|
if(dstVal > *ceilVal)
|
|
{
|
|
*ceilVal = dstVal;
|
|
}
|
|
else if(dstVal < *ceilVal)
|
|
{
|
|
*ceilVal = TimeAdjustHUDVal(*ceilVal, dstVal, factor);
|
|
}
|
|
}
|
|
|
|
float CG_GetValue(int ownerDraw)
|
|
{
|
|
centity_t *cent;
|
|
playerState_t *ps;
|
|
|
|
cent = CG_GetEntity ( cg.snap->ps.clientNum );
|
|
ps = &cg.snap->ps;
|
|
|
|
switch (ownerDraw)
|
|
{
|
|
case CG_PLAYER_WEAPON_AMMO:
|
|
if ( cent->currentState.weapon )
|
|
{
|
|
return ps->ammo[weaponData[cent->currentState.weapon].attack[ATTACK_NORMAL].ammoIndex];
|
|
}
|
|
break;
|
|
|
|
case CG_PLAYER_SCORE:
|
|
return cg.snap->ps.persistant[PERS_SCORE];
|
|
|
|
case CG_PLAYER_HEALTH:
|
|
return ((float) ps->stats[STAT_HEALTH] * 0.01f) + 0.01f;
|
|
|
|
case CG_PLAYER_HEALTH_FADE:
|
|
{
|
|
static float healthEdge = 0.0;
|
|
static float healthFull = 0.0;
|
|
|
|
float curHealth = ps->stats[STAT_HEALTH] * 0.01;
|
|
float adjustFactor = (cg.frametime / MSECS_PER_FRAME) * HUD_FADE_SPEED;
|
|
|
|
HandleHUDSegment(&healthEdge, &healthFull, curHealth, adjustFactor);
|
|
|
|
if ( healthFull < 0 )
|
|
healthFull = 0;
|
|
|
|
return healthFull;
|
|
}
|
|
|
|
case CG_PLAYER_ARMOR_FADE:
|
|
{
|
|
static float armorEdge = 0.0;
|
|
static float armorFull = 0.0;
|
|
|
|
float curArmor = ps->stats[STAT_ARMOR] * 0.01;
|
|
float adjustFactor = (cg.frametime / MSECS_PER_FRAME) * HUD_FADE_SPEED;
|
|
|
|
HandleHUDSegment(&armorEdge, &armorFull, curArmor, adjustFactor);
|
|
|
|
if ( armorFull < 0 )
|
|
armorFull = 0;
|
|
|
|
return armorFull;
|
|
}
|
|
|
|
case CG_PLAYER_ARMOR:
|
|
return ((float) ps->stats[STAT_ARMOR] * 0.01f);;
|
|
|
|
case CG_RED_SCORE:
|
|
return cgs.scores1;
|
|
break;
|
|
|
|
case CG_BLUE_SCORE:
|
|
return cgs.scores2;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
qboolean CG_OwnerDrawDisabled(int flags, const char* param )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean CG_OwnerDrawVisible(int flags, const char* param )
|
|
{
|
|
qboolean visible = qtrue;
|
|
|
|
while ( visible )
|
|
{
|
|
// Player on the red team?
|
|
if ( flags & CG_SHOW_ONREDTEAM )
|
|
{
|
|
visible = cg.predictedPlayerState.persistant[PERS_TEAM]==TEAM_RED?qtrue:qfalse;
|
|
flags &= ~(CG_SHOW_ONREDTEAM);
|
|
continue;
|
|
}
|
|
// Player on the blue team?
|
|
else if ( flags & CG_SHOW_ONBLUETEAM )
|
|
{
|
|
visible = cg.predictedPlayerState.persistant[PERS_TEAM]==TEAM_BLUE?qtrue:qfalse;
|
|
flags &= ~(CG_SHOW_ONBLUETEAM);
|
|
}
|
|
else if ( flags & CG_SHOW_HUD_NIGHTVISION )
|
|
{
|
|
visible = ((cg.predictedPlayerState.pm_flags & PMF_GOGGLES_ON) && cg.predictedPlayerState.stats[STAT_GOGGLES] == GOGGLES_NIGHTVISION && !(cg.predictedPlayerState.pm_flags&PMF_ZOOMED))? qtrue : qfalse;
|
|
flags &= ~(CG_SHOW_HUD_NIGHTVISION);
|
|
}
|
|
else if ( flags & CG_SHOW_HUD_THERMAL )
|
|
{
|
|
visible = ((cg.predictedPlayerState.pm_flags & PMF_GOGGLES_ON) && cg.predictedPlayerState.stats[STAT_GOGGLES] == GOGGLES_INFRARED )? qtrue : qfalse;
|
|
flags &= ~(CG_SHOW_HUD_THERMAL);
|
|
}
|
|
// Only draw the sniper scope when zoomed
|
|
else if ( flags & CG_SHOW_HUD_SNIPERSCOPE )
|
|
{
|
|
visible = (cg.predictedPlayerState.pm_flags&PMF_ZOOMED)?qtrue:qfalse;
|
|
flags &= ~(CG_SHOW_HUD_SNIPERSCOPE);
|
|
}
|
|
// Draw the health as long as we arent zoomed
|
|
else if ( flags & CG_SHOW_HUD_HEALTH )
|
|
{
|
|
visible = cg.showScores ? qfalse : qtrue;
|
|
flags &= ~(CG_SHOW_HUD_HEALTH);
|
|
}
|
|
// Timer
|
|
else if ( flags & CG_SHOW_HUD_TIMER )
|
|
{
|
|
if ( cg.showScores )
|
|
{
|
|
visible = qfalse;
|
|
}
|
|
else if ( !cg_drawTimer.integer )
|
|
{
|
|
visible = qfalse;
|
|
}
|
|
|
|
flags &= ~(CG_SHOW_HUD_TIMER);
|
|
}
|
|
// Should the alternate weapon information be shown?
|
|
else if (flags & (CG_SHOW_PLAYER_ALT_WEAPONINFO|CG_HIDE_PLAYER_ALT_WEAPONINFO) )
|
|
{
|
|
if ( cg.predictedPlayerState.pm_flags & PMF_ZOOMED )
|
|
{
|
|
visible = qfalse;
|
|
}
|
|
|
|
if ( cg.showScores )
|
|
{
|
|
visible = qfalse;
|
|
}
|
|
else
|
|
{
|
|
if ( !BG_WeaponHasAlternateAmmo ( cg.weaponSelect ) )
|
|
{
|
|
visible = qfalse;
|
|
}
|
|
|
|
// Dont show it if we dont have ammo
|
|
if ( !cg.predictedPlayerState.ammo[ weaponData[cg.weaponSelect].attack[ATTACK_ALTERNATE].ammoIndex ] &&
|
|
!cg.predictedPlayerState.clip[ATTACK_ALTERNATE][ cg.weaponSelect ] )
|
|
{
|
|
visible = qfalse;
|
|
}
|
|
|
|
// INvert the visible flag for hidden
|
|
if ( flags & CG_HIDE_PLAYER_ALT_WEAPONINFO )
|
|
{
|
|
if ( cg.predictedPlayerState.pm_flags & PMF_ZOOMED )
|
|
{
|
|
visible = qfalse;
|
|
}
|
|
else
|
|
{
|
|
visible = !visible;
|
|
}
|
|
}
|
|
}
|
|
|
|
flags &= ~(CG_SHOW_PLAYER_ALT_WEAPONINFO|CG_HIDE_PLAYER_ALT_WEAPONINFO);
|
|
}
|
|
// Draw the weapon info when we arent zoomed
|
|
else if ( flags & CG_SHOW_HUD_WEAPONINFO )
|
|
{
|
|
visible = (cg.showScores||(cg.predictedPlayerState.pm_flags&PMF_ZOOMED))?qfalse:qtrue;
|
|
flags &= ~(CG_SHOW_HUD_WEAPONINFO);
|
|
}
|
|
else if (flags & CG_SHOW_ANYTEAMGAME)
|
|
{
|
|
if( !cgs.gametypeData->teams )
|
|
{
|
|
visible = qfalse;
|
|
}
|
|
|
|
flags &= ~(CG_SHOW_ANYTEAMGAME);
|
|
}
|
|
else if (flags & CG_SHOW_ANYNONTEAMGAME)
|
|
{
|
|
if( cgs.gametypeData->teams )
|
|
{
|
|
visible = qfalse;
|
|
}
|
|
|
|
flags &= ~(CG_SHOW_ANYNONTEAMGAME);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return visible;
|
|
}
|
|
|
|
static void CG_Draw1stPlace(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
if (cgs.scores1 != SCORE_NOT_PRESENT)
|
|
{
|
|
CG_DrawText(rect->x, rect->y, font, scale, color, va("%2i", cgs.scores1),0, 0 );
|
|
}
|
|
}
|
|
|
|
static void CG_Draw2ndPlace(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
if (cgs.scores2 != SCORE_NOT_PRESENT)
|
|
{
|
|
CG_DrawText(rect->x, rect->y, font, scale, color, va("%2i", cgs.scores2),0, 0 );
|
|
}
|
|
}
|
|
|
|
// Draw an entire row of weapons for the visual weapon selection menu
|
|
|
|
static void CG_DrawWeaponList(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
static vec4_t colorNormal = { 0.5f, 0.5f, 0.5f, 0.8f };
|
|
static vec4_t colorShadow = { 0.0f, 0.0f, 0.0f, 0.25f };
|
|
static vec4_t colorSelected = { 204.0f / 255.0f, 222.0f / 255.0f, 159.0f / 255.0f, 0.925f };
|
|
static vec4_t colorDisabled = { 0.4f, 0.4f, 0.4f, 0.8f };
|
|
|
|
centity_t *cent;
|
|
playerState_t *ps;
|
|
qhandle_t icon;
|
|
int weaponToDraw;
|
|
int x,y;
|
|
int w,h;
|
|
int i,wid;
|
|
int category, activeCategory;
|
|
char numStr[3];
|
|
int category_x[CAT_MAX];
|
|
gitem_t *item;
|
|
const char *s;
|
|
|
|
|
|
vec4_t colorDraw;
|
|
|
|
rect->x = 20;
|
|
rect->y = 65;
|
|
rect->h = 320;
|
|
|
|
// are we showing weapon menu?
|
|
if (!cg.weaponMenuUp)
|
|
{
|
|
return;
|
|
}
|
|
|
|
cent = CG_GetEntity ( cg.snap->ps.clientNum );
|
|
ps = &cg.snap->ps;
|
|
|
|
// If the menu was up during follow then turn it off
|
|
if ( (ps->pm_flags & PMF_FOLLOW) || ps->pm_type == PM_SPECTATOR )
|
|
{
|
|
cg.weaponMenuUp = qfalse;
|
|
return;
|
|
}
|
|
|
|
|
|
h = rect->h / CAT_MAX;
|
|
w = h*2; // we know that the weapon icons are a 2:1 aspect ratio
|
|
|
|
activeCategory = -1;
|
|
|
|
// start at left edge for all weapon categories
|
|
for (i=CAT_NONE; i<CAT_MAX; i++)
|
|
{
|
|
category_x[i] = rect->x + w;
|
|
}
|
|
|
|
for (weaponToDraw = WP_NONE + 1; weaponToDraw < WP_NUM_WEAPONS; weaponToDraw++ )
|
|
{
|
|
category = weaponData[weaponToDraw].category;
|
|
|
|
x = category_x[category];
|
|
y = rect->y + (category-1) * h;
|
|
|
|
// found a weapon in this catagory
|
|
if (weaponToDraw == cg.weaponMenuSelect)
|
|
{
|
|
// this is the currently selected weapon, so draw in green
|
|
Vector4Copy(colorSelected, colorDraw);
|
|
activeCategory = category;
|
|
}
|
|
else if ( (ps->stats[STAT_WEAPONS] & ( 1 << weaponToDraw )) )
|
|
{
|
|
int ammoCount = 0;
|
|
|
|
ammoCount += ps->ammo[weaponData[weaponToDraw].attack[ATTACK_NORMAL].ammoIndex];
|
|
ammoCount += ps->clip[ATTACK_NORMAL][weaponToDraw];
|
|
ammoCount += ps->ammo[weaponData[weaponToDraw].attack[ATTACK_ALTERNATE].ammoIndex];
|
|
ammoCount += ps->clip[ATTACK_ALTERNATE][weaponToDraw];
|
|
|
|
if ( !ammoCount )
|
|
{
|
|
if (CAT_GRENADE <= category)
|
|
{
|
|
// no grenades means no grenades
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// weapon has no ammo so show it disabled
|
|
Vector4Copy(colorDisabled, colorDraw );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// draw in normal color
|
|
Vector4Copy(colorNormal, colorDraw);
|
|
}
|
|
}
|
|
else
|
|
{ // don't have it, so don't draw
|
|
continue;
|
|
}
|
|
|
|
icon = cg_weapons[ weaponToDraw ].weaponIcon;
|
|
if (icon)
|
|
{
|
|
// draw weapon icon
|
|
if (CAT_GRENADE <= category)
|
|
{
|
|
// draw square icons
|
|
trap_R_SetColor( colorShadow );
|
|
CG_DrawPic( x+2, y+2, h * 0.90f, h * 0.90f, icon );
|
|
|
|
trap_R_SetColor( colorDraw );
|
|
CG_DrawPic( x, y, h * 0.90f, h * 0.90f, icon );
|
|
|
|
category_x[category] += h;
|
|
}
|
|
else
|
|
{
|
|
// draw rectangular icons
|
|
trap_R_SetColor( colorShadow );
|
|
CG_DrawPic( x+2, y+2, w * 0.90f, h * 0.90f, icon );
|
|
|
|
trap_R_SetColor( colorDraw );
|
|
CG_DrawPic( x, y, w * 0.90f, h * 0.90f, icon );
|
|
|
|
category_x[category] += w;
|
|
}
|
|
}
|
|
|
|
trap_R_SetColor( NULL );
|
|
}
|
|
|
|
// show weapon catagory numbers
|
|
for (i = CAT_NONE + 1; i < CAT_MAX; i++)
|
|
{
|
|
y = rect->y + (i - 1) * h;
|
|
Com_sprintf(numStr, sizeof(numStr),"%d", i );
|
|
wid = trap_R_GetTextWidth (numStr, font, 1.25f, 0 );
|
|
if (i == activeCategory)
|
|
{
|
|
Vector4Copy(colorSelected, colorDraw);
|
|
}
|
|
else
|
|
{
|
|
Vector4Copy(colorNormal, colorDraw);
|
|
}
|
|
|
|
colorDraw[3] = 1.0f;
|
|
|
|
CG_DrawText (rect->x + (w - wid) / 2 + 2, y, font, 0.6f, colorDraw, numStr, 0, DT_DROPSHADOW );
|
|
}
|
|
|
|
item = BG_FindWeaponItem ( cg.weaponMenuSelect );
|
|
if ( item )
|
|
{
|
|
// Draw the selected weapons name
|
|
s = va("Weapon: %s", item->pickup_name);
|
|
w = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.43f, 0 );
|
|
CG_DrawText ( 640 - rect->x - w, rect->y, cgs.media.hudFont, 0.43f, colorSelected, s, 0, 0 );
|
|
|
|
// Draw the selected weapons ammo count
|
|
if ( BG_WeaponHasAlternateAmmo ( cg.weaponMenuSelect ) )
|
|
{
|
|
s = va("Ammo: %i / %i", cg.predictedPlayerState.clip[ATTACK_NORMAL][cg.weaponMenuSelect] + cg.predictedPlayerState.ammo[weaponData[cg.weaponMenuSelect].attack[ATTACK_NORMAL].ammoIndex],
|
|
cg.predictedPlayerState.clip[ATTACK_ALTERNATE][cg.weaponMenuSelect] + cg.predictedPlayerState.ammo[weaponData[cg.weaponMenuSelect].attack[ATTACK_ALTERNATE].ammoIndex]);
|
|
}
|
|
else
|
|
{
|
|
s = va("Ammo: %i", cg.predictedPlayerState.clip[ATTACK_NORMAL][cg.weaponMenuSelect] + cg.predictedPlayerState.ammo[weaponData[cg.weaponMenuSelect].attack[ATTACK_NORMAL].ammoIndex]);
|
|
}
|
|
|
|
w = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.43f, 0 );
|
|
CG_DrawText ( 640 - rect->x - w, rect->y + 15, cgs.media.hudFont, 0.43f, colorSelected, s, 0, 0 );
|
|
}
|
|
}
|
|
|
|
const char *CG_GetGameStatusText()
|
|
{
|
|
const char *s = "";
|
|
|
|
if ( !cgs.gametypeData->teams )
|
|
{
|
|
if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR )
|
|
{
|
|
s = va("%s place with %i",CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),cg.snap->ps.persistant[PERS_SCORE] );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( cg.teamScores[0] == cg.teamScores[1] )
|
|
{
|
|
s = va("Teams are tied at %i", cg.teamScores[0] );
|
|
}
|
|
else if ( cg.teamScores[0] >= cg.teamScores[1] )
|
|
{
|
|
s = va("Red leads Blue, %i to %i", cg.teamScores[0], cg.teamScores[1] );
|
|
}
|
|
else
|
|
{
|
|
s = va("Blue leads Red, %i to %i", cg.teamScores[1], cg.teamScores[0] );
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
static void CG_DrawGameStatus(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
CG_DrawText (rect->x, rect->y + rect->h, font, scale, color, CG_GetGameStatusText(), 0 , 0 );
|
|
}
|
|
|
|
const char *CG_GameTypeString()
|
|
{
|
|
return cgs.gametypeData->displayName;
|
|
}
|
|
|
|
static void CG_DrawGameType(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
|
|
{
|
|
CG_DrawText (rect->x, rect->y + rect->h, font, scale, color, CG_GameTypeString(), 0, 0 );
|
|
}
|
|
|
|
void CG_OwnerDraw ( float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, qhandle_t font, float scale, vec4_t color, qhandle_t shader, int textStyle, const char* param )
|
|
{
|
|
rectDef_t rect;
|
|
|
|
rect.x = x;
|
|
rect.y = y;
|
|
rect.w = w;
|
|
rect.h = h;
|
|
|
|
switch (ownerDraw)
|
|
{
|
|
case CG_USE_ICON:
|
|
CG_DrawUseIcon ( &rect );
|
|
break;
|
|
|
|
case CG_PLAYER_GAMETYPE_ITEMS:
|
|
CG_DrawPlayerGametypeItems ( &rect );
|
|
break;
|
|
|
|
case CG_PLAYER_ARMOR:
|
|
CG_DrawPlayerArmor ( &rect );
|
|
break;
|
|
|
|
case CG_PLAYER_WEAPON_AMMO:
|
|
CG_DrawPlayerWeaponAmmo(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_PLAYER_WEAPON_CLIP:
|
|
CG_DrawPlayerWeaponClip(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_PLAYER_WEAPON_NAME:
|
|
CG_DrawPlayerWeaponName(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_PLAYER_ALT_WEAPON_NAME:
|
|
CG_DrawPlayerAltWeaponName(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_PLAYER_ALT_WEAPON_AMMO:
|
|
CG_DrawPlayerAltWeaponAmmo(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_PLAYER_ALT_WEAPON_AMMOICON:
|
|
CG_DrawPlayerAltWeaponAmmoIcon ( &rect, color );
|
|
break;
|
|
|
|
case CG_PLAYER_WEAPON_MODE:
|
|
CG_DrawPlayerWeaponMode(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_PLAYER_SCORE:
|
|
CG_DrawPlayerScore(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_GAME_TYPE:
|
|
CG_DrawGameType(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_RED_SCORE:
|
|
CG_DrawRedScore(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_BLUE_SCORE:
|
|
CG_DrawBlueScore(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_GAME_STATUS:
|
|
CG_DrawGameStatus(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_1STPLACE:
|
|
CG_Draw1stPlace(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_2NDPLACE:
|
|
CG_Draw2ndPlace(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_WEAPON_LIST:
|
|
CG_DrawWeaponList(&rect, font, scale, color );
|
|
break;
|
|
|
|
case CG_PLAYER_LOCATION:
|
|
CG_DrawPlayerLocation(&rect, scale, color, textStyle);
|
|
break;
|
|
|
|
case CG_PLAYER_SNIPER_BULLET_1:
|
|
case CG_PLAYER_SNIPER_BULLET_2:
|
|
case CG_PLAYER_SNIPER_BULLET_3:
|
|
case CG_PLAYER_SNIPER_BULLET_4:
|
|
case CG_PLAYER_SNIPER_BULLET_5:
|
|
case CG_PLAYER_SNIPER_BULLET_6:
|
|
CG_DrawPlayerSniperBullet ( &rect, shader, ownerDraw - CG_PLAYER_SNIPER_BULLET_1 + 1);
|
|
break;
|
|
|
|
case CG_PLAYER_SNIPER_MAGNIFICATION:
|
|
CG_DrawPlayerSniperMagnification ( &rect, font, scale, color );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CG_MouseEvent(int x, int y)
|
|
{
|
|
int n;
|
|
|
|
if ( (cg.predictedPlayerState.pm_type == PM_NORMAL || cg.predictedPlayerState.pm_type == PM_SPECTATOR) && cg.showScores == qfalse)
|
|
{
|
|
trap_Key_SetCatcher(0);
|
|
return;
|
|
}
|
|
|
|
cgs.cursorX+= x;
|
|
if (cgs.cursorX < 0)
|
|
{
|
|
cgs.cursorX = 0;
|
|
}
|
|
else if (cgs.cursorX > 640)
|
|
{
|
|
cgs.cursorX = 640;
|
|
}
|
|
|
|
cgs.cursorY += y;
|
|
if (cgs.cursorY < 0)
|
|
{
|
|
cgs.cursorY = 0;
|
|
}
|
|
else if (cgs.cursorY > 480)
|
|
{
|
|
cgs.cursorY = 480;
|
|
}
|
|
|
|
n = Display_CursorType(cgs.cursorX, cgs.cursorY);
|
|
cgs.activeCursor = 0;
|
|
if (n == CURSOR_ARROW)
|
|
{
|
|
cgs.activeCursor = cgs.media.cursor;
|
|
}
|
|
else if (n == CURSOR_SIZER)
|
|
{
|
|
cgs.activeCursor = cgs.media.cursor;
|
|
}
|
|
|
|
if (cgs.capturedItem)
|
|
{
|
|
Display_MouseMove(cgs.capturedItem, x, y);
|
|
}
|
|
else
|
|
{
|
|
Display_MouseMove(NULL, cgs.cursorX, cgs.cursorY);
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
CG_EventHandling
|
|
==================
|
|
type 0 - no event handling
|
|
1 - team menu
|
|
2 - hud editor
|
|
|
|
*/
|
|
void CG_EventHandling(int type)
|
|
{
|
|
cgs.eventHandling = type;
|
|
}
|
|
|
|
|
|
void CG_KeyEvent(int key, qboolean down)
|
|
{
|
|
if (!down)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( cg.predictedPlayerState.pm_type == PM_NORMAL || (cg.predictedPlayerState.pm_type == PM_SPECTATOR && cg.showScores == qfalse))
|
|
{
|
|
CG_EventHandling(CGAME_EVENT_NONE);
|
|
trap_Key_SetCatcher(0);
|
|
return;
|
|
}
|
|
|
|
Display_HandleKey(key, down, cgs.cursorX, cgs.cursorY);
|
|
|
|
if (cgs.capturedItem)
|
|
{
|
|
cgs.capturedItem = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (key == K_MOUSE2 && down)
|
|
{
|
|
cgs.capturedItem = Display_CaptureItem(cgs.cursorX, cgs.cursorY);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CG_RunMenuScript(const char **args)
|
|
{
|
|
}
|
|
|
|
|
|
void CG_GetTeamColor(vec4_t *color)
|
|
{
|
|
if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED) {
|
|
(*color)[0] = 1.0f;
|
|
(*color)[3] = 0.25f;
|
|
(*color)[1] = (*color)[2] = 0.0f;
|
|
} else if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE) {
|
|
(*color)[0] = (*color)[1] = 0.0f;
|
|
(*color)[2] = 1.0f;
|
|
(*color)[3] = 0.25f;
|
|
} else {
|
|
(*color)[0] = (*color)[2] = 0.0f;
|
|
(*color)[1] = 0.17f;
|
|
(*color)[3] = 0.25f;
|
|
}
|
|
}
|
|
|