q3rally/engine/code/cgame/cg_rally_hud.c

947 lines
22 KiB
C
Raw Normal View History

2011-02-18 14:31:32 +00:00
/*
** 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
2011-02-18 14:31:32 +00:00
};
/*
=====================
2011-02-18 14:31:32 +00:00
CG_DrawRearviewMirror
=====================
2011-02-18 14:31:32 +00:00
*/
void CG_DrawRearviewMirror( float x, float y, float w, float h) {
// static int lastLowFPSTime;
2011-02-18 14:31:32 +00:00
int i;
// int fps;
2011-02-18 14:31:32 +00:00
float mx, my, mw, mh;
int tmp;
2011-02-18 14:31:32 +00:00
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;
/*
2011-02-18 14:31:32 +00:00
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;
}
}
*/
2011-02-18 14:31:32 +00:00
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;
2011-02-18 14:31:32 +00:00
cg.mirrorRefdef.time = cg.time;
cg.mirrorRefdef.rdflags = 0;
/*
AnglesToAxis( cg.predictedPlayerState.viewangles, mirrorRefdef.viewaxis );
VectorInverse( mirrorRefdef.viewaxis[0] );
VectorInverse( mirrorRefdef.viewaxis[1] );
2011-02-18 14:31:32 +00:00
VectorCopy( cg.predictedPlayerState.origin, mirrorRefdef.vieworg );
VectorMA( mirrorRefdef.vieworg, 16, mirrorRefdef.viewaxis[2], mirrorRefdef.vieworg );
*/
2011-02-18 14:31:32 +00:00
// 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 );
}
/*
===========
2011-02-18 14:31:32 +00:00
CG_DrawMMap
===========
*/
2011-02-18 14:31:32 +00:00
void CG_DrawMMap( float x, float y, float w, float h ) {
int i;
float mx, my, mw, mh;
int tmp;
2011-02-18 14:31:32 +00:00
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;
/* minimap to show for only racing and team racing no weapons (for now)
2011-02-18 14:31:32 +00:00
if ( cgs.gametype != GT_RACING )
return;
if ( (cgs.gametype != GT_RACING) || (cgs.gametype != GT_TEAM_RACING) )
return;
*/
2011-02-18 14:31:32 +00:00
mx = x ;
my = y ;
mw = w;
mh = h;
CG_AdjustFrom640( &x, &y, &w, &h );
cg.mmapRefdef.x = x;
2011-02-18 14:31:32 +00:00
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;
2011-02-18 14:31:32 +00:00
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 );
/*only add players to minimap scene
add ctf flag entities later*/
2011-02-18 14:31:32 +00:00
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 );
2011-02-18 14:31:32 +00:00
}
/*
========================
2011-02-18 14:31:32 +00:00
CG_DrawArrowToCheckpoint
========================
2011-02-18 14:31:32 +00:00
*/
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;
ioquake3 resync to revision 2369 from 2317. Some revision messages: Cache servers for each master server in q3_ui, otherwise servers from last updated master for shown for all Internet# sources. Play correct team sounds when in spectator mode and following a player. Check last listener number instead of clc.clientNum in S_AL_HearingThroughEntity so sound work correctly when spectate following a client. (Related to bug 5741.) When in third person, don't play player's sounds as full volume in Base sound system. OpenAL already does this. (Related to bug 5741.) really fix the confusion with game entity and refentity numbers to further reduce confusion, rename constants like MAX_ENTITIES to MAX_REFENTITIES Added Rend2, an alternate renderer. (Bug #4358) Fix restoring fs_game when default.cfg is missing. Fix restoring old fs_game upon leaving a server. Patch by Ensiform. Change more operator commands to require sv_running to be usable. Patch by Ensiform. Fix some "> MAX_*" to be ">= MAX_*". Fix follow command to find clients whose name begins with a number. Fix up "gc" command, make it more like "tell". Based on patch by Ensiform. Add usage messages for gc, tell, vtell, and votell commands. Check player names in gc, tell, vtell, and votell commands. #5799 - Change messagemode text box to display colors like in console input box. Improve "play" command, based on a patch from Ensiform. Check for invalid filename in OpenAL's RegisterSound function. Changed Base sound system to warn not error when sound filename is empty or too long. Remove references to non-existent functions CM_MarkFragments and CM_LerpTag.
2012-12-06 07:07:19 +00:00
for (i = 0; i < MAX_GENTITIES; i++){
2011-02-18 14:31:32 +00:00
cent = &cg_entities[i];
if (cent->currentState.eType != ET_CHECKPOINT) continue;
if (cent->currentState.weapon != cg.snap->ps.stats[STAT_NEXT_CHECKPOINT]) continue;
break;
}
ioquake3 resync to revision 2369 from 2317. Some revision messages: Cache servers for each master server in q3_ui, otherwise servers from last updated master for shown for all Internet# sources. Play correct team sounds when in spectator mode and following a player. Check last listener number instead of clc.clientNum in S_AL_HearingThroughEntity so sound work correctly when spectate following a client. (Related to bug 5741.) When in third person, don't play player's sounds as full volume in Base sound system. OpenAL already does this. (Related to bug 5741.) really fix the confusion with game entity and refentity numbers to further reduce confusion, rename constants like MAX_ENTITIES to MAX_REFENTITIES Added Rend2, an alternate renderer. (Bug #4358) Fix restoring fs_game when default.cfg is missing. Fix restoring old fs_game upon leaving a server. Patch by Ensiform. Change more operator commands to require sv_running to be usable. Patch by Ensiform. Fix some "> MAX_*" to be ">= MAX_*". Fix follow command to find clients whose name begins with a number. Fix up "gc" command, make it more like "tell". Based on patch by Ensiform. Add usage messages for gc, tell, vtell, and votell commands. Check player names in gc, tell, vtell, and votell commands. #5799 - Change messagemode text box to display colors like in console input box. Improve "play" command, based on a patch from Ensiform. Check for invalid filename in OpenAL's RegisterSound function. Changed Base sound system to warn not error when sound filename is empty or too long. Remove references to non-existent functions CM_MarkFragments and CM_LerpTag.
2012-12-06 07:07:19 +00:00
if (i == MAX_GENTITIES)
2011-02-18 14:31:32 +00:00
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 );
/* Developer Mode for Racing Bots
if (cg_developer.integer)
CG_Draw3DLine( cent->currentState.origin, cg.snap->ps.origin );
*/
2022-03-19 19:19:51 +00:00
// CG_SetScreenPlacement(PLACE_CENTER, PLACE_CENTER);
CG_DrawStringExt( x, SCREEN_HEIGHT * .30, "WRONG WAY!", color, qfalse, qtrue, BIGCHAR_WIDTH, (int)(BIGCHAR_WIDTH * 1.5), 0 );
2011-02-18 14:31:32 +00:00
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
//
2011-02-18 14:31:32 +00:00
if ( cgs.gametype != GT_DERBY ){
time = getStringForTime( cent->bestLapTime );
Com_sprintf(s, sizeof(s), "B: %s", time);
// x = 600 - CG_DrawStrlen(s) * TINYCHAR_WIDTH;
x = 636 - 80;
CG_FillRect ( x, y, 90, 18, bgColor );
x+= 10;
2011-02-18 14:31:32 +00:00
y+= 4;
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
2011-02-18 14:31:32 +00:00
y += TINYCHAR_HEIGHT + 4;
}
//
// Lap Time
//
2011-02-18 14:31:32 +00:00
if (cgs.gametype != GT_DERBY){
time = getStringForTime(lapTime);
Com_sprintf(s, sizeof(s), "L: %s", time);
// x = 600 - CG_DrawStrlen(s) * TINYCHAR_WIDTH;
x = 636 - 80;
CG_FillRect( x, y, 90, 18, bgColor );
x+= 10;
y+= 4;
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
2011-02-18 14:31:32 +00:00
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 - 80;
CG_FillRect( x, y, 90, 18, bgColor );
x += 10;
2011-02-18 14:31:32 +00:00
y += 4;
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
2011-02-18 14:31:32 +00:00
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 - 80;
CG_FillRect( x, y, 90, 18, bgColor );
x += 10;
2011-02-18 14:31:32 +00:00
y += 4;
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
2011-02-18 14:31:32 +00:00
y += TINYCHAR_HEIGHT + 4;
return y;
}
/*
======================
2011-02-18 14:31:32 +00:00
CG_DrawCurrentPosition
======================
2011-02-18 14:31:32 +00:00
*/
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: ");
2021-11-30 19:57:37 +00:00
x = 636 - 80;
width = 90;
2011-02-18 14:31:32 +00:00
height = 18;
CG_FillRect( x, y, width, height, bgColor );
2011-02-18 14:31:32 +00:00
2021-11-30 19:57:37 +00:00
x += 10;
2011-02-18 14:31:32 +00:00
y += 4;
CG_DrawTinyDigitalStringColor( x, y, s, colorWhite);
2011-02-18 14:31:32 +00:00
x += TINYCHAR_WIDTH * 5;
CG_DrawTinyDigitalStringColor( x, y, va("%i/%i", pos, cgs.numRacers), colorWhite);
y += 20;
2011-02-18 14:31:32 +00:00
return y;
}
/*
========================
2011-02-18 14:31:32 +00:00
CG_DrawCarAheadAndBehind
========================
2011-02-18 14:31:32 +00:00
*/
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;
2021-11-30 19:57:37 +00:00
x = 636 - 80;
width = 90;
2011-02-18 14:31:32 +00:00
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 );
2011-02-18 14:31:32 +00:00
}
else {
CG_FillRect( x, y, width, height, background );
2011-02-18 14:31:32 +00:00
}
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);
2011-02-18 14:31:32 +00:00
y += TINYCHAR_HEIGHT;
2021-11-30 22:44:46 +00:00
2011-02-18 14:31:32 +00:00
}
return y;
}
#if 0
/*
====================
2011-02-18 14:31:32 +00:00
CG_DrawHUD_DerbyList
====================
2011-02-18 14:31:32 +00:00
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_DrawTinyStringColor( x + 42, y, "PLAYER:", colorWhite);
2011-02-18 14:31:32 +00:00
// time
CG_DrawTinyStringColor( x + 206, y, "TIME:", colorWhite);
2011-02-18 14:31:32 +00:00
// dmg dealt
CG_DrawTinyStringColor( x + 294, y, "DMG DEALT:", colorWhite);
2011-02-18 14:31:32 +00:00
// dmg taken
CG_DrawTinyStringColor( x + 442, y, "DMG TAKEN:", colorWhite);
2011-02-18 14:31:32 +00:00
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_DrawTinyStringColor( x + 6, y, va("0%i", (i+1)), color);
2011-02-18 14:31:32 +00:00
// name
CG_DrawTinyStringColor( x + 42, y, cgs.clientinfo[cg.scores[i].client].name, color);
2011-02-18 14:31:32 +00:00
// time
CG_DrawTinyStringColor( x + 192, y, time, color);
2011-02-18 14:31:32 +00:00
// dmg dealt
CG_DrawTinyStringColor( x + 326, y, va("%i", cg.scores[i].damageDealt), color);
2011-02-18 14:31:32 +00:00
// dmg taken
CG_DrawTinyStringColor( x + 474, y, va("%i", cg.scores[i].damageTaken), color);
2011-02-18 14:31:32 +00:00
y += 20;
}
}
*/
2011-02-18 14:31:32 +00:00
#endif
/*
============
2011-02-18 14:31:32 +00:00
CG_DrawSpeed
============
2011-02-18 14:31:32 +00:00
*/
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"));
2011-02-18 14:31:32 +00:00
// draw digital speed
x -= 48 + (CG_DrawStrlen(va("%i", vel_speed)) * SMALLCHAR_WIDTH) / 2;
y -= 28;
CG_DrawSmallDigitalStringColor( x, y, va("%i", vel_speed), colorWhite);
2011-02-18 14:31:32 +00:00
// 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;
2011-02-18 14:31:32 +00:00
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"));
2011-02-18 14:31:32 +00:00
// draw gear over center of gauge
if ( cg.predictedPlayerState.stats[STAT_GEAR] == -1 )
CG_DrawSmallDigitalStringColor( x+10, y+4, "R", colorWhite);
2011-02-18 14:31:32 +00:00
else if ( cg.predictedPlayerState.stats[STAT_GEAR] == 0 )
CG_DrawSmallDigitalStringColor( x+10, y+4, "N", colorWhite);
2011-02-18 14:31:32 +00:00
else
CG_DrawSmallDigitalStringColor( x+10, y+4, va("%i", cg.predictedPlayerState.stats[STAT_GEAR]), colorWhite);
2011-02-18 14:31:32 +00:00
y -= 39;
y -= SMALLCHAR_HEIGHT;
return y;
}
/*
2011-02-18 14:31:32 +00:00
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("Not the finished game.") * TINYCHAR_WIDTH);
2011-02-18 14:31:32 +00:00
y -= 3*TINYCHAR_HEIGHT+2;
CG_FillRect( x, y, w, 3*TINYCHAR_HEIGHT+2, bg_color );
CG_DrawTinyStringColor( x, y, Q3_VERSION, colorWhite);
2011-02-18 14:31:32 +00:00
y += TINYCHAR_HEIGHT;
CG_DrawTinyStringColor( x, y, "Beta Version", colorWhite);
2011-02-18 14:31:32 +00:00
y += TINYCHAR_HEIGHT;
CG_DrawTinyStringColor( x, y, "Not the finished game.", colorWhite);
2011-02-18 14:31:32 +00:00
y += TINYCHAR_HEIGHT;
y -= 3*TINYCHAR_HEIGHT+2;
return y;
}
*/
2011-02-18 14:31:32 +00:00
#if 0
/*
===========
2011-02-18 14:31:32 +00:00
CG_DrawGear
===========
2011-02-18 14:31:32 +00:00
*/
static float CG_DrawGear( float y ) {
CG_DrawSmallDigitalStringColor( 560, y, va("Gear: %d", cg.predictedPlayerState.stats[STAT_GEAR]), colors[0]);
2011-02-18 14:31:32 +00:00
y -= SMALLCHAR_HEIGHT;
CG_DrawTinyDigitalStringColor( 560, y, va("RPM: %d", cg.predictedPlayerState.stats[STAT_RPM]), colorWhite);
2011-02-18 14:31:32 +00:00
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 );
// 0.5
// CG_DrawHUD_DerbyList(44, 130);
2011-02-18 14:31:32 +00:00
}
if (!isRallyNonDMRace() && cgs.gametype != GT_DERBY){
y = CG_DrawScores( 636, y );
2011-02-18 14:31:32 +00:00
}
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 );
2011-02-18 14:31:32 +00:00
return y;
}