2023-04-30 00:02:16 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
Copyright (C) 2023 the OpenMoHAA team
|
|
|
|
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
OpenMoHAA source code is distributed in the hope that it will be
|
|
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OpenMoHAA source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// DESCRIPTION:
|
|
|
|
// Some tools used to drawing 2d stuff
|
|
|
|
|
|
|
|
#include "cg_local.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
CG_AdjustFrom640
|
|
|
|
|
|
|
|
Adjusted for resolution and screen aspect ratio
|
|
|
|
================
|
|
|
|
*/
|
2023-07-05 21:24:23 +02:00
|
|
|
void CG_AdjustFrom640(float *x, float *y, float *w, float *h)
|
|
|
|
{
|
2023-04-30 00:02:16 +02:00
|
|
|
#if 0
|
|
|
|
// adjust for wide screens
|
|
|
|
if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
|
|
|
|
*x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) );
|
|
|
|
}
|
|
|
|
#endif
|
2023-07-05 21:24:23 +02:00
|
|
|
// scale for screen sizes
|
|
|
|
*x *= cgs.screenXScale;
|
|
|
|
*y *= cgs.screenYScale;
|
|
|
|
*w *= cgs.screenXScale;
|
|
|
|
*h *= cgs.screenYScale;
|
2023-04-30 00:02:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
CG_TileClearBox
|
|
|
|
|
|
|
|
This repeats a 64*64 tile graphic to fill the screen around a sized down
|
|
|
|
refresh window.
|
|
|
|
=============
|
|
|
|
*/
|
2023-07-05 21:24:23 +02:00
|
|
|
void CG_TileClearBox(int x, int y, int w, int h, qhandle_t hShader)
|
|
|
|
{
|
|
|
|
float s1, t1, s2, t2;
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
s1 = x / 64.0;
|
|
|
|
t1 = y / 64.0;
|
|
|
|
s2 = (x + w) / 64.0;
|
|
|
|
t2 = (y + h) / 64.0;
|
|
|
|
cgi.R_DrawStretchPic(x, y, w, h, s1, t1, s2, t2, hShader);
|
|
|
|
}
|
2023-04-30 00:02:16 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
CG_TileClear
|
|
|
|
|
|
|
|
Clear around a sized down screen
|
|
|
|
==============
|
|
|
|
*/
|
2023-07-05 21:24:23 +02:00
|
|
|
void CG_TileClear(void)
|
|
|
|
{
|
|
|
|
int top, bottom, left, right;
|
|
|
|
int w, h;
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
w = cgs.glconfig.vidWidth;
|
|
|
|
h = cgs.glconfig.vidHeight;
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cg.refdef.x == 0 && cg.refdef.y == 0 && cg.refdef.width == w && cg.refdef.height == h) {
|
|
|
|
return; // full screen rendering
|
|
|
|
}
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
top = cg.refdef.y;
|
|
|
|
bottom = top + cg.refdef.height - 1;
|
|
|
|
left = cg.refdef.x;
|
|
|
|
right = left + cg.refdef.width - 1;
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
// clear above view screen
|
|
|
|
CG_TileClearBox(0, 0, w, top, cgs.media.backTileShader);
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
// clear below view screen
|
|
|
|
CG_TileClearBox(0, bottom, w, h - bottom, cgs.media.backTileShader);
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
// clear left of view screen
|
|
|
|
CG_TileClearBox(0, top, left, bottom - top + 1, cgs.media.backTileShader);
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
// clear right of view screen
|
|
|
|
CG_TileClearBox(right, top, w - right, bottom - top + 1, cgs.media.backTileShader);
|
2023-04-30 00:02:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============================================================================
|
|
|
|
|
|
|
|
LAGOMETER
|
|
|
|
|
|
|
|
===============================================================================
|
|
|
|
*/
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
#define LAG_SAMPLES 128
|
2023-04-30 00:02:16 +02:00
|
|
|
|
|
|
|
typedef struct {
|
2023-07-05 21:24:23 +02:00
|
|
|
int frameSamples[LAG_SAMPLES];
|
|
|
|
int frameCount;
|
|
|
|
int snapshotFlags[LAG_SAMPLES];
|
|
|
|
int snapshotSamples[LAG_SAMPLES];
|
|
|
|
int snapshotCount;
|
2023-04-30 00:02:16 +02:00
|
|
|
} lagometer_t;
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
lagometer_t lagometer;
|
2023-04-30 00:02:16 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
CG_AddLagometerFrameInfo
|
|
|
|
|
|
|
|
Adds the current interpolate / extrapolate bar for this frame
|
|
|
|
==============
|
|
|
|
*/
|
2023-07-05 21:24:23 +02:00
|
|
|
void CG_AddLagometerFrameInfo(void)
|
|
|
|
{
|
|
|
|
int offset;
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
offset = cg.time - cg.latestSnapshotTime;
|
|
|
|
lagometer.frameSamples[lagometer.frameCount & (LAG_SAMPLES - 1)] = offset;
|
|
|
|
lagometer.frameCount++;
|
2023-04-30 00:02:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
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.
|
|
|
|
==============
|
|
|
|
*/
|
2023-07-05 21:24:23 +02:00
|
|
|
void CG_AddLagometerSnapshotInfo(snapshot_t *snap)
|
|
|
|
{
|
|
|
|
// dropped packet
|
|
|
|
if (!snap) {
|
|
|
|
lagometer.snapshotSamples[lagometer.snapshotCount & (LAG_SAMPLES - 1)] = -1;
|
|
|
|
lagometer.snapshotCount++;
|
|
|
|
return;
|
|
|
|
}
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
// 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++;
|
2023-04-30 00:02:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
CG_DrawDisconnect
|
|
|
|
==============
|
|
|
|
*/
|
2023-07-05 21:24:23 +02:00
|
|
|
void CG_DrawDisconnect(void)
|
|
|
|
{
|
|
|
|
float x, y;
|
|
|
|
float w, h;
|
|
|
|
int cmdNum;
|
|
|
|
qhandle_t handle;
|
2023-05-07 19:37:07 +02:00
|
|
|
usercmd_t cmd;
|
|
|
|
|
|
|
|
// draw the phone jack if we are completely past our buffers
|
|
|
|
cmdNum = cgi.GetCurrentCmdNumber() - CMD_BACKUP + 1;
|
|
|
|
cgi.GetUserCmd(cmdNum, &cmd);
|
|
|
|
if (!cg.snap || cmd.serverTime <= cg.snap->ps.commandTime
|
2023-07-05 21:24:23 +02:00
|
|
|
|| cmd.serverTime > cg.time) { // special check for map_restart
|
2023-05-07 19:37:07 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-05-07 19:37:07 +02:00
|
|
|
// blink it
|
|
|
|
if ((cg.time >> 9) & 1) {
|
|
|
|
return;
|
|
|
|
}
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
handle = cgi.R_RegisterShader("gfx/2d/net.tga");
|
2024-11-30 19:59:54 +01:00
|
|
|
w = cgi.R_GetShaderWidth(handle) * cgs.uiHiResScale[0];
|
|
|
|
h = cgi.R_GetShaderHeight(handle) * cgs.uiHiResScale[1];
|
2023-07-05 21:24:23 +02:00
|
|
|
x = ((float)cgs.glconfig.vidWidth - w) * 0.5;
|
|
|
|
y = (float)cgs.glconfig.vidHeight - h;
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-05-07 19:37:07 +02:00
|
|
|
cgi.R_DrawStretchPic(x, y, w, h, 0, 0, 1, 1, handle);
|
2023-04-30 00:02:16 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
#define MAX_LAGOMETER_PING 900
|
|
|
|
#define MAX_LAGOMETER_RANGE 300
|
2023-04-30 00:02:16 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
CG_DrawLagometer
|
|
|
|
==============
|
|
|
|
*/
|
2023-07-05 21:24:23 +02:00
|
|
|
void CG_DrawLagometer(void)
|
|
|
|
{
|
|
|
|
int a, i;
|
|
|
|
float v;
|
|
|
|
float ax, ay, aw, ah, mid, range;
|
|
|
|
int color;
|
|
|
|
float vscale;
|
|
|
|
|
|
|
|
if (!cg_lagometer->integer) {
|
|
|
|
CG_DrawDisconnect();
|
|
|
|
return;
|
|
|
|
}
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
//
|
|
|
|
// draw the graph
|
2023-05-07 19:37:07 +02:00
|
|
|
//
|
|
|
|
ax = 272.0;
|
|
|
|
ay = 432.0;
|
|
|
|
aw = 96.0;
|
|
|
|
ah = 48.0;
|
|
|
|
CG_AdjustFrom640(&ax, &ay, &aw, &ah);
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-05-07 19:37:07 +02:00
|
|
|
cgi.R_SetColor(NULL);
|
|
|
|
cgi.R_DrawStretchPic(ax, ay, aw, ah, 0, 0, 1, 1, cgs.media.lagometerShader);
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
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;
|
|
|
|
cgi.R_SetColor(g_color_table[ColorIndex(COLOR_YELLOW)]);
|
|
|
|
}
|
|
|
|
if (v > range) {
|
|
|
|
v = range;
|
|
|
|
}
|
|
|
|
cgi.R_DrawBox(ax + aw - a, mid - v, 1, v);
|
|
|
|
} else if (v < 0) {
|
|
|
|
if (color != 2) {
|
|
|
|
color = 2;
|
|
|
|
cgi.R_SetColor(g_color_table[ColorIndex(COLOR_BLUE)]);
|
|
|
|
}
|
|
|
|
v = -v;
|
|
|
|
if (v > range) {
|
|
|
|
v = range;
|
|
|
|
}
|
|
|
|
cgi.R_DrawBox(ax + aw - a, mid, 1, v);
|
|
|
|
}
|
|
|
|
}
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
// 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
|
|
|
|
cgi.R_SetColor(g_color_table[ColorIndex(COLOR_YELLOW)]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (color != 3) {
|
|
|
|
color = 3;
|
|
|
|
cgi.R_SetColor(g_color_table[ColorIndex(COLOR_GREEN)]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v = v * vscale;
|
|
|
|
if (v > range) {
|
|
|
|
v = range;
|
|
|
|
}
|
|
|
|
cgi.R_DrawBox(ax + aw - a, ay + ah - v, 1, v);
|
|
|
|
} else if (v < 0) {
|
|
|
|
if (color != 4) {
|
|
|
|
color = 4; // RED for dropped snapshots
|
|
|
|
cgi.R_SetColor(g_color_table[ColorIndex(COLOR_RED)]);
|
|
|
|
}
|
|
|
|
cgi.R_DrawBox(ax + aw - a, ay + ah - range, 1, range);
|
|
|
|
}
|
|
|
|
}
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.R_SetColor(NULL);
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
CG_DrawDisconnect();
|
2023-04-30 00:02:16 +02:00
|
|
|
}
|
|
|
|
|
2023-05-07 19:37:07 +02:00
|
|
|
static void CG_DrawPauseIcon()
|
|
|
|
{
|
|
|
|
qhandle_t handle;
|
2023-07-05 21:24:23 +02:00
|
|
|
float x, y, w, h;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (paused->integer) {
|
2023-05-07 19:37:07 +02:00
|
|
|
handle = cgs.media.pausedShader;
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
|
|
|
if (cg.predicted_player_state.pm_flags & PMF_LEVELEXIT) {
|
2023-05-07 19:37:07 +02:00
|
|
|
// blink it
|
2023-07-05 21:24:23 +02:00
|
|
|
if ((cg.time >> 9) & 1) {
|
2023-05-07 19:37:07 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
handle = cgs.media.levelExitShader;
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
2023-05-07 19:37:07 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
w = cgi.R_GetShaderWidth(handle);
|
|
|
|
h = cgi.R_GetShaderHeight(handle);
|
2023-11-07 19:20:52 +01:00
|
|
|
if (cg.snap && cg.snap->ps.blend[3] > 0) {
|
|
|
|
y = cgs.glconfig.vidHeight * 0.45f - h / 2.f;
|
|
|
|
} else {
|
|
|
|
y = cgs.glconfig.vidHeight * 0.75f - h / 2.f;
|
|
|
|
}
|
|
|
|
x = (cgs.glconfig.vidWidth - w) / 2.f;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
cgi.R_SetColor(colorWhite);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawStretchPic(x, y, w * cgs.uiHiResScale[0], h * cgs.uiHiResScale[1], 0, 0, 1, 1, handle);
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void CG_DrawServerLag()
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
float x, y;
|
|
|
|
float w, h;
|
2023-05-07 19:37:07 +02:00
|
|
|
qhandle_t handle;
|
|
|
|
|
|
|
|
if (!cg_drawsvlag->integer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!developer->integer && !cgs.gametype) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cgs.serverLagTime) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cg.time - cgs.serverLagTime > 3000) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// blink it
|
|
|
|
if ((cg.time >> 9) & 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
handle = cgi.R_RegisterShader("gfx/2d/slowserver");
|
2024-11-30 19:59:54 +01:00
|
|
|
w = (float)cgi.R_GetShaderWidth(handle) * cgs.uiHiResScale[0] / 4;
|
|
|
|
h = (float)cgi.R_GetShaderHeight(handle) * cgs.uiHiResScale[1] / 4;
|
2023-07-05 21:24:23 +02:00
|
|
|
x = ((float)cgs.glconfig.vidWidth - w) / 2;
|
|
|
|
y = (float)cgs.glconfig.vidHeight - h;
|
2023-05-07 19:37:07 +02:00
|
|
|
cgi.R_DrawStretchPic(x, y, w, h, 0.0, 0.0, 1.0, 1.0, handle);
|
|
|
|
}
|
|
|
|
|
2023-04-30 00:02:16 +02:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
CG_DrawIcons
|
|
|
|
==============
|
|
|
|
*/
|
2023-05-07 19:37:07 +02:00
|
|
|
void CG_DrawIcons(void)
|
|
|
|
{
|
|
|
|
if (!cg_hud->integer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CG_DrawPauseIcon();
|
|
|
|
CG_DrawServerLag();
|
|
|
|
}
|
2023-04-30 00:02:16 +02:00
|
|
|
|
2023-04-30 14:47:27 +02:00
|
|
|
void CG_DrawOverlayTopBottom(qhandle_t handleTop, qhandle_t handleBottom, float fAlpha)
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
int iHalfWidth;
|
|
|
|
int iWidthOffset;
|
|
|
|
vec4_t color;
|
2023-04-30 14:47:27 +02:00
|
|
|
|
2023-05-07 19:37:07 +02:00
|
|
|
color[0] = 1.0;
|
|
|
|
color[1] = 1.0;
|
|
|
|
color[2] = 1.0;
|
|
|
|
color[3] = fAlpha;
|
|
|
|
cgi.R_SetColor(color);
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
iHalfWidth = cgs.glconfig.vidHeight >> 1;
|
2023-05-07 19:37:07 +02:00
|
|
|
iWidthOffset = (cgs.glconfig.vidWidth - cgs.glconfig.vidHeight) >> 1;
|
|
|
|
|
2023-05-29 21:14:43 +02:00
|
|
|
cgi.R_DrawStretchPic(iWidthOffset, 0.0, iHalfWidth, iHalfWidth, 1.0, 0.0, 0.0, 1.0, handleTop);
|
|
|
|
cgi.R_DrawStretchPic(iWidthOffset + iHalfWidth, 0.0, iHalfWidth, iHalfWidth, 0.0, 0.0, 1.0, 1.0, handleTop);
|
|
|
|
cgi.R_DrawStretchPic(iWidthOffset, iHalfWidth, iHalfWidth, iHalfWidth, 1.0, 0.0, 0.0, 1.0, handleBottom);
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.R_DrawStretchPic(
|
|
|
|
iWidthOffset + iHalfWidth, iHalfWidth, iHalfWidth, iHalfWidth, 0.0, 0.0, 1.0, 1.0, handleBottom
|
|
|
|
);
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
color[0] = 0.0;
|
|
|
|
color[1] = 0.0;
|
|
|
|
color[2] = 0.0;
|
|
|
|
cgi.R_SetColor(color);
|
|
|
|
|
|
|
|
cgi.R_DrawStretchPic(0.0, 0.0, iWidthOffset, cgs.glconfig.vidHeight, 0.0, 0.0, 1.0, 1.0, cgs.media.lagometerShader);
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.R_DrawStretchPic(
|
|
|
|
cgs.glconfig.vidWidth - iWidthOffset,
|
|
|
|
0.0,
|
|
|
|
iWidthOffset,
|
|
|
|
cgs.glconfig.vidHeight,
|
|
|
|
0.0,
|
|
|
|
0.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
cgs.media.lagometerShader
|
|
|
|
);
|
2023-04-30 14:47:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_DrawOverlayMiddle(qhandle_t handle, float fAlpha)
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
int iHalfWidth;
|
|
|
|
int iWidthOffset;
|
2023-04-30 14:47:27 +02:00
|
|
|
vec4_t color;
|
|
|
|
|
2023-05-07 19:37:07 +02:00
|
|
|
color[0] = 1.0;
|
|
|
|
color[1] = 1.0;
|
|
|
|
color[2] = 1.0;
|
|
|
|
color[3] = fAlpha;
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.R_SetColor(color);
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
iHalfWidth = cgs.glconfig.vidHeight >> 1;
|
|
|
|
iWidthOffset = (cgs.glconfig.vidWidth - cgs.glconfig.vidHeight) >> 1;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.R_DrawStretchPic(iWidthOffset, 0.0, iHalfWidth, iHalfWidth, 0.0, 0.0, 1.0, 1.0, handle);
|
2023-05-07 19:37:07 +02:00
|
|
|
cgi.R_DrawStretchPic(iWidthOffset + iHalfWidth, 0.0, iHalfWidth, iHalfWidth, 1.0, 0.0, 0.0, 1.0, handle);
|
|
|
|
cgi.R_DrawStretchPic(iWidthOffset, iHalfWidth, iHalfWidth, iHalfWidth, 0.0, 1.0, 1.0, 0.0, handle);
|
|
|
|
cgi.R_DrawStretchPic(iWidthOffset + iHalfWidth, iHalfWidth, iHalfWidth, iHalfWidth, 1.0, 1.0, 0.0, 0.0, handle);
|
|
|
|
|
|
|
|
color[0] = 0.0;
|
|
|
|
color[1] = 0.0;
|
|
|
|
color[2] = 0.0;
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.R_SetColor(color);
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.R_DrawStretchPic(0.0, 0.0, iWidthOffset, cgs.glconfig.vidHeight, 0.0, 0.0, 1.0, 1.0, cgs.media.lagometerShader);
|
|
|
|
cgi.R_DrawStretchPic(
|
|
|
|
cgs.glconfig.vidWidth - iWidthOffset,
|
|
|
|
0.0,
|
|
|
|
iWidthOffset,
|
|
|
|
cgs.glconfig.vidHeight,
|
|
|
|
.0,
|
|
|
|
0.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
cgs.media.lagometerShader
|
|
|
|
);
|
2023-04-30 14:47:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_DrawOverlayFullScreen(qhandle_t handle, float fAlpha)
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
int iHalfWidth, iHalfHeight;
|
2023-04-30 14:47:27 +02:00
|
|
|
vec4_t color;
|
|
|
|
|
2023-05-07 19:37:07 +02:00
|
|
|
color[0] = 1.0;
|
|
|
|
color[1] = 1.0;
|
|
|
|
color[2] = 1.0;
|
|
|
|
color[3] = fAlpha;
|
|
|
|
cgi.R_SetColor(color);
|
|
|
|
|
|
|
|
iHalfHeight = cgs.glconfig.vidHeight >> 1;
|
2023-07-05 21:24:23 +02:00
|
|
|
iHalfWidth = cgs.glconfig.vidWidth >> 1;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
cgi.R_DrawStretchPic(0.0, 0.0, iHalfWidth, iHalfHeight, 0.0, 0.0, 1.0, 1.0, handle);
|
|
|
|
cgi.R_DrawStretchPic(iHalfWidth, 0.0, iHalfWidth, iHalfHeight, 1.0, 0.0, 0.0, 1.0, handle);
|
|
|
|
cgi.R_DrawStretchPic(0.0, iHalfHeight, iHalfWidth, iHalfHeight, 0.0, 1.0, 1.0, 0.0, handle);
|
|
|
|
cgi.R_DrawStretchPic(iHalfWidth, iHalfHeight, iHalfWidth, iHalfHeight, 1.0, 1.0, 0.0, 0.0, handle);
|
2023-04-30 14:47:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_DrawZoomOverlay()
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
static int zoomType;
|
2023-04-30 14:47:27 +02:00
|
|
|
static float fAlpha;
|
2023-07-05 21:24:23 +02:00
|
|
|
const char *weaponstring;
|
|
|
|
qboolean bDrawOverlay;
|
2023-04-30 14:47:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
weaponstring = "";
|
|
|
|
bDrawOverlay = qtrue;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!cg.snap) {
|
|
|
|
return;
|
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cg.snap->ps.activeItems[1] >= 0) {
|
|
|
|
weaponstring = CG_ConfigString(CS_WEAPONS + cg.snap->ps.activeItems[1]);
|
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!Q_stricmp(weaponstring, "Spy Camera")) {
|
|
|
|
zoomType = 2;
|
|
|
|
} else if (!Q_stricmp(weaponstring, "Binoculars")) {
|
|
|
|
zoomType = 3;
|
|
|
|
} else {
|
|
|
|
if (cg.snap->ps.stats[STAT_INZOOM] && cg.snap->ps.stats[STAT_INZOOM] <= 30) {
|
|
|
|
if (!Q_stricmp(weaponstring, "KAR98 - Sniper")) {
|
|
|
|
zoomType = 1;
|
|
|
|
} else {
|
|
|
|
zoomType = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bDrawOverlay = qfalse;
|
|
|
|
}
|
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (bDrawOverlay) {
|
|
|
|
fAlpha += cg.frametime * 0.015;
|
|
|
|
if (fAlpha > 1.0) {
|
|
|
|
fAlpha = 1.0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fAlpha -= cg.frametime * 0.015;
|
|
|
|
if (fAlpha < 0.0) {
|
|
|
|
fAlpha = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fAlpha) {
|
|
|
|
return;
|
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
switch (zoomType) {
|
2023-05-07 19:37:07 +02:00
|
|
|
case 1:
|
|
|
|
CG_DrawOverlayTopBottom(cgs.media.kar98TopOverlayShader, cgs.media.kar98BottomOverlayShader, fAlpha);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
CG_DrawOverlayFullScreen(cgs.media.binocularsOverlayShader, fAlpha);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CG_DrawOverlayMiddle(cgs.media.zoomOverlayShader, fAlpha);
|
|
|
|
break;
|
|
|
|
}
|
2023-04-30 14:47:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_HudDrawShader(int iInfo)
|
|
|
|
{
|
2023-05-01 15:12:01 +02:00
|
|
|
if (cgi.HudDrawElements[iInfo].shaderName[0]) {
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.HudDrawElements[iInfo].hShader = cgi.R_RegisterShaderNoMip(cgi.HudDrawElements[iInfo].shaderName);
|
2023-05-01 15:12:01 +02:00
|
|
|
} else {
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.HudDrawElements[iInfo].hShader = 0;
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|
2023-04-30 14:47:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_HudDrawFont(int iInfo)
|
|
|
|
{
|
2023-05-01 15:12:01 +02:00
|
|
|
if (cgi.HudDrawElements[iInfo].fontName[0]) {
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.HudDrawElements[iInfo].pFont = cgi.R_LoadFont(cgi.HudDrawElements[iInfo].fontName);
|
2023-05-01 15:12:01 +02:00
|
|
|
} else {
|
2023-07-05 21:24:23 +02:00
|
|
|
cgi.HudDrawElements[iInfo].pFont = nullptr;
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|
2023-04-30 14:47:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_RefreshHudDrawElements()
|
|
|
|
{
|
2023-05-01 15:12:01 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_HUDDRAW_ELEMENTS; ++i) {
|
2023-07-05 21:24:23 +02:00
|
|
|
CG_HudDrawShader(i);
|
|
|
|
CG_HudDrawFont(i);
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|
2023-04-30 14:47:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_HudDrawElements()
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
int i;
|
|
|
|
float fX, fY;
|
|
|
|
float fWidth, fHeight;
|
2024-11-30 19:59:54 +01:00
|
|
|
vec2_t virtualScale;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!cg_huddraw_force->integer && !cg_hud->integer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-11-30 19:59:54 +01:00
|
|
|
virtualScale[0] = cgs.glconfig.vidWidth / 640.0;
|
2024-11-30 23:07:32 +01:00
|
|
|
virtualScale[1] = cgs.glconfig.vidHeight / 480.0;
|
2024-11-30 19:59:54 +01:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
for (i = 0; i < MAX_HUDDRAW_ELEMENTS; i++) {
|
|
|
|
if ((!cgi.HudDrawElements[i].hShader && !cgi.HudDrawElements[i].string[0])
|
|
|
|
|| !cgi.HudDrawElements[i].vColor[3]) {
|
|
|
|
// skip invisible elements
|
|
|
|
continue;
|
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
fX = cgi.HudDrawElements[i].iX;
|
|
|
|
fY = cgi.HudDrawElements[i].iY;
|
|
|
|
fWidth = cgi.HudDrawElements[i].iWidth;
|
2023-05-07 19:37:07 +02:00
|
|
|
fHeight = cgi.HudDrawElements[i].iHeight;
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cgi.HudDrawElements[i].iHorizontalAlign == HUD_ALIGN_X_CENTER) {
|
|
|
|
if (cgi.HudDrawElements[i].bVirtualScreen) {
|
2023-05-07 19:37:07 +02:00
|
|
|
fX += 320.0 - fWidth * 0.5;
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
2023-05-07 19:37:07 +02:00
|
|
|
fX += cgs.glconfig.vidWidth * 0.5 - fWidth * 0.5;
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
|
|
|
} else if (cgi.HudDrawElements[i].iHorizontalAlign == HUD_ALIGN_X_RIGHT) {
|
|
|
|
if (cgi.HudDrawElements[i].bVirtualScreen) {
|
2023-05-07 19:37:07 +02:00
|
|
|
fX += 640.0;
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
2023-05-07 19:37:07 +02:00
|
|
|
fX += cgs.glconfig.vidWidth;
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cgi.HudDrawElements[i].iVerticalAlign == HUD_ALIGN_Y_CENTER) {
|
|
|
|
if (cgi.HudDrawElements[i].bVirtualScreen) {
|
2023-05-07 19:37:07 +02:00
|
|
|
fY += 240.0 - fHeight * 0.5;
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
2023-05-07 19:37:07 +02:00
|
|
|
fY += cgs.glconfig.vidHeight * 0.5 - fHeight * 0.5;
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
|
|
|
} else if (cgi.HudDrawElements[i].iVerticalAlign == HUD_ALIGN_Y_BOTTOM) {
|
|
|
|
if (cgi.HudDrawElements[i].bVirtualScreen) {
|
2023-05-07 19:37:07 +02:00
|
|
|
fY += 480.0;
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
2023-05-07 19:37:07 +02:00
|
|
|
fY += cgs.glconfig.vidHeight;
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cgi.R_SetColor(cgi.HudDrawElements[i].vColor);
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cgi.HudDrawElements[i].string[0]) {
|
2024-11-30 23:07:32 +01:00
|
|
|
fontheader_t* pFont = cgi.HudDrawElements[i].pFont;
|
|
|
|
if (!pFont) {
|
|
|
|
pFont = cgs.media.hudDrawFont;
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
2024-11-30 23:07:32 +01:00
|
|
|
|
|
|
|
cgi.R_DrawString(
|
|
|
|
pFont,
|
|
|
|
cgi.LV_ConvertString(cgi.HudDrawElements[i].string),
|
|
|
|
fX,
|
|
|
|
fY,
|
|
|
|
-1,
|
|
|
|
cgi.HudDrawElements[i].bVirtualScreen ? virtualScale : cgs.uiHiResScale
|
|
|
|
);
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
|
|
|
if (cgi.HudDrawElements[i].bVirtualScreen) {
|
2023-05-07 19:37:07 +02:00
|
|
|
CG_AdjustFrom640(&fX, &fY, &fWidth, &fHeight);
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
cgi.R_DrawStretchPic(fX, fY, fWidth, fHeight, 0.0, 0.0, 1.0, 1.0, cgi.HudDrawElements[i].hShader);
|
|
|
|
}
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
2023-04-30 14:47:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_InitializeObjectives()
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
int i;
|
2023-04-30 14:47:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
cg.ObjectivesAlphaTime = 0.0;
|
|
|
|
cg.ObjectivesBaseAlpha = 0.0;
|
2023-04-30 14:47:27 +02:00
|
|
|
cg.ObjectivesDesiredAlpha = 0.0;
|
|
|
|
cg.ObjectivesCurrentAlpha = 0.0;
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
for (i = 0; i < MAX_OBJECTIVES; i++) {
|
|
|
|
cg.Objectives[i].flags = 0;
|
2023-04-30 14:47:27 +02:00
|
|
|
cg.Objectives[i].text[0] = 0;
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
2023-04-30 14:47:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_DrawObjectives()
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
float vColor[4];
|
|
|
|
float fX, fY;
|
2024-11-19 19:41:46 +01:00
|
|
|
int iNumObjectives;
|
|
|
|
float fObjectivesTop;
|
2023-07-05 21:24:23 +02:00
|
|
|
static float fWidth;
|
|
|
|
float fHeight;
|
|
|
|
int iNumLines[20];
|
|
|
|
int iTotalNumLines;
|
|
|
|
int i;
|
|
|
|
int iCurrentObjective;
|
|
|
|
float fTimeDelta;
|
2024-11-19 19:41:46 +01:00
|
|
|
const char *pszLocalizedText;
|
|
|
|
const char *pszLine;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
iTotalNumLines = 0;
|
2023-07-05 21:24:23 +02:00
|
|
|
for (i = CS_OBJECTIVES; i < CS_OBJECTIVES + MAX_OBJECTIVES; ++i) {
|
2023-10-29 20:40:07 +01:00
|
|
|
CG_ProcessConfigString(i, qfalse);
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-11-07 22:43:13 +01:00
|
|
|
iCurrentObjective = atoi(CG_ConfigString(CS_CURRENT_OBJECTIVE));
|
|
|
|
fTimeDelta = cg.ObjectivesAlphaTime - cg.time;
|
2023-08-13 20:17:23 +02:00
|
|
|
cg.ObjectivesCurrentAlpha = cg.ObjectivesDesiredAlpha;
|
|
|
|
if (fTimeDelta > 0) {
|
2023-07-05 21:24:23 +02:00
|
|
|
cg.ObjectivesCurrentAlpha =
|
2023-08-13 20:17:23 +02:00
|
|
|
(cg.ObjectivesBaseAlpha - cg.ObjectivesDesiredAlpha) * sin(fTimeDelta / (M_PI * 50.f + 2.f))
|
|
|
|
+ cg.ObjectivesDesiredAlpha;
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cg.ObjectivesCurrentAlpha < 0.02) {
|
|
|
|
return;
|
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2024-11-19 19:41:46 +01:00
|
|
|
// Added in 2.0
|
|
|
|
// Get the minimum Y value, it should be below the compass
|
|
|
|
fObjectivesTop = cgi.UI_GetObjectivesTop();
|
|
|
|
iNumObjectives = 0;
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
for (i = 0; i < MAX_OBJECTIVES; i++) {
|
2024-11-19 19:41:46 +01:00
|
|
|
if ((cg.Objectives[i].flags == OBJ_FLAG_NONE) || (cg.Objectives[i].flags & OBJ_FLAG_HIDDEN)) {
|
|
|
|
continue;
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
2024-11-19 19:41:46 +01:00
|
|
|
|
|
|
|
iNumObjectives++;
|
|
|
|
iNumLines[i] = 0;
|
|
|
|
pszLocalizedText = cgi.LV_ConvertString(cg.Objectives[i].text);
|
|
|
|
|
2024-11-19 20:26:23 +01:00
|
|
|
for (pszLine = strchr(pszLocalizedText, '\n'); pszLine; pszLine = strchr(pszLine + 1, '\n')) {
|
2024-11-19 19:41:46 +01:00
|
|
|
iNumLines[i]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
iTotalNumLines += iNumLines[i];
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
fX = 25.0;
|
2024-11-19 19:41:46 +01:00
|
|
|
fY = fObjectivesTop + 5;
|
|
|
|
fWidth = (float)(iTotalNumLines * 12 + fObjectivesTop + iNumObjectives * 25 + 32) - fY;
|
2023-05-07 19:37:07 +02:00
|
|
|
vColor[2] = 0.2f;
|
|
|
|
vColor[1] = 0.2f;
|
|
|
|
vColor[0] = 0.2f;
|
|
|
|
vColor[3] = cg.ObjectivesCurrentAlpha * 0.75;
|
|
|
|
cgi.R_SetColor(vColor);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawStretchPic(fX, fY, 450.0 * cgs.uiHiResScale[0], fWidth * cgs.uiHiResScale[1], 0.0, 0.0, 1.0, 1.0, cgs.media.objectivesBackShader);
|
2023-07-05 21:24:23 +02:00
|
|
|
|
|
|
|
fX = 30.0;
|
2024-11-19 19:41:46 +01:00
|
|
|
fY = fObjectivesTop + 10;
|
2023-05-07 19:37:07 +02:00
|
|
|
vColor[0] = 1.0;
|
|
|
|
vColor[1] = 1.0;
|
|
|
|
vColor[2] = 1.0;
|
|
|
|
vColor[3] = cg.ObjectivesCurrentAlpha;
|
|
|
|
cgi.R_SetColor(vColor);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.objectiveFont, cgi.LV_ConvertString("Mission Objectives:"), fX, fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
2023-05-07 19:37:07 +02:00
|
|
|
fY = fY + 5.0;
|
|
|
|
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.objectiveFont, "_______________________________________________________", fX, fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
|
|
|
fHeight = fObjectivesTop + 35 * cgs.uiHiResScale[1];
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
for (i = 0; i < MAX_OBJECTIVES; ++i) {
|
2023-05-07 19:37:07 +02:00
|
|
|
qhandle_t hBoxShader;
|
2024-11-19 19:41:46 +01:00
|
|
|
|
|
|
|
if ((cg.Objectives[i].flags == OBJ_FLAG_NONE) || (cg.Objectives[i].flags & OBJ_FLAG_HIDDEN)) {
|
2023-05-07 19:37:07 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-08-14 02:34:06 +02:00
|
|
|
if ((cg.Objectives[i].flags & OBJ_FLAG_CURRENT) != 0) {
|
2023-07-05 21:24:23 +02:00
|
|
|
vColor[0] = 1.0;
|
|
|
|
vColor[1] = 1.0;
|
|
|
|
vColor[2] = 1.0;
|
|
|
|
vColor[3] = cg.ObjectivesCurrentAlpha;
|
2023-05-07 19:37:07 +02:00
|
|
|
hBoxShader = cgs.media.uncheckedBoxShader;
|
2023-08-14 02:34:06 +02:00
|
|
|
} else if ((cg.Objectives[i].flags & OBJ_FLAG_COMPLETED) != 0) {
|
2023-07-05 21:24:23 +02:00
|
|
|
vColor[0] = 0.75;
|
|
|
|
vColor[1] = 0.75;
|
|
|
|
vColor[2] = 0.75;
|
|
|
|
vColor[3] = cg.ObjectivesCurrentAlpha;
|
2023-05-07 19:37:07 +02:00
|
|
|
hBoxShader = cgs.media.checkedBoxShader;
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
|
|
|
vColor[0] = 1.0;
|
|
|
|
vColor[1] = 1.0;
|
|
|
|
vColor[2] = 1.0;
|
|
|
|
vColor[3] = cg.ObjectivesCurrentAlpha;
|
2023-05-07 19:37:07 +02:00
|
|
|
hBoxShader = cgs.media.uncheckedBoxShader;
|
|
|
|
}
|
2023-08-14 02:34:06 +02:00
|
|
|
if (i == iCurrentObjective && !(cg.Objectives[i].flags & OBJ_FLAG_COMPLETED)) {
|
2023-05-07 19:37:07 +02:00
|
|
|
vColor[0] = 1.0;
|
|
|
|
vColor[1] = 1.0;
|
|
|
|
vColor[2] = 0.0;
|
|
|
|
vColor[3] = cg.ObjectivesCurrentAlpha;
|
|
|
|
}
|
|
|
|
|
|
|
|
cgi.R_SetColor(vColor);
|
|
|
|
fX = 55.0;
|
|
|
|
fY = fHeight;
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(
|
|
|
|
cgs.media.objectiveFont,
|
|
|
|
cgi.LV_ConvertString(cg.Objectives[i].text),
|
|
|
|
55.0,
|
|
|
|
fY / cgs.uiHiResScale[1],
|
|
|
|
-1,
|
|
|
|
cgs.uiHiResScale
|
|
|
|
);
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
fX = 30.0;
|
|
|
|
fY = fHeight;
|
2023-05-07 19:37:07 +02:00
|
|
|
vColor[0] = 1.0;
|
|
|
|
vColor[1] = 1.0;
|
|
|
|
vColor[2] = 1.0;
|
|
|
|
vColor[3] = cg.ObjectivesCurrentAlpha;
|
|
|
|
cgi.R_SetColor(vColor);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawStretchPic(
|
|
|
|
fX * cgs.uiHiResScale[0],
|
|
|
|
fY,
|
|
|
|
16.0 * cgs.uiHiResScale[0],
|
|
|
|
16.0 * cgs.uiHiResScale[1],
|
|
|
|
0.0,
|
|
|
|
0.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
hBoxShader
|
|
|
|
);
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2024-11-30 19:59:54 +01:00
|
|
|
fHeight += iNumLines[i] * 12 + 25 * cgs.uiHiResScale[1];
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_DrawPlayerTeam()
|
|
|
|
{
|
2023-05-07 19:37:07 +02:00
|
|
|
qhandle_t handle;
|
|
|
|
if (!cg_hud->integer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cg.snap || cgs.gametype <= GT_FFA) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-22 02:38:43 +02:00
|
|
|
handle = 0;
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cg.snap->ps.stats[STAT_TEAM] == 3) {
|
2023-05-07 19:37:07 +02:00
|
|
|
handle = cgi.R_RegisterShader("textures/hud/allies");
|
2023-07-05 21:24:23 +02:00
|
|
|
} else if (cg.snap->ps.stats[STAT_TEAM] == 4) {
|
2023-05-07 19:37:07 +02:00
|
|
|
handle = cgi.R_RegisterShader("textures/hud/axis");
|
|
|
|
}
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (handle) {
|
2023-05-07 19:37:07 +02:00
|
|
|
cgi.R_SetColor(NULL);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawStretchPic(
|
|
|
|
96.0 * cgs.uiHiResScale[0],
|
|
|
|
cgs.glconfig.vidHeight - 46 * cgs.uiHiResScale[1],
|
|
|
|
24.0 * cgs.uiHiResScale[0],
|
|
|
|
24.0 * cgs.uiHiResScale[1],
|
|
|
|
0.0,
|
|
|
|
0.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
handle
|
|
|
|
);
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_DrawPlayerEntInfo()
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
int iClientNum;
|
|
|
|
const char *pszClientInfo;
|
|
|
|
const char *pszName;
|
|
|
|
float fX, fY;
|
|
|
|
float color[4];
|
|
|
|
qhandle_t handle;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
if (!cg_hud->integer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cg.snap || cg.snap->ps.stats[STAT_INFOCLIENT] == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
iClientNum = cg.snap->ps.stats[STAT_INFOCLIENT];
|
|
|
|
handle = 0;
|
2023-05-07 19:37:07 +02:00
|
|
|
pszClientInfo = CG_ConfigString(iClientNum + CS_PLAYERS);
|
2023-07-05 21:24:23 +02:00
|
|
|
pszName = Info_ValueForKey(pszClientInfo, "name");
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
color[0] = 0.5;
|
|
|
|
color[1] = 1.0;
|
|
|
|
color[2] = 0.5;
|
|
|
|
color[3] = 1.0;
|
|
|
|
|
|
|
|
fX = 56.0;
|
|
|
|
fY = (float)cgs.glconfig.vidHeight * 0.5;
|
|
|
|
|
|
|
|
if (cg.clientinfo[iClientNum].team == TEAM_ALLIES) {
|
|
|
|
handle = cgi.R_RegisterShader("textures/hud/allies");
|
|
|
|
} else if (cg.clientinfo[iClientNum].team == TEAM_AXIS) {
|
|
|
|
handle = cgi.R_RegisterShader("textures/hud/axis");
|
|
|
|
}
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (handle) {
|
2023-05-07 19:37:07 +02:00
|
|
|
cgi.R_SetColor(0);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawStretchPic(fX, fY, 16.0 * cgs.uiHiResScale[0], 16.0 * cgs.uiHiResScale[1], 0.0, 0.0, 1.0, 1.0, handle);
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cgi.R_SetColor(color);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.hudDrawFont, (char *)pszName, fX / cgs.uiHiResScale[0] + 24.0, fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
|
|
|
cgi.R_DrawString(cgs.media.hudDrawFont, va("%i", cg.snap->ps.stats[STAT_INFOCLIENT_HEALTH]), fX / cgs.uiHiResScale[0] + 24.0, fY / cgs.uiHiResScale[1] + 20.0, -1, cgs.uiHiResScale);
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_UpdateAttackerDisplay()
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
int iClientNum;
|
|
|
|
const char *pszClientInfo;
|
|
|
|
const char *pszName;
|
|
|
|
float fX, fY;
|
|
|
|
float color[4];
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
if (!cg_hud->integer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cg.snap || cg.snap->ps.stats[STAT_ATTACKERCLIENT] == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
iClientNum = cg.snap->ps.stats[STAT_ATTACKERCLIENT];
|
2023-05-07 19:37:07 +02:00
|
|
|
pszClientInfo = CG_ConfigString(CS_PLAYERS + iClientNum);
|
2023-07-05 21:24:23 +02:00
|
|
|
pszName = Info_ValueForKey(pszClientInfo, "name");
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
color[3] = 1.0;
|
2023-07-05 21:24:23 +02:00
|
|
|
fY = (float)(cgs.glconfig.vidHeight - 90);
|
|
|
|
fX = 56.0;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cgs.gametype > GT_FFA) {
|
2023-05-07 19:37:07 +02:00
|
|
|
qhandle_t handle;
|
|
|
|
|
|
|
|
handle = 0;
|
|
|
|
if (cg.clientinfo[iClientNum].team == TEAM_ALLIES) {
|
|
|
|
handle = cgi.R_RegisterShader("textures/hud/allies");
|
2023-07-05 21:24:23 +02:00
|
|
|
} else if (cg.clientinfo[iClientNum].team == TEAM_AXIS) {
|
2023-05-07 19:37:07 +02:00
|
|
|
handle = cgi.R_RegisterShader("textures/hud/axis");
|
|
|
|
}
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (handle) {
|
2023-05-07 19:37:07 +02:00
|
|
|
cgi.R_SetColor(0);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawStretchPic(
|
|
|
|
56.0 * cgs.uiHiResScale[0],
|
|
|
|
fY,
|
|
|
|
24.0 * cgs.uiHiResScale[0],
|
|
|
|
24.0 * cgs.uiHiResScale[1],
|
|
|
|
0.0,
|
|
|
|
0.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
handle
|
|
|
|
);
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((cg.snap->ps.stats[STAT_TEAM] == TEAM_ALLIES || cg.snap->ps.stats[STAT_TEAM] == TEAM_AXIS)
|
2023-07-05 21:24:23 +02:00
|
|
|
&& cg.clientinfo[iClientNum].team == cg.snap->ps.stats[STAT_TEAM]) {
|
2023-05-07 19:37:07 +02:00
|
|
|
color[0] = 0.5;
|
|
|
|
color[1] = 1.0;
|
|
|
|
color[2] = 0.5;
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
2023-05-07 19:37:07 +02:00
|
|
|
color[0] = 1.0;
|
|
|
|
color[1] = 0.5;
|
|
|
|
color[2] = 0.5;
|
|
|
|
}
|
|
|
|
|
2024-11-30 19:59:54 +01:00
|
|
|
fX = 56.0;
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
2023-05-07 19:37:07 +02:00
|
|
|
color[0] = 1.0;
|
|
|
|
color[1] = 0.5;
|
|
|
|
color[2] = 0.5;
|
|
|
|
}
|
|
|
|
|
|
|
|
cgi.R_SetColor(color);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, pszName, fX / cgs.uiHiResScale[0] + 32.0, fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_UpdateCountdown()
|
|
|
|
{
|
2024-09-18 20:55:02 +02:00
|
|
|
const char* message = "";
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!cg.snap) {
|
|
|
|
return;
|
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cg.matchStartTime != -1) {
|
|
|
|
int iSecondsLeft, iMinutesLeft;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
iSecondsLeft = (cgs.matchEndTime - cg.time) / 1000;
|
|
|
|
if (iSecondsLeft >= 0) {
|
|
|
|
iMinutesLeft = iSecondsLeft / 60;
|
2024-09-18 20:55:02 +02:00
|
|
|
message = va("%s %2i:%02i", cgi.LV_ConvertString("Time Left:"), iMinutesLeft, iSecondsLeft % 60);
|
2023-07-05 21:24:23 +02:00
|
|
|
} else if (!cgs.matchEndTime) {
|
2024-09-18 20:55:02 +02:00
|
|
|
message = "";
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
2023-07-05 21:24:23 +02:00
|
|
|
} else {
|
|
|
|
// The match has not started yet
|
2024-09-18 20:55:02 +02:00
|
|
|
message = "Waiting For Players";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(ui_timemessage->string, message)) {
|
|
|
|
cgi.Cvar_Set("ui_timemessage", message);
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|
|
|
|
|
2024-10-20 18:52:50 +02:00
|
|
|
static void CG_RemoveStopwatch() {
|
|
|
|
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_stopwatch\n");
|
|
|
|
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_fuse\n");
|
|
|
|
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_fuse_wet\n");
|
|
|
|
}
|
|
|
|
|
2023-05-01 15:12:01 +02:00
|
|
|
void CG_DrawStopwatch()
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
int iFraction;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!cg_hud->integer) {
|
2024-10-20 18:52:50 +02:00
|
|
|
CG_RemoveStopwatch();
|
2023-07-05 21:24:23 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-05-22 12:30:20 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!cgi.stopWatch->iStartTime) {
|
2024-10-20 18:52:50 +02:00
|
|
|
CG_RemoveStopwatch();
|
2023-07-05 21:24:23 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-05-22 12:30:20 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cgi.stopWatch->iStartTime >= cgi.stopWatch->iEndTime) {
|
2024-10-20 18:52:50 +02:00
|
|
|
CG_RemoveStopwatch();
|
2023-07-05 21:24:23 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-05-22 12:30:20 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cgi.stopWatch->iEndTime <= cg.time) {
|
2024-10-20 18:52:50 +02:00
|
|
|
CG_RemoveStopwatch();
|
2023-07-05 21:24:23 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-05-22 12:30:20 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cg.ObjectivesCurrentAlpha >= 0.02) {
|
2024-10-20 18:52:50 +02:00
|
|
|
CG_RemoveStopwatch();
|
2023-07-05 21:24:23 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-05-22 12:30:20 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cg.snap && cg.snap->ps.stats[STAT_HEALTH] <= 0) {
|
2024-10-20 18:52:50 +02:00
|
|
|
CG_RemoveStopwatch();
|
2023-07-05 21:24:23 +02:00
|
|
|
return;
|
|
|
|
}
|
2024-10-20 18:52:50 +02:00
|
|
|
if (cgi.stopWatch->eType >= SWT_FUSE_WET) {
|
|
|
|
iFraction = cgi.stopWatch->iEndTime - cgi.stopWatch->iStartTime;
|
|
|
|
} else {
|
|
|
|
iFraction = cgi.stopWatch->iEndTime - cg.time;
|
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
cgi.Cvar_Set("ui_stopwatch", va("%i", iFraction));
|
2024-10-20 18:52:50 +02:00
|
|
|
|
|
|
|
switch (cgi.stopWatch->eType) {
|
|
|
|
case SWT_NORMAL:
|
|
|
|
default:
|
|
|
|
cgi.Cmd_Execute(EXEC_NOW, "ui_addhud hud_stopwatch\n");
|
|
|
|
break;
|
|
|
|
case SWT_FUSE:
|
|
|
|
cgi.Cmd_Execute(EXEC_NOW, "ui_addhud hud_fuse\n");
|
|
|
|
break;
|
|
|
|
case SWT_FUSE_WET:
|
|
|
|
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_fuse\n");
|
|
|
|
cgi.Cmd_Execute(EXEC_NOW, "ui_addhud hud_fuse_wet\n");
|
|
|
|
break;
|
|
|
|
}
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CG_DrawInstantMessageMenu()
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
float w, h;
|
|
|
|
float x, y;
|
|
|
|
qhandle_t handle;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!cg.iInstaMessageMenu) {
|
|
|
|
return;
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cg.iInstaMessageMenu > 0) {
|
|
|
|
handle = cgi.R_RegisterShader(va("textures/hud/instamsg_group_%c", cg.iInstaMessageMenu + 96));
|
|
|
|
} else {
|
|
|
|
handle = cgi.R_RegisterShader("textures/hud/instamsg_main");
|
|
|
|
}
|
|
|
|
|
|
|
|
w = cgi.R_GetShaderWidth(handle);
|
|
|
|
h = cgi.R_GetShaderHeight(handle);
|
|
|
|
x = 8.0;
|
|
|
|
y = ((float)cgs.glconfig.vidHeight - h) * 0.5;
|
|
|
|
cgi.R_SetColor(0);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawStretchPic(x * cgs.uiHiResScale[0], y, w * cgs.uiHiResScale[0], h * cgs.uiHiResScale[1], 0.0, 0.0, 1.0, 1.0, handle);
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|
|
|
|
|
2023-07-01 21:18:58 +02:00
|
|
|
void CG_DrawSpectatorView_ver_15()
|
2023-05-22 01:45:27 +02:00
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
const char *pszString;
|
|
|
|
int iKey1, iKey2;
|
|
|
|
int iKey1b, iKey2b;
|
|
|
|
float fX, fY;
|
|
|
|
qboolean bOnTeam;
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!(cg.predicted_player_state.pm_flags & PMF_SPECTATING)) {
|
|
|
|
return;
|
|
|
|
}
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
bOnTeam = qfalse;
|
|
|
|
if (cg.snap->ps.stats[STAT_TEAM] == TEAM_ALLIES || cg.snap->ps.stats[STAT_TEAM] == TEAM_AXIS) {
|
|
|
|
bOnTeam = 1;
|
|
|
|
}
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!bOnTeam) {
|
|
|
|
cgi.Key_GetKeysForCommand("+attackprimary", &iKey1, &iKey2);
|
|
|
|
pszString = cgi.LV_ConvertString(va("Press Fire(%s) to join the battle!", cgi.Key_KeynumToBindString(iKey1)));
|
|
|
|
fX = (float)(cgs.glconfig.vidWidth - cgi.UI_FontStringWidth(cgs.media.attackerFont, pszString, -1)) * 0.5;
|
|
|
|
fY = cgs.glconfig.vidHeight - 64.0;
|
|
|
|
cgi.R_SetColor(NULL);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, pszString, fX / cgs.uiHiResScale[0], fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cg.predicted_player_state.pm_flags & PMF_CAMERA_VIEW) {
|
|
|
|
cgi.Key_GetKeysForCommand("+moveup", &iKey1, &iKey2);
|
|
|
|
cgi.Key_GetKeysForCommand("+movedown", &iKey1b, &iKey2b);
|
|
|
|
|
|
|
|
pszString = cgi.LV_ConvertString(
|
|
|
|
va("Press Jump(%s) or Duck(%s) to follow a different player.",
|
|
|
|
cgi.Key_KeynumToBindString(iKey1),
|
|
|
|
cgi.Key_KeynumToBindString(iKey1b))
|
|
|
|
);
|
|
|
|
|
|
|
|
fX = (float)(cgs.glconfig.vidWidth - cgi.UI_FontStringWidth(cgs.media.attackerFont, pszString, -1)) * 0.5;
|
|
|
|
fY = (float)cgs.glconfig.vidHeight - 40.0;
|
|
|
|
cgi.R_SetColor(0);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, pszString, fX / cgs.uiHiResScale[0], fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!bOnTeam && (cg.predicted_player_state.pm_flags & PMF_CAMERA_VIEW)) {
|
2023-05-22 01:45:27 +02:00
|
|
|
cgi.Key_GetKeysForCommand("+use", &iKey1, &iKey2);
|
2023-07-05 21:24:23 +02:00
|
|
|
pszString =
|
|
|
|
cgi.LV_ConvertString(va("Press Use(%s) to enter free spectate mode.", cgi.Key_KeynumToBindString(iKey1)));
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
fX = (float)(cgs.glconfig.vidWidth - cgi.UI_FontStringWidth(cgs.media.attackerFont, pszString, -1)) * 0.5;
|
|
|
|
fY = (float)cgs.glconfig.vidHeight - 24.0;
|
|
|
|
cgi.R_SetColor(0);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, pszString, fX / cgs.uiHiResScale[0], fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!(cg.predicted_player_state.pm_flags & PMF_CAMERA_VIEW)) {
|
2023-05-22 01:45:27 +02:00
|
|
|
cgi.Key_GetKeysForCommand("+use", &iKey1, &iKey2);
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
pszString = cgi.LV_ConvertString(
|
|
|
|
va("Press Use(%s) to enter player following spectate mode.", cgi.Key_KeynumToBindString(iKey1))
|
|
|
|
);
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
fX = (float)(cgs.glconfig.vidWidth - cgi.UI_FontStringWidth(cgs.media.attackerFont, pszString, -1)) * 0.5;
|
|
|
|
fY = (float)cgs.glconfig.vidHeight - 24.0;
|
|
|
|
cgi.R_SetColor(0);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, pszString, fX / cgs.uiHiResScale[0], fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
|
|
|
|
2024-11-30 19:59:54 +01:00
|
|
|
if ((cg.predicted_player_state.pm_flags & PMF_CAMERA_VIEW) != 0 && cg.snap && cg.snap->ps.stats[STAT_INFOCLIENT] != -1) {
|
2023-07-05 21:24:23 +02:00
|
|
|
int iClientNum;
|
2023-05-22 01:45:27 +02:00
|
|
|
qhandle_t hShader;
|
2023-07-05 21:24:23 +02:00
|
|
|
vec4_t color;
|
|
|
|
char buf[128];
|
2023-05-22 01:45:27 +02:00
|
|
|
|
|
|
|
iClientNum = cg.snap->ps.stats[STAT_INFOCLIENT];
|
2024-09-20 21:53:48 +02:00
|
|
|
Com_sprintf(buf, sizeof(buf), "%s : %i", cg.clientinfo[iClientNum].name, cg.snap->ps.stats[STAT_INFOCLIENT_HEALTH]);
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-11-07 22:43:13 +01:00
|
|
|
hShader = 0;
|
2023-05-22 01:45:27 +02:00
|
|
|
color[0] = 0.5;
|
|
|
|
color[1] = 1.0;
|
|
|
|
color[2] = 0.5;
|
2023-07-05 21:24:23 +02:00
|
|
|
color[3] = 1.0;
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
fX = (float)(cgs.glconfig.vidWidth - cgi.UI_FontStringWidth(cgs.media.attackerFont, pszString, -1) - 16) * 0.5;
|
|
|
|
fY = (float)cgs.glconfig.vidHeight - 80.0;
|
|
|
|
cgi.R_SetColor(color);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, buf, fX / cgs.uiHiResScale[0], fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (cg.clientinfo[iClientNum].team == TEAM_ALLIES) {
|
|
|
|
hShader = cgi.R_RegisterShader("textures/hud/allies");
|
|
|
|
} else if (cg.clientinfo[iClientNum].team == TEAM_AXIS) {
|
|
|
|
hShader = cgi.R_RegisterShader("textures/hud/axis");
|
|
|
|
}
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (hShader) {
|
|
|
|
cgi.R_SetColor(NULL);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawStretchPic(
|
|
|
|
fX - 20.0 * cgs.uiHiResScale[0],
|
|
|
|
fY,
|
|
|
|
16.0 * cgs.uiHiResScale[0],
|
|
|
|
16.0 * cgs.uiHiResScale[1],
|
|
|
|
0.0,
|
|
|
|
0.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
hShader
|
|
|
|
);
|
2023-07-05 21:24:23 +02:00
|
|
|
}
|
2023-05-22 01:45:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-01 21:18:58 +02:00
|
|
|
void CG_DrawSpectatorView_ver_6()
|
2023-05-01 15:12:01 +02:00
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
const char *pszString;
|
|
|
|
int iKey1, iKey2;
|
|
|
|
int iKey1b, iKey2b;
|
|
|
|
float fX, fY;
|
|
|
|
qboolean bOnTeam;
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!(cg.predicted_player_state.pm_flags & PMF_SPECTATING)) {
|
|
|
|
return;
|
|
|
|
}
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
bOnTeam = qfalse;
|
|
|
|
if (cg.snap->ps.stats[STAT_TEAM] == TEAM_ALLIES || cg.snap->ps.stats[STAT_TEAM] == TEAM_AXIS) {
|
|
|
|
bOnTeam = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// retrieve keys for +use
|
|
|
|
cgi.Key_GetKeysForCommand("+use", &iKey1, &iKey2);
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
if (cg.predicted_player_state.pm_flags & PMF_CAMERA_VIEW) {
|
2023-07-05 21:24:23 +02:00
|
|
|
pszString =
|
|
|
|
cgi.LV_ConvertString(va("Press Use(%s) to follow a different player.", cgi.Key_KeynumToBindString(iKey1)));
|
2023-05-07 19:37:07 +02:00
|
|
|
} else {
|
2023-07-05 21:24:23 +02:00
|
|
|
pszString = cgi.LV_ConvertString(va("Press Use(%s) to follow a player.", cgi.Key_KeynumToBindString(iKey1)));
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fX = (float)(cgs.glconfig.vidWidth - cgi.UI_FontStringWidth(cgs.media.attackerFont, pszString, -1)) * 0.5;
|
|
|
|
fY = (float)cgs.glconfig.vidHeight - 40.0;
|
|
|
|
cgi.R_SetColor(0);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, pszString, fX / cgs.uiHiResScale[0], fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
2023-05-07 19:37:07 +02:00
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
if (!bOnTeam && (cg.predicted_player_state.pm_flags & PMF_CAMERA_VIEW)) {
|
2023-05-07 19:37:07 +02:00
|
|
|
cgi.Key_GetKeysForCommand("+moveup", &iKey1, &iKey2);
|
|
|
|
cgi.Key_GetKeysForCommand("+movedown", &iKey1b, &iKey2b);
|
|
|
|
pszString = cgi.LV_ConvertString(
|
2023-07-05 21:24:23 +02:00
|
|
|
va("Press Jump(%s) or Duck(%s) to free spectate.",
|
|
|
|
cgi.Key_KeynumToBindString(iKey1),
|
|
|
|
cgi.Key_KeynumToBindString(iKey1b))
|
|
|
|
);
|
2023-05-07 19:37:07 +02:00
|
|
|
|
|
|
|
fX = (float)(cgs.glconfig.vidWidth - cgi.UI_FontStringWidth(cgs.media.attackerFont, pszString, -1)) * 0.5;
|
|
|
|
fY = (float)cgs.glconfig.vidHeight - 24.0;
|
|
|
|
cgi.R_SetColor(0);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, pszString, fX / cgs.uiHiResScale[0], fY / cgs.uiHiResScale[1], -1, cgs.uiHiResScale);
|
2023-05-07 19:37:07 +02:00
|
|
|
}
|
2023-04-30 14:47:27 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:24:23 +02:00
|
|
|
void CG_DrawSpectatorView()
|
|
|
|
{
|
2023-07-02 19:16:09 +02:00
|
|
|
if (cg_protocol >= PROTOCOL_MOHTA_MIN) {
|
2023-07-01 21:18:58 +02:00
|
|
|
CG_DrawSpectatorView_ver_15();
|
|
|
|
} else {
|
|
|
|
CG_DrawSpectatorView_ver_6();
|
|
|
|
}
|
|
|
|
}
|
2023-05-22 01:45:27 +02:00
|
|
|
|
2023-11-07 22:43:13 +01:00
|
|
|
void CG_DrawCrosshair()
|
|
|
|
{
|
|
|
|
centity_t *friendEnt;
|
|
|
|
qhandle_t shader;
|
|
|
|
vec3_t forward;
|
|
|
|
vec3_t end;
|
|
|
|
vec3_t mins, maxs;
|
|
|
|
trace_t trace;
|
|
|
|
float x, y;
|
|
|
|
float width, height;
|
|
|
|
|
2024-06-07 20:34:13 +02:00
|
|
|
shader = (qhandle_t)0;
|
2023-11-13 22:18:38 +01:00
|
|
|
|
2023-11-07 22:43:13 +01:00
|
|
|
if (!cg_hud->integer || !ui_crosshair->integer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cg.snap) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-11-02 13:48:03 +01:00
|
|
|
if ((cg.snap->ps.pm_flags & PMF_NO_HUD) || (cg.snap->ps.pm_flags & PMF_INTERMISSION)) {
|
2023-11-07 22:43:13 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cg.snap->ps.stats[STAT_CROSSHAIR]
|
|
|
|
&& (!cg.snap->ps.stats[STAT_INZOOM] || cg.snap->ps.stats[STAT_INZOOM] > 30)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cgs.gametype != GT_FFA) {
|
|
|
|
AngleVectorsLeft(cg.refdefViewAngles, forward, NULL, NULL);
|
|
|
|
|
2023-11-07 23:05:54 +01:00
|
|
|
VectorMA(cg.refdef.vieworg, 8192, forward, end);
|
2023-11-07 22:43:13 +01:00
|
|
|
VectorClear(mins);
|
|
|
|
VectorClear(maxs);
|
|
|
|
|
|
|
|
CG_Trace(&trace, cg.refdef.vieworg, mins, maxs, end, 9999, MASK_SOLID, qfalse, qtrue, "CG_DrawCrosshair");
|
|
|
|
|
2023-11-07 22:54:05 +01:00
|
|
|
// ENTITYNUM_WORLD check added in OPM
|
|
|
|
if ((trace.entityNum != ENTITYNUM_NONE && trace.entityNum != ENTITYNUM_WORLD)
|
|
|
|
&& trace.entityNum != cg.snap->ps.clientNum) {
|
2023-11-07 22:43:13 +01:00
|
|
|
int myFlags;
|
|
|
|
|
|
|
|
friendEnt = &cg_entities[trace.entityNum];
|
|
|
|
if (cgs.gametype != GT_SINGLE_PLAYER) {
|
|
|
|
myFlags = cg_entities[cg.snap->ps.clientNum].currentState.eFlags & EF_ANY_TEAM;
|
|
|
|
} else {
|
|
|
|
// the player will always be considered as an allied
|
|
|
|
// in single-player
|
|
|
|
myFlags = EF_ALLIES;
|
|
|
|
}
|
|
|
|
|
2023-11-07 22:54:05 +01:00
|
|
|
if (((myFlags & EF_ALLIES) && (friendEnt->currentState.eFlags & EF_ALLIES))
|
|
|
|
|| ((myFlags & EF_AXIS) && (friendEnt->currentState.eFlags & EF_AXIS))) {
|
2023-11-07 22:43:13 +01:00
|
|
|
// friend
|
|
|
|
if (cg.snap->ps.stats[STAT_CROSSHAIR]) {
|
|
|
|
shader = cgi.R_RegisterShader(cg_crosshair_friend->string);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// enemy
|
|
|
|
if (cg.snap->ps.stats[STAT_CROSSHAIR]) {
|
|
|
|
shader = cgi.R_RegisterShader(cg_crosshair->string);
|
|
|
|
}
|
|
|
|
}
|
2023-11-07 22:54:05 +01:00
|
|
|
} else {
|
|
|
|
if (cg.snap->ps.stats[STAT_CROSSHAIR]) {
|
|
|
|
shader = cgi.R_RegisterShader(cg_crosshair->string);
|
|
|
|
}
|
2023-11-07 22:43:13 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// FFA
|
|
|
|
if (cg.snap->ps.stats[STAT_CROSSHAIR]) {
|
|
|
|
shader = cgi.R_RegisterShader(cg_crosshair->string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shader) {
|
|
|
|
width = cgi.R_GetShaderWidth(shader);
|
|
|
|
height = cgi.R_GetShaderHeight(shader);
|
|
|
|
x = (cgs.glconfig.vidWidth - width) * 0.5f;
|
|
|
|
y = (cgs.glconfig.vidHeight - height) * 0.5f;
|
|
|
|
|
|
|
|
cgi.R_SetColor(NULL);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawStretchPic(
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width * cgs.uiHiResScale[0],
|
|
|
|
height * cgs.uiHiResScale[1],
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
1,
|
|
|
|
1,
|
|
|
|
shader
|
|
|
|
);
|
2023-11-07 22:43:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CG_DrawVote()
|
|
|
|
{
|
|
|
|
const char *text;
|
|
|
|
int seconds;
|
|
|
|
int percentYes;
|
|
|
|
int percentNo;
|
|
|
|
int percentUndecided;
|
|
|
|
float x, y;
|
|
|
|
vec4_t col;
|
|
|
|
|
|
|
|
if (!cgs.voteTime) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cgs.voteRefreshed) {
|
|
|
|
cgs.voteRefreshed = qfalse;
|
|
|
|
}
|
|
|
|
|
|
|
|
seconds = (30000 - (cg.time - cgs.voteTime)) / 1000 + 1;
|
|
|
|
if (seconds < 0) {
|
|
|
|
seconds = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
percentYes = cgs.numVotesYes * 100 / (cgs.numUndecidedVotes + cgs.numVotesNo + cgs.numVotesYes);
|
|
|
|
percentNo = cgs.numVotesNo * 100 / (cgs.numUndecidedVotes + cgs.numVotesNo + cgs.numVotesYes);
|
|
|
|
percentUndecided = cgs.numUndecidedVotes * 100 / (cgs.numUndecidedVotes + cgs.numVotesNo + cgs.numVotesYes);
|
|
|
|
|
|
|
|
x = 8;
|
|
|
|
y = (cgs.glconfig.vidHeight > 480) ? (cgs.glconfig.vidHeight * 0.725f) : (cgs.glconfig.vidHeight * 0.75f);
|
|
|
|
|
|
|
|
cgi.R_SetColor(NULL);
|
|
|
|
|
|
|
|
text = va("%s: %s", cgi.LV_ConvertString("Vote Running"), cgs.voteString);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, text, x, y, -1, cgs.uiHiResScale);
|
2023-11-07 22:43:13 +01:00
|
|
|
|
|
|
|
y += 12;
|
2023-11-07 23:02:00 +01:00
|
|
|
|
2023-11-07 22:43:13 +01:00
|
|
|
text =
|
|
|
|
va("%s: %isec %s: %i%% %s: %i%% %s: %i%%",
|
|
|
|
cgi.LV_ConvertString("Time"),
|
|
|
|
seconds,
|
|
|
|
cgi.LV_ConvertString("Yes"),
|
|
|
|
percentYes,
|
|
|
|
cgi.LV_ConvertString("No"),
|
|
|
|
percentNo,
|
|
|
|
cgi.LV_ConvertString("Undecided"),
|
|
|
|
percentUndecided);
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, text, x, y, -1, cgs.uiHiResScale);
|
2023-11-07 22:43:13 +01:00
|
|
|
|
|
|
|
if (cg.snap && !cg.snap->ps.voted) {
|
|
|
|
col[0] = 0.5;
|
|
|
|
col[1] = 1.0;
|
|
|
|
col[2] = 0.5;
|
|
|
|
col[3] = 1.0;
|
|
|
|
cgi.R_SetColor(col);
|
|
|
|
|
2023-11-07 23:02:00 +01:00
|
|
|
y += 12;
|
|
|
|
|
2023-11-07 22:43:13 +01:00
|
|
|
text = cgi.LV_ConvertString("Vote now, it's your patriotic duty!");
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, text, x, y, -1, cgs.uiHiResScale);
|
2023-11-07 22:43:13 +01:00
|
|
|
|
2023-11-07 23:06:11 +01:00
|
|
|
y += 12;
|
|
|
|
|
2023-11-07 22:43:13 +01:00
|
|
|
text = cgi.LV_ConvertString("To vote Yes, press F1. To vote No, press F2.");
|
2024-11-30 19:59:54 +01:00
|
|
|
cgi.R_DrawString(cgs.media.attackerFont, text, x, y, -1, cgs.uiHiResScale);
|
2023-11-07 22:43:13 +01:00
|
|
|
cgi.R_SetColor(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-30 00:02:16 +02:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
CG_Draw2D
|
|
|
|
==============
|
|
|
|
*/
|
2023-05-01 15:12:01 +02:00
|
|
|
void CG_Draw2D(void)
|
|
|
|
{
|
2023-07-05 21:24:23 +02:00
|
|
|
CG_UpdateCountdown();
|
|
|
|
CG_DrawZoomOverlay();
|
|
|
|
CG_DrawLagometer();
|
|
|
|
CG_HudDrawElements();
|
|
|
|
CG_DrawObjectives();
|
|
|
|
CG_DrawIcons();
|
|
|
|
CG_DrawStopwatch();
|
|
|
|
CG_DrawSpectatorView();
|
|
|
|
CG_DrawPlayerTeam();
|
|
|
|
CG_DrawPlayerEntInfo();
|
|
|
|
CG_UpdateAttackerDisplay();
|
2023-11-07 22:43:13 +01:00
|
|
|
CG_DrawVote();
|
2023-07-05 21:24:23 +02:00
|
|
|
CG_DrawInstantMessageMenu();
|
2023-11-07 22:43:13 +01:00
|
|
|
CG_DrawCrosshair();
|
2023-05-01 15:12:01 +02:00
|
|
|
}
|