q3rally/engine/code/cgame/cg_rally_hud.c

956 lines
22 KiB
C

/*
** Copyright (C) 2004 by the Q3Rally Development team
** All rights reserved.
**
** cg_rally_hud.c
**
** Components for the common HUD elements.
**
** Author: STONELANCE
*/
#include "cg_local.h"
float colors[4][4] = {
// { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
{ 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
};
/*
================
CG_DrawRearviewMirror
================
*/
void CG_DrawRearviewMirror( float x, float y, float w, float h) {
//static int lastLowFPSTime;
int i;
//int fps;
float mx, my, mw, mh;
int tmp;
if ( !cg_drawRearView.integer )
return;
if (cg.snap->ps.pm_type == PM_INTERMISSION)
return;
if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR)
return;
/*
if (cg_fpsLimit.integer >= 100)
return;
if (cg_fpsLimit.integer > 0){
fps = 0;
if (cg.frametime){
fps = 1000 / cg.frametime;
}
if (lastLowFPSTime + 3000 >= cg.time){
return;
}
if (fps < cg_fpsLimit.integer){
lastLowFPSTime = cg.time;
return;
}
}
*/
mx = x - 8;
my = y - 7;
mw = w * 1.0534F;
mh = h * 1.2F;
CG_AdjustFrom640( &x, &y, &w, &h );
cg.mirrorRefdef.x = x;
cg.mirrorRefdef.y = y;
cg.mirrorRefdef.width = w;
cg.mirrorRefdef.height = h;
cg.mirrorRefdef.fov_x = 70;
tmp = cg.mirrorRefdef.width / tan( cg.mirrorRefdef.fov_x / 360 * M_PI );
cg.mirrorRefdef.fov_y = atan2( cg.mirrorRefdef.height, tmp );
cg.mirrorRefdef.fov_y = cg.mirrorRefdef.fov_y * 360 / M_PI;
cg.mirrorRefdef.time = cg.time;
cg.mirrorRefdef.rdflags = 0;
// AnglesToAxis( cg.predictedPlayerState.viewangles, mirrorRefdef.viewaxis );
// VectorInverse( mirrorRefdef.viewaxis[0] );
// VectorInverse( mirrorRefdef.viewaxis[1] );
// VectorCopy( cg.predictedPlayerState.origin, mirrorRefdef.vieworg );
// VectorMA( mirrorRefdef.vieworg, 16, mirrorRefdef.viewaxis[2], mirrorRefdef.vieworg );
// add entities and graphics to rearview scene
if (cg_rearViewRenderLevel.integer & RL_MARKS){
CG_AddMarks();
}
if (cg_rearViewRenderLevel.integer & RL_SMOKE){
CG_AddLocalEntities();
}
if (cg_rearViewRenderLevel.integer & RL_PLAYERS || cg_rearViewRenderLevel.integer & RL_OBJECTS){
for (i = 0; i < cg.snap->numEntities; i++){
if (!(cg_rearViewRenderLevel.integer & RL_OBJECTS)){
// skip non-players
if ( cg.snap->entities[i].eType != ET_PLAYER ) continue;
}
if (!(cg_rearViewRenderLevel.integer & RL_PLAYERS)){
// skip players
if ( cg.snap->entities[i].eType == ET_PLAYER ) continue;
}
// FIXME: dont re-lerp entity
CG_AddCEntity( &cg_entities[ cg.snap->entities[ i ].number ] );
}
}
trap_R_RenderScene( &cg.mirrorRefdef );
CG_DrawPic( mx, my, mw, mh, cgs.media.rearviewMirrorShader );
}
/*
================
CG_DrawMMap
TBB - minimap EXPERIMENTAL -
modified rearview but only render stuff from +8192(Z) from
center of bsp, pitched downward, and render only players (flags for ctf).
this will probably drop fps, hopefully not too much and ,
might have to make a cvar for displaying it plus opacity
trying to get this to work like the minimap from UrT
from scratch. must try to make it 2d bitmap
================
*/
void CG_DrawMMap( float x, float y, float w, float h ) {
int i;
float mx, my, mw, mh;
int tmp;
if ( !cg_drawMMap.integer )
return;
if (cg.snap->ps.pm_type == PM_INTERMISSION)
return;
if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR)
return;
/* TBB - minimap to show for only racing and team racing no weapons (for now)
if ( cgs.gametype != GT_RACING )
return;
if ( (cgs.gametype != GT_RACING) || (cgs.gametype != GT_TEAM_RACING) )
return; */
mx = x ;
my = y ;
mw = w;
mh = h;
CG_AdjustFrom640( &x, &y, &w, &h );
cg.mmapRefdef.x = x;
cg.mmapRefdef.y = y;
cg.mmapRefdef.width = w;
cg.mmapRefdef.height = h;
cg.mmapRefdef.fov_x = 70;
tmp = cg.mmapRefdef.width / tan( cg.mmapRefdef.fov_x / 360 * M_PI );
cg.mmapRefdef.fov_y = atan2( cg.mmapRefdef.height, tmp );
cg.mmapRefdef.fov_y = cg.mmapRefdef.fov_y * 360 / M_PI;
cg.mmapRefdef.time = cg.time;
cg.mmapRefdef.rdflags = 0;
// AnglesToAxis( cg.predictedPlayerState.viewangles, mirrorRefdef.viewaxis );
// VectorInverse( mirrorRefdef.viewaxis[0] );
// VectorInverse( mirrorRefdef.viewaxis[1] );
// VectorCopy( cg.predictedPlayerState.origin, mirrorRefdef.vieworg );
// VectorMA( mirrorRefdef.vieworg, 16, mirrorRefdef.viewaxis[2], mirrorRefdef.vieworg );
//TBB
/*only add players to minimap scene
add ctf flag entities later*/
if (cg_rearViewRenderLevel.integer & RL_MARKS){
CG_AddMarks();
}
if (cg_rearViewRenderLevel.integer & RL_SMOKE){
CG_AddLocalEntities();
}
if (cg_rearViewRenderLevel.integer & RL_PLAYERS || cg_rearViewRenderLevel.integer & RL_OBJECTS){
for (i = 0; i < cg.snap->numEntities; i++){
if (!(cg_rearViewRenderLevel.integer & RL_OBJECTS)){
// skip non-players
if ( cg.snap->entities[i].eType != ET_PLAYER ) continue;
}
if (!(cg_rearViewRenderLevel.integer & RL_PLAYERS)){
// skip players
if ( cg.snap->entities[i].eType == ET_PLAYER ) continue;
}
// FIXME: dont re-lerp entity
CG_AddCEntity( &cg_entities[ cg.snap->entities[ i ].number ] );
}
}
//trap_R_RenderScene( &cg.mirrorRefdef );
trap_R_RenderScene( &cg.mmapRefdef );
CG_DrawPic( mx, my, mw, mh, cgs.media.MMapShader );
}
//TBB FIN
/*
================
CG_DrawArrowToCheckpoint
================
*/
static float CG_DrawArrowToCheckpoint( float y ) {
centity_t *cent;
//vec3_t dir;
vec3_t forward, origin, angles;
int i;
float angle1, angle2, angleDiff;
int x, w;
float fx, fy, fw, fh;
float *color;
refdef_t refdef;
refEntity_t ent;
vec3_t mins, maxs, v;
if (cg_entities[cg.snap->ps.clientNum].finishRaceTime)
return y;
for (i = 0; i < MAX_GENTITIES; i++){
cent = &cg_entities[i];
if (cent->currentState.eType != ET_CHECKPOINT) continue;
if (cent->currentState.weapon != cg.snap->ps.stats[STAT_NEXT_CHECKPOINT]) continue;
break;
}
if (i == MAX_GENTITIES)
return y; // no checkpoints found
// VectorSubtract(cent->currentState.origin, cg.predictedPlayerState.origin, dir);
// angle2 = vectoyaw(dir);
// find the distance from the edge of the bounding box
trap_R_ModelBounds( cgs.inlineDrawModel[cent->currentState.modelindex], mins, maxs );
// if the checkpoint was one with no target then mins and maxs are relative to the origin
if( cent->currentState.frame == 0 )
{
VectorAdd( mins, cent->currentState.origin, mins );
VectorAdd( maxs, cent->currentState.origin, maxs );
}
for ( i = 0 ; i < 3 ; i++ ) {
if ( cg.predictedPlayerState.origin[i] < mins[i] ) {
v[i] = mins[i] - cg.predictedPlayerState.origin[i];
} else if ( cg.predictedPlayerState.origin[i] > maxs[i] ) {
v[i] = maxs[i] - cg.predictedPlayerState.origin[i];
} else {
v[i] = 0;
}
}
if( v[0] == 0 && v[1] == 0 && v[2] == 0 )
angle2 = cg.predictedPlayerState.viewangles[YAW];
else
angle2 = vectoyaw(v);
if (cg_checkpointArrowMode.integer == 1){
AngleVectors(cg.refdefViewAngles, forward, NULL, NULL);
angle1 = vectoyaw(forward);
angleDiff = AngleDifference(angle1, angle2);
// draw arrow:
VectorSet(origin, 80, 0, 20);
VectorClear(angles);
angles[YAW] = -angleDiff;
fx = 320 - 64;
fy = 16;
fw = 128;
fh = 96;
CG_AdjustFrom640( &fx, &fy, &fw, &fh );
memset( &refdef, 0, sizeof( refdef ) );
memset( &ent, 0, sizeof( ent ) );
AnglesToAxis( angles, ent.axis );
VectorCopy( origin, ent.origin );
VectorCopy( origin, ent.lightingOrigin );
ent.hModel = cgs.media.checkpointArrow;
// ent.customSkin = trap_R_RegisterShader("gfx/hud/arrow");
ent.renderfx = RF_NOSHADOW; // no stencil shadows
refdef.rdflags = RDF_NOWORLDMODEL;
vectoangles( origin, angles );
AnglesToAxis( angles, refdef.viewaxis );
refdef.fov_x = 40;
refdef.fov_y = 30;
refdef.x = fx;
refdef.y = fy;
refdef.width = fw;
refdef.height = fh;
refdef.time = cg.time;
trap_R_ClearScene();
trap_R_AddRefEntityToScene( &ent );
trap_R_RenderScene( &refdef );
}
//end draw arrow
AngleVectors(cg.predictedPlayerEntity.lerpAngles, forward, NULL, NULL);
angle1 = vectoyaw(forward);
angleDiff = AngleDifference(angle1, angle2);
// if (VectorLength(dir) < 20.0f)
// return y;
if (fabs(angleDiff) > 100){
cg.wrongWayTime = cg.time;
if( !cg.wrongWayStartTime )
cg.wrongWayStartTime = cg.time;
}
else
cg.wrongWayStartTime = 0;
if( !cg.wrongWayStartTime || cg.wrongWayStartTime > cg.time - 2000 )
return y;
w = BIGCHAR_WIDTH * CG_DrawStrlen( "WRONG WAY!" );
x = ( SCREEN_WIDTH - w ) / 2;
color = CG_FadeColor( cg.wrongWayTime, 300 );
if ( !color ) {
return y;
}
trap_R_SetColor( color );
// if (cg_developer.integer)
// CG_Draw3DLine( cent->currentState.origin, cg.snap->ps.origin );
CG_DrawStringExt( x, SCREEN_HEIGHT * .30, "WRONG WAY!", color, qfalse, qtrue,
BIGCHAR_WIDTH, (int)(BIGCHAR_WIDTH * 1.5), 0 );
return y;
}
// takes a 3d coord and change it to screen coords
/*
// Thanks to Golliwog who implemented this bit of code in q3f
static float CG_SFK_AngleToCoord( float angle, int coordRange, float fov, qboolean reverseCoord ){
// Take an angle and return the coord it maps to (may be out of visible range)
// The conversion is: correct fov to degrees: (90.0 / fov), convert to radians: M_PI / 180,
// obtain tangent (results in -1 - 1, at least in visible coords). The first two steps can
// be combined, hence the M_PI * 0.5f / fov.
angle = tan( angle * M_PI * 0.5f / fov );
angle = coordRange * (reverseCoord ? (1.0f - angle) : (1.0f + angle));
return( angle );
}
code:
--------------------------------------------------------------------------------
angles[PITCH] = AngleNormalize180( angles[PITCH] - cg.refdefViewAngles[PITCH] );
adjustedY = CG_SFK_AngleToCoord( angles[PITCH], 240, cg.refdef.fov_y, qfalse );
angles[YAW] = AngleNormalize180( angles[YAW] - cg.refdefViewAngles[YAW] );
adjustedX = CG_SFK_AngleToCoord( angles[YAW], 320, cg.refdef.fov_x, qtrue );
*/
/*
================
CG_DrawTimes
================
*/
static float CG_DrawTimes( float y ) {
centity_t *cent;
int lapTime;
int totalTime;
int x;
char s[128];
char *time;
//ps = &cg.snap->ps;
cent = &cg_entities[cg.snap->ps.clientNum];
if ( cent->finishRaceTime ){
lapTime = cent->finishRaceTime - cent->startLapTime;
totalTime = cent->finishRaceTime - cent->startRaceTime;
}
else if ( cent->startRaceTime ){
lapTime = cg.time - cent->startLapTime;
totalTime = cg.time - cent->startRaceTime;
}
else {
lapTime = 0;
totalTime = 0;
}
//
// Best Time
//
if ( cgs.gametype != GT_DERBY ){
time = getStringForTime( cent->bestLapTime );
Com_sprintf(s, sizeof(s), "B; %s", time);
x = 600 - CG_DrawStrlen(s) * TINYCHAR_WIDTH;
CG_FillRect ( x, y, 96, 18, bgColor );
x+= 8;
y+= 4;
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
y += TINYCHAR_HEIGHT + 4;
}
//
// Lap Time
//
if (cgs.gametype != GT_DERBY){
time = getStringForTime(lapTime);
Com_sprintf(s, sizeof(s), "L: %s", time);
x = 600 - CG_DrawStrlen(s) * TINYCHAR_WIDTH;
CG_FillRect( x, y, 96, 18, bgColor );
x+= 8;
y+= 4;
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
y += TINYCHAR_HEIGHT + 4;
}
//
// Total Time
//
time = getStringForTime(totalTime);
/*
Com_sprintf(s, sizeof(s), "TOTAL TIME: %s", time);
x = 630 - CG_DrawStrlen(s) * SMALLCHAR_WIDTH;
CG_DrawSmallStringColor( x, y, s, colors[0]);
y += SMALLCHAR_HEIGHT;
*/
Com_sprintf(s, sizeof(s), "T: %s", time);
x = 636 - 96;
CG_FillRect( x, y, 96, 18, bgColor );
x += 8;
y += 4;
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
y += TINYCHAR_HEIGHT + 4;
return y;
}
/*
================
CG_DrawLaps
================
*/
static float CG_DrawLaps( float y ) {
centity_t *cent;
//playerState_t *ps;
int curLap;
int numLaps;
char s[64];
int x;
//ps = &cg.snap->ps;
cent = &cg_entities[cg.snap->ps.clientNum];
curLap = cent->currentLap;
numLaps = cgs.laplimit;
Com_sprintf(s, sizeof(s), "LAP: %i/%i", curLap, numLaps);
x = 636 - 96;
CG_FillRect( x, y, 96, 18, bgColor );
x += 8;
y += 4;
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
y += TINYCHAR_HEIGHT + 4;
return y;
}
/*
================
CG_DrawCurrentPosition
================
*/
static float CG_DrawCurrentPosition( float y ) {
centity_t *cent;
//playerState_t *ps;
int pos;
char s[64];
float x, width, height;
//float foreground[4] = { 0, 0, 0.75, 1.0 };
//ps = &cg.snap->ps;
cent = &cg_entities[cg.snap->ps.clientNum];
pos = cent->currentPosition;
Com_sprintf(s, sizeof(s), "POS: ");
x = 636 - 96;
width = 96;
height = 18;
CG_FillRect( x, y, width, height, bgColor );
x += 8;
y += 4;
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
x += TINYCHAR_WIDTH * 5;
CG_DrawTinyDigitalStringColor( x, y, va("%i/%i", pos, cgs.numRacers), colorWhite);
y += 10 + 4;
return y;
}
/*
================
CG_DrawCarAheadAndBehind
================
*/
static float CG_DrawCarAheadAndBehind( float y ) {
centity_t *cent, *other;
char player[64];
int i, j, num;
float x, width, height;
int startPos, endPos;
char s[64];
float background[4] = { 0, 0, 0, 0.5 };
float selected[4] = { 0.75, 0.0, 0.0, 0.5 };
//ps = &cg.snap->ps;
cent = &cg_entities[cg.snap->ps.clientNum];
startPos = cent->currentPosition - 4 < 1 ? 1 : cent->currentPosition - 4;
endPos = startPos + 8 > cgs.numRacers ? cgs.numRacers : startPos + 8;
startPos = endPos - 8 < 1 ? 1 : endPos - 8;
x = 636 - 96;
width = 96;
height = TINYCHAR_HEIGHT;
for (i = startPos; i <= endPos; i++){
num = -1;
for (j = 0; j < cgs.maxclients; j++){
other = &cg_entities[j];
if (!other) continue;
if (other->currentPosition == i){
num = other->currentState.clientNum;
}
}
if (num < 0 || num > cgs.maxclients) continue;
if (num == cent->currentState.clientNum){
CG_FillRect( x, y, width, height, selected );
}
else {
CG_FillRect( x, y, width, height, background );
}
Q_strncpyz(player, cgs.clientinfo[num].name, 16 );
Com_sprintf(s, sizeof(s), "%i-%s", cg_entities[num].currentPosition, player);
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
y += TINYCHAR_HEIGHT;
}
return y;
}
#if 0
/*
=================
CG_DrawHUD_DerbyList
=================
*/
void CG_DrawHUD_DerbyList(float x, float y){
int i;
vec4_t color;
centity_t *cent;
char *time;
float playTime;
// draw heading
CG_FillRect(x, y, 536, 18, bgColor);
// name
CG_DrawTinyDigitalStringColor( x + 42, y, "PLAYER:", colorWhite);
// time
CG_DrawTinyDigitalStringColor( x + 206, y, "TIME:", colorWhite);
// dmg dealt
CG_DrawTinyDigitalStringColor( x + 294, y, "DMG DEALT:", colorWhite);
// dmg taken
CG_DrawTinyDigitalStringColor( x + 442, y, "DMG TAKEN:", colorWhite);
y += 20;
// draw top 8 players
for (i = 0; i < 8; i++){
if (cg.scores[i].scoreFlags < 0) continue; // score is not valid so skip it
cent = &cg_entities[cg.scores[i].client];
if (!cent) continue;
CG_FillRect(x, y, 536, 18, bgColor);
Vector4Copy(colorWhite, color);
if (cg.scores[i].client == cg.snap->ps.clientNum){
if (cg.snap->ps.stats[STAT_HEALTH] <= 0 || cgs.clientinfo[cg.scores[i].client].team == TEAM_SPECTATOR)
Vector4Copy(colorMdGrey, color);
}
else if (cent->currentState.eFlags & EF_DEAD || cgs.clientinfo[cg.scores[i].client].team == TEAM_SPECTATOR){
Vector4Copy(colorMdGrey, color);
}
playTime = 0;
if (cent->finishRaceTime){
playTime = cent->finishRaceTime - cent->startLapTime;
}
else if (cent->startRaceTime){
playTime = cg.time - cent->startLapTime;
}
time = getStringForTime(playTime);
// num
CG_DrawTinyDigitalStringColor( x + 6, y, va("0%i", (i+1)), color);
// name
CG_DrawTinyDigitalStringColor( x + 42, y, cgs.clientinfo[cg.scores[i].client].name, color);
// time
CG_DrawTinyDigitalStringColor( x + 192, y, time, color);
// dmg dealt
CG_DrawTinyDigitalStringColor( x + 326, y, va("%i", cg.scores[i].damageDealt), color);
// dmg taken
CG_DrawTinyDigitalStringColor( x + 474, y, va("%i", cg.scores[i].damageTaken), color);
y += 20;
}
}
#endif
/*
================
CG_DrawSpeed
================
*/
static float CG_DrawSpeed( float y ) {
playerState_t *ps;
int vel_speed;
vec3_t forward, origin, angles, mins, maxs;
int x, yorg;
float x2, y2, w, h;
refdef_t refdef;
refEntity_t ent;
x = 630;
yorg = y;
ps = &cg.predictedPlayerState;
AngleVectors( ps->viewangles, forward, NULL, NULL );
// use actual speed
vel_speed = (int)fabs( Q3VelocityToRL( DotProduct(ps->velocity, forward) ) );
/*
#ifdef Q3_VM
if (ps->stats[STAT_GEAR] == -1)
vel_speed = (int)fabs(10.0f * Q3UnitsToRL(WHEEL_RADIUS * min(cg_entities[cg.snap->ps.clientNum].wheelSpeeds[0], cg_entities[cg.snap->ps.clientNum].wheelSpeeds[1])));
else
vel_speed = (int)fabs(10.0f * Q3UnitsToRL(WHEEL_RADIUS * max(cg_entities[cg.snap->ps.clientNum].wheelSpeeds[0], cg_entities[cg.snap->ps.clientNum].wheelSpeeds[1])));
#else
if (ps->stats[STAT_GEAR] == -1)
vel_speed = (int)fabs(Q3UnitsToRL(WHEEL_RADIUS * min(cg_entities[cg.snap->ps.clientNum].wheelSpeeds[0], cg_entities[cg.snap->ps.clientNum].wheelSpeeds[1])));
else
vel_speed = (int)fabs(Q3UnitsToRL(WHEEL_RADIUS * max(cg_entities[cg.snap->ps.clientNum].wheelSpeeds[0], cg_entities[cg.snap->ps.clientNum].wheelSpeeds[1])));
#endif
*/
// draw speedometer here
x2 = x - 96;
y2 = y - 96;
CG_DrawPic( x2, y2, 96, 96, trap_R_RegisterShaderNoMip("gfx/hud/gauge01"));
// draw digital speed
x -= 48 + (CG_DrawStrlen(va("%i", vel_speed)) * SMALLCHAR_WIDTH) / 2;
y -= 28;
CG_DrawSmallDigitalStringColor( x, y, va("%i", vel_speed), colors[0]);
// draw needle
w = h = 96;
CG_AdjustFrom640( &x2, &y2, &w, &h );
memset( &refdef, 0, sizeof( refdef ) );
memset( &ent, 0, sizeof( ent ) );
ent.hModel = trap_R_RegisterModel("gfx/hud/needle.md3");
ent.customShader = trap_R_RegisterShader("gfx/hud/needle01");
ent.renderfx = RF_NOSHADOW; // no stencil shadows
trap_R_ModelBounds(ent.hModel, mins, maxs);
// origin[2] = -0.5 * ( mins[2] + maxs[2] );
origin[2] = 0;
origin[1] = 0.5 * ( mins[1] + maxs[1] );
origin[0] = ( maxs[2] - mins[2] ) / 0.268;
VectorClear(angles);
angles[YAW] -= 90;
angles[PITCH] = -150.0f + (300.0f * vel_speed / 200.0f);
AnglesToAxis( angles, ent.axis );
VectorCopy(origin, ent.origin);
refdef.rdflags = RDF_NOWORLDMODEL;
AxisClear( refdef.viewaxis );
refdef.fov_x = 30;
refdef.fov_y = 30;
refdef.x = x2;
refdef.y = y2;
refdef.width = w;
refdef.height = h;
refdef.time = cg.time;
trap_R_ClearScene();
trap_R_AddRefEntityToScene( &ent );
trap_R_RenderScene( &refdef );
// draw center here
x = 630;
y = yorg;
x -= 60;
y -= 60;
CG_DrawPic( x, y, 24, 24, trap_R_RegisterShaderNoMip("gfx/hud/center01"));
// draw gear over center of gauge
if ( cg.predictedPlayerState.stats[STAT_GEAR] == -1 )
CG_DrawSmallDigitalStringColor( x+10, y+4, "R", colors[0]);
else if ( cg.predictedPlayerState.stats[STAT_GEAR] == 0 )
CG_DrawSmallDigitalStringColor( x+10, y+4, "N", colors[0]);
else
CG_DrawSmallDigitalStringColor( x+10, y+4, va("%i", cg.predictedPlayerState.stats[STAT_GEAR]), colors[0]);
y -= 39;
y -= SMALLCHAR_HEIGHT;
return y;
}
static float CG_DrawSDKMessage( float y ) {
int x, w;
vec4_t bg_color;
switch (cgs.clientinfo[cg.snap->ps.clientNum].team){
case TEAM_RED:
Vector4Copy(colorRed, bg_color);
bg_color[3] = 0.5;
break;
case TEAM_BLUE:
Vector4Copy(colorBlue, bg_color);
bg_color[3] = 0.5;
break;
case TEAM_GREEN:
Vector4Copy(colorGreen, bg_color);
bg_color[3] = 0.5;
break;
case TEAM_YELLOW:
Vector4Copy(colorYellow, bg_color);
bg_color[3] = 0.5;
break;
default:
Vector4Copy(bgColor, bg_color);
}
x = 4;
w = (CG_DrawStrlen("does not represent the finished game.") * TINYCHAR_WIDTH);
y -= 3*TINYCHAR_HEIGHT+2;
CG_FillRect( x, y, w, 3*TINYCHAR_HEIGHT+2, bg_color );
CG_DrawTinyStringColor( x, y, Q3_VERSION, colorWhite);
y += TINYCHAR_HEIGHT;
CG_DrawTinyStringColor( x, y, "For development purposes only, this", colorWhite);
y += TINYCHAR_HEIGHT;
CG_DrawTinyStringColor( x, y, "does not represent the finished game.", colorWhite);
y += TINYCHAR_HEIGHT;
y -= 3*TINYCHAR_HEIGHT+2;
return y;
}
#if 0
/*
================
CG_DrawGear
================
*/
static float CG_DrawGear( float y ) {
CG_DrawSmallDigitalStringColor( 560, y, va("Gear: %d", cg.predictedPlayerState.stats[STAT_GEAR]), colors[0]);
y -= SMALLCHAR_HEIGHT;
CG_DrawTinyDigitalStringColor( 560, y, va("RPM: %d", cg.predictedPlayerState.stats[STAT_RPM]), colorWhite);
y -= SMALLCHAR_HEIGHT;
return y;
}
#endif
/*
// for translating a 3d point to the screen ?
planeCameraDist = 50;
VectorSubtract(targetv, cg.refdef.viewaxis, dir);
viewdist = DotProduct(dir, cg.refdef.viewaxis[0]);
planedist = viewdist - planeCameraDist;
VectorMA(targetv, -planedist, cg.refdef.viewaxis[0], pointOnPlane);
VectorMA(pointOnPlane, -(planedist / viewdist) * DotProduct(dir, cg.refdef.viewaxis[1]), cg.refdef.viewaxis[1], pointOnPlane);
VectorMA(pointOnPlane, -(planedist / viewdist) * DotProduct(dir, cg.refdef.viewaxis[2]), cg.refdef.viewaxis[2], pointOnPlane);
*/
float CG_DrawUpperRightHUD( float y ) {
int i;
// FIXME: this should be moved somewhere else
cgs.numRacers = 0;
for ( i = 0 ; i < cgs.maxclients ; i++ ) {
if (!cgs.clientinfo[i].infoValid) continue;
if (cgs.clientinfo[i].team == TEAM_SPECTATOR) continue;
if (cg.scores[i].ping == -1) continue;
cgs.numRacers++;
}
if (cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR){
if (isRallyRace()){
y = CG_DrawArrowToCheckpoint( y );
y = CG_DrawTimes( y );
y = CG_DrawLaps( y );
y = CG_DrawCurrentPosition( y );
y = CG_DrawCarAheadAndBehind( y );
}
else if (cgs.gametype == GT_DERBY)
y = CG_DrawTimes( y );
// CG_DrawHUD_DerbyList(44, 130);
}
if (!isRallyNonDMRace() && cgs.gametype != GT_DERBY){
y = CG_DrawScores( 636, y );
}
return y;
}
float CG_DrawLowerRightHUD( float y ) {
if (cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR){
y = CG_DrawSpeed( y );
// y = CG_DrawGear( y );
}
return y;
}
float CG_DrawLowerLeftHUD( float y ) {
// check if there is rear ammo being displayed
int i;
y += 36;
for (i = RWP_SMOKE; i < WP_NUM_WEAPONS; i++){
if (cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << i )){
if (cg.snap->ps.ammo[ i ]){
y -= 36;
break;
}
}
}
// Comment this out in the full release Version
y = CG_DrawSDKMessage( y );
return y;
}