fteqw/plugins/ezhud/hud_common.c

8776 lines
253 KiB
C

/*
Copyright (C) 2011 azazello and ezQuake team
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
//
// common HUD elements
// like clock etc..
//
#include "../plugin.h"
/*
#include "common_draw.h"
#include "mp3_player.h"
#include <png.h>
#include "image.h"
#include "stats_grid.h"
#include "vx_stuff.h"
#include "gl_model.h"
#include "gl_local.h"
#include "tr_types.h"
#include "rulesets.h"
#include "utils.h"
#include "sbar.h"
#include "Ctrl.h"
#include "console.h"
#include "teamplay.h"
#include "mvd_utils.h"
*/
#include "ezquakeisms.h"
#include "hud.h"
//#define WITH_PNG //more WITH_RADAR than anything else.
#define draw_disc draw_disc2
static mpic_t *sb_ammo[4];
static mpic_t *sb_faces[7][2];
static mpic_t *sb_face_invis;
static mpic_t *sb_face_quad;
static mpic_t *sb_face_invuln;
static mpic_t *sb_face_invis_invuln;
static mpic_t *sb_weapons[7][8];
static mpic_t *sb_items[6];
static mpic_t *sb_sigil[4];
mpic_t *sb_nums[2][11];
static mpic_t *sb_ibar;
static mpic_t *sb_armor[3];
mpic_t *sb_colon;
static mpic_t *sb_slash;
static mpic_t *sb_disc;
static mpic_t *sb_net;
void HUD_InitSbarImages(void)
{
int i;
sb_disc = Draw_CacheWadPic("disc");
sb_net = Draw_CacheWadPic("net");
for (i = 0; i < 10; i++) {
sb_nums[0][i] = Draw_CacheWadPic (va("num_%i",i));
sb_nums[1][i] = Draw_CacheWadPic (va("anum_%i",i));
}
sb_nums[0][10] = Draw_CacheWadPic ("num_minus");
sb_nums[1][10] = Draw_CacheWadPic ("anum_minus");
sb_colon = Draw_CacheWadPic ("num_colon");
sb_slash = Draw_CacheWadPic ("num_slash");
sb_weapons[0][0] = Draw_CacheWadPic ("inv_shotgun");
sb_weapons[0][1] = Draw_CacheWadPic ("inv_sshotgun");
sb_weapons[0][2] = Draw_CacheWadPic ("inv_nailgun");
sb_weapons[0][3] = Draw_CacheWadPic ("inv_snailgun");
sb_weapons[0][4] = Draw_CacheWadPic ("inv_rlaunch");
sb_weapons[0][5] = Draw_CacheWadPic ("inv_srlaunch");
sb_weapons[0][6] = Draw_CacheWadPic ("inv_lightng");
sb_weapons[1][0] = Draw_CacheWadPic ("inv2_shotgun");
sb_weapons[1][1] = Draw_CacheWadPic ("inv2_sshotgun");
sb_weapons[1][2] = Draw_CacheWadPic ("inv2_nailgun");
sb_weapons[1][3] = Draw_CacheWadPic ("inv2_snailgun");
sb_weapons[1][4] = Draw_CacheWadPic ("inv2_rlaunch");
sb_weapons[1][5] = Draw_CacheWadPic ("inv2_srlaunch");
sb_weapons[1][6] = Draw_CacheWadPic ("inv2_lightng");
for (i = 0; i < 5; i++)
{
sb_weapons[2 + i][0] = Draw_CacheWadPic (va("inva%i_shotgun", i + 1));
sb_weapons[2 + i][1] = Draw_CacheWadPic (va("inva%i_sshotgun", i + 1));
sb_weapons[2 + i][2] = Draw_CacheWadPic (va("inva%i_nailgun", i + 1));
sb_weapons[2 + i][3] = Draw_CacheWadPic (va("inva%i_snailgun", i + 1));
sb_weapons[2 + i][4] = Draw_CacheWadPic (va("inva%i_rlaunch", i + 1));
sb_weapons[2 + i][5] = Draw_CacheWadPic (va("inva%i_srlaunch", i + 1));
sb_weapons[2 + i][6] = Draw_CacheWadPic (va("inva%i_lightng", i + 1));
}
sb_ammo[0] = Draw_CacheWadPic ("sb_shells");
sb_ammo[1] = Draw_CacheWadPic ("sb_nails");
sb_ammo[2] = Draw_CacheWadPic ("sb_rocket");
sb_ammo[3] = Draw_CacheWadPic ("sb_cells");
sb_armor[0] = Draw_CacheWadPic ("sb_armor1");
sb_armor[1] = Draw_CacheWadPic ("sb_armor2");
sb_armor[2] = Draw_CacheWadPic ("sb_armor3");
sb_items[0] = Draw_CacheWadPic ("sb_key1");
sb_items[1] = Draw_CacheWadPic ("sb_key2");
sb_items[2] = Draw_CacheWadPic ("sb_invis");
sb_items[3] = Draw_CacheWadPic ("sb_invuln");
sb_items[4] = Draw_CacheWadPic ("sb_suit");
sb_items[5] = Draw_CacheWadPic ("sb_quad");
sb_sigil[0] = Draw_CacheWadPic ("sb_sigil1");
sb_sigil[1] = Draw_CacheWadPic ("sb_sigil2");
sb_sigil[2] = Draw_CacheWadPic ("sb_sigil3");
sb_sigil[3] = Draw_CacheWadPic ("sb_sigil4");
sb_faces[4][0] = Draw_CacheWadPic ("face1");
sb_faces[4][1] = Draw_CacheWadPic ("face_p1");
sb_faces[3][0] = Draw_CacheWadPic ("face2");
sb_faces[3][1] = Draw_CacheWadPic ("face_p2");
sb_faces[2][0] = Draw_CacheWadPic ("face3");
sb_faces[2][1] = Draw_CacheWadPic ("face_p3");
sb_faces[1][0] = Draw_CacheWadPic ("face4");
sb_faces[1][1] = Draw_CacheWadPic ("face_p4");
sb_faces[0][0] = Draw_CacheWadPic ("face5");
sb_faces[0][1] = Draw_CacheWadPic ("face_p5");
sb_face_invis = Draw_CacheWadPic ("face_invis");
sb_face_invuln = Draw_CacheWadPic ("face_invul2");
sb_face_invis_invuln = Draw_CacheWadPic ("face_inv2");
sb_face_quad = Draw_CacheWadPic ("face_quad");
sb_ibar = Draw_CacheWadPic("ibar");
}
plugnetinfo_t *GetNetworkInfo(void)
{
static plugnetinfo_t ni;
static int uc;
if (uc != host_screenupdatecount)
{
uc = host_screenupdatecount;
clientfuncs->GetNetworkInfo(&ni, sizeof(ni));
}
return &ni;
}
#ifndef STAT_MINUS
#define STAT_MINUS 10
#endif
hud_t *hud_netgraph = NULL;
// ----------------
// HUD planning
//
struct
{
// this is temporary storage place for some of user's settings
// hud_* values will be dumped into config file
int old_multiview;
int old_fov;
int old_newhud;
qbool active;
} autohud;
void OnAutoHudChange(cvar_t *var, char *value, qbool *cancel);
qbool autohud_loaded = false;
cvar_t *hud_planmode;
cvar_t *mvd_autohud;
cvar_t *hud_digits_trim;
cvar_t *cl_multiview;
int hud_stats[MAX_CL_STATS];
cvar_t *cl_weaponpreselect;
extern int IN_BestWeapon(void);
extern void DumpHUD(char *);
extern char *Macro_MatchType(void);
int HUD_Stats(int stat_num)
{
if (hud_planmode->value)
return hud_stats[stat_num];
else
return cl.stats[stat_num];
}
// ----------------
// HUD low levels
//
cvar_t *hud_tp_need;
/* tp need levels
int TP_IsHealthLow(void);
int TP_IsArmorLow(void);
int TP_IsAmmoLow(int weapon); */
cvar_t *tp_need_health, *tp_need_ra, *tp_need_ya, *tp_need_ga,
*tp_weapon_order, *tp_need_weapon, *tp_need_shells,
*tp_need_nails, *tp_need_rockets, *tp_need_cells;
int State_AmmoNumForWeapon(int weapon)
{ // returns ammo number (shells = 1, nails = 2, rox = 3, cells = 4) for given weapon
switch (weapon) {
case 2: case 3: return 1;
case 4: case 5: return 2;
case 6: case 7: return 3;
case 8: return 4;
default: return 0;
}
}
int State_AmmoForWeapon(int weapon)
{ // returns ammo amount for given weapon
int ammon = State_AmmoNumForWeapon(weapon);
if (ammon)
return cl.stats[STAT_SHELLS + ammon - 1];
else
return 0;
}
int TP_IsHealthLow(void)
{
return cl.stats[STAT_HEALTH] <= tp_need_health->value;
}
int TP_IsArmorLow(void)
{
if ((cl.stats[STAT_ARMOR] > 0) && (cl.stats[STAT_ITEMS] & IT_ARMOR3))
return cl.stats[STAT_ARMOR] <= tp_need_ra->value;
if ((cl.stats[STAT_ARMOR] > 0) && (cl.stats[STAT_ITEMS] & IT_ARMOR2))
return cl.stats[STAT_ARMOR] <= tp_need_ya->value;
if ((cl.stats[STAT_ARMOR] > 0) && (cl.stats[STAT_ITEMS] & IT_ARMOR1))
return cl.stats[STAT_ARMOR] <= tp_need_ga->value;
return 1;
}
int TP_IsWeaponLow(void)
{
char *s = tp_weapon_order->string;
while (*s && *s != tp_need_weapon->string[0])
{
if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN << (*s-'0'-2)))
return false;
s++;
}
return true;
}
int TP_IsAmmoLow(int weapon)
{
int ammo = State_AmmoForWeapon(weapon);
switch (weapon)
{
case 2:
case 3: return ammo <= tp_need_shells->value;
case 4:
case 5: return ammo <= tp_need_nails->value;
case 6:
case 7: return ammo <= tp_need_rockets->value;
case 8: return ammo <= tp_need_cells->value;
default: return 0;
}
}
int TP_TeamFortressEngineerSpanner(void)
{
#ifdef HAXX
char *player_skin=Info_ValueForKey(cl.players[cl.playernum].userinfo,"skin");
char *model_name=cl.model_precache[cl.viewent.current.modelindex]->name;
if (cl.teamfortress && player_skin
&& (strcasecmp(player_skin, "tf_eng") == 0)
&& model_name
&& (strcasecmp(model_name, "progs/v_span.mdl") == 0))
{
return 1;
}
else
#endif
{
return 0;
}
}
qbool HUD_HealthLow(void)
{
if (hud_tp_need->value)
return TP_IsHealthLow();
else
return HUD_Stats(STAT_HEALTH) <= 25;
}
qbool HUD_ArmorLow(void)
{
if (hud_tp_need->value)
return (TP_IsArmorLow());
else
return (HUD_Stats(STAT_ARMOR) <= 25);
}
qbool HUD_AmmoLow(void)
{
if (hud_tp_need->value)
{
if (HUD_Stats(STAT_ITEMS) & IT_SHELLS)
return TP_IsAmmoLow(2);
else if (HUD_Stats(STAT_ITEMS) & IT_NAILS)
return TP_IsAmmoLow(4);
else if (HUD_Stats(STAT_ITEMS) & IT_ROCKETS)
return TP_IsAmmoLow(6);
else if (HUD_Stats(STAT_ITEMS) & IT_CELLS)
return TP_IsAmmoLow(8);
return false;
}
else
return (HUD_Stats(STAT_AMMO) <= 10);
}
int HUD_AmmoLowByWeapon(int weapon)
{
if (hud_tp_need->value)
return TP_IsAmmoLow(weapon);
else
{
int a;
switch (weapon)
{
case 2:
case 3:
a = STAT_SHELLS; break;
case 4:
case 5:
a = STAT_NAILS; break;
case 6:
case 7:
a = STAT_ROCKETS; break;
case 8:
a = STAT_CELLS; break;
default:
return false;
}
return (HUD_Stats(a) <= 10);
}
}
// ----------------
// DrawFPS
void SCR_HUD_DrawFPS(hud_t *hud)
{
int x, y;
char st[128];
static cvar_t
*hud_fps_show_min = NULL,
*hud_fps_style,
*hud_fps_title,
*hud_fps_drop;
if (hud_fps_show_min == NULL) // first time called
{
hud_fps_show_min = HUD_FindVar(hud, "show_min");
hud_fps_style = HUD_FindVar(hud, "style");
hud_fps_title = HUD_FindVar(hud, "title");
hud_fps_drop = HUD_FindVar(hud, "drop");
}
if (hud_fps_show_min->value)
snprintf (st, sizeof (st), "%3d^Ue00f%3d", (int)(cls.min_fps + 0.25), (int) (cls.fps + 0.25));
else
snprintf (st, sizeof (st), "%3d", (int)(cls.fps + 0.25));
if (hud_fps_title->value)
strlcat (st, " fps", sizeof (st));
if (HUD_PrepareDraw(hud, strlen(st)*8, 8, &x, &y))
{
plugnetinfo_t *netinfo = GetNetworkInfo();
if (netinfo->capturing == 2) //don't show fps if its locked to something anyway.
return;
if ((hud_fps_style->value) == 1)
Draw_Alt_String(x, y, st);
else if ((hud_fps_style->value) == 2) {
if ((hud_fps_drop->value) >= cls.fps) // if fps is less than a user-set value, then show it
Draw_String(x, y, st);
}
else if ((hud_fps_style->value) == 3) {
if ((hud_fps_drop->value) >= cls.fps) // if fps is less than a user-set value, then show it
Draw_Alt_String(x, y, st);
}
else // hud_fps_style is anything other than 1,2,3
Draw_String(x, y, st);
}
}
void SCR_HUD_DrawVidLag(hud_t *hud)
{
int x, y;
char st[128];
static cvar_t *hud_vidlag_style = NULL;
plugnetinfo_t *netinfo = GetNetworkInfo();
static double old_lag;
if (netinfo->vlatency)
{
// take the average of last two values, otherwise it
// changes very fast and is hard to read
double current, avg;
current = netinfo->vlatency;
avg = (current + old_lag) * 0.5;
old_lag = current;
snprintf (st, sizeof (st), "%2.1f", avg * 1000);
}
else
strcpy(st, "?");
if (hud_vidlag_style == NULL) // first time called
{
hud_vidlag_style = HUD_FindVar(hud, "style");
}
strlcat (st, " ms", sizeof (st));
if (HUD_PrepareDraw(hud, strlen(st)*8, 8, &x, &y))
{
if (hud_vidlag_style->value)
{
Draw_Alt_String(x, y, st);
}
else
{
Draw_String(x, y, st);
}
}
}
void SCR_HUD_DrawMouserate(hud_t *hud)
{
int x, y;
static int lastresult = 0;
int newresult;
char st[80]; // string buffer
double t; // current time
static double lastframetime; // last refresh
plugnetinfo_t *netinfo = GetNetworkInfo();
static cvar_t *hud_mouserate_title = NULL,
*hud_mouserate_interval,
*hud_mouserate_style;
if (hud_mouserate_title == NULL) // first time called
{
hud_mouserate_style = HUD_FindVar(hud, "style");
hud_mouserate_title = HUD_FindVar(hud, "title");
hud_mouserate_interval = HUD_FindVar(hud, "interval");
}
t = cls.realtime;
if ((t - lastframetime) >= hud_mouserate_interval->value) {
newresult = netinfo->mrate;
lastframetime = t;
} else
newresult = 0;
if (newresult > 0) {
snprintf(st, sizeof(st), "%4d", newresult);
lastresult = newresult;
} else if (!newresult)
snprintf(st, sizeof(st), "%4d", lastresult);
else
snprintf(st, sizeof(st), "n/a");
if (hud_mouserate_title->value)
strlcat(st, " Hz", sizeof (st));
if (HUD_PrepareDraw(hud, strlen(st)*8, 8, &x, &y))
{
if (hud_mouserate_style->value)
{
Draw_Alt_String(x, y, st);
}
else
{
Draw_String(x, y, st);
}
}
}
#define MAX_TRACKING_STRING 512
void SCR_HUD_DrawTracking(hud_t *hud)
{
#ifdef HAXX
static char tracked_strings[MV_VIEWS][MAX_TRACKING_STRING];
static int tracked[MV_VIEWS] = {-1, -1, -1, -1};
int view = 0;
#endif
int views = 1;
int x = 0, y = 0, width = 0, height = 0;
char track_string[MAX_TRACKING_STRING];
static cvar_t *hud_tracking_format = NULL,
*hud_tracking_scale;
if (!hud_tracking_format) {
hud_tracking_format = HUD_FindVar(hud, "format");
hud_tracking_scale = HUD_FindVar(hud, "scale");
}
strlcpy(track_string, hud_tracking_format->string, sizeof(track_string));
#ifdef HAXX
if(cls.mvdplayback && cl_multiview->value && CURRVIEW > 0)
{
//
// Multiview.
//
views = cl_multiview->value;
// Save the currently tracked player for the slot being drawn
// (this will be done for all views and we'll get a complete
// list over who we're tracking).
tracked[CURRVIEW - 1] = spec_track;
for(view = 0; view < MV_VIEWS; view++)
{
int new_width = 0;
// We haven't found who we're tracking in this view.
if(tracked[view] < 0)
{
continue;
}
strlcpy(tracked_strings[view], hud_tracking_format->string, sizeof(tracked_strings[view]));
Replace_In_String(tracked_strings[view], sizeof(tracked_strings[view]), '%', 3,
"v", cl_multiview->value ? va("%d", view+1) : "", // Replace %v with the current view (in multiview)
"n", cl.players[tracked[view]].name, // Replace %n with player name.
"t", cl.teamplay ? cl.players[tracked[view]].team : ""); // Replace %t with player team if teamplay is on.
// Set the width.
new_width = 8 * strlen_color(tracked_strings[view]);
width = (new_width > width) ? new_width : width;
}
}
else
#endif
{
// Normal.
Replace_In_String(track_string, sizeof(track_string), '%', 2,
"n", cl.players[spec_track].name, // Replace %n with player name.
"t", cl.teamplay ? cl.players[spec_track].team : ""); // Replace %t with player team if teamplay is on.
width = 8 * strlen_color(track_string);
}
height = 8 * views;
height *= hud_tracking_scale->value;
width *= hud_tracking_scale->value;
if (!(cl.spectator && autocam == CAM_TRACK))
height = 0;
if(!HUD_PrepareDraw(hud, width, height, &x, &y))
{
return;
}
if (height == 0)
return;
#ifdef HAXX
if (cls.mvdplayback && cl_multiview->value && autocam == CAM_TRACK)
{
// Multiview
for(view = 0; view < MV_VIEWS; view++)
{
if(tracked[view] < 0 || CURRVIEW <= 0)
{
continue;
}
Draw_SString(x, y + view*8, tracked_strings[view], hud_tracking_scale->value);
}
}
else
#endif
if (cl.spectator && autocam == CAM_TRACK && !cl_multiview->value)
{
// Normal
Draw_SString(x, y, track_string, hud_tracking_scale->value);
}
}
#ifdef HAXX
void R_MQW_NetGraph(int outgoing_sequence, int incoming_sequence, int *packet_latency,
int lost, int minping, int avgping, int maxping, int devping,
int posx, int posy, int width, int height, int revx, int revy);
// ----------------
// Netgraph
static void SCR_HUD_Netgraph(hud_t *hud)
{
static cvar_t
*par_width = NULL, *par_height,
*par_swap_x, *par_swap_y,
*par_ploss;
if (par_width == NULL) // first time
{
par_width = HUD_FindVar(hud, "width");
par_height = HUD_FindVar(hud, "height");
par_swap_x = HUD_FindVar(hud, "swap_x");
par_swap_y = HUD_FindVar(hud, "swap_y");
par_ploss = HUD_FindVar(hud, "ploss");
}
R_MQW_NetGraph(cls.netchan.outgoing_sequence, cls.netchan.incoming_sequence,
packet_latency, par_ploss->value ? CL_CalcNet() : -1, -1, -1, -1, -1, -1,
-1, (int)par_width->value, (int)par_height->value,
(int)par_swap_x->value, (int)par_swap_y->value);
}
#endif
//---------------------
//
// draw HUD ping
//
static void SCR_HUD_DrawPing(hud_t *hud)
{
double t;
static double last_calculated;
static int ping_avg, pl, ping_min, ping_max;
static float ping_dev;
int width, height;
int x, y;
char buf[512];
plugnetinfo_t *netinfo = GetNetworkInfo();
static cvar_t
*hud_ping_period = NULL,
*hud_ping_show_pl,
*hud_ping_show_dev,
*hud_ping_show_min,
*hud_ping_show_max,
*hud_ping_style,
*hud_ping_blink;
if (hud_ping_period == NULL) // first time
{
hud_ping_period = HUD_FindVar(hud, "period");
hud_ping_show_pl = HUD_FindVar(hud, "show_pl");
hud_ping_show_dev = HUD_FindVar(hud, "show_dev");
hud_ping_show_min = HUD_FindVar(hud, "show_min");
hud_ping_show_max = HUD_FindVar(hud, "show_max");
hud_ping_style = HUD_FindVar(hud, "style");
hud_ping_blink = HUD_FindVar(hud, "blink");
}
t = cls.realtime;
if (t - last_calculated > hud_ping_period->value)
{
// float period;
last_calculated = t;
// period = max(hud_ping_period->value, 0);
ping_avg = (int)(netinfo->ping.s_avg*1000 + 0.5);
ping_min = (int)(netinfo->ping.s_mn*1000 + 0.5);
ping_max = (int)(netinfo->ping.s_mx*1000 + 0.5);
ping_dev = netinfo->ping.ms_stddev;
pl = netinfo->loss.dropped*100;
clamp(ping_avg, 0, 999);
clamp(ping_min, 0, 999);
clamp(ping_max, 0, 999);
clamp(ping_dev, 0, 99.9);
clamp(pl, 0, 100);
}
buf[0] = 0;
// blink
if (hud_ping_blink->value) // add dot
strlcat (buf, (last_calculated + hud_ping_period->value/2 > cls.realtime) ? "^Ue08f" : " ", sizeof (buf));
// min ping
if (hud_ping_show_min->value)
strlcat (buf, va("%d^Ue00f", ping_min), sizeof (buf));
// ping
strlcat (buf, va("%d", ping_avg), sizeof (buf));
// max ping
if (hud_ping_show_max->value)
strlcat (buf, va("^Ue00f%d", ping_max), sizeof (buf));
// unit
strlcat (buf, " ms", sizeof (buf));
// standard deviation
if (hud_ping_show_dev->value)
strlcat (buf, va(" (%.1f)", ping_dev), sizeof (buf));
// pl
if (hud_ping_show_pl->value)
strlcat (buf, va(" ^Ue08f %d%%", pl), sizeof (buf));
// display that on screen
width = strlen(buf) * 8;
height = 8;
if (HUD_PrepareDraw(hud, width, height, &x, &y))
{
if (hud_ping_style->value)
{
Draw_Alt_String(x, y, buf);
}
else
{
Draw_String(x, y, buf);
}
}
}
static const char *SCR_HUD_ClockFormat(int format)
{
switch (format) {
case 1: return "%I:%M %p";
case 2: return "%I:%M:%S %p";
case 3: return "%H:%M";
default: case 0: return "%H:%M:%S";
}
}
//---------------------
//
// draw HUD clock
//
void SCR_HUD_DrawClock(hud_t *hud)
{
int width, height;
int x, y;
const char *t;
static cvar_t
*hud_clock_big = NULL,
*hud_clock_style,
*hud_clock_blink,
*hud_clock_scale,
*hud_clock_format;
if (hud_clock_big == NULL) // first time
{
hud_clock_big = HUD_FindVar(hud, "big");
hud_clock_style = HUD_FindVar(hud, "style");
hud_clock_blink = HUD_FindVar(hud, "blink");
hud_clock_scale = HUD_FindVar(hud, "scale");
hud_clock_format= HUD_FindVar(hud, "format");
}
t = SCR_GetTimeString(TIMETYPE_CLOCK, SCR_HUD_ClockFormat(hud_clock_format->ival));
width = SCR_GetClockStringWidth(t, hud_clock_big->ival, hud_clock_scale->value);
height = SCR_GetClockStringHeight(hud_clock_big->ival, hud_clock_scale->value);
if (HUD_PrepareDraw(hud, width, height, &x, &y))
{
if (hud_clock_big->value)
SCR_DrawBigClock(x, y, hud_clock_style->value, hud_clock_blink->value, hud_clock_scale->value, t);
else
SCR_DrawSmallClock(x, y, hud_clock_style->value, hud_clock_blink->value, hud_clock_scale->value, t);
}
}
//---------------------
//
// draw HUD notify
//
static void SCR_HUD_DrawNotify(hud_t* hud)
{
static cvar_t* hud_notify_rows = NULL;
static cvar_t* hud_notify_scale;
static cvar_t* hud_notify_time;
static cvar_t* hud_notify_cols;
int x;
int y;
int width;
int height;
if (hud_notify_rows == NULL) // First time.
{
hud_notify_rows = HUD_FindVar(hud, "rows");
hud_notify_cols = HUD_FindVar(hud, "cols");
hud_notify_scale = HUD_FindVar(hud, "scale");
hud_notify_time = HUD_FindVar(hud, "time");
}
height = hud_notify_rows->ival * 8 * hud_notify_scale->value;
width = 8 * hud_notify_cols->ival * hud_notify_scale->value;
if (HUD_PrepareDraw(hud, width, height, &x, &y))
{
cvarfuncs->SetFloat("con_notify_x", (float)x / vid.width);
cvarfuncs->SetFloat("con_notify_y", (float)y / vid.height);
cvarfuncs->SetFloat("con_notify_w", (float)width / vid.width);
cvarfuncs->SetFloat("con_numnotifylines",(int)(height/(8*hud_notify_scale->value) + 0.01));
cvarfuncs->SetFloat("con_notifytime", (float)hud_notify_time->ival);
cvarfuncs->SetFloat("con_textsize", 8.0 * hud_notify_scale->value);
// SCR_DrawNotify(x, y, hud_notify_scale->value, hud_notify_time->ival, hud_notify_rows->ival, hud_notify_cols->ival);
}
}
//---------------------
//
// draw HUD gameclock
//
void SCR_HUD_DrawGameClock(hud_t *hud)
{
int width, height;
int x, y;
int timetype;
const char *t;
static cvar_t
*hud_gameclock_big = NULL,
*hud_gameclock_style,
*hud_gameclock_blink,
*hud_gameclock_countdown,
*hud_gameclock_scale
// *hud_gameclock_offset
;
if (hud_gameclock_big == NULL) // first time
{
hud_gameclock_big = HUD_FindVar(hud, "big");
hud_gameclock_style = HUD_FindVar(hud, "style");
hud_gameclock_blink = HUD_FindVar(hud, "blink");
hud_gameclock_countdown = HUD_FindVar(hud, "countdown");
hud_gameclock_scale = HUD_FindVar(hud, "scale");
// hud_gameclock_offset = HUD_FindVar(hud, "offset");
// gameclockoffset = &hud_gameclock_offset->ival;
}
timetype = (hud_gameclock_countdown->value) ? TIMETYPE_GAMECLOCKINV : TIMETYPE_GAMECLOCK;
t = SCR_GetTimeString(timetype, NULL);
width = SCR_GetClockStringWidth(t, hud_gameclock_big->ival, hud_gameclock_scale->value);
height = SCR_GetClockStringHeight(hud_gameclock_big->ival, hud_gameclock_scale->value);
if (HUD_PrepareDraw(hud, width, height, &x, &y))
{
if (hud_gameclock_big->value)
SCR_DrawBigClock(x, y, hud_gameclock_style->value, hud_gameclock_blink->value, hud_gameclock_scale->value, t);
else
SCR_DrawSmallClock(x, y, hud_gameclock_style->value, hud_gameclock_blink->value, hud_gameclock_scale->value, t);
}
}
//---------------------
//
// draw HUD democlock
//
void SCR_HUD_DrawDemoClock(hud_t *hud)
{
int width = 0;
int height = 0;
int x = 0;
int y = 0;
const char *t;
static cvar_t
*hud_democlock_big = NULL,
*hud_democlock_style,
*hud_democlock_blink,
*hud_democlock_scale;
if (!cls.demoplayback || cls.mvdplayback == 2)
{
HUD_PrepareDraw(hud, width, height, &x, &y);
return;
}
if (hud_democlock_big == NULL) // first time
{
hud_democlock_big = HUD_FindVar(hud, "big");
hud_democlock_style = HUD_FindVar(hud, "style");
hud_democlock_blink = HUD_FindVar(hud, "blink");
hud_democlock_scale = HUD_FindVar(hud, "scale");
}
t = SCR_GetTimeString(TIMETYPE_DEMOCLOCK, NULL);
width = SCR_GetClockStringWidth(t, hud_democlock_big->ival, hud_democlock_scale->value);
height = SCR_GetClockStringHeight(hud_democlock_big->ival, hud_democlock_scale->value);
if (HUD_PrepareDraw(hud, width, height, &x, &y))
{
if (hud_democlock_big->value)
SCR_DrawBigClock(x, y, hud_democlock_style->value, hud_democlock_blink->value, hud_democlock_scale->value, t);
else
SCR_DrawSmallClock(x, y, hud_democlock_style->value, hud_democlock_blink->value, hud_democlock_scale->value, t);
}
}
//---------------------
//
// network statistics
//
static void SCR_NetStats(int x, int y, float period, plugnetinfo_t *netinfo)
{
char line[128];
double t;
// static data
static double last_calculated;
static int ping_min, ping_max, ping_avg;
static float ping_dev;
static float f_min, f_max, f_avg;
static int lost_lost, lost_delta, lost_rate, lost_total;
static int size_all, size_in, size_out, pps_in, pps_out;
static int bandwidth_all, bandwidth_in, bandwidth_out;
static int with_delta;
if (cls.state != ca_active)
return;
if (period < 0)
period = 0;
t = cls.realtime;
if (t - last_calculated > period)
{
// recalculate
last_calculated = t;
ping_avg = (int)(netinfo->ping.s_avg*1000 + 0.5);
ping_min = (int)(netinfo->ping.s_mn*1000 + 0.5);
ping_max = (int)(netinfo->ping.s_mx*1000 + 0.5);
ping_dev = netinfo->ping.ms_stddev;
clamp(ping_avg, 0, 999);
clamp(ping_min, 0, 999);
clamp(ping_max, 0, 999);
clamp(ping_dev, 0, 99.9);
f_avg = (int)(netinfo->ping.fr_avg+0.5);
f_min = netinfo->ping.fr_mn;
f_max = netinfo->ping.fr_mx;
clamp(f_avg, 0, 99);
clamp(f_min, 0, 99);
clamp(f_max, 0, 99);
lost_lost = (int)(netinfo->loss.dropped*100 + 0.5);
lost_rate = (int)(netinfo->loss.choked*100 + 0.5);
lost_delta = (int)(netinfo->loss.invalid*100 + 0.5);
lost_total = (int)((netinfo->loss.dropped + netinfo->loss.choked + netinfo->loss.invalid)*100 + 0.5);
clamp(lost_lost, 0, 100);
clamp(lost_rate, 0, 100);
clamp(lost_delta, 0, 100);
clamp(lost_total, 0, 100);
pps_in = netinfo->clrate.in_pps;
pps_out = netinfo->clrate.out_pps;
//per packet sizes
size_in = (int)(netinfo->clrate.in_bps/netinfo->clrate.in_pps + 0.5);
size_out = (int)(netinfo->clrate.out_bps/netinfo->clrate.out_pps + 0.5);
size_all = (int)(netinfo->clrate.in_bps/netinfo->clrate.in_pps + netinfo->clrate.out_bps/netinfo->clrate.out_pps + 0.5);
//overall rate
bandwidth_in = (int)(netinfo->clrate.in_bps + 0.5);
bandwidth_out = (int)(netinfo->clrate.out_bps + 0.5);
bandwidth_all = (int)(netinfo->clrate.in_bps + netinfo->clrate.out_bps + 0.5);
clamp(size_in, 0, 999);
clamp(size_out, 0, 999);
clamp(size_all, 0, 999);
clamp(bandwidth_in, 0, 99999);
clamp(bandwidth_out, 0, 99999);
clamp(bandwidth_all, 0, 99999);
with_delta = !cvarfuncs->GetFloat("cl_nodelta");
}
Draw_Alt_String(x+36, y, "latency");
y+=12;
snprintf (line, sizeof (line), "min %4f %3d ms", f_min, ping_min);
Draw_String(x, y, line);
y+=8;
snprintf(line, sizeof (line), "avg %4f %3d ms", f_avg, ping_avg);
Draw_String(x, y, line);
y+=8;
snprintf(line, sizeof (line), "max %4f %3d ms", f_max, ping_max);
Draw_String(x, y, line);
y+=8;
snprintf(line, sizeof (line), "dev %f ms", ping_dev);
Draw_String(x, y, line);
y+=12;
Draw_Alt_String(x+20, y, "packet loss");
y+=12;
snprintf(line, sizeof (line), "lost %3d %%", lost_lost);
Draw_String(x, y, line);
y+=8;
snprintf(line, sizeof (line), "rate cut %3d %%", lost_rate);
Draw_String(x, y, line);
y+=8;
if (with_delta)
snprintf(line, sizeof (line), "bad delta %3d %%", lost_delta);
else
strlcpy (line, "no delta compr", sizeof (line));
Draw_String(x, y, line);
y+=8;
snprintf(line, sizeof (line), "total %3d %%", lost_total);
Draw_String(x, y, line);
y+=12;
Draw_Alt_String(x+4, y, "packet size/BPS");
y+=12;
snprintf(line, sizeof (line), "out %3d %5d %d", size_out, bandwidth_out, pps_out);
Draw_String(x, y, line);
y+=8;
snprintf(line, sizeof (line), "in %3d %5d %3d", size_in, bandwidth_in, pps_in);
Draw_String(x, y, line);
y+=8;
snprintf(line, sizeof (line), "total %3d %5d %3d", size_all, bandwidth_all, pps_in+pps_out);
Draw_String(x, y, line);
y+=8;
}
static void SCR_HUD_DrawNetStats(hud_t *hud)
{
int width, height;
int x, y;
plugnetinfo_t *netinfo = GetNetworkInfo();
static cvar_t *hud_net_period = NULL;
if (hud_net_period == NULL) // first time
{
hud_net_period = HUD_FindVar(hud, "period");
}
width = 16*8 ;
height = 12 + 8 + 8 + 8 + 8 + 16 + 8 + 8 + 8 + 8 + 16 + 8 + 8 + 8;
if (!netinfo || netinfo->capturing==2)
HUD_PrepareDraw(hud, 0, 0, &x, &y);
else if (HUD_PrepareDraw(hud, width, height, &x, &y))
{
SCR_NetStats(x, y, hud_net_period->value, netinfo);
}
}
#define SPEED_GREEN "52"
#define SPEED_BROWN_RED "100"
#define SPEED_DARK_RED "72"
#define SPEED_BLUE "216"
#define SPEED_RED "229"
#define SPEED_STOPPED SPEED_GREEN
#define SPEED_NORMAL SPEED_BROWN_RED
#define SPEED_FAST SPEED_DARK_RED
#define SPEED_FASTEST SPEED_BLUE
#define SPEED_INSANE SPEED_RED
//---------------------
//
// speed-o-meter
//
#define SPEED_TAG_LENGTH 2
#define SPEED_OUTLINE_SPACING SPEED_TAG_LENGTH
#define SPEED_FILL_SPACING SPEED_OUTLINE_SPACING + 1
#define SPEED_WHITE 10
#define SPEED_TEXT_ONLY 1
#define SPEED_TEXT_ALIGN_NONE 0
#define SPEED_TEXT_ALIGN_CLOSE 1
#define SPEED_TEXT_ALIGN_CENTER 2
#define SPEED_TEXT_ALIGN_FAR 3
// FIXME: hud-only now, can/should be moved
void SCR_DrawHUDSpeed (
int x, int y, int width, int height,
int type,
float tick_spacing,
float opacity,
int vertical,
int vertical_text,
int text_align,
byte color_stopped,
byte color_normal,
byte color_fast,
byte color_fastest,
byte color_insane,
int style,
float scale
)
{
byte color_offset;
byte color1, color2;
int player_speed;
vec_t *velocity;
if (scr_con_current == vid.height) {
return; // console is full screen
}
// Get the velocity.
// if (cl.players[cl.playernum].spectator && Cam_TrackNum() >= 0) {
// velocity = cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK].playerstate[Cam_TrackNum()].velocity;
// }
// else {
velocity = cl.simvel;
// }
// Calculate the speed
if (!type)
{
// Based on XY.
player_speed = sqrt(velocity[0]*velocity[0]
+ velocity[1]*velocity[1]);
}
else
{
// Based on XYZ.
player_speed = sqrt(velocity[0]*velocity[0]
+ velocity[1]*velocity[1]
+ velocity[2]*velocity[2]);
}
// Calculate the color offset for the "background color".
if (vertical) {
color_offset = height * (player_speed % 500) / 500;
}
else {
color_offset = width * (player_speed % 500) / 500;
}
// Set the color based on the speed.
switch (player_speed / 500)
{
case 0:
color1 = color_stopped;
color2 = color_normal;
break;
case 1:
color1 = color_normal;
color2 = color_fast;
break;
case 2:
color1 = color_fast;
color2 = color_fastest;
break;
default:
color1 = color_fastest;
color2 = color_insane;
break;
}
// Draw tag marks.
if (tick_spacing > 0.0 && style != SPEED_TEXT_ONLY)
{
float f;
for(f = tick_spacing; f < 1.0; f += tick_spacing)
{
if(vertical)
{
// Left.
Draw_AlphaFill(x, // x
y + (int)(f * height), // y
SPEED_TAG_LENGTH, // Width
1, // Height
SPEED_WHITE, // Color
opacity); // Opacity
// Right.
Draw_AlphaFill(x + width - SPEED_TAG_LENGTH + 1,
y + (int)(f * height),
SPEED_TAG_LENGTH,
1,
SPEED_WHITE,
opacity);
}
else
{
// Above.
Draw_AlphaFill(x + (int)(f * width),
y,
1,
SPEED_TAG_LENGTH,
SPEED_WHITE,
opacity);
// Below.
Draw_AlphaFill(x + (int)(f * width),
y + height - SPEED_TAG_LENGTH + 1,
1,
SPEED_TAG_LENGTH,
SPEED_WHITE,
opacity);
}
}
}
//
// Draw outline.
//
if (style != SPEED_TEXT_ONLY)
{
if(vertical)
{
// Left.
Draw_AlphaFill(x + SPEED_OUTLINE_SPACING,
y,
1,
height,
SPEED_WHITE,
opacity);
// Right.
Draw_AlphaFill(x + width - SPEED_OUTLINE_SPACING,
y,
1,
height,
SPEED_WHITE,
opacity);
}
else
{
// Above.
Draw_AlphaFill(x,
y + SPEED_OUTLINE_SPACING,
width,
1,
SPEED_WHITE,
opacity);
// Below.
Draw_AlphaFill(x,
y + height - SPEED_OUTLINE_SPACING,
width,
1,
SPEED_WHITE,
opacity);
}
}
//
// Draw fill.
//
if (style != SPEED_TEXT_ONLY)
{
if(vertical)
{
// Draw the right color (slower).
Draw_AlphaFill (x + SPEED_FILL_SPACING,
y,
width - (2 * SPEED_FILL_SPACING),
height - color_offset,
color1,
opacity);
// Draw the left color (faster).
Draw_AlphaFill (x + SPEED_FILL_SPACING,
y + height - color_offset,
width - (2 * SPEED_FILL_SPACING),
color_offset,
color2,
opacity);
}
else
{
// Draw the right color (slower).
Draw_AlphaFill (x + color_offset,
y + SPEED_FILL_SPACING,
width - color_offset,
height - (2 * SPEED_FILL_SPACING),
color1,
opacity);
// Draw the left color (faster).
Draw_AlphaFill (x,
y + SPEED_FILL_SPACING,
color_offset,
height - (2 * SPEED_FILL_SPACING),
color2,
opacity);
}
}
// Draw the speed text.
if(vertical && vertical_text)
{
int i = 1;
int len = 0;
// Align the text accordingly.
switch(text_align)
{
case SPEED_TEXT_ALIGN_NONE: return;
case SPEED_TEXT_ALIGN_FAR: y = y + height - 4*8; break;
case SPEED_TEXT_ALIGN_CENTER: y = Q_rint(y + height/2.0 - 16); break;
case SPEED_TEXT_ALIGN_CLOSE:
default: break;
}
len = strlen(va("%d", player_speed));
// 10^len
while(len > 0)
{
i *= 10;
len--;
}
// Write one number per row.
for(; i > 1; i /= 10)
{
int next;
next = (i/10);
// Really make sure we don't try division by zero :)
if(next <= 0)
{
break;
}
Draw_SString(Q_rint(x + width/2.0 - 4 * scale), y, va("%1d", (player_speed % i) / next), scale);
y += 8;
}
}
else
{
// Align the text accordingly.
switch(text_align)
{
case SPEED_TEXT_ALIGN_FAR:
x = x + width - 4 * 8 * scale;
break;
case SPEED_TEXT_ALIGN_CENTER:
x = Q_rint(x + width / 2.0 - 2 * 8 * scale);
break;
case SPEED_TEXT_ALIGN_CLOSE:
case SPEED_TEXT_ALIGN_NONE:
default:
break;
}
Draw_SString(x, Q_rint(y + height/2.0 - 4 * scale), va("%4d", player_speed), scale);
}
}
static void SCR_HUD_DrawSpeed(hud_t *hud)
{
int width, height;
int x, y;
static cvar_t *hud_speed_xyz = NULL,
*hud_speed_width,
*hud_speed_height,
*hud_speed_tick_spacing,
*hud_speed_opacity,
*hud_speed_color_stopped,
*hud_speed_color_normal,
*hud_speed_color_fast,
*hud_speed_color_fastest,
*hud_speed_color_insane,
*hud_speed_vertical,
*hud_speed_vertical_text,
*hud_speed_text_align,
*hud_speed_style,
*hud_speed_scale;
if (hud_speed_xyz == NULL) // first time
{
hud_speed_xyz = HUD_FindVar(hud, "xyz");
hud_speed_width = HUD_FindVar(hud, "width");
hud_speed_height = HUD_FindVar(hud, "height");
hud_speed_tick_spacing = HUD_FindVar(hud, "tick_spacing");
hud_speed_opacity = HUD_FindVar(hud, "opacity");
hud_speed_color_stopped = HUD_FindVar(hud, "color_stopped");
hud_speed_color_normal = HUD_FindVar(hud, "color_normal");
hud_speed_color_fast = HUD_FindVar(hud, "color_fast");
hud_speed_color_fastest = HUD_FindVar(hud, "color_fastest");
hud_speed_color_insane = HUD_FindVar(hud, "color_insane");
hud_speed_vertical = HUD_FindVar(hud, "vertical");
hud_speed_vertical_text = HUD_FindVar(hud, "vertical_text");
hud_speed_text_align = HUD_FindVar(hud, "text_align");
hud_speed_style = HUD_FindVar(hud, "style");
hud_speed_scale = HUD_FindVar(hud, "scale");
}
width = max(0, hud_speed_width->value);
height = max(0, hud_speed_height->value);
if (HUD_PrepareDraw(hud, width, height, &x, &y))
{
SCR_DrawHUDSpeed(x, y, width, height,
hud_speed_xyz->value,
hud_speed_tick_spacing->value,
hud_speed_opacity->value,
hud_speed_vertical->value,
hud_speed_vertical_text->value,
hud_speed_text_align->value,
hud_speed_color_stopped->value,
hud_speed_color_normal->value,
hud_speed_color_fast->value,
hud_speed_color_fastest->value,
hud_speed_color_insane->value,
hud_speed_style->ival,
hud_speed_scale->value);
}
}
#define HUD_SPEED2_ORIENTATION_UP 0
#define HUD_SPEED2_ORIENTATION_DOWN 1
#define HUD_SPEED2_ORIENTATION_RIGHT 2
#define HUD_SPEED2_ORIENTATION_LEFT 3
void SCR_HUD_DrawSpeed2(hud_t *hud)
{
int width, height;
int x, y;
static cvar_t *hud_speed2_xyz = NULL,
// *hud_speed2_opacity,
*hud_speed2_color_stopped,
*hud_speed2_color_normal,
*hud_speed2_color_fast,
*hud_speed2_color_fastest,
*hud_speed2_color_insane,
*hud_speed2_radius,
*hud_speed2_wrapspeed,
*hud_speed2_orientation;
if (hud_speed2_xyz == NULL) // first time
{
hud_speed2_xyz = HUD_FindVar(hud, "xyz");
// hud_speed2_opacity = HUD_FindVar(hud, "opacity");
hud_speed2_color_stopped = HUD_FindVar(hud, "color_stopped");
hud_speed2_color_normal = HUD_FindVar(hud, "color_normal");
hud_speed2_color_fast = HUD_FindVar(hud, "color_fast");
hud_speed2_color_fastest = HUD_FindVar(hud, "color_fastest");
hud_speed2_color_insane = HUD_FindVar(hud, "color_insane");
hud_speed2_radius = HUD_FindVar(hud, "radius");
hud_speed2_wrapspeed = HUD_FindVar(hud, "wrapspeed");
hud_speed2_orientation = HUD_FindVar(hud, "orientation");
}
// Calculate the height and width based on the radius.
switch((int)hud_speed2_orientation->value)
{
case HUD_SPEED2_ORIENTATION_LEFT :
case HUD_SPEED2_ORIENTATION_RIGHT :
height = max(0, 2*hud_speed2_radius->value);
width = max(0, (hud_speed2_radius->value));
break;
case HUD_SPEED2_ORIENTATION_DOWN :
case HUD_SPEED2_ORIENTATION_UP :
default :
// Include the height of the speed text in the height.
height = max(0, (hud_speed2_radius->value));
width = max(0, 2*hud_speed2_radius->value);
break;
}
if (HUD_PrepareDraw(hud, width, height, &x, &y))
{
int player_speed;
int arc_length;
int color1, color2;
int text_x = x;
int text_y = y;
vec_t *velocity;
// Start and end points for the needle
int needle_start_x = 0;
int needle_start_y = 0;
int needle_end_x = 0;
int needle_end_y = 0;
// The length of the arc between the zero point
// and where the needle is pointing at.
int needle_offset = 0;
// The angle between the zero point and the position
// that the needle is drawn on.
float needle_angle = 0.0;
// The angle where to start drawing the half circle and where to end.
// This depends on the orientation of the circle (left, right, up, down).
float circle_startangle = 0.0;
float circle_endangle = 0.0;
// Avoid divison by zero.
if(hud_speed2_radius->value <= 0)
{
return;
}
// Get the velocity.
#ifdef HAXX
if (cl.players[cl.playernum].spectator && Cam_TrackNum() >= 0)
{
velocity = cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK].playerstate[Cam_TrackNum()].velocity;
}
else
#endif
{
velocity = cl.simvel;
}
// Calculate the speed
if (!hud_speed2_xyz->value)
{
// Based on XY.
player_speed = sqrt(velocity[0]*velocity[0]
+ velocity[1]*velocity[1]);
}
else
{
// Based on XYZ.
player_speed = sqrt(velocity[0]*velocity[0]
+ velocity[1]*velocity[1]
+ velocity[2]*velocity[2]);
}
// Set the color based on the wrap speed.
switch ((int)(player_speed / hud_speed2_wrapspeed->value))
{
case 0:
color1 = hud_speed2_color_stopped->ival;
color2 = hud_speed2_color_normal->ival;
break;
case 1:
color1 = hud_speed2_color_normal->ival;
color2 = hud_speed2_color_fast->ival;
break;
case 2:
color1 = hud_speed2_color_fast->ival;
color2 = hud_speed2_color_fastest->ival;
break;
default:
color1 = hud_speed2_color_fastest->ival;
color2 = hud_speed2_color_insane->ival;
break;
}
// Set some properties how to draw the half circle, needle and text
// based on the orientation of the hud item.
switch((int)hud_speed2_orientation->value)
{
case HUD_SPEED2_ORIENTATION_LEFT :
{
x += width;
y += height / 2;
circle_startangle = M_PI / 2.0;
circle_endangle = (3*M_PI) / 2.0;
text_x = x - 32;
text_y = y - 4;
break;
}
case HUD_SPEED2_ORIENTATION_RIGHT :
{
y += height / 2;
circle_startangle = (3*M_PI) / 2.0;
circle_endangle = (5*M_PI) / 2.0;
needle_end_y = y + hud_speed2_radius->value * sin (needle_angle);
text_x = x;
text_y = y - 4;
break;
}
case HUD_SPEED2_ORIENTATION_DOWN :
{
x += width / 2;
circle_startangle = M_PI;
circle_endangle = 2*M_PI;
needle_end_y = y + hud_speed2_radius->value * sin (needle_angle);
text_x = x - 16;
text_y = y;
break;
}
case HUD_SPEED2_ORIENTATION_UP :
default :
{
x += width / 2;
y += height;
circle_startangle = 0;
circle_endangle = M_PI;
needle_end_y = y - hud_speed2_radius->value * sin (needle_angle);
text_x = x - 16;
text_y = y - 8;
break;
}
}
//
// Calculate the offsets and angles.
//
{
// Calculate the arc length of the half circle background.
arc_length = fabs((circle_endangle - circle_startangle) * hud_speed2_radius->value);
// Calculate the angle where the speed needle should point.
needle_offset = arc_length * (player_speed % Q_rint(hud_speed2_wrapspeed->value)) / Q_rint(hud_speed2_wrapspeed->value);
needle_angle = needle_offset / hud_speed2_radius->value;
// Draw from the center of the half circle.
needle_start_x = x;
needle_start_y = y;
}
// Set the needle end point depending on the orientation of the hud item.
switch((int)hud_speed2_orientation->value)
{
case HUD_SPEED2_ORIENTATION_LEFT :
{
needle_end_x = x - hud_speed2_radius->value * sin (needle_angle);
needle_end_y = y + hud_speed2_radius->value * cos (needle_angle);
break;
}
case HUD_SPEED2_ORIENTATION_RIGHT :
{
needle_end_x = x + hud_speed2_radius->value * sin (needle_angle);
needle_end_y = y - hud_speed2_radius->value * cos (needle_angle);
break;
}
case HUD_SPEED2_ORIENTATION_DOWN :
{
needle_end_x = x + hud_speed2_radius->value * cos (needle_angle);
needle_end_y = y + hud_speed2_radius->value * sin (needle_angle);
break;
}
case HUD_SPEED2_ORIENTATION_UP :
default :
{
needle_end_x = x - hud_speed2_radius->value * cos (needle_angle);
needle_end_y = y - hud_speed2_radius->value * sin (needle_angle);
break;
}
}
#ifdef HAXX
// Draw the speed-o-meter background.
Draw_AlphaPieSlice (x, y, // Position
hud_speed2_radius->value, // Radius
circle_startangle, // Start angle
circle_endangle - needle_angle, // End angle
1, // Thickness
true, // Fill
color1, // Color
hud_speed2_opacity->value); // Opacity
// Draw a pie slice that shows the "color" of the speed.
Draw_AlphaPieSlice (x, y, // Position
hud_speed2_radius->value, // Radius
circle_endangle - needle_angle, // Start angle
circle_endangle, // End angle
1, // Thickness
true, // Fill
color2, // Color
hud_speed2_opacity->value); // Opacity
// Draw the "needle attachment" circle.
Draw_AlphaCircle (x, y, 2.0, 1, true, 15, hud_speed2_opacity->value);
// Draw the speed needle.
Draw_AlphaLineRGB (needle_start_x, needle_start_y, needle_end_x, needle_end_y, 1, RGBA_TO_COLOR(250, 250, 250, 255 * hud_speed2_opacity->value));
#else
(void)color1;
(void)color2;
(void)needle_start_x;
(void)needle_start_y;
(void)needle_end_x;
(void)needle_end_y;
#endif
// Draw the speed.
Draw_String (text_x, text_y, va("%d", player_speed));
}
}
// =======================================================
//
// s t a t u s b a r e l e m e n t s
//
//
// -----------
// gunz
//
void SCR_HUD_DrawGunByNum (hud_t *hud, int num, float scale, int style, int wide)
{
int i = num - 2;
int width, height;
int x, y;
char *tmp;
scale = max(scale, 0.01);
switch (style)
{
case 3: // opposite colors of case 1
case 1: // text, gold inactive, white active
width = 16 * scale;
height = 8 * scale;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
if ( HUD_Stats(STAT_ITEMS) & (IT_SHOTGUN<<i) )
{
switch (num)
{
case 2: tmp = "sg"; break;
case 3: tmp = "bs"; break;
case 4: tmp = "ng"; break;
case 5: tmp = "sn"; break;
case 6: tmp = "gl"; break;
case 7: tmp = "rl"; break;
case 8: tmp = "lg"; break;
default: tmp = "";
}
if ( ((HUD_Stats(STAT_ACTIVEWEAPON) == (IT_SHOTGUN<<i)) && (style==1)) ||
((HUD_Stats(STAT_ACTIVEWEAPON) != (IT_SHOTGUN<<i)) && (style==3))
)
Draw_SString(x, y, tmp, scale);
else
Draw_SAlt_String(x, y, tmp, scale);
}
break;
case 4: // opposite colors of case 2
case 2: // numbers, gold inactive, white active
width = 8 * scale;
height = 8 * scale;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
if ( HUD_Stats(STAT_ITEMS) & (IT_SHOTGUN<<i) )
{
if ( HUD_Stats(STAT_ACTIVEWEAPON) == (IT_SHOTGUN<<i) )
num += '0' + (style == 4 ? 128 : 0);
else
num += '0' + (style == 4 ? 0 : 128);
Draw_SCharacter(x, y, num, scale);
}
break;
case 5: // COLOR active, gold inactive
case 7: // COLOR active, white inactive
case 6: // white active, COLOR inactive
case 8: // gold active, COLOR inactive
width = 16 * scale;
height = 8 * scale;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
if ( HUD_Stats(STAT_ITEMS) & (IT_SHOTGUN<<i) ) {
if ( HUD_Stats(STAT_ACTIVEWEAPON) == (IT_SHOTGUN<<i) ) {
if ((style==5) || (style==7)) { // strip {}
char *weap_str = TP_ItemName((IT_SHOTGUN<<i));
char weap_white_stripped[32];
Util_SkipChars(weap_str, "{}", weap_white_stripped, 32);
Draw_SString(x, y, weap_white_stripped, scale);
}
else { //Strip both &cRGB and {}
char inactive_weapon_buf[16];
char inactive_weapon_buf_nowhite[16];
Util_SkipEZColors(inactive_weapon_buf, TP_ItemName(IT_SHOTGUN<<i), sizeof(inactive_weapon_buf));
Util_SkipChars(inactive_weapon_buf, "{}", inactive_weapon_buf_nowhite, sizeof(inactive_weapon_buf_nowhite));
if (style==8) // gold active
Draw_SAlt_String(x, y, inactive_weapon_buf_nowhite, scale);
else if (style==6) // white active
Draw_SString(x, y, inactive_weapon_buf_nowhite, scale);
}
}
else {
if ((style==5) || (style==7)) { //Strip both &cRGB and {}
char inactive_weapon_buf[16];
char inactive_weapon_buf_nowhite[16];
Util_SkipEZColors(inactive_weapon_buf, TP_ItemName(IT_SHOTGUN<<i), sizeof(inactive_weapon_buf));
Util_SkipChars(inactive_weapon_buf, "{}", inactive_weapon_buf_nowhite, sizeof(inactive_weapon_buf_nowhite));
if (style==5) // gold inactive
Draw_SAlt_String(x, y, inactive_weapon_buf_nowhite, scale);
else if (style==7) // white inactive
Draw_SString(x, y, inactive_weapon_buf_nowhite, scale);
}
else if ((style==6) || (style==8)) { // strip only {}
char *weap_str = TP_ItemName((IT_SHOTGUN<<i));
char weap_white_stripped[32];
Util_SkipChars(weap_str, "{}", weap_white_stripped, 32);
Draw_SString(x, y, weap_white_stripped, scale);
}
}
}
break;
default: // classic - pictures
width = scale * (wide ? 48 : 24);
height = scale * 16;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
if ( HUD_Stats(STAT_ITEMS) & (IT_SHOTGUN<<i) )
{
float time;
int flashon;
time = cl.item_gettime[i];
flashon = (int)((cl.time - time)*10);
if (flashon < 0)
flashon = 0;
if (flashon >= 10)
{
if ( HUD_Stats(STAT_ACTIVEWEAPON) == (IT_SHOTGUN<<i) )
flashon = 1;
else
flashon = 0;
}
else
flashon = (flashon%5) + 2;
if (wide || num != 8)
Draw_SPic (x, y, sb_weapons[flashon][i], scale);
else
Draw_SSubPic (x, y, sb_weapons[flashon][i], 0, 0, 24, 16, scale);
}
break;
}
}
void SCR_HUD_DrawGun2 (hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time callse
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawGunByNum (hud, 2, scale->value, style->value, 0);
}
void SCR_HUD_DrawGun3 (hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawGunByNum (hud, 3, scale->value, style->value, 0);
}
void SCR_HUD_DrawGun4 (hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawGunByNum (hud, 4, scale->value, style->value, 0);
}
void SCR_HUD_DrawGun5 (hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawGunByNum (hud, 5, scale->value, style->value, 0);
}
void SCR_HUD_DrawGun6 (hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawGunByNum (hud, 6, scale->value, style->value, 0);
}
void SCR_HUD_DrawGun7 (hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawGunByNum (hud, 7, scale->value, style->value, 0);
}
void SCR_HUD_DrawGun8 (hud_t *hud)
{
static cvar_t *scale = NULL, *style, *wide;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
wide = HUD_FindVar(hud, "wide");
}
SCR_HUD_DrawGunByNum (hud, 8, scale->value, style->value, wide->value);
}
void SCR_HUD_DrawGunCurrent (hud_t *hud)
{
int gun;
static cvar_t *scale = NULL, *style, *wide;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
wide = HUD_FindVar(hud, "wide");
}
if (ShowPreselectedWeap()) {
// using weapon pre-selection so show info for current best pre-selected weapon
gun = IN_BestWeapon();
if (gun < 2) {
return;
}
} else {
// not using weapon pre-selection or player is dead so show current selected weapon
switch (HUD_Stats(STAT_ACTIVEWEAPON))
{
case IT_SHOTGUN << 0: gun = 2; break;
case IT_SHOTGUN << 1: gun = 3; break;
case IT_SHOTGUN << 2: gun = 4; break;
case IT_SHOTGUN << 3: gun = 5; break;
case IT_SHOTGUN << 4: gun = 6; break;
case IT_SHOTGUN << 5: gun = 7; break;
case IT_SHOTGUN << 6: gun = 8; break;
default: return;
}
}
SCR_HUD_DrawGunByNum (hud, gun, scale->value, style->value, wide->value);
}
// ----------------
// powerzz
//
void SCR_HUD_DrawPowerup(hud_t *hud, int num, float scale, int style)
{
int x, y, width, height;
int c;
scale = max(scale, 0.01);
switch (style)
{
case 1: // letter
width = height = 8 * scale;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
if (HUD_Stats(STAT_ITEMS) & (1<<(17+num)))
{
switch (num)
{
case 0: c = '1'; break;
case 1: c = '2'; break;
case 2: c = 'r'; break;
case 3: c = 'p'; break;
case 4: c = 's'; break;
case 5: c = 'q'; break;
default: c = '?';
}
Draw_SCharacter(x, y, c, scale);
}
break;
default: // classic - pics
width = height = scale * 16;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
if (HUD_Stats(STAT_ITEMS) & (1<<(17+num)))
Draw_SPic (x, y, sb_items[num], scale);
break;
}
}
void SCR_HUD_DrawKey1(hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawPowerup(hud, 0, scale->value, style->value);
}
void SCR_HUD_DrawKey2(hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawPowerup(hud, 1, scale->value, style->value);
}
void SCR_HUD_DrawRing(hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawPowerup(hud, 2, scale->value, style->value);
}
void SCR_HUD_DrawPent(hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawPowerup(hud, 3, scale->value, style->value);
}
void SCR_HUD_DrawSuit(hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawPowerup(hud, 4, scale->value, style->value);
}
void SCR_HUD_DrawQuad(hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawPowerup(hud, 5, scale->value, style->value);
}
// -----------
// sigils
//
void SCR_HUD_DrawSigil(hud_t *hud, int num, float scale, int style)
{
int x, y;
scale = max(scale, 0.01);
switch (style)
{
case 1: // sigil number
if (!HUD_PrepareDraw(hud, 8*scale, 8*scale, &x, &y))
return;
if (HUD_Stats(STAT_ITEMS) & (1<<(28+num)))
Draw_SCharacter(x, y, num + '0', scale);
break;
default: // classic - picture
if (!HUD_PrepareDraw(hud, 8*scale, 16*scale, &x, &y))
return;
if (HUD_Stats(STAT_ITEMS) & (1<<(28+num)))
Draw_SPic(x, y, sb_sigil[num], scale);
break;
}
}
void SCR_HUD_DrawSigil1(hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawSigil(hud, 0, scale->value, style->value);
}
void SCR_HUD_DrawSigil2(hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawSigil(hud, 1, scale->value, style->value);
}
void SCR_HUD_DrawSigil3(hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawSigil(hud, 2, scale->value, style->value);
}
void SCR_HUD_DrawSigil4(hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawSigil(hud, 3, scale->value, style->value);
}
// icons - active ammo, armor, face etc..
void SCR_HUD_DrawAmmoIcon(hud_t *hud, int num, float scale, int style)
{
int x, y, width, height;
scale = max(scale, 0.01);
width = height = (style ? 8 : 24) * scale;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
if (style)
{
switch (num)
{
case 1: Draw_SAlt_String(x, y, "s", scale); break;
case 2: Draw_SAlt_String(x, y, "n", scale); break;
case 3: Draw_SAlt_String(x, y, "r", scale); break;
case 4: Draw_SAlt_String(x, y, "c", scale); break;
}
}
else
{
Draw_SPic (x, y, sb_ammo[num-1], scale);
}
}
void SCR_HUD_DrawAmmoIconCurrent (hud_t *hud)
{
int num;
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
if (ShowPreselectedWeap()) {
// using weapon pre-selection so show info for current best pre-selected weapon ammo
if (!(num = State_AmmoNumForWeapon(IN_BestWeapon())))
return;
} else {
// not using weapon pre-selection or player is dead so show current selected ammo
if (HUD_Stats(STAT_ITEMS) & IT_SHELLS)
num = 1;
else if (HUD_Stats(STAT_ITEMS) & IT_NAILS)
num = 2;
else if (HUD_Stats(STAT_ITEMS) & IT_ROCKETS)
num = 3;
else if (HUD_Stats(STAT_ITEMS) & IT_CELLS)
num = 4;
else if (TP_TeamFortressEngineerSpanner())
num = 4;
else
return;
}
SCR_HUD_DrawAmmoIcon(hud, num, scale->value, style->value);
}
void SCR_HUD_DrawAmmoIcon1 (hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawAmmoIcon(hud, 1, scale->value, style->value);
}
void SCR_HUD_DrawAmmoIcon2 (hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawAmmoIcon(hud, 2, scale->value, style->value);
}
void SCR_HUD_DrawAmmoIcon3 (hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawAmmoIcon(hud, 3, scale->value, style->value);
}
void SCR_HUD_DrawAmmoIcon4 (hud_t *hud)
{
static cvar_t *scale = NULL, *style;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
}
SCR_HUD_DrawAmmoIcon(hud, 4, scale->value, style->value);
}
void SCR_HUD_DrawArmorIcon(hud_t *hud)
{
int x, y, width, height;
int style;
float scale;
static cvar_t *v_scale = NULL, *v_style;
if (v_scale == NULL) // first time called
{
v_scale = HUD_FindVar(hud, "scale");
v_style = HUD_FindVar(hud, "style");
}
scale = max(v_scale->value, 0.01);
style = (int)(v_style->value);
width = height = (style ? 8 : 24) * scale;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
if (style)
{
int c;
if (HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY)
c = '@';
else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3)
c = 'r';
else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR2)
c = 'y';
else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1)
c = 'g';
else return;
c += 128;
Draw_SCharacter(x, y, c, scale);
}
else
{
mpic_t *pic;
if (HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY)
pic = sb_disc;
else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3)
pic = sb_armor[2];
else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR2)
pic = sb_armor[1];
else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1)
pic = sb_armor[0];
else return;
Draw_SPic (x, y, pic, scale);
}
}
// face
void SCR_HUD_DrawFace(hud_t *hud)
{
int f, anim;
int x, y;
float scale;
static cvar_t *v_scale = NULL;
if (v_scale == NULL) // first time called
{
v_scale = HUD_FindVar(hud, "scale");
}
scale = max(v_scale->value, 0.01);
if (!HUD_PrepareDraw(hud, 24*scale, 24*scale, &x, &y))
return;
if ( (HUD_Stats(STAT_ITEMS) & (IT_INVISIBILITY | IT_INVULNERABILITY) )
== (IT_INVISIBILITY | IT_INVULNERABILITY) )
{
Draw_SPic (x, y, sb_face_invis_invuln, scale);
return;
}
if (HUD_Stats(STAT_ITEMS) & IT_QUAD)
{
Draw_SPic (x, y, sb_face_quad, scale);
return;
}
if (HUD_Stats(STAT_ITEMS) & IT_INVISIBILITY)
{
Draw_SPic (x, y, sb_face_invis, scale);
return;
}
if (HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY)
{
Draw_SPic (x, y, sb_face_invuln, scale);
return;
}
if (HUD_Stats(STAT_HEALTH) >= 100)
f = 4;
else
f = max(0, HUD_Stats(STAT_HEALTH)) / 20;
if (cl.time <= cl.faceanimtime)
anim = 1;
else
anim = 0;
Draw_SPic (x, y, sb_faces[f][anim], scale);
}
// status numbers
void SCR_HUD_DrawNum(hud_t *hud, int num, qbool low,
float scale, int style, int digits, char *s_align)
{
int i;
char buf[sizeof(int) * 3]; // each byte need <= 3 chars
int len;
int width, height, x, y;
int size;
int align;
clamp(num, -99999, 999999);
scale = max(scale, 0.01);
if (digits > 0)
clamp(digits, 1, 6);
else
digits = 0; // auto-resize
align = 2;
switch (tolower(s_align[0]))
{
default:
case 'l': // 'l'eft
align = 0; break;
case 'c': // 'c'enter
align = 1; break;
case 'r': // 'r'ight
align = 2; break;
}
snprintf(buf, sizeof (buf), "%d", (style == 2 || style == 3) ? num : abs(num));
if(digits)
{
switch (hud_digits_trim->ival)
{
case 0: // 10030 -> 999
len = strlen(buf);
if (len > digits)
{
char *p = buf;
if(num < 0)
*p++ = '-';
for (i = (num < 0) ? 1 : 0 ; i < digits; i++)
*p++ = '9';
*p = 0;
len = digits;
}
break;
default:
case 1: // 10030 -> 030
len = strlen(buf);
if(len > digits)
{
char *p = buf;
memmove(p, p + (len - digits), digits);
buf[digits] = '\0';
len = strlen(buf);
}
break;
case 2: // 10030 -> 100
buf[digits] = '\0';
len = strlen(buf);
break;
}
}
else
{
len = strlen(buf);
}
switch (style)
{
case 1:
case 3:
size = 8;
break;
case 0:
case 2:
default:
size = 24;
break;
}
if(digits)
width = digits * size;
else
width = size * len;
height = size;
switch (style)
{
case 1:
case 3:
if (!HUD_PrepareDraw(hud, scale*width, scale*height, &x, &y))
return;
switch (align)
{
case 0: break;
case 1: x += scale * (width - size * len) / 2; break;
case 2: x += scale * (width - size * len); break;
}
if (low)
Draw_SAlt_String(x, y, buf, scale);
else
Draw_SString(x, y, buf, scale);
break;
case 0:
case 2:
default:
if (!HUD_PrepareDraw(hud, scale*width, scale*height, &x, &y))
return;
switch (align)
{
case 0: break;
case 1: x += scale * (width - size * len) / 2; break;
case 2: x += scale * (width - size * len); break;
}
for (i = 0; i < len; i++)
{
if(buf[i] == '-' && style == 2)
{
Draw_STransPic (x, y, sb_nums[low ? 1 : 0][STAT_MINUS], scale);
x += 24 * scale;
}
else
{
Draw_STransPic (x, y, sb_nums[low ? 1 : 0][buf[i] - '0'], scale);
x += 24 * scale;
}
}
break;
}
}
void SCR_HUD_DrawHealth(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *digits, *align;
static int value;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
}
value = HUD_Stats(STAT_HEALTH);
SCR_HUD_DrawNum(hud, (value < 0 ? 0 : value), HUD_HealthLow(),
scale->value, style->value, digits->value, align->string);
}
void SCR_HUD_DrawArmor(hud_t *hud)
{
int level;
qbool low;
static cvar_t *scale = NULL, *style, *digits, *align, *pent_666;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
pent_666 = HUD_FindVar(hud, "pent_666"); // Show 666 or armor value when carrying pentagram
}
if (HUD_Stats(STAT_HEALTH) > 0)
{
if ((HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY) && pent_666->ival)
{
level = 666;
low = true;
}
else
{
level = HUD_Stats(STAT_ARMOR);
low = HUD_ArmorLow();
}
}
else
{
level = 0;
low = true;
}
SCR_HUD_DrawNum(hud, level, low,
scale->value, style->value, digits->value, align->string);
}
//void Draw_AMFStatLoss (int stat, hud_t* hud);
static int vxdamagecount, vxdamagecount_time, vxdamagecount_oldhealth;
static int vxdamagecountarmour, vxdamagecountarmour_time, vxdamagecountarmour_oldhealth;
void Amf_Reset_DamageStats(void)
{
vxdamagecount = vxdamagecount_time = vxdamagecount_oldhealth = 0;
vxdamagecountarmour = vxdamagecountarmour_time = vxdamagecountarmour_oldhealth = 0;
}
void Draw_AMFStatLoss (int stat, hud_t* hud) {
//fixme: should reset these on pov change
int * vxdmgcnt, * vxdmgcnt_t, * vxdmgcnt_o;
float alpha;
int elem;
if (stat == STAT_HEALTH) {
vxdmgcnt = &vxdamagecount;
vxdmgcnt_t = &vxdamagecount_time;
vxdmgcnt_o = &vxdamagecount_oldhealth;
elem = 0;
} else {
vxdmgcnt = &vxdamagecountarmour;
vxdmgcnt_t = &vxdamagecountarmour_time;
vxdmgcnt_o = &vxdamagecountarmour_oldhealth;
elem = 1;
}
//VULT STAT LOSS
//Pretty self explanitory, I just thought it would be a nice feature to go with my "what the hell is going on?" theme
//and obscure even more of the screen
if (cl.stats[stat] < (*vxdmgcnt_o - 1))
{
if (*vxdmgcnt_t > cl.time) //add to damage
*vxdmgcnt = *vxdmgcnt + (*vxdmgcnt_o - cl.stats[stat]);
else
*vxdmgcnt = *vxdmgcnt_o - cl.stats[stat];
*vxdmgcnt_t = cl.time + 2 * (HUD_FindVar(hud, "duration")->value);
}
*vxdmgcnt_o = cl.stats[stat];
if (*vxdmgcnt_t > cl.time)
alpha = min(1, (*vxdmgcnt_t - cl.time));
else
alpha = 0;
drawfuncs->Colour4f(1,1,1,alpha);
{
static cvar_t *scale[2] = {NULL}, *style[2], *digits[2], *align[2];
if (scale[elem] == NULL) // first time called
{
scale[elem] = HUD_FindVar(hud, "scale");
style[elem] = HUD_FindVar(hud, "style");
digits[elem] = HUD_FindVar(hud, "digits");
align[elem] = HUD_FindVar(hud, "align");
}
SCR_HUD_DrawNum (hud, abs(*vxdmgcnt), 1,
scale[elem]->value, style[elem]->value, digits[elem]->ival, align[elem]->string);
}
drawfuncs->Colour4f(1,1,1,1);
}
static void SCR_HUD_DrawHealthDamage(hud_t *hud)
{
Draw_AMFStatLoss (STAT_HEALTH, hud);
if (HUD_Stats(STAT_HEALTH) <= 0)
{
Amf_Reset_DamageStats();
}
}
static void SCR_HUD_DrawArmorDamage(hud_t *hud)
{
Draw_AMFStatLoss (STAT_ARMOR, hud);
}
void SCR_HUD_DrawAmmo(hud_t *hud, int num,
float scale, int style, int digits, char *s_align)
{
int value, num_old;
qbool low;
num_old = num;
if (num < 1 || num > 4)
{ // draw 'current' ammo, which one is it?
if (ShowPreselectedWeap()) {
// using weapon pre-selection so show info for current best pre-selected weapon ammo
if (!(num = State_AmmoNumForWeapon(IN_BestWeapon())))
return;
} else {
// not using weapon pre-selection or player is dead so show current selected ammo
if (HUD_Stats(STAT_ITEMS) & IT_SHELLS)
num = 1;
else if (HUD_Stats(STAT_ITEMS) & IT_NAILS)
num = 2;
else if (HUD_Stats(STAT_ITEMS) & IT_ROCKETS)
num = 3;
else if (HUD_Stats(STAT_ITEMS) & IT_CELLS)
num = 4;
else if (TP_TeamFortressEngineerSpanner())
num = 4;
else
return;
}
}
low = HUD_AmmoLowByWeapon(num * 2);
if (num_old == 0 && (!ShowPreselectedWeap() || cl.standby)) {
// this check is here to display a feature from KTPRO/KTX where you can see received damage in prewar
// also we make sure this applies only to 'ammo' element
// weapon preselection must always use HUD_Stats()
value = cl.stats[STAT_AMMO];
} else {
value = HUD_Stats(STAT_SHELLS + num - 1);
}
if (style < 2)
{
// simply draw number
SCR_HUD_DrawNum(hud, value, low, scale, style, digits, s_align);
}
else
{
// else - draw classic ammo-count box with background
char buf[8];
int x, y;
scale = max(scale, 0.01);
if (!HUD_PrepareDraw(hud, 42*scale, 11*scale, &x, &y))
return;
snprintf (buf, sizeof (buf), "%3i", value);
Draw_SSubPic(x, y, sb_ibar, 3+((num-1)*48), 0, 42, 11, scale);
if (buf[0] != ' ') Draw_SCharacter (x + 7*scale, y, 18+buf[0]-'0', scale);
if (buf[1] != ' ') Draw_SCharacter (x + 15*scale, y, 18+buf[1]-'0', scale);
if (buf[2] != ' ') Draw_SCharacter (x + 23*scale, y, 18+buf[2]-'0', scale);
}
}
void SCR_HUD_DrawAmmoCurrent(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *digits, *align;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
}
SCR_HUD_DrawAmmo(hud, 0, scale->value, style->value, digits->value, align->string);
}
void SCR_HUD_DrawAmmo1(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *digits, *align;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
}
SCR_HUD_DrawAmmo(hud, 1, scale->value, style->value, digits->value, align->string);
}
void SCR_HUD_DrawAmmo2(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *digits, *align;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
}
SCR_HUD_DrawAmmo(hud, 2, scale->value, style->value, digits->value, align->string);
}
void SCR_HUD_DrawAmmo3(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *digits, *align;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
}
SCR_HUD_DrawAmmo(hud, 3, scale->value, style->value, digits->value, align->string);
}
void SCR_HUD_DrawAmmo4(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *digits, *align;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
}
SCR_HUD_DrawAmmo(hud, 4, scale->value, style->value, digits->value, align->string);
}
// Problem icon, Net
static void SCR_HUD_NetProblem (hud_t *hud) {
static cvar_t *scale = NULL;
int x, y;
extern qbool hud_editor;
plugnetinfo_t *netinfo = GetNetworkInfo();
float picwidth = 64;
float picheight = 64;
drawfuncs->ImageSize((intptr_t)sb_net, &picwidth, &picheight);
if(scale == NULL)
scale = HUD_FindVar(hud, "scale");
if (netinfo->loss.dropped < 1)
{
if (hud_editor)
HUD_PrepareDraw(hud, picwidth, picheight, &x, &y);
return;
}
if (!HUD_PrepareDraw(hud, picwidth, picheight, &x, &y))
return;
Draw_SPic (x, y, sb_net, scale->value);
}
// ============================================================================0
// Groups
// ============================================================================0
mpic_t *hud_pic_group1;
mpic_t *hud_pic_group2;
mpic_t *hud_pic_group3;
mpic_t *hud_pic_group4;
mpic_t *hud_pic_group5;
mpic_t *hud_pic_group6;
mpic_t *hud_pic_group7;
mpic_t *hud_pic_group8;
mpic_t *hud_pic_group9;
void SCR_HUD_DrawGroup(hud_t *hud, int width, int height, mpic_t *pic, int pic_scalemode, float pic_alpha)
{
#define HUD_GROUP_SCALEMODE_TILE 1
#define HUD_GROUP_SCALEMODE_STRETCH 2
#define HUD_GROUP_SCALEMODE_GROW 3
#define HUD_GROUP_SCALEMODE_CENTER 4
int x, y;
float picwidth = 64;
float picheight = 64;
if (pic && drawfuncs->ImageSize((intptr_t)pic, &picwidth, &picheight) <= 0)
{
pic = NULL;
picwidth = 64;
picheight = 64;
}
clamp(width, 1, 99999);
clamp(height, 1, 99999);
// Set it to this, because 1.0 will make the colors
// completly saturated, and no semi-transparency will show.
pic_alpha = (pic_alpha) >= 1.0 ? 0.99 : pic_alpha;
// Grow the group if necessary.
if (pic_scalemode == HUD_GROUP_SCALEMODE_GROW
&& pic != NULL && picheight > 0 && picwidth > 0)
{
width = max(picwidth, width);
height = max(picheight, height);
}
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
{
return;
}
// Draw the picture if it's set.
if (pic != NULL && picheight > 0)
{
int pw, ph;
if (pic_scalemode == HUD_GROUP_SCALEMODE_TILE)
{
// Tile.
int cx = 0, cy = 0;
while (cy < height)
{
while (cx < width)
{
pw = min(picwidth, width - cx);
ph = min(picheight, height - cy);
if (pw >= picwidth && ph >= picheight)
{
Draw_AlphaPic (x + cx , y + cy, pic, pic_alpha);
}
else
{
Draw_AlphaSubPic (x + cx, y + cy, pic, 0, 0, pw, ph, pic_alpha);
}
cx += picwidth;
}
cx = 0;
cy += picheight;
}
}
else if (pic_scalemode == HUD_GROUP_SCALEMODE_STRETCH)
{
// Stretch or shrink the picture to fit.
float scale_x = (float)width / picwidth;
float scale_y = (float)height / picheight;
Draw_SAlphaSubPic2 (x, y, pic, 0, 0, picwidth, picheight, scale_x, scale_y, pic_alpha);
}
else if (pic_scalemode == HUD_GROUP_SCALEMODE_CENTER)
{
// Center the picture in the group.
int pic_x = x + (width - picwidth) / 2;
int pic_y = y + (height - picheight) / 2;
int src_x = 0;
int src_y = 0;
if(x > pic_x)
{
src_x = x - pic_x;
pic_x = x;
}
if(y > pic_y)
{
src_y = y - pic_y;
pic_y = y;
}
Draw_AlphaSubPic (pic_x, pic_y, pic, src_x, src_y, min(width, picwidth), min(height, picheight), pic_alpha);
}
else
{
// Normal. Draw in the top left corner.
Draw_AlphaSubPic (x, y, pic, 0, 0, min(width, picwidth), min(height, picheight), pic_alpha);
}
}
}
void SCR_HUD_LoadGroupPic(cvar_t *var, mpic_t **hud_pic, char *oldval)
{
char *newpic = var->string;
#define HUD_GROUP_PIC_BASEPATH "gfx/%s"
mpic_t *temp_pic = NULL;
char pic_path[MAX_QPATH];
if (!hud_pic)
{
Com_Printf ("Couldn't load picture %s for hud group. HUD PIC is null\n", newpic);
return;
}
// If we have no pic name.
if(!newpic || !strcmp (newpic, ""))
{
*hud_pic = NULL;
return;
}
// Get the path for the pic.
snprintf (pic_path, sizeof(pic_path), HUD_GROUP_PIC_BASEPATH, newpic);
// Try loading the pic.
if (!(temp_pic = Draw_CachePicSafe(pic_path, false, true)))
{
Com_Printf("Couldn't load picture %s for hud group.\n", newpic);
cvarfuncs->SetString(var->name, "");
return;
}
// Save the pic.
if (hud_pic)
*hud_pic = temp_pic;
return;
}
void SCR_HUD_OnChangePic_Group1(cvar_t *var, char *oldval)
{
SCR_HUD_LoadGroupPic(var, &hud_pic_group1, oldval);
}
void SCR_HUD_OnChangePic_Group2(cvar_t *var, char *oldval)
{
SCR_HUD_LoadGroupPic(var, &hud_pic_group2, oldval);
}
void SCR_HUD_OnChangePic_Group3(cvar_t *var, char *oldval)
{
SCR_HUD_LoadGroupPic(var, &hud_pic_group3, oldval);
}
void SCR_HUD_OnChangePic_Group4(cvar_t *var, char *oldval)
{
SCR_HUD_LoadGroupPic(var, &hud_pic_group4, oldval);
}
void SCR_HUD_OnChangePic_Group5(cvar_t *var, char *oldval)
{
SCR_HUD_LoadGroupPic(var, &hud_pic_group5, oldval);
}
void SCR_HUD_OnChangePic_Group6(cvar_t *var, char *oldval)
{
SCR_HUD_LoadGroupPic(var, &hud_pic_group6, oldval);
}
void SCR_HUD_OnChangePic_Group7(cvar_t *var, char *oldval)
{
SCR_HUD_LoadGroupPic(var, &hud_pic_group7, oldval);
}
void SCR_HUD_OnChangePic_Group8(cvar_t *var, char *oldval)
{
SCR_HUD_LoadGroupPic(var, &hud_pic_group8, oldval);
}
void SCR_HUD_OnChangePic_Group9(cvar_t *var, char *oldval)
{
SCR_HUD_LoadGroupPic(var, &hud_pic_group9, oldval);
}
void SCR_HUD_Group1(hud_t *hud)
{
static cvar_t *width = NULL,
*height,
*picture,
*pic_alpha,
*pic_scalemode;
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
picture = HUD_FindVar(hud, "picture");
pic_alpha = HUD_FindVar(hud, "pic_alpha");
pic_scalemode = HUD_FindVar(hud, "pic_scalemode");
picture->callback = SCR_HUD_OnChangePic_Group1;
SCR_HUD_LoadGroupPic(picture, &hud_pic_group1, picture->string);
}
SCR_HUD_DrawGroup(hud,
width->value,
height->value,
hud_pic_group1,
pic_scalemode->value,
pic_alpha->value);
}
void SCR_HUD_Group2(hud_t *hud)
{
extern void DrawNewText(int x, int y, char *text);
static cvar_t *width = NULL,
*height,
*picture,
*pic_alpha,
*pic_scalemode;
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
picture = HUD_FindVar(hud, "picture");
pic_alpha = HUD_FindVar(hud, "pic_alpha");
pic_scalemode = HUD_FindVar(hud, "pic_scalemode");
picture->callback = SCR_HUD_OnChangePic_Group2;
SCR_HUD_LoadGroupPic(picture, &hud_pic_group2, picture->string);
}
SCR_HUD_DrawGroup(hud,
width->value,
height->value,
hud_pic_group2,
pic_scalemode->value,
pic_alpha->value);
}
void SCR_HUD_Group3(hud_t *hud)
{
static cvar_t *width = NULL,
*height,
*picture,
*pic_alpha,
*pic_scalemode;
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
picture = HUD_FindVar(hud, "picture");
pic_alpha = HUD_FindVar(hud, "pic_alpha");
pic_scalemode = HUD_FindVar(hud, "pic_scalemode");
picture->callback = SCR_HUD_OnChangePic_Group3;
SCR_HUD_LoadGroupPic(picture, &hud_pic_group3, picture->string);
}
SCR_HUD_DrawGroup(hud,
width->value,
height->value,
hud_pic_group3,
pic_scalemode->value,
pic_alpha->value);
}
void SCR_HUD_Group4(hud_t *hud)
{
static cvar_t *width = NULL,
*height,
*picture,
*pic_alpha,
*pic_scalemode;
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
picture = HUD_FindVar(hud, "picture");
pic_alpha = HUD_FindVar(hud, "pic_alpha");
pic_scalemode = HUD_FindVar(hud, "pic_scalemode");
picture->callback = SCR_HUD_OnChangePic_Group4;
SCR_HUD_LoadGroupPic(picture, &hud_pic_group4, picture->string);
}
SCR_HUD_DrawGroup(hud,
width->value,
height->value,
hud_pic_group4,
pic_scalemode->value,
pic_alpha->value);
}
void SCR_HUD_Group5(hud_t *hud)
{
static cvar_t *width = NULL,
*height,
*picture,
*pic_alpha,
*pic_scalemode;
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
picture = HUD_FindVar(hud, "picture");
pic_alpha = HUD_FindVar(hud, "pic_alpha");
pic_scalemode = HUD_FindVar(hud, "pic_scalemode");
picture->callback = SCR_HUD_OnChangePic_Group5;
SCR_HUD_LoadGroupPic(picture, &hud_pic_group5, picture->string);
}
SCR_HUD_DrawGroup(hud,
width->value,
height->value,
hud_pic_group5,
pic_scalemode->value,
pic_alpha->value);
}
void SCR_HUD_Group6(hud_t *hud)
{
static cvar_t *width = NULL,
*height,
*picture,
*pic_alpha,
*pic_scalemode;
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
picture = HUD_FindVar(hud, "picture");
pic_alpha = HUD_FindVar(hud, "pic_alpha");
pic_scalemode = HUD_FindVar(hud, "pic_scalemode");
picture->callback = SCR_HUD_OnChangePic_Group6;
SCR_HUD_LoadGroupPic(picture, &hud_pic_group6, picture->string);
}
SCR_HUD_DrawGroup(hud,
width->value,
height->value,
hud_pic_group6,
pic_scalemode->value,
pic_alpha->value);
}
void SCR_HUD_Group7(hud_t *hud)
{
static cvar_t *width = NULL,
*height,
*picture,
*pic_alpha,
*pic_scalemode;
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
picture = HUD_FindVar(hud, "picture");
pic_alpha = HUD_FindVar(hud, "pic_alpha");
pic_scalemode = HUD_FindVar(hud, "pic_scalemode");
picture->callback = SCR_HUD_OnChangePic_Group7;
SCR_HUD_LoadGroupPic(picture, &hud_pic_group7, picture->string);
}
SCR_HUD_DrawGroup(hud,
width->value,
height->value,
hud_pic_group7,
pic_scalemode->value,
pic_alpha->value);
}
void SCR_HUD_Group8(hud_t *hud)
{
static cvar_t *width = NULL,
*height,
*picture,
*pic_alpha,
*pic_scalemode;
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
picture = HUD_FindVar(hud, "picture");
pic_alpha = HUD_FindVar(hud, "pic_alpha");
pic_scalemode = HUD_FindVar(hud, "pic_scalemode");
picture->callback = SCR_HUD_OnChangePic_Group8;
SCR_HUD_LoadGroupPic(picture, &hud_pic_group8, picture->string);
}
SCR_HUD_DrawGroup(hud,
width->value,
height->value,
hud_pic_group8,
pic_scalemode->value,
pic_alpha->value);
}
void SCR_HUD_Group9(hud_t *hud)
{
static cvar_t *width = NULL,
*height,
*picture,
*pic_alpha,
*pic_scalemode;
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
picture = HUD_FindVar(hud, "picture");
pic_alpha = HUD_FindVar(hud, "pic_alpha");
pic_scalemode = HUD_FindVar(hud, "pic_scalemode");
picture->callback = SCR_HUD_OnChangePic_Group9;
SCR_HUD_LoadGroupPic(picture, &hud_pic_group9, picture->string);
}
SCR_HUD_DrawGroup(hud,
width->value,
height->value,
hud_pic_group9,
pic_scalemode->value,
pic_alpha->value);
}
// player sorting
// for frags and players
typedef struct sort_teams_info_s
{
char *name;
int frags;
int min_ping;
int avg_ping;
int max_ping;
int nplayers;
int top, bottom; // leader colours
int rlcount; // Number of RL's present in the team. (Cokeman 2006-05-27)
}
sort_teams_info_t;
typedef struct sort_players_info_s
{
int playernum;
sort_teams_info_t *team;
}
sort_players_info_t;
static sort_players_info_t sorted_players[MAX_CLIENTS];
static sort_teams_info_t sorted_teams[MAX_CLIENTS];
static int n_teams;
static int n_players;
static int n_spectators;
static int sort_teamsort = 0;
static int HUD_ComparePlayers(const void *vp1, const void *vp2)
{
const sort_players_info_t *p1 = vp1;
const sort_players_info_t *p2 = vp2;
int r = 0;
player_info_t *i1 = &cl.players[p1->playernum];
player_info_t *i2 = &cl.players[p2->playernum];
if (i1->spectator && !i2->spectator)
{
r = -1;
}
else if (!i1->spectator && i2->spectator)
{
r = 1;
}
else if (i1->spectator && i2->spectator)
{
r = strcmp(i1->name, i2->name);
}
else
{
//
// Both are players.
//
if(sort_teamsort && cl.teamplay && p1->team && p2->team)
{
// Leading team on top, sort players inside of the teams.
// Teamsort 1, first sort on team frags.
if (sort_teamsort == 1)
{
r = p1->team->frags - p2->team->frags;
}
// Teamsort == 2, sort on team name only.
r = (r == 0) ? -strcmp(p1->team->name, p2->team->name) : r;
}
r = (r == 0) ? i1->frags - i2->frags : r;
r = (r == 0) ? strcmp(i1->name, i2->name) : r;
}
r = (r == 0) ? (p1->playernum - p2->playernum) : r;
// qsort() sorts ascending by default, we want descending.
// So negate the result.
return -r;
}
static int HUD_CompareTeams(const void *vt1, const void *vt2)
{
int r = 0;
const sort_teams_info_t *t1 = vt1;
const sort_teams_info_t *t2 = vt2;
r = (t1->frags - t2->frags);
r = !r ? strcmp(t1->name, t2->name) : r;
// qsort() sorts ascending by default, we want descending.
// So negate the result.
return -r;
}
#define HUD_SCOREBOARD_ALL 0xffffffff
#define HUD_SCOREBOARD_SORT_TEAMS (1 << 0)
#define HUD_SCOREBOARD_SORT_PLAYERS (1 << 1)
#define HUD_SCOREBOARD_UPDATE (1 << 2)
#define HUD_SCOREBOARD_AVG_PING (1 << 3)
static void HUD_Sort_Scoreboard(int flags)
{
int i;
int team;
n_teams = 0;
n_players = 0;
n_spectators = 0;
// Set team properties.
if(flags & HUD_SCOREBOARD_UPDATE)
{
memset(sorted_teams, 0, sizeof(sorted_teams));
for (i=0; i < MAX_CLIENTS; i++)
{
if (cl.players[i].name[0] && !cl.players[i].spectator)
{
// Find players team
for (team = 0; team < n_teams; team++)
{
if (!strcmp(cl.players[i].team, sorted_teams[team].name)
&& sorted_teams[team].name[0])
{
break;
}
}
// The team wasn't found in the list of existing teams
// so add a new team.
if (team == n_teams)
{
team = n_teams++;
sorted_teams[team].avg_ping = 0;
sorted_teams[team].max_ping = 0;
sorted_teams[team].min_ping = 999;
sorted_teams[team].nplayers = 0;
sorted_teams[team].frags = 0;
sorted_teams[team].top = Sbar_TopColor(&cl.players[i]);
sorted_teams[team].bottom = Sbar_BottomColor(&cl.players[i]);
sorted_teams[team].name = cl.players[i].team;
sorted_teams[team].rlcount = 0;
}
sorted_teams[team].nplayers++;
sorted_teams[team].frags += cl.players[i].frags;
sorted_teams[team].avg_ping += cl.players[i].ping;
sorted_teams[team].min_ping = min(sorted_teams[team].min_ping, cl.players[i].ping);
sorted_teams[team].max_ping = max(sorted_teams[team].max_ping, cl.players[i].ping);
#ifdef HAXX
// The total RL count for the players team.
if(cl.players[i].stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER)
{
sorted_teams[team].rlcount++;
}
#endif
// Set player data.
sorted_players[n_players + n_spectators].playernum = i;
//sorted_players[n_players + n_spectators].team = &sorted_teams[team];
// Increase the count.
if (cl.players[i].spectator)
{
n_spectators++;
}
else
{
n_players++;
}
}
}
}
// Calc avg ping.
if(flags & HUD_SCOREBOARD_AVG_PING)
{
for (team = 0; team < n_teams; team++)
{
sorted_teams[team].avg_ping /= sorted_teams[team].nplayers;
}
}
// Sort teams.
if(flags & HUD_SCOREBOARD_SORT_TEAMS)
{
qsort(sorted_teams, n_teams, sizeof(sort_teams_info_t), HUD_CompareTeams);
// BUGFIX, this needs to happen AFTER the team array has been sorted, otherwise the
// players might be pointing to the incorrect team adress.
for (i = 0; i < MAX_CLIENTS; i++)
{
player_info_t *player = &cl.players[sorted_players[i].playernum];
sorted_players[i].team = NULL;
// Find players team.
for (team = 0; team < n_teams; team++)
{
if (!strcmp(player->team, sorted_teams[team].name)
&& sorted_teams[team].name[0])
{
sorted_players[i].team = &sorted_teams[team];
break;
}
}
}
}
// Sort players.
if(flags & HUD_SCOREBOARD_SORT_PLAYERS)
{
qsort(sorted_players, n_players + n_spectators, sizeof(sort_players_info_t), HUD_ComparePlayers);
}
}
void Frags_DrawColors(int x, int y, int width, int height,
int top_color, int bottom_color, float color_alpha,
int frags, int drawBrackets, int style,
float bignum)
{
char buf[32];
int posy = 0;
int char_size = (bignum > 0) ? Q_rint(24 * bignum) : 8;
Draw_AlphaFill(x, y, width, height / 2, top_color, color_alpha);
Draw_AlphaFill(x, y + height / 2, width, height - height / 2, bottom_color, color_alpha);
posy = y + (height - char_size) / 2;
if (bignum > 0)
{
//
// Scaled big numbers for frags.
//
char *t = buf;
int char_x;
int char_y;
snprintf(buf, sizeof (buf), "%d", frags);
char_x = max(x, x + (width - (int)strlen(buf) * char_size) / 2);
char_y = max(y, posy);
while (*t)
{
if (*t >= '0' && *t <= '9')
{
Draw_STransPic(char_x, char_y, sb_nums[0][*t - '0'], bignum);
char_x += char_size;
}
else if (*t == '-')
{
Draw_STransPic(char_x, char_y, sb_nums[0][STAT_MINUS], bignum);
char_x += char_size;
}
t++;
}
}
else
{
// Normal text size.
snprintf(buf, sizeof (buf), "%3d", frags);
Draw_String(x - 2 + (width - char_size * strlen(buf) - 2) / 2, posy, buf);
}
if(drawBrackets)
{
// Brackets [] are not available scaled, so use normal size even
// if we're drawing big frag nums.
int brack_posy = y + (height - 8) / 2;
int d = (width >= 32) ? 0 : 1;
switch(style)
{
case 1 :
Draw_Character(x - 8, posy, 13);
break;
case 2 :
// Red outline.
Draw_Fill(x, y - 1, width, 1, 0x4f);
Draw_Fill(x, y - 1, 1, height + 2, 0x4f);
Draw_Fill(x + width - 1, y - 1, 1, height + 2, 0x4f);
Draw_Fill(x, y + height, width, 1, 0x4f);
break;
case 0 :
default :
Draw_Character(x - 2 - 2 * d, brack_posy, 16); // [
Draw_Character(x + width - 8 + 1 + d, brack_posy, 17); // ]
break;
}
}
}
#define FRAGS_HEALTHBAR_WIDTH 5
#define FRAGS_HEALTHBAR_NORMAL_COLOR 75
#define FRAGS_HEALTHBAR_MEGA_COLOR 251
#define FRAGS_HEALTHBAR_TWO_MEGA_COLOR 238
#define FRAGS_HEALTHBAR_UNNATURAL_COLOR 144
void Frags_DrawHealthBar(int original_health, int x, int y, int height, int width)
{
float health_height = 0.0;
int health;
// Get the health.
health = original_health;
health = min(100, health);
// Draw a health bar.
health_height = Q_rint((height / 100.0) * health);
health_height = (health_height > 0.0 && health_height < 1.0) ? 1 : health_height;
health_height = (health_height < 0.0) ? 0.0 : health_height;
Draw_Fill(x, y + height - (int)health_height, 3, (int)health_height, FRAGS_HEALTHBAR_NORMAL_COLOR);
// Get the health again to check if health is more than 100.
health = original_health;
if(health > 100 && health <= 200)
{
health_height = (int)Q_rint((height / 100.0) * (health - 100));
Draw_Fill(x, y + height - health_height, width, health_height, FRAGS_HEALTHBAR_MEGA_COLOR);
}
else if(health > 200 && health <= 250)
{
health_height = (int)Q_rint((height / 100.0) * (health - 200));
Draw_Fill(x, y, width, height, FRAGS_HEALTHBAR_MEGA_COLOR);
Draw_Fill(x, y + height - health_height, width, health_height, FRAGS_HEALTHBAR_TWO_MEGA_COLOR);
}
else if(health > 250)
{
// This will never happen during a normal game.
Draw_Fill(x, y, width, health_height, FRAGS_HEALTHBAR_UNNATURAL_COLOR);
}
}
#define TEAMFRAGS_EXTRA_SPEC_NONE 0
#define TEAMFRAGS_EXTRA_SPEC_BEFORE 1
#define TEAMFRAGS_EXTRA_SPEC_ONTOP 2
#define TEAMFRAGS_EXTRA_SPEC_NOICON 3
#define TEAMFRAGS_EXTRA_SPEC_RLTEXT 4
int TeamFrags_DrawExtraSpecInfo(int num, int px, int py, int width, int height, int style)
{
float rl_width, rl_height;
mpic_t *pic = sb_weapons[0][5];
drawfuncs->ImageSize((intptr_t)pic, &rl_width, &rl_height);
// Only allow this for spectators.
if (!(cls.demoplayback || cl.spectator)
|| style > TEAMFRAGS_EXTRA_SPEC_RLTEXT
|| style <= TEAMFRAGS_EXTRA_SPEC_NONE
|| !style)
{
return px;
}
// Check if the team has any RL's.
if(sorted_teams[num].rlcount > 0)
{
int y_pos = py;
//
// Draw the RL + count depending on style.
//
if((style == TEAMFRAGS_EXTRA_SPEC_BEFORE || style == TEAMFRAGS_EXTRA_SPEC_NOICON)
&& style != TEAMFRAGS_EXTRA_SPEC_RLTEXT)
{
y_pos = Q_rint(py + (height / 2.0) - 4);
Draw_ColoredString(px, y_pos, va("%d", sorted_teams[num].rlcount), 0);
px += 8 + 1;
}
if(style != TEAMFRAGS_EXTRA_SPEC_NOICON && style != TEAMFRAGS_EXTRA_SPEC_RLTEXT)
{
y_pos = Q_rint(py + (height / 2.0) - (rl_height / 2.0));
Draw_SSubPic (px, y_pos, pic, 0, 0, rl_width, rl_height, 1);
px += rl_width + 1;
}
if(style == TEAMFRAGS_EXTRA_SPEC_ONTOP && style != TEAMFRAGS_EXTRA_SPEC_RLTEXT)
{
y_pos = Q_rint(py + (height / 2.0) - 4);
Draw_ColoredString(px - 14, y_pos, va("%d", sorted_teams[num].rlcount), 0);
}
if(style == TEAMFRAGS_EXTRA_SPEC_RLTEXT)
{
y_pos = Q_rint(py + (height / 2.0) - 4);
Draw_ColoredString(px, y_pos, va("&ce00RL&cfff%d", sorted_teams[num].rlcount), 0);
px += 8*3 + 1;
}
}
else
{
// If the team has no RL's just pad with nothing.
if(style == TEAMFRAGS_EXTRA_SPEC_BEFORE)
{
// Draw the rl count before the rl icon.
px += rl_width + 8 + 1 + 1;
}
else if(style == TEAMFRAGS_EXTRA_SPEC_ONTOP)
{
// Draw the rl count on top of the RL instead of infront.
px += rl_width + 1;
}
else if(style == TEAMFRAGS_EXTRA_SPEC_NOICON)
{
// Only draw the rl count.
px += 8 + 1;
}
else if(style == TEAMFRAGS_EXTRA_SPEC_RLTEXT)
{
px += 8*3 + 1;
}
}
return px;
}
static qbool hud_frags_extra_spec_info = true;
static qbool hud_frags_show_rl = true;
static qbool hud_frags_show_armor = true;
static qbool hud_frags_show_health = true;
static qbool hud_frags_show_powerup = true;
static qbool hud_frags_textonly = false;
static void QDECL Frags_OnChangeExtraSpecInfo(cvar_t *var, char *oldvalue)
{
// Parse the extra spec info.
hud_frags_show_rl = Utils_RegExpMatch("RL|ALL", var->string);
hud_frags_show_armor = Utils_RegExpMatch("ARMOR|ALL", var->string);
hud_frags_show_health = Utils_RegExpMatch("HEALTH|ALL", var->string);
hud_frags_show_powerup = Utils_RegExpMatch("POWERUP|ALL", var->string);
hud_frags_textonly = Utils_RegExpMatch("TEXT", var->string);
hud_frags_extra_spec_info = (hud_frags_show_rl || hud_frags_show_armor || hud_frags_show_health || hud_frags_show_powerup);
}
static int Frags_DrawExtraSpecInfo(player_info_t *info,
int px, int py,
int cell_width, int cell_height,
int space_x, int space_y, int flip)
{
#ifdef HAXX
mpic_t *rl_picture = sb_weapons[0][5]; // Picture of RL.
float rl_width, rl_height;
float armor_height = 0.0;
int armor = 0;
int armor_bg_color = 0;
float armor_bg_power = 0;
int health_spacing = 1;
int weapon_width = 24;
drawfuncs->ImageSize((intptr_t)rl_picture, &rl_width, &rl_height);
// Only allow this for spectators.
if (!(cls.demoplayback || cl.spectator))
{
return px;
}
// Set width based on text or picture.
weapon_width = hud_frags_textonly ? rl_width : 24;
// Draw health bar. (flipped)
if(flip && hud_frags_show_health)
{
Frags_DrawHealthBar(info->stats[STAT_HEALTH], px, py, cell_height, 3);
px += 3 + health_spacing;
}
armor = info->stats[STAT_ARMOR];
// If the player has any armor, draw it in the appropriate color.
if(info->stats[STAT_ITEMS] & IT_ARMOR1)
{
armor_bg_power = 100;
armor_bg_color = 178; // Green armor.
}
else if(info->stats[STAT_ITEMS] & IT_ARMOR2)
{
armor_bg_power = 150;
armor_bg_color = 111; // Yellow armor.
}
else if(info->stats[STAT_ITEMS] & IT_ARMOR3)
{
armor_bg_power = 200;
armor_bg_color = 79; // Red armor.
}
// Only draw the armor if the current player has one and if the style allows it.
if(armor_bg_power && hud_frags_show_armor)
{
armor_height = Q_rint((cell_height / armor_bg_power) * armor);
Draw_AlphaFill(px, // x
py + cell_height - (int)armor_height, // y (draw from bottom up)
weapon_width, // width
(int)armor_height, // height
armor_bg_color, // color
0.3); // alpha
}
// Draw the rl if the current player has it and the style allows it.
if(info->stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER && hud_frags_show_rl)
{
if(!hud_frags_textonly)
{
// Draw the rl-pic.
Draw_SSubPic (px,
py + Q_rint((cell_height/2.0)) - (rl_height/2.0),
rl_picture, 0, 0,
rl_width,
rl_height, 1);
}
else
{
// Just print "RL" instead.
Draw_String(px + 12 - 8, py + Q_rint((cell_height/2.0)) - 4, "RL");
}
}
// Only draw powerups is the current player has it and the style allows it.
if(hud_frags_show_powerup)
{
//float powerups_x = px + (spec_extra_weapon_w / 2.0);
float powerups_x = px + (weapon_width / 2.0);
if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY
&& info->stats[STAT_ITEMS] & IT_INVISIBILITY
&& info->stats[STAT_ITEMS] & IT_QUAD)
{
Draw_ColoredString(Q_rint(powerups_x - 10), py, "&c0ffQ&cf00P&cff0R", 0);
}
else if(info->stats[STAT_ITEMS] & IT_QUAD
&& info->stats[STAT_ITEMS] & IT_INVULNERABILITY)
{
Draw_ColoredString(Q_rint(powerups_x - 8), py, "&c0ffQ&cf00P", 0);
}
else if(info->stats[STAT_ITEMS] & IT_QUAD
&& info->stats[STAT_ITEMS] & IT_INVISIBILITY)
{
Draw_ColoredString(Q_rint(powerups_x - 8), py, "&c0ffQ&cff0R", 0);
}
else if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY
&& info->stats[STAT_ITEMS] & IT_INVISIBILITY)
{
Draw_ColoredString(Q_rint(powerups_x - 8), py, "&cf00P&cff0R", 0);
}
else if(info->stats[STAT_ITEMS] & IT_QUAD)
{
Draw_ColoredString(Q_rint(powerups_x - 4), py, "&c0ffQ", 0);
}
else if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY)
{
Draw_ColoredString(Q_rint(powerups_x - 4), py, "&cf00P", 0);
}
else if(info->stats[STAT_ITEMS] & IT_INVISIBILITY)
{
Draw_ColoredString(Q_rint(powerups_x - 4), py, "&cff0R", 0);
}
}
px += weapon_width + health_spacing;
// Draw health bar. (not flipped)
if(!flip && hud_frags_show_health)
{
Frags_DrawHealthBar(info->stats[STAT_HEALTH], px, py, cell_height, 3);
px += 3 + health_spacing;
}
#endif
return px;
}
void Frags_DrawBackground(int px, int py, int cell_width, int cell_height,
int space_x, int space_y, int max_name_length, int max_team_length,
int bg_color, int shownames, int showteams, int drawBrackets, int style)
{
int bg_width = cell_width + space_x;
//int bg_color = Sbar_BottomColor(info);
float bg_alpha = 0.3;
if(style == 4
|| style == 6
|| style == 8)
bg_alpha = 0;
if(shownames)
bg_width += max_name_length*8 + space_x;
if(showteams)
bg_width += max_team_length * 8 + space_x;
if(drawBrackets)
bg_alpha = 0.7;
if(style == 7 || style == 8)
bg_color = 0x4f;
Draw_AlphaFill(px - 1, py - space_y / 2, bg_width, cell_height + space_y, bg_color, bg_alpha);
if(drawBrackets && (style == 5 || style == 6))
{
Draw_Fill(px - 1, py - 1 - space_y / 2, bg_width, 1, 0x4f);
Draw_Fill(px - 1, py - space_y / 2, 1, cell_height + space_y, 0x4f);
Draw_Fill(px + bg_width - 1, py - 1 - space_y / 2, 1, cell_height + 1 + space_y, 0x4f);
Draw_Fill(px - 1, py + cell_height + space_y / 2, bg_width + 1, 1, 0x4f);
}
}
int Frags_DrawText(int px, int py,
int cell_width, int cell_height,
int space_x, int space_y,
int max_name_length, int max_team_length,
int flip, int pad,
int shownames, int showteams,
char* name, char* team)
{
char _name[MAX_SCOREBOARDNAME + 1];
char _team[MAX_SCOREBOARDNAME + 1];
int team_length = 0;
int name_length = 0;
int char_size = 8;
int y_pos;
y_pos = Q_rint(py + (cell_height / 2.0) - 4);
// Draw team
if(showteams && cl.teamplay)
{
strlcpy(_team, team, clamp(max_team_length, 0, sizeof(_team)));
team_length = strlen(_team);
if(!flip)
px += space_x;
if(pad && flip)
{
px += (max_team_length - team_length) * char_size;
Draw_String(px, y_pos, _team);
px += team_length * char_size;
}
else if(pad)
{
Draw_String(px, y_pos, _team);
px += max_team_length * char_size;
}
else
{
Draw_String(px, y_pos, _team);
px += team_length * char_size;
}
if(flip)
px += space_x;
}
if(shownames)
{
// Draw name
strlcpy(_name, name, clamp(max_name_length, 0, sizeof(_name)));
name_length = strlen(_name);
if(flip && pad)
{
px += (max_name_length - name_length) * char_size;
Draw_String(px, y_pos, _name);
px += name_length * char_size;
}
else if(pad)
{
Draw_String(px, y_pos, _name);
px += max_name_length * char_size;
}
else
{
Draw_String(px, y_pos, _name);
px += name_length * char_size;
}
px += space_x;
}
return px;
}
void SCR_HUD_DrawFrags(hud_t *hud)
{
int width = 0, height = 0;
int x, y;
int max_team_length = 0;
int max_name_length = 0;
int rows, cols, cell_width, cell_height, space_x, space_y;
int a_rows, a_cols; // actual
static cvar_t
*hud_frags_cell_width = NULL,
*hud_frags_cell_height,
*hud_frags_rows,
*hud_frags_cols,
*hud_frags_space_x,
*hud_frags_space_y,
*hud_frags_vertical,
*hud_frags_strip,
*hud_frags_teamsort,
*hud_frags_shownames,
*hud_frags_teams,
*hud_frags_padtext,
*hud_frags_showself,
*hud_frags_extra_spec,
*hud_frags_fliptext,
*hud_frags_style,
*hud_frags_bignum,
*hud_frags_colors_alpha,
*hud_frags_maxname,
*hud_frags_notintp;
mpic_t *rl_picture = sb_weapons[0][5];
float rl_width, rl_height;
drawfuncs->ImageSize((intptr_t)rl_picture, &rl_width, &rl_height);
if (hud_frags_cell_width == NULL) // first time
{
char specval[256];
hud_frags_cell_width = HUD_FindVar(hud, "cell_width");
hud_frags_cell_height = HUD_FindVar(hud, "cell_height");
hud_frags_rows = HUD_FindVar(hud, "rows");
hud_frags_cols = HUD_FindVar(hud, "cols");
hud_frags_space_x = HUD_FindVar(hud, "space_x");
hud_frags_space_y = HUD_FindVar(hud, "space_y");
hud_frags_teamsort = HUD_FindVar(hud, "teamsort");
hud_frags_strip = HUD_FindVar(hud, "strip");
hud_frags_vertical = HUD_FindVar(hud, "vertical");
hud_frags_shownames = HUD_FindVar(hud, "shownames");
hud_frags_teams = HUD_FindVar(hud, "showteams");
hud_frags_padtext = HUD_FindVar(hud, "padtext");
hud_frags_showself = HUD_FindVar(hud, "showself_always");
hud_frags_extra_spec = HUD_FindVar(hud, "extra_spec_info");
hud_frags_fliptext = HUD_FindVar(hud, "fliptext");
hud_frags_style = HUD_FindVar(hud, "style");
hud_frags_bignum = HUD_FindVar(hud, "bignum");
hud_frags_colors_alpha = HUD_FindVar(hud, "colors_alpha");
hud_frags_maxname = HUD_FindVar(hud, "maxname");
hud_frags_notintp = HUD_FindVar(hud, "notintp");
// Set the OnChange function for extra spec info.
hud_frags_extra_spec->callback = Frags_OnChangeExtraSpecInfo;
strlcpy(specval, hud_frags_extra_spec->string, sizeof(specval));
Cvar_Set(hud_frags_extra_spec, specval);
}
// Don't draw the frags if we're in teamplay.
if(hud_frags_notintp->value && cl.teamplay)
{
HUD_PrepareDraw(hud, width, height, &x, &y);
return;
}
//
// Clamp values to be "sane".
//
{
rows = hud_frags_rows->value;
clamp(rows, 1, MAX_CLIENTS);
cols = hud_frags_cols->value;
clamp(cols, 1, MAX_CLIENTS);
// Some users doesn't want to show the actual frags, just
// extra_spec_info stuff + names.
cell_width = hud_frags_cell_width->value;
clamp(cell_width, 0, 128);
cell_height = hud_frags_cell_height->value;
clamp(cell_height, 7, 32);
space_x = hud_frags_space_x->value;
clamp(space_x, 0, 128);
space_y = hud_frags_space_y->value;
clamp(space_y, 0, 128);
}
sort_teamsort = hud_frags_teamsort->ival;
if (hud_frags_strip->ival)
{
// Auto set the number of rows / cols based on the number of players.
// (This is kinda fucked up, but I won't mess with it for the sake of backwards compability).
if (hud_frags_vertical->value)
{
a_cols = min((n_players + rows - 1) / rows, cols);
a_rows = min(rows, n_players);
}
else
{
a_rows = min((n_players + cols - 1) / cols, rows);
a_cols = min(cols, n_players);
}
}
else
{
a_rows = rows;
a_cols = cols;
}
width = (a_cols * cell_width) + ((a_cols + 1) * space_x);
height = (a_rows * cell_height) + ((a_rows + 1) * space_y);
// Get the longest name/team name for padding.
if(hud_frags_shownames->value || hud_frags_teams->value)
{
int cur_length = 0;
int n;
for(n = 0; n < n_players; n++)
{
player_info_t *info = &cl.players[sorted_players[n].playernum];
cur_length = strlen(info->name);
// Name.
if(cur_length >= max_name_length)
{
max_name_length = cur_length + 1;
}
cur_length = strlen(info->team);
// Team name.
if(cur_length >= max_team_length)
{
max_team_length = cur_length + 1;
}
}
// If the user has set a limit on how many chars that
// are allowed to be shown for a name/teamname.
max_name_length = min(max(0, (int)hud_frags_maxname->value), max_name_length) + 1;
max_team_length = min(max(0, (int)hud_frags_maxname->value), max_team_length) + 1;
// We need a wider box to draw in if we show the names.
if(hud_frags_shownames->value)
{
width += (a_cols * (max_name_length + 3) * 8) + ((a_cols + 1) * space_x);
}
if(cl.teamplay && hud_frags_teams->value)
{
width += (a_cols * max_team_length * 8) + ((a_cols + 1) * space_x);
}
}
// Make room for the extra spectator stuff.
if(hud_frags_extra_spec_info && (cls.demoplayback || cl.spectator) )
{
width += a_cols * (rl_width + FRAGS_HEALTHBAR_WIDTH);
}
if (HUD_PrepareDraw(hud, width, height, &x, &y))
{
int i = 0;
int player_x = 0;
int player_y = 0;
int num = 0;
int drawBrackets = 0;
// The number of players that are to be visible.
int limit = min(n_players, a_rows * a_cols);
// Always show my current frags (don't just show the leaders).
// TODO: When all players aren't being shown in the frags, draw
// a small arrow that indicates that there are more frags to be seen.
if(hud_frags_showself->value && !cl_multiview->value)
{
int player_pos = 0;
// Find my position in the scoreboard.
for(player_pos = 0; i < n_players; player_pos++)
{
if (cls.demoplayback || cl.spectator)
{
if (spec_track == sorted_players[player_pos].playernum)
{
break;
}
}
else if(sorted_players[player_pos].playernum == cl.playernum)
{
break;
}
}
if(player_pos + 1 <= (a_rows * a_cols))
{
// If I'm not "outside" the shown frags, start drawing from the top.
num = 0;
}
else
{
// Always include me in the shown frags.
num = abs((a_rows * a_cols) - (player_pos + 1));
}
// Make sure we're not trying to go outside the player array.
num = (num < 0 || num > n_players) ? 0 : num;
}
//num = 0; // FIXME! johnnycz; (see fixme below)
//
// Loop through all the positions that should be drawn (columns * rows or number of players).
//
// Start drawing player "num", usually the first player in the array, but if
// showself_always is set this might be someone else (since we need to make sure the current
// player is always shown).
//
for (i = 0; i < limit; i++)
{
player_info_t *info = &cl.players[sorted_players[num].playernum]; // FIXME! johnnycz; causes crashed on some demos
//
// Set the coordinates where to draw the next element.
//
if (hud_frags_vertical->value)
{
if (i % a_rows == 0)
{
// We're drawing a new column.
int element_width = cell_width + space_x;
// Get the width of all the stuff that is shown, the name, frag cell and so on.
if(hud_frags_shownames->value)
{
element_width += (max_name_length) * 8;
}
if(hud_frags_teams->value)
{
element_width += (max_team_length) * 8;
}
if(hud_frags_extra_spec_info && (cls.demoplayback || cl.spectator) )
{
element_width += rl_width;
}
player_x = x + space_x + ((i / a_rows) * element_width);
// New column.
player_y = y + space_y;
}
}
else
{
if (i % a_cols == 0)
{
// Drawing new row.
player_x = x + space_x;
player_y = y + space_y + (i / a_cols) * (cell_height + space_y);
}
}
drawBrackets = 0;
// Bug fix. Before the wrong player would be higlighted
// during qwd-playback, since you ARE the player that you're
// being spectated (you're not a spectator).
if(cls.demoplayback && !cl.spectator && !cls.mvdplayback)
{
drawBrackets = (sorted_players[num].playernum == cl.playernum);
}
else if (cls.demoplayback || cl.spectator)
{
drawBrackets = (spec_track == sorted_players[num].playernum && Cam_TrackNum() >= 0);
}
else
{
drawBrackets = (sorted_players[num].playernum == cl.playernum);
}
// Don't draw any brackets in multiview since we're
// tracking several players.
if (cl_multiview->value > 1 && cls.mvdplayback)
{
// TODO: Highlight all players being tracked (See tracking hud-element)
drawBrackets = 0;
}
if(hud_frags_shownames->value || hud_frags_teams->value || hud_frags_extra_spec_info)
{
// Relative x coordinate where we draw the subitems.
int rel_player_x = player_x;
if(hud_frags_style->value >= 4 && hud_frags_style->value <= 8)
{
// Draw background based on the style.
Frags_DrawBackground(player_x, player_y, cell_width, cell_height, space_x, space_y,
max_name_length, max_team_length, Sbar_BottomColor(info),
hud_frags_shownames->value, hud_frags_teams->value, drawBrackets,
hud_frags_style->value);
}
if(hud_frags_fliptext->value)
{
//
// Flip the text
// NAME | TEAM | FRAGS | EXTRA_SPEC_INFO
//
// Draw name.
rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height,
space_x, space_y, max_name_length, max_team_length,
hud_frags_fliptext->value, hud_frags_padtext->value,
hud_frags_shownames->value, 0,
info->name, info->team);
// Draw team.
rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height,
space_x, space_y, max_name_length, max_team_length,
hud_frags_fliptext->value, hud_frags_padtext->value,
0, hud_frags_teams->value,
info->name, info->team);
Frags_DrawColors(rel_player_x, player_y, cell_width, cell_height,
Sbar_TopColor(info), Sbar_BottomColor(info), hud_frags_colors_alpha->value,
info->frags,
drawBrackets,
hud_frags_style->value,
hud_frags_bignum->value);
rel_player_x += cell_width + space_x;
// Show extra information about all the players if spectating:
// - What armor they have.
// - How much health.
// - If they have RL or not.
rel_player_x = Frags_DrawExtraSpecInfo(info, rel_player_x, player_y, cell_width, cell_height,
space_x, space_y,
hud_frags_fliptext->value);
}
else
{
//
// Don't flip the text
// EXTRA_SPEC_INFO | FRAGS | TEAM | NAME
//
rel_player_x = Frags_DrawExtraSpecInfo(info, rel_player_x, player_y, cell_width, cell_height,
space_x, space_y,
hud_frags_fliptext->value);
Frags_DrawColors(rel_player_x, player_y, cell_width, cell_height,
Sbar_TopColor(info), Sbar_BottomColor(info), hud_frags_colors_alpha->value,
info->frags,
drawBrackets,
hud_frags_style->value,
hud_frags_bignum->value);
rel_player_x += cell_width + space_x;
// Draw team.
rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height,
space_x, space_y, max_name_length, max_team_length,
hud_frags_fliptext->value, hud_frags_padtext->value,
0, hud_frags_teams->value,
info->name, info->team);
// Draw name.
rel_player_x = Frags_DrawText(rel_player_x, player_y, cell_width, cell_height,
space_x, space_y, max_name_length, max_team_length,
hud_frags_fliptext->value, hud_frags_padtext->value,
hud_frags_shownames->value, 0,
info->name, info->team);
}
if(hud_frags_vertical->value)
{
// Next row.
player_y += cell_height + space_y;
}
else
{
// Next column.
player_x = rel_player_x + space_x;
}
}
else
{
// Only showing the frags, no names or extra spec info.
Frags_DrawColors(player_x, player_y, cell_width, cell_height,
Sbar_TopColor(info), Sbar_BottomColor(info), hud_frags_colors_alpha->value,
info->frags,
drawBrackets,
hud_frags_style->value,
hud_frags_bignum->value);
if (hud_frags_vertical->value)
{
// Next row.
player_y += cell_height + space_y;
}
else
{
// Next column.
player_x += cell_width + space_x;
}
}
// Next player.
num++;
}
}
}
void SCR_HUD_DrawTeamFrags(hud_t *hud)
{
int width = 0, height = 0;
int x, y;
int max_team_length = 0, num = 0;
int rows, cols, cell_width, cell_height, space_x, space_y;
int a_rows, a_cols; // actual
static cvar_t
*hud_teamfrags_cell_width,
*hud_teamfrags_cell_height,
*hud_teamfrags_rows,
*hud_teamfrags_cols,
*hud_teamfrags_space_x,
*hud_teamfrags_space_y,
*hud_teamfrags_vertical,
*hud_teamfrags_strip,
*hud_teamfrags_shownames,
*hud_teamfrags_fliptext,
*hud_teamfrags_padtext,
*hud_teamfrags_style,
*hud_teamfrags_extra_spec,
*hud_teamfrags_onlytp,
*hud_teamfrags_bignum,
*hud_teamfrags_colors_alpha;
mpic_t *rl_picture = sb_weapons[0][5];
float rl_width, rl_height;
drawfuncs->ImageSize((intptr_t)rl_picture, &rl_width, &rl_height);
if (hud_teamfrags_cell_width == 0) // first time
{
hud_teamfrags_cell_width = HUD_FindVar(hud, "cell_width");
hud_teamfrags_cell_height = HUD_FindVar(hud, "cell_height");
hud_teamfrags_rows = HUD_FindVar(hud, "rows");
hud_teamfrags_cols = HUD_FindVar(hud, "cols");
hud_teamfrags_space_x = HUD_FindVar(hud, "space_x");
hud_teamfrags_space_y = HUD_FindVar(hud, "space_y");
hud_teamfrags_strip = HUD_FindVar(hud, "strip");
hud_teamfrags_vertical = HUD_FindVar(hud, "vertical");
hud_teamfrags_shownames = HUD_FindVar(hud, "shownames");
hud_teamfrags_fliptext = HUD_FindVar(hud, "fliptext");
hud_teamfrags_padtext = HUD_FindVar(hud, "padtext");
hud_teamfrags_style = HUD_FindVar(hud, "style");
hud_teamfrags_extra_spec = HUD_FindVar(hud, "extra_spec_info");
hud_teamfrags_onlytp = HUD_FindVar(hud, "onlytp");
hud_teamfrags_bignum = HUD_FindVar(hud, "bignum");
hud_teamfrags_colors_alpha = HUD_FindVar(hud, "colors_alpha");
}
// Don't draw the frags if we're not in teamplay.
if(hud_teamfrags_onlytp->value && !cl.teamplay)
{
HUD_PrepareDraw(hud, width, height, &x, &y);
return;
}
rows = hud_teamfrags_rows->value;
clamp(rows, 1, MAX_CLIENTS);
cols = hud_teamfrags_cols->value;
clamp(cols, 1, MAX_CLIENTS);
cell_width = hud_teamfrags_cell_width->value;
clamp(cell_width, 28, 128);
cell_height = hud_teamfrags_cell_height->value;
clamp(cell_height, 7, 32);
space_x = hud_teamfrags_space_x->value;
clamp(space_x, 0, 128);
space_y = hud_teamfrags_space_y->value;
clamp(space_y, 0, 128);
if (hud_teamfrags_strip->value)
{
if (hud_teamfrags_vertical->value)
{
a_cols = min((n_teams+rows-1) / rows, cols);
a_rows = min(rows, n_teams);
}
else
{
a_rows = min((n_teams+cols-1) / cols, rows);
a_cols = min(cols, n_teams);
}
}
else
{
a_rows = rows;
a_cols = cols;
}
width = a_cols*cell_width + (a_cols+1)*space_x;
height = a_rows*cell_height + (a_rows+1)*space_y;
// Get the longest team name for padding.
if(hud_teamfrags_shownames->value || hud_teamfrags_extra_spec->value)
{
int rlcount_width = 0;
int cur_length = 0;
int n;
for(n=0; n < n_teams; n++)
{
if(hud_teamfrags_shownames->value)
{
cur_length = strlen(sorted_teams[n].name);
// Team name
if(cur_length >= max_team_length)
{
max_team_length = cur_length + 1;
}
}
}
// Calculate the length of the extra spec info.
if(hud_teamfrags_extra_spec->value && (cls.demoplayback || cl.spectator))
{
if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_BEFORE)
{
// Draw the rl count before the rl icon.
rlcount_width = rl_width + 8 + 1 + 1;
}
else if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_ONTOP)
{
// Draw the rl count on top of the RL instead of infront.
rlcount_width = rl_width + 1;
}
else if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_NOICON)
{
// Only draw the rl count.
rlcount_width = 8 + 1;
}
else if(hud_teamfrags_extra_spec->value == TEAMFRAGS_EXTRA_SPEC_RLTEXT)
{
rlcount_width = 8*3 + 1;
}
}
width += a_cols*max_team_length*8 + (a_cols+1)*space_x + a_cols*rlcount_width;
}
if (HUD_PrepareDraw(hud, width, height, &x, &y))
{
int i;
int px = 0;
int py = 0;
int drawBrackets;
int limit = min(n_teams, a_rows*a_cols);
for (i=0; i < limit; i++)
{
if (hud_teamfrags_vertical->value)
{
if (i % a_rows == 0)
{
px = x + space_x + (i/a_rows) * (cell_width+space_x);
py = y + space_y;
}
}
else
{
if (i % a_cols == 0)
{
px = x + space_x;
py = y + space_y + (i/a_cols) * (cell_height+space_y);
}
}
drawBrackets = 0;
// Bug fix. Before the wrong player would be higlighted
// during qwd-playback, since you ARE the player that you're
// being spectated.
if(cls.demoplayback && !cl.spectator && !cls.mvdplayback)
{
// QWD Playback.
if (!strcmp(sorted_teams[num].name, cl.players[cl.playernum].team))
{
drawBrackets = 1;
}
}
else if (cls.demoplayback || cl.spectator)
{
// MVD playback / spectating.
if (!strcmp(cl.players[spec_track].team, sorted_teams[num].name) && Cam_TrackNum() >= 0)
{
drawBrackets = 1;
}
}
else
{
// Normal player.
if (!strcmp(sorted_teams[num].name, cl.players[cl.playernum].team))
{
drawBrackets = 1;
}
}
if (cl_multiview->value && cl.splitscreenview != 0 ) // Only draw bracket for first view, might make todo below unnecessary
{
// TODO: Check if "track team" is set, if it is then draw brackets around that team.
//cl.players[nPlayernum]
drawBrackets = 0;
}
if(hud_teamfrags_shownames->value || hud_teamfrags_extra_spec->value)
{
int _px = px;
// Draw a background if the style tells us to.
if(hud_teamfrags_style->value >= 4 && hud_teamfrags_style->value <= 8)
{
Frags_DrawBackground(px, py, cell_width, cell_height, space_x, space_y,
0, max_team_length, sorted_teams[num].bottom,
0, hud_teamfrags_shownames->value, drawBrackets,
hud_teamfrags_style->value);
}
// Draw the text on the left or right side of the score?
if(hud_teamfrags_fliptext->value)
{
// Draw team.
_px = Frags_DrawText(_px, py, cell_width, cell_height,
space_x, space_y, 0, max_team_length,
hud_teamfrags_fliptext->value, hud_teamfrags_padtext->value,
0, hud_teamfrags_shownames->value,
"", sorted_teams[num].name);
Frags_DrawColors(_px, py, cell_width, cell_height,
sorted_teams[num].top,
sorted_teams[num].bottom,
hud_teamfrags_colors_alpha->value,
sorted_teams[num].frags,
drawBrackets,
hud_teamfrags_style->value,
hud_teamfrags_bignum->value);
_px += cell_width + space_x;
// Draw the rl if the current player has it and the style allows it.
_px = TeamFrags_DrawExtraSpecInfo(num, _px, py, cell_width, cell_height, hud_teamfrags_extra_spec->value);
}
else
{
// Draw the rl if the current player has it and the style allows it.
_px = TeamFrags_DrawExtraSpecInfo(num, _px, py, cell_width, cell_height, hud_teamfrags_extra_spec->value);
Frags_DrawColors(_px, py, cell_width, cell_height,
sorted_teams[num].top,
sorted_teams[num].bottom,
hud_teamfrags_colors_alpha->value,
sorted_teams[num].frags,
drawBrackets,
hud_teamfrags_style->value,
hud_teamfrags_bignum->value);
_px += cell_width + space_x;
// Draw team.
_px = Frags_DrawText(_px, py, cell_width, cell_height,
space_x, space_y, 0, max_team_length,
hud_teamfrags_fliptext->value, hud_teamfrags_padtext->value,
0, hud_teamfrags_shownames->value,
"", sorted_teams[num].name);
}
if(hud_teamfrags_vertical->value)
{
py += cell_height + space_y;
}
else
{
px = _px + space_x;
}
}
else
{
Frags_DrawColors(px, py, cell_width, cell_height,
sorted_teams[num].top,
sorted_teams[num].bottom,
hud_teamfrags_colors_alpha->value,
sorted_teams[num].frags,
drawBrackets,
hud_teamfrags_style->value,
hud_teamfrags_bignum->value);
if (hud_teamfrags_vertical->value)
{
py += cell_height + space_y;
}
else
{
px += cell_width + space_x;
}
}
num ++;
}
}
}
char *Get_MP3_HUD_style(float style, char *st)
{
static char HUD_style[32];
if(style == 1.0)
{
strlcpy(HUD_style, va("%s:", st), sizeof(HUD_style));
}
else if(style == 2.0)
{
strlcpy(HUD_style, va("^Ue010%s^Ue011", st), sizeof(HUD_style));
}
else
{
strlcpy(HUD_style, "", sizeof(HUD_style));
}
return HUD_style;
}
// Draws MP3 Title.
void SCR_HUD_DrawMP3_Title(hud_t *hud)
{
int x=0, y=0/*, n=1*/;
int width = 64;
int height = 8;
#ifdef WITH_MP3_PLAYER
//int width_as_text = 0;
static int title_length = 0;
//int row_break = 0;
//int i=0;
int status = 0;
static char title[MP3_MAXSONGTITLE];
double t; // current time
static double lastframetime; // last refresh
static cvar_t *style = NULL, *width_var, *height_var, *scroll, *scroll_delay, *on_scoreboard, *wordwrap;
if (style == NULL) // first time called
{
style = HUD_FindVar(hud, "style");
width_var = HUD_FindVar(hud, "width");
height_var = HUD_FindVar(hud, "height");
scroll = HUD_FindVar(hud, "scroll");
scroll_delay = HUD_FindVar(hud, "scroll_delay");
on_scoreboard = HUD_FindVar(hud, "on_scoreboard");
wordwrap = HUD_FindVar(hud, "wordwrap");
}
if(on_scoreboard->value)
{
hud->flags |= HUD_ON_SCORES;
}
else if((int)on_scoreboard->value & HUD_ON_SCORES)
{
hud->flags -= HUD_ON_SCORES;
}
width = (int)width_var->value;
height = (int)height_var->value;
if(width < 0) width = 0;
if(width > vid.width) width = vid.width;
if(height < 0) height = 0;
if(height > vid.width) height = vid.height;
t = Sys_DoubleTime();
if ((t - lastframetime) >= 2) { // 2 sec refresh rate
lastframetime = t;
status = MP3_GetStatus();
switch(status)
{
case MP3_PLAYING :
title_length = snprintf(title, sizeof(title)-1, "%s %s", Get_MP3_HUD_style(style->value, "Playing"), MP3_Macro_MP3Info());
break;
case MP3_PAUSED :
title_length = snprintf(title, sizeof(title)-1, "%s %s", Get_MP3_HUD_style(style->value, "Paused"), MP3_Macro_MP3Info());
break;
case MP3_STOPPED :
title_length = snprintf(title, sizeof(title)-1, "%s %s", Get_MP3_HUD_style(style->value, "Stopped"), MP3_Macro_MP3Info());
break;
case MP3_NOTRUNNING :
default :
status = MP3_NOTRUNNING;
title_length = snprintf (title, sizeof (title), "%s is not running.", mp3_player->PlayerName_AllCaps);
break;
}
if(title_length < 0)
{
snprintf(title, sizeof (title), "Error retrieving current song.");
}
}
if (HUD_PrepareDraw(hud, width , height, &x, &y))
{
SCR_DrawWordWrapString(x, y, 8, width, height, (int)wordwrap->value, (int)scroll->value, (float)scroll_delay->value, title);
}
#else
HUD_PrepareDraw(hud, width , height, &x, &y);
#endif
}
// Draws MP3 Time as a HUD-element.
void SCR_HUD_DrawMP3_Time(hud_t *hud)
{
int x = 0, y = 0, width = 0, height = 0;
#ifdef WITH_MP3_PLAYER
int elapsed = 0;
int remain = 0;
int total = 0;
static char time_string[MP3_MAXSONGTITLE];
static char elapsed_string[MP3_MAXSONGTITLE];
double t; // current time
static double lastframetime; // last refresh
static cvar_t *style = NULL, *on_scoreboard;
if(style == NULL)
{
style = HUD_FindVar(hud, "style");
on_scoreboard = HUD_FindVar(hud, "on_scoreboard");
}
if(on_scoreboard->value)
{
hud->flags |= HUD_ON_SCORES;
}
else if((int)on_scoreboard->value & HUD_ON_SCORES)
{
hud->flags -= HUD_ON_SCORES;
}
t = Sys_DoubleTime();
if ((t - lastframetime) >= 2) { // 2 sec refresh rate
lastframetime = t;
if(!MP3_GetOutputtime(&elapsed, &total) || elapsed < 0 || total < 0)
{
snprintf (time_string, sizeof (time_string), "^Ue010-:-^Ue011");
}
else
{
switch((int)style->value)
{
case 1 :
remain = total - elapsed;
strlcpy (elapsed_string, SecondsToMinutesString (remain), sizeof (elapsed_string));
snprintf (time_string, sizeof (time_string), "^Ue010-%s/%s^Ue011", elapsed_string, SecondsToMinutesString (total));
break;
case 2 :
remain = total - elapsed;
snprintf (time_string, sizeof (time_string), "^Ue010-%s^Ue011", SecondsToMinutesString (remain));
break;
case 3 :
snprintf (time_string, sizeof (time_string), "^Ue010%s^Ue011", SecondsToMinutesString (elapsed));
break;
case 4 :
remain = total - elapsed;
strlcpy (elapsed_string, SecondsToMinutesString (remain), sizeof (elapsed_string));
snprintf (time_string, sizeof (time_string), "%s/%s", elapsed_string, SecondsToMinutesString (total));
break;
case 5 :
strlcpy (elapsed_string, SecondsToMinutesString (elapsed), sizeof (elapsed_string));
snprintf (time_string, sizeof (time_string), "-%s/%s", elapsed_string, SecondsToMinutesString (total));
break;
case 6 :
remain = total - elapsed;
snprintf (time_string, sizeof (time_string), "-%s", SecondsToMinutesString (remain));
break;
case 7 :
snprintf (time_string, sizeof (time_string), "%s", SecondsToMinutesString (elapsed));
break;
case 0 :
default :
strlcpy (elapsed_string, SecondsToMinutesString (elapsed), sizeof (elapsed_string));
snprintf (time_string, sizeof (time_string), "^Ue010%s/%s^Ue011", elapsed_string, SecondsToMinutesString (total));
break;
}
}
}
// Don't allow showing the timer if ruleset disallows it
// It could be used for timing powerups
// Use same check that is used for any external communication
if(Rulesets_RestrictPacket())
snprintf (time_string, sizeof (time_string), "^Ue010%s^Ue011", "Not allowed");
width = strlen (time_string) * 8;
height = 8;
if (HUD_PrepareDraw(hud, width , height, &x, &y))
Draw_String(x, y, time_string);
#else
HUD_PrepareDraw(hud, width , height, &x, &y);
#endif
}
#ifdef WITH_PNG
// Map picture to draw for the mapoverview hud control.
mpic_t *radar_pic;
static qbool radar_pic_found = false;
// The conversion formula used for converting from quake coordinates to pixel coordinates
// when drawing on the map overview.
static float map_x_slope;
static float map_x_intercept;
static float map_y_slope;
static float map_y_intercept;
static qbool conversion_formula_found = false;
// Used for drawing the height of the player.
static float map_height_diff = 0.0;
#define RADAR_BASE_PATH_FORMAT "radars/%s.png"
//
// Is run when a new map is loaded.
//
void HUD_NewRadarMap()
{
int i = 0;
int len = 0;
int n_textcount = 0;
mpic_t *radar_pic_p = NULL;
png_textp txt = NULL;
char *radar_filename = NULL;
if (!cl.worldmodel)
return; // seems we are not ready to do that
// Reset the radar pic status.
radar_pic = NULL;
radar_pic_found = false;
conversion_formula_found = false;
// Allocate a string for the path to the radar image.
len = strlen (RADAR_BASE_PATH_FORMAT) + strlen (host_mapname.string);
radar_filename = Q_calloc (len, sizeof(char));
snprintf (radar_filename, len, RADAR_BASE_PATH_FORMAT, host_mapname.string);
// Load the map picture.
if ((radar_pic_p = GL_LoadPicImage (radar_filename, host_mapname.string, 0, 0, TEX_ALPHA)) != NULL)
{
radar_pic = *radar_pic_p;
radar_pic_found = true;
// Calculate the height of the map.
map_height_diff = abs(cl.worldmodel->maxs[2] - cl.worldmodel->mins[2]);
// Get the comments from the PNG.
txt = Image_LoadPNG_Comments(radar_filename, &n_textcount);
// Check if we found any comments.
if(txt != NULL)
{
int found_count = 0;
// Find the conversion formula in the comments found in the PNG.
for(i = 0; i < n_textcount; i++)
{
if(!strcmp(txt[i].key, "QWLMConversionSlopeX"))
{
map_x_slope = atof(txt[i].text);
found_count++;
}
else if(!strcmp(txt[i].key, "QWLMConversionInterceptX"))
{
map_x_intercept = atof(txt[i].text);
found_count++;
}
else if(!strcmp(txt[i].key, "QWLMConversionSlopeY"))
{
map_y_slope = atof(txt[i].text);
found_count++;
}
else if(!strcmp(txt[i].key, "QWLMConversionInterceptY"))
{
map_y_intercept = atof(txt[i].text);
found_count++;
}
conversion_formula_found = (found_count == 4);
}
// Free the text chunks.
Q_free(txt);
}
else
{
conversion_formula_found = false;
}
}
else
{
// No radar pic found.
memset (&radar_pic, 0, sizeof(radar_pic));
radar_pic_found = false;
conversion_formula_found = false;
}
// Free the path string to the radar png.
Q_free (radar_filename);
}
#endif // WITH_PNG
#define TEMPHUD_NAME "_temphud"
#define TEMPHUD_FULLPATH "configs/"TEMPHUD_NAME".cfg"
// will check if user wants to un/load external MVD HUD automatically
void HUD_AutoLoad_MVD(int autoload) {
#ifdef HAXX
char *cfg_suffix = "custom";
extern cvar_t *scr_fov;
extern cvar_t *scr_newHud;
extern void Cmd_Exec_f (void);
extern void DumpConfig(char *name);
if (autoload && cls.mvdplayback) {
// Turn autohud ON here
Com_DPrintf("Loading MVD Hud\n");
// Store current settings.
if (!autohud.active)
{
// Save old cfg_save values so that we don't screw the users
// settings when saving the temp config.
int old_cmdline = cvarfuncs->GetFloat("cfg_save_cmdline");
int old_cvars = cvarfuncs->GetFloat("cfg_save_cvars");
int old_cmds = cvarfuncs->GetFloat("cfg_save_cmds");
int old_aliases = cvarfuncs->GetFloat("cfg_save_aliases");
int old_binds = cvarfuncs->GetFloat("cfg_save_binds");
autohud.old_fov = (int) scr_fov->value;
autohud.old_multiview = (int) cl_multiview->value;
autohud.old_newhud = (int) scr_newHud->value;
// Make sure everything current settings are saved.
cvarfuncs->SetFloat("cfg_save_cmdline", 1);
cvarfuncs->SetFloat("cfg_save_cvars", 1);
cvarfuncs->SetFloat("cfg_save_cmds", 1);
cvarfuncs->SetFloat("cfg_save_aliases", 1);
cvarfuncs->SetFloat("cfg_save_binds", 1);
// Save a temporary config.
DumpConfig(TEMPHUD_NAME".cfg");
cvarfuncs->SetFloat("cfg_save_cmdline", old_cmdline);
cvarfuncs->SetFloat("cfg_save_cvars", old_cvars);
cvarfuncs->SetFloat("cfg_save_cmds", old_cmds);
cvarfuncs->SetFloat("cfg_save_aliases", old_aliases);
cvarfuncs->SetFloat("cfg_save_binds", old_binds);
}
// load MVD HUD config
switch ((int) autoload) {
case 1: // load 1on1 or 4on4 or custom according to $matchtype
if (!strncmp(Macro_MatchType(), "duel", 4)) {
cfg_suffix = "1on1";
} else if (!strncmp(Macro_MatchType(), "4on4", 4)) {
cfg_suffix = "4on4";
} else {
cfg_suffix = "custom";
}
break;
default:
case 2:
cfg_suffix = "custom";
break;
}
Cbuf_AddText(va("exec cfg/mvdhud_%s.cfg\n", cfg_suffix));
autohud.active = true;
return;
}
if ((!cls.mvdplayback || !autoload) && autohud.active) {
// either user decided to turn mvd autohud off or mvd playback is over
// -> Turn autohud OFF here
FILE *tempfile;
char *fullname = va("%s/ezquake/"TEMPHUD_FULLPATH, com_basedir);
Com_DPrintf("Unloading MVD Hud\n");
// load stored settings
cvarfuncs->SetFloat(scr_fov->name, autohud.old_fov);
cvarfuncs->SetFloat(cl_multiview->name, autohud.old_multiview);
cvarfuncs->SetFloat(scr_newHud->name, autohud.old_newhud);
//Cmd_TokenizeString("exec "TEMPHUD_FULLPATH);
Cmd_TokenizeString("cfg_load "TEMPHUD_FULLPATH);
Cmd_Exec_f();
// delete temp config with hud_* settings
if ((tempfile = fopen(fullname, "rb")) && (fclose(tempfile) != EOF))
unlink(fullname);
autohud.active = false;
return;
}
#endif
}
void OnAutoHudChange(cvar_t *var, char *value, qbool *cancel) {
HUD_AutoLoad_MVD(Q_atoi(value));
}
// Is run when a new map is loaded.
void HUD_NewMap(void) {
#if defined(WITH_PNG)
HUD_NewRadarMap();
#endif // WITH_PNG
autohud_loaded = false;
}
#define HUD_SHOW_ONLY_IN_TEAMPLAY 1
#define HUD_SHOW_ONLY_IN_DEMOPLAYBACK 2
qbool HUD_ShowInDemoplayback(int val)
{
if(!cl.teamplay && val == HUD_SHOW_ONLY_IN_TEAMPLAY)
{
return false;
}
else if(!cls.demoplayback && val == HUD_SHOW_ONLY_IN_DEMOPLAYBACK)
{
return false;
}
else if(!cl.teamplay && !cls.demoplayback
&& val == HUD_SHOW_ONLY_IN_TEAMPLAY + HUD_SHOW_ONLY_IN_DEMOPLAYBACK)
{
return false;
}
return true;
}
// Team hold filters.
static qbool teamhold_show_pent = false;
static qbool teamhold_show_quad = false;
static qbool teamhold_show_ring = false;
static qbool teamhold_show_suit = false;
static qbool teamhold_show_rl = false;
static qbool teamhold_show_lg = false;
static qbool teamhold_show_gl = false;
static qbool teamhold_show_sng = false;
static qbool teamhold_show_mh = false;
static qbool teamhold_show_ra = false;
static qbool teamhold_show_ya = false;
static qbool teamhold_show_ga = false;
void TeamHold_DrawBars(int x, int y, int width, int height,
float team1_percent, float team2_percent,
int team1_color, int team2_color,
float opacity)
{
int team1_width = 0;
int team2_width = 0;
int bar_height = 0;
bar_height = Q_rint (height/2.0);
team1_width = (int) (width * team1_percent);
team2_width = (int) (width * team2_percent);
clamp(team1_width, 0, width);
clamp(team2_width, 0, width);
Draw_AlphaFill(x, y, team1_width, bar_height, team1_color, opacity);
y += bar_height;
Draw_AlphaFill(x, y, team2_width, bar_height, team2_color, opacity);
}
void TeamHold_DrawPercentageBar(int x, int y, int width, int height,
float team1_percent, float team2_percent,
int team1_color, int team2_color,
int show_text, int vertical,
int vertical_text, float opacity)
{
int _x, _y;
int _width, _height;
if(vertical)
{
//
// Draw vertical.
//
// Team 1.
_x = x;
_y = y;
_width = max(0, width);
_height = Q_rint(height * team1_percent);
_height = max(0, height);
Draw_AlphaFill(_x, _y, _width, _height, team1_color, opacity);
// Team 2.
_x = x;
_y = Q_rint(y + (height * team1_percent));
_width = max(0, width);
_height = Q_rint(height * team2_percent);
_height = max(0, _height);
Draw_AlphaFill(_x, _y, _width, _height, team2_color, opacity);
// Show the percentages in numbers also.
if(show_text)
{
// TODO: Move this to a separate function (since it's prett much copy and paste for both teams).
// Team 1.
if(team1_percent > 0.05)
{
if(vertical_text)
{
int percent = 0;
int percent10 = 0;
int percent100 = 0;
_x = x + (width / 2) - 4;
_y = Q_rint(y + (height * team1_percent)/2 - 12);
percent = Q_rint(100 * team1_percent);
if((percent100 = percent / 100))
{
Draw_String(_x, _y, va("%d", percent100));
_y += 8;
}
if((percent10 = percent / 10))
{
Draw_String(_x, _y, va("%d", percent10));
_y += 8;
}
Draw_String(_x, _y, va("%d", percent % 10));
_y += 8;
Draw_String(_x, _y, "%");
}
else
{
_x = x + (width / 2) - 12;
_y = Q_rint(y + (height * team1_percent)/2 - 4);
Draw_String(_x, _y, va("%2.0f%%", 100 * team1_percent));
}
}
// Team 2.
if(team2_percent > 0.05)
{
if(vertical_text)
{
int percent = 0;
int percent10 = 0;
int percent100 = 0;
_x = x + (width / 2) - 4;
_y = Q_rint(y + (height * team1_percent) + (height * team2_percent)/2 - 12);
percent = Q_rint(100 * team2_percent);
if((percent100 = percent / 100))
{
Draw_String(_x, _y, va("%d", percent100));
_y += 8;
}
if((percent10 = percent / 10))
{
Draw_String(_x, _y, va("%d", percent10));
_y += 8;
}
Draw_String(_x, _y, va("%d", percent % 10));
_y += 8;
Draw_String(_x, _y, "%");
}
else
{
_x = x + (width / 2) - 12;
_y = Q_rint(y + (height * team1_percent) + (height * team2_percent)/2 - 4);
Draw_String(_x, _y, va("%2.0f%%", 100 * team2_percent));
}
}
}
}
else
{
//
// Draw horizontal.
//
// Team 1.
_x = x;
_y = y;
_width = Q_rint(width * team1_percent);
_width = max(0, _width);
_height = max(0, height);
Draw_AlphaFill(_x, _y, _width, _height, team1_color, opacity);
// Team 2.
_x = Q_rint(x + (width * team1_percent));
_y = y;
_width = Q_rint(width * team2_percent);
_width = max(0, _width);
_height = max(0, height);
Draw_AlphaFill(_x, _y, _width, _height, team2_color, opacity);
// Show the percentages in numbers also.
if(show_text)
{
// Team 1.
if(team1_percent > 0.05)
{
_x = Q_rint(x + (width * team1_percent)/2 - 8);
_y = y + (height / 2) - 4;
Draw_String(_x, _y, va("%2.0f%%", 100 * team1_percent));
}
// Team 2.
if(team2_percent > 0.05)
{
_x = Q_rint(x + (width * team1_percent) + (width * team2_percent)/2 - 8);
_y = y + (height / 2) - 4;
Draw_String(_x, _y, va("%2.0f%%", 100 * team2_percent));
}
}
}
}
#ifdef HAXX
static void SCR_HUD_DrawTeamHoldBar(hud_t *hud)
{
int x, y;
int height = 8;
int width = 0;
float team1_percent = 0;
float team2_percent = 0;
static cvar_t
*hud_teamholdbar_style = NULL,
*hud_teamholdbar_opacity,
*hud_teamholdbar_width,
*hud_teamholdbar_height,
*hud_teamholdbar_vertical,
*hud_teamholdbar_show_text,
*hud_teamholdbar_onlytp,
*hud_teamholdbar_vertical_text;
if (hud_teamholdbar_style == NULL) // first time
{
hud_teamholdbar_style = HUD_FindVar(hud, "style");
hud_teamholdbar_opacity = HUD_FindVar(hud, "opacity");
hud_teamholdbar_width = HUD_FindVar(hud, "width");
hud_teamholdbar_height = HUD_FindVar(hud, "height");
hud_teamholdbar_vertical = HUD_FindVar(hud, "vertical");
hud_teamholdbar_show_text = HUD_FindVar(hud, "show_text");
hud_teamholdbar_onlytp = HUD_FindVar(hud, "onlytp");
hud_teamholdbar_vertical_text = HUD_FindVar(hud, "vertical_text");
}
height = max(1, hud_teamholdbar_height->value);
width = max(0, hud_teamholdbar_width->value);
// Don't show when not in teamplay/demoplayback.
if(!HUD_ShowInDemoplayback(hud_teamholdbar_onlytp->value))
{
HUD_PrepareDraw(hud, width , height, &x, &y);
return;
}
if (HUD_PrepareDraw(hud, width , height, &x, &y))
{
// We need something to work with.
if(stats_grid != NULL)
{
// Check if we have any hold values to calculate from.
if(stats_grid->teams[STATS_TEAM1].hold_count + stats_grid->teams[STATS_TEAM2].hold_count > 0)
{
// Calculate the percentage for the two teams for the "team strength bar".
team1_percent = ((float)stats_grid->teams[STATS_TEAM1].hold_count) / (stats_grid->teams[STATS_TEAM1].hold_count + stats_grid->teams[STATS_TEAM2].hold_count);
team2_percent = ((float)stats_grid->teams[STATS_TEAM2].hold_count) / (stats_grid->teams[STATS_TEAM1].hold_count + stats_grid->teams[STATS_TEAM2].hold_count);
team1_percent = fabs(max(0, team1_percent));
team2_percent = fabs(max(0, team2_percent));
}
else
{
Draw_AlphaFill(x, y, hud_teamholdbar_width->value, height, 0, hud_teamholdbar_opacity->value*0.5);
return;
}
// Draw the percentage bar.
TeamHold_DrawPercentageBar(x, y, width, height,
team1_percent, team2_percent,
stats_grid->teams[STATS_TEAM1].color,
stats_grid->teams[STATS_TEAM2].color,
hud_teamholdbar_show_text->value,
hud_teamholdbar_vertical->value,
hud_teamholdbar_vertical_text->value,
hud_teamholdbar_opacity->value);
}
else
{
// If there's no stats grid available we don't know what to show, so just show a black frame.
Draw_AlphaFill(x, y, hud_teamholdbar_width->value, height, 0, hud_teamholdbar_opacity->value * 0.5);
}
}
}
#endif
void TeamHold_OnChangeItemFilterInfo(cvar_t *var, char *oldvalue)
{
// char *start = var->string;
// char *end = start;
// int order = 0;
// Parse the item filter.
teamhold_show_rl = Utils_RegExpMatch("RL", var->string);
teamhold_show_quad = Utils_RegExpMatch("QUAD", var->string);
teamhold_show_ring = Utils_RegExpMatch("RING", var->string);
teamhold_show_pent = Utils_RegExpMatch("PENT", var->string);
teamhold_show_suit = Utils_RegExpMatch("SUIT", var->string);
teamhold_show_lg = Utils_RegExpMatch("LG", var->string);
teamhold_show_gl = Utils_RegExpMatch("GL", var->string);
teamhold_show_sng = Utils_RegExpMatch("SNG", var->string);
teamhold_show_mh = Utils_RegExpMatch("MH", var->string);
teamhold_show_ra = Utils_RegExpMatch("RA", var->string);
teamhold_show_ya = Utils_RegExpMatch("YA", var->string);
teamhold_show_ga = Utils_RegExpMatch("GA", var->string);
#ifdef HAXX
// Reset the ordering of the items.
StatsGrid_ResetHoldItemsOrder();
// Trim spaces from the start of the word.
while (*start && *start == ' ')
{
start++;
}
end = start;
// Go through the string word for word and set a
// rising order for each hold item based on their
// order in the string.
while (*end)
{
if (*end != ' ')
{
// Not at the end of the word yet.
end++;
continue;
}
else
{
// We've found a word end.
char temp[256];
// Try matching the current word with a hold item
// and set it's ordering according to it's placement
// in the string.
strlcpy (temp, start, min(end - start, sizeof(temp)));
StatsGrid_SetHoldItemOrder(temp, order);
order++;
// Get rid of any additional spaces.
while (*end && *end == ' ')
{
end++;
}
// Start trying to find a new word.
start = end;
}
}
// Order the hold items.
StatsGrid_SortHoldItems();
#endif
}
#define HUD_TEAMHOLDINFO_STYLE_TEAM_NAMES 0
#define HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS 1
#define HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS2 2
#ifdef HAXX
static void SCR_HUD_DrawTeamHoldInfo(hud_t *hud)
{
int i;
int x, y;
int width, height;
static cvar_t
*hud_teamholdinfo_style = NULL,
*hud_teamholdinfo_opacity,
*hud_teamholdinfo_width,
*hud_teamholdinfo_height,
*hud_teamholdinfo_onlytp,
*hud_teamholdinfo_itemfilter;
if (hud_teamholdinfo_style == NULL) // first time
{
char val[256];
hud_teamholdinfo_style = HUD_FindVar(hud, "style");
hud_teamholdinfo_opacity = HUD_FindVar(hud, "opacity");
hud_teamholdinfo_width = HUD_FindVar(hud, "width");
hud_teamholdinfo_height = HUD_FindVar(hud, "height");
hud_teamholdinfo_onlytp = HUD_FindVar(hud, "onlytp");
hud_teamholdinfo_itemfilter = HUD_FindVar(hud, "itemfilter");
// Unecessary to parse the item filter string on each frame.
hud_teamholdinfo_itemfilter->OnChange = TeamHold_OnChangeItemFilterInfo;
// Parse the item filter the first time (trigger the OnChange function above).
strlcpy (val, hud_teamholdinfo_itemfilter->string, sizeof(val));
Cvar_Set (hud_teamholdinfo_itemfilter, val);
}
// Get the height based on how many items we have, or what the user has set it to.
height = max(0, hud_teamholdinfo_height->value);
width = max(0, hud_teamholdinfo_width->value);
// Don't show when not in teamplay/demoplayback.
if(!HUD_ShowInDemoplayback(hud_teamholdinfo_onlytp->value))
{
HUD_PrepareDraw(hud, width , height, &x, &y);
return;
}
// We don't have anything to show.
if(stats_important_ents == NULL || stats_grid == NULL)
{
HUD_PrepareDraw(hud, width , height, &x, &y);
return;
}
if (HUD_PrepareDraw(hud, width , height, &x, &y))
{
int _y = 0;
_y = y;
// Go through all the items and print the stats for them.
for(i = 0; i < stats_important_ents->count; i++)
{
float team1_percent;
float team2_percent;
int team1_hold_count = 0;
int team2_hold_count = 0;
int names_width = 0;
// Don't draw outside the specified height.
if((_y - y) + 8 > height)
{
break;
}
// If the item isn't of the specified type, then skip it.
if(!( (teamhold_show_rl && !strncmp(stats_important_ents->list[i].name, "RL", 2))
|| (teamhold_show_quad && !strncmp(stats_important_ents->list[i].name, "QUAD", 4))
|| (teamhold_show_ring && !strncmp(stats_important_ents->list[i].name, "RING", 4))
|| (teamhold_show_pent && !strncmp(stats_important_ents->list[i].name, "PENT", 4))
|| (teamhold_show_suit && !strncmp(stats_important_ents->list[i].name, "SUIT", 4))
|| (teamhold_show_lg && !strncmp(stats_important_ents->list[i].name, "LG", 2))
|| (teamhold_show_gl && !strncmp(stats_important_ents->list[i].name, "GL", 2))
|| (teamhold_show_sng && !strncmp(stats_important_ents->list[i].name, "SNG", 3))
|| (teamhold_show_mh && !strncmp(stats_important_ents->list[i].name, "MH", 2))
|| (teamhold_show_ra && !strncmp(stats_important_ents->list[i].name, "RA", 2))
|| (teamhold_show_ya && !strncmp(stats_important_ents->list[i].name, "YA", 2))
|| (teamhold_show_ga && !strncmp(stats_important_ents->list[i].name, "GA", 2))
))
{
continue;
}
// Calculate the width of the longest item name so we can use it for padding.
names_width = 8 * (stats_important_ents->longest_name + 1);
// Calculate the percentages of this item that the two teams holds.
team1_hold_count = stats_important_ents->list[i].teams_hold_count[STATS_TEAM1];
team2_hold_count = stats_important_ents->list[i].teams_hold_count[STATS_TEAM2];
team1_percent = ((float)team1_hold_count) / (team1_hold_count + team2_hold_count);
team2_percent = ((float)team2_hold_count) / (team1_hold_count + team2_hold_count);
team1_percent = fabs(max(0, team1_percent));
team2_percent = fabs(max(0, team2_percent));
// Write the name of the item.
Draw_ColoredString(x, _y, va("&cff0%s:", stats_important_ents->list[i].name), 0);
if(hud_teamholdinfo_style->value == HUD_TEAMHOLDINFO_STYLE_TEAM_NAMES)
{
//
// Prints the team name that holds the item.
//
if(team1_percent > team2_percent)
{
Draw_ColoredString(x + names_width, _y, stats_important_ents->teams[STATS_TEAM1].name, 0);
}
else if(team1_percent < team2_percent)
{
Draw_ColoredString(x + names_width, _y, stats_important_ents->teams[STATS_TEAM2].name, 0);
}
}
else if(hud_teamholdinfo_style->value == HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS)
{
//
// Show a percenteage bar for the item.
//
TeamHold_DrawPercentageBar(x + names_width, _y,
Q_rint(hud_teamholdinfo_width->value - names_width), 8,
team1_percent, team2_percent,
stats_important_ents->teams[STATS_TEAM1].color,
stats_important_ents->teams[STATS_TEAM2].color,
0, // Don't show percentage values, get's too cluttered.
false,
false,
hud_teamholdinfo_opacity->value);
}
else if(hud_teamholdinfo_style->value == HUD_TEAMHOLDINFO_STYLE_PERCENT_BARS2)
{
TeamHold_DrawBars(x + names_width, _y,
Q_rint(hud_teamholdinfo_width->value - names_width), 8,
team1_percent, team2_percent,
stats_important_ents->teams[STATS_TEAM1].color,
stats_important_ents->teams[STATS_TEAM2].color,
hud_teamholdinfo_opacity->value);
}
// Next line.
_y += 8;
}
}
}
#endif
static int SCR_HudDrawTeamInfoPlayer(teamplayerinfo_t *ti_cl, int x, int y, int maxname, int maxloc, qbool width_only, hud_t *hud);
#define FONTWIDTH 8
static void SCR_HUD_DrawTeamInfo(hud_t *hud)
{
int x, y, _y, width, height;
int i, j, k, slots_num, maxname, maxloc;
char tmp[1024], *nick;
teamplayerinfo_t ti_clients[MAX_CLIENTS];
extern qbool hud_editor;
static cvar_t
*hud_teaminfo_weapon_style = NULL,
*hud_teaminfo_align_right,
*hud_teaminfo_loc_width,
*hud_teaminfo_name_width,
*hud_teaminfo_show_enemies,
*hud_teaminfo_show_self,
*hud_teaminfo_scale;
if (hud_teaminfo_weapon_style == NULL) // first time
{
hud_teaminfo_weapon_style = HUD_FindVar(hud, "weapon_style");
hud_teaminfo_align_right = HUD_FindVar(hud, "align_right");
hud_teaminfo_loc_width = HUD_FindVar(hud, "loc_width");
hud_teaminfo_name_width = HUD_FindVar(hud, "name_width");
hud_teaminfo_show_enemies = HUD_FindVar(hud, "show_enemies");
hud_teaminfo_show_self = HUD_FindVar(hud, "show_self");
hud_teaminfo_scale = HUD_FindVar(hud, "scale");
}
// Don't update hud item unless first view is beeing displayed
// if ( CURRVIEW != 1 && CURRVIEW != 0)
// return;
slots_num = clientfuncs->GetTeamInfo?clientfuncs->GetTeamInfo(ti_clients, countof(ti_clients), hud_teaminfo_show_enemies->ival, hud_teaminfo_show_self->ival?-1:0):0;
// fill data we require to draw teaminfo
for ( maxloc = maxname = i = 0; i < slots_num; i++ ) {
// dynamically guess max length of name/location
nick = (ti_clients[i].nick[0] ? ti_clients[i].nick : cl.players[i].name); // we use nick or name
maxname = max(maxname, strlen(TP_ParseFunChars(nick, false)));
strlcpy(tmp, TP_LocationName(ti_clients[i].org), sizeof(tmp));
maxloc = max(maxloc, strlen(TP_ParseFunChars(tmp, false)));
}
// well, better use fixed loc length
maxloc = bound(0, hud_teaminfo_loc_width->ival, 100);
// limit name length
maxname = bound(0, maxname, hud_teaminfo_name_width->ival);
// this does't draw anything, just calculate width
width = FONTWIDTH * hud_teaminfo_scale->value * SCR_HudDrawTeamInfoPlayer(&ti_clients[0], 0, 0, maxname, maxloc, true, hud);
height = FONTWIDTH * hud_teaminfo_scale->value * (hud_teaminfo_show_enemies->ival?slots_num+n_teams:slots_num);
if (hud_editor)
HUD_PrepareDraw(hud, width , FONTWIDTH, &x, &y);
if ( !slots_num )
return;
if (!cl.teamplay) // non teamplay mode
return;
if (!HUD_PrepareDraw(hud, width , height, &x, &y))
return;
_y = y ;
x = (hud_teaminfo_align_right->value ? x - (width * (FONTWIDTH * hud_teaminfo_scale->value)) : x);
// If multiple teams are displayed then sort the display and print team header on overlay
k=0;
if (hud_teaminfo_show_enemies->ival)
{
while (sorted_teams[k].name)
{
Draw_SString (x, _y, sorted_teams[k].name, hud_teaminfo_scale->value);
sprintf(tmp,"%s %i",TP_ParseFunChars("$.",false), sorted_teams[k].frags);
Draw_SString (x+(strlen(sorted_teams[k].name)+1)*FONTWIDTH, _y, tmp, hud_teaminfo_scale->value);
_y += FONTWIDTH * hud_teaminfo_scale->value;
for ( j = 0; j < slots_num; j++ )
{
i = ti_clients[j].client;
if (!strcmp(cl.players[i].team,sorted_teams[k].name))
{
SCR_HudDrawTeamInfoPlayer(&ti_clients[j], x, _y, maxname, maxloc, false, hud);
_y += FONTWIDTH * hud_teaminfo_scale->value;
}
}
k++;
}
}
else
{
for ( j = 0; j < slots_num; j++ ) {
SCR_HudDrawTeamInfoPlayer(&ti_clients[j], x, _y, maxname, maxloc, false, hud);
_y += FONTWIDTH * hud_teaminfo_scale->value;
}
}
}
qbool Has_Both_RL_and_LG (int flags) { return (flags & IT_ROCKET_LAUNCHER) && (flags & IT_LIGHTNING); }
#define FONTWIDTH 8
void str_align_right (char *target, size_t size, const char *source, size_t length)
{
if (length > size - 1)
length = size - 1;
if (strlen(source) >= length) {
strlcpy(target, source, size);
target[length] = 0;
} else {
int i;
for (i = 0; i < length - strlen(source); i++) {
target[i] = ' ';
}
strlcpy(target + i, source, size - i);
}
}
int Player_GetTrackId(int uid)
{
return uid;
}
unsigned int BestWeaponFromStatItems(unsigned int items)
{
int i;
for (i = 1<<7; i; i>>=1)
{
if (items & i)
return i;
}
return 0;
}
mpic_t * SCR_GetWeaponIconByFlag (int flag)
{
int i, j;
for (i = 0, j = 1; i < 7; i++, j*=2)
{
if (flag == j)
return sb_weapons[0][i];
}
return NULL;
}
static int SCR_HudDrawTeamInfoPlayer(teamplayerinfo_t *ti_cl, int x, int y, int maxname, int maxloc, qbool width_only, hud_t *hud)
{
extern mpic_t * SCR_GetWeaponIconByFlag (int flag);
char *s, *loc, tmp[1024], tmp2[1024], *aclr;
int x_in = x; // save x
int i;
mpic_t *pic;
float scale = HUD_FindVar(hud, "scale")->value;
if (!ti_cl)
return 0;
i = ti_cl->client;
if (i < 0 || i >= MAX_CLIENTS)
{
Com_DPrintf("SCR_Draw_TeamInfoPlayer: wrong client %d\n", i);
return 0;
}
// this limit len of string because TP_ParseFunChars() do not check overflow
strlcpy(tmp2, HUD_FindVar(hud, "layout")->string , sizeof(tmp2));
strlcpy(tmp2, TP_ParseFunChars(tmp2, false), sizeof(tmp2));
s = tmp2;
//
// parse/draw string like this "%n %h:%a %l %p %w"
//
for ( ; *s; s++) {
switch( (int) s[0] ) {
case '%':
s++; // advance
switch( (int) s[0] ) {
case 'n': // draw name
if(!width_only) {
char *nick = TP_ParseFunChars(ti_cl->nick[0] ? ti_cl->nick : cl.players[i].name, false);
str_align_right(tmp, sizeof(tmp), nick, maxname);
Draw_SString (x, y, tmp, scale);
}
x += maxname * FONTWIDTH * scale;
break;
case 'w': // draw "best" weapon icon/name
switch (HUD_FindVar(hud, "weapon_style")->ival) {
case 1:
if(!width_only) {
if (Has_Both_RL_and_LG(ti_cl->items)) {
char *weap_str = cvarfuncs->GetNVFDG("tp_name_rlg", "rlg", 0, NULL, NULL)->string;
char weap_white_stripped[32];
Util_SkipChars(weap_str, "{}", weap_white_stripped, 32);
Draw_ColoredString (x, y, weap_white_stripped, false);
}
else {
char *weap_str = TP_ItemName(BestWeaponFromStatItems( ti_cl->items ));
char weap_white_stripped[32];
Util_SkipChars(weap_str, "{}", weap_white_stripped, 32);
Draw_ColoredString (x, y, weap_white_stripped, false);
}
}
x += 3 * FONTWIDTH * scale;
break;
default: // draw image by default
if(!width_only)
if ( (pic = SCR_GetWeaponIconByFlag(BestWeaponFromStatItems( ti_cl->items ))) )
Draw_SPic (x, y, pic, 0.5 * scale);
x += 2 * FONTWIDTH * scale;
break;
}
break;
case 'h': // draw health, padding with space on left side
case 'H': // draw health, padding with space on right side
if(!width_only) {
snprintf(tmp, sizeof(tmp), (s[0] == 'h' ? "%s%3d" : "%s%-3d"), (ti_cl->health < HUD_FindVar(hud, "low_health")->ival ? "&cf00" : ""), (int)ti_cl->health);
Draw_SString (x, y, tmp, scale);
}
x += 3 * FONTWIDTH * scale;
break;
case 'a': // draw armor, padded with space on left side
case 'A': // draw armor, padded with space on right side
aclr = "";
//
// different styles of armor
//
switch (HUD_FindVar(hud,"armor_style")->ival) {
case 1: // image prefixed armor value
if(!width_only) {
if (ti_cl->items & IT_ARMOR3)
Draw_SPic (x, y, sb_armor[2], 1.0/3 * scale);
else if (ti_cl->items & IT_ARMOR2)
Draw_SPic (x, y, sb_armor[1], 1.0/3 * scale);
else if (ti_cl->items & IT_ARMOR1)
Draw_SPic (x, y, sb_armor[0], 1.0/3 * scale);
}
x += FONTWIDTH * scale;
break;
case 2: // colored background of armor value
/*
if(!width_only) {
byte col[4] = {255, 255, 255, 0};
if (ti_cl->items & IT_ARMOR3) {
col[0] = 255; col[1] = 0; col[2] = 0; col[3] = 255;
}
else if (ti_cl->items & IT_ARMOR2) {
col[0] = 255; col[1] = 255; col[2] = 0; col[3] = 255;
}
else if (ti_cl->items & IT_ARMOR1) {
col[0] = 0; col[1] = 255; col[2] = 0; col[3] = 255;
}
}
*/
break;
case 3: // colored armor value
if(!width_only) {
if (ti_cl->items & IT_ARMOR3)
aclr = "&cf00";
else if (ti_cl->items & IT_ARMOR2)
aclr = "&cff0";
else if (ti_cl->items & IT_ARMOR1)
aclr = "&c0f0";
}
break;
case 4: // armor value prefixed with letter
if(!width_only) {
if (ti_cl->items & IT_ARMOR3)
Draw_SString (x, y, "r", scale);
else if (ti_cl->items & IT_ARMOR2)
Draw_SString (x, y, "y", scale);
else if (ti_cl->items & IT_ARMOR1)
Draw_SString (x, y, "g", scale);
}
x += FONTWIDTH * scale;
break;
}
if(!width_only) { // value drawed no matter which style
snprintf(tmp, sizeof(tmp), (s[0] == 'a' ? "%s%3d" : "%s%-3d"), aclr, (int)ti_cl->armor);
Draw_SString (x, y, tmp, scale);
}
x += 3 * FONTWIDTH * scale;
break;
case 'l': // draw location
if(!width_only) {
loc = TP_LocationName(ti_cl->org);
if (!loc[0])
loc = "unknown";
str_align_right(tmp, sizeof(tmp), TP_ParseFunChars(loc, false), maxloc);
Draw_SString (x, y, tmp, scale);
}
x += maxloc * FONTWIDTH * scale;
break;
case 'p': // draw powerups
switch (HUD_FindVar(hud, "powerup_style")->ival) {
case 1: // quad/pent/ring image
if(!width_only) {
if (ti_cl->items & IT_QUAD)
Draw_SPic (x, y, sb_items[5], 1.0/2);
x += FONTWIDTH;
if (ti_cl->items & IT_INVULNERABILITY)
Draw_SPic (x, y, sb_items[3], 1.0/2);
x += FONTWIDTH;
if (ti_cl->items & IT_INVISIBILITY)
Draw_SPic (x, y, sb_items[2], 1.0/2);
x += FONTWIDTH;
}
else { x += 3* FONTWIDTH; }
break;
case 2: // player powerup face
if(!width_only) {
if ( sb_face_quad && (ti_cl->items & IT_QUAD))
Draw_SPic (x, y, sb_face_quad, 1.0/3);
x += FONTWIDTH;
if ( sb_face_invuln && (ti_cl->items & IT_INVULNERABILITY))
Draw_SPic (x, y, sb_face_invuln, 1.0/3);
x += FONTWIDTH;
if ( sb_face_invis && (ti_cl->items & IT_INVISIBILITY))
Draw_SPic (x, y, sb_face_invis, 1.0/3);
x += FONTWIDTH;
}
else { x += 3* FONTWIDTH; }
break;
case 3: // colored font (QPR)
if(!width_only) {
if (ti_cl->items & IT_QUAD)
Draw_ColoredString (x, y, "&c03fQ", false);
x += FONTWIDTH;
if (ti_cl->items & IT_INVULNERABILITY)
Draw_ColoredString (x, y, "&cf00P", false);
x += FONTWIDTH;
if (ti_cl->items & IT_INVISIBILITY)
Draw_ColoredString (x, y, "&cff0R", false);
x += FONTWIDTH;
}
else { x += 3* FONTWIDTH; }
break;
}
break;
case 't':
if(!width_only)
{
sprintf(tmp, "%i", Player_GetTrackId(cl.players[ti_cl->client].userid));
Draw_SString (x, y, tmp, scale);
}
x += FONTWIDTH * scale; // will break if tracknumber is double digits
break;
case '%': // wow, %% result in one %, how smart
if(!width_only)
Draw_SString (x, y, "%", scale);
x += FONTWIDTH * scale;
break;
default: // print %x - that mean sequence unknown
if(!width_only) {
snprintf(tmp, sizeof(tmp), "%%%c", s[0]);
Draw_SString (x, y, tmp, scale);
}
x += (s[0] ? 2 : 1) * FONTWIDTH * scale;
break;
}
break;
default: // print x
if(!width_only) {
snprintf(tmp, sizeof(tmp), "%c", s[0]);
if (s[0] != ' ') // inhuman smart optimization, do not print space!
Draw_SString (x, y, tmp, scale);
}
x += FONTWIDTH * scale;
break;
}
}
return (x - x_in) / (FONTWIDTH * scale); // return width
}
#ifdef HAXX
void SCR_HUD_DrawItemsClock(hud_t *hud)
{
extern qbool hud_editor;
int width, height;
int x, y;
static cvar_t *hud_itemsclock_timelimit = NULL, *hud_itemsclock_style;
if (hud_itemsclock_timelimit == NULL) {
hud_itemsclock_timelimit = HUD_FindVar(hud, "timelimit");
hud_itemsclock_style = HUD_FindVar(hud, "style");
}
MVD_ClockList_TopItems_DimensionsGet(hud_itemsclock_timelimit->value, hud_itemsclock_style->ival, &width, &height);
if (hud_editor)
HUD_PrepareDraw(hud, width, LETTERHEIGHT, &x, &y);
if (!height)
return;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
MVD_ClockList_TopItems_Draw(hud_itemsclock_timelimit->value, hud_itemsclock_style->ival, x, y);
}
#endif
//
// TODO: decide what to do in freefly mode (and how to catch it?!), now all score_* hud elements just draws "0"
//
void SCR_HUD_DrawScoresTeam(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *digits, *align, *colorize;
int value = 0;
int i;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
colorize = HUD_FindVar(hud, "colorize");
}
//
// AAS: someone please tell me how to do it in a proper way!
//
if(cl.teamplay)
{
for(i = 0; i < n_teams; i++)
{
// playing qwd demo || mvd spec/demo || playing
if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ||
((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) ||
(strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) )
{
value = sorted_teams[i].frags;
break;
}
}
}
else if(cl.deathmatch)
{
for(i = 0; i < n_players; i++)
{
if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ||
((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) ||
(strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) )
{
value = cl.players[sorted_players[i].playernum].frags;
break;
}
}
}
SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string);
}
void SCR_HUD_DrawScoresEnemy(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *digits, *align, *colorize;
int value = 0;
int i;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
colorize = HUD_FindVar(hud, "colorize");
}
//
// AAS: voodoo, again
//
if(cl.teamplay)
{
for(i = 0; i < n_teams; i++)
{
if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ||
((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) ||
(strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) )
{
if(n_teams > 1)
value = sorted_teams[i == 0 ? 1 : 0].frags;
break;
}
}
}
else if(cl.deathmatch)
{
for(i = 0; i < n_players; i++)
{
if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ||
((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) ||
(strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) )
{
if(n_players > 1)
value = cl.players[sorted_players[i == 0 ? 1 : 0].playernum].frags;
break;
}
}
}
SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string);
}
void SCR_HUD_DrawScoresDifference(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *digits, *align, *colorize;
int value = 0;
int i;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
colorize = HUD_FindVar(hud, "colorize");
}
//
// AAS: more voodoo
//
if(cl.teamplay)
{
for(i = 0; i < n_teams; i++)
{
if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ||
((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) ||
(strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) )
{
if(i == 0)
{
if(n_teams > 1)
value = sorted_teams[0].frags - sorted_teams[1].frags;
else
value = sorted_teams[0].frags;
}
else
{
if(n_teams > 1)
value = sorted_teams[i].frags - sorted_teams[0].frags;
}
break;
}
}
}
else if(cl.deathmatch)
{
for(i = 0; i < n_players; i++)
{
if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ||
((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) ||
(strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) )
{
if(i == 0)
{
if(n_players > 1)
value = cl.players[sorted_players[0].playernum].frags - cl.players[sorted_players[1].playernum].frags;
else
value = cl.players[sorted_players[0].playernum].frags;
}
else
{
if(n_players > 1)
value = cl.players[sorted_players[i].playernum].frags - cl.players[sorted_players[0].playernum].frags;
}
break;
}
}
}
SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string);
}
void SCR_HUD_DrawScoresPosition(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *digits, *align, *colorize;
int value = 0;
int i;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
digits = HUD_FindVar(hud, "digits");
align = HUD_FindVar(hud, "align");
colorize = HUD_FindVar(hud, "colorize");
}
//
// AAS: someone, please stop me
//
if(cl.teamplay)
{
for(i = 0; i < n_teams; i++)
{
if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ||
((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) ||
(strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) )
{
value = i;
break;
}
}
}
else if(cl.deathmatch)
{
for(i = 0; i < n_players; i++)
{
if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ||
((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) ||
(strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) )
{
value = i;
break;
}
}
}
SCR_HUD_DrawNum(hud, value, (colorize->ival) ? (value < 0 || colorize->ival > 1) : false, scale->value, style->value, digits->value, align->string);
}
/*
ezQuake's analogue of +scores of KTX
( t:x e:x [x] )
*/
void SCR_HUD_DrawScoresBar(hud_t *hud)
{
static cvar_t *scale = NULL, *style, *format_big, *format_small;
int width = 0, height = 0, x, y;
int i = 0;
int s_team = 0, s_enemy = 0, s_difference = 0;
char *n_team = "T", *n_enemy = "E";
char buf[256];
char c, *out, *temp, *in;
if (scale == NULL) // first time called
{
scale = HUD_FindVar(hud, "scale");
style = HUD_FindVar(hud, "style");
format_big = HUD_FindVar(hud, "format_big");
format_small= HUD_FindVar(hud, "format_small");
}
//
// AAS: nightmare comes back
//
if(cl.teamplay)
{
for(i = 0; i < n_teams; i++)
{
if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) ||
((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].team, sorted_teams[i].name) == 0) && (Cam_TrackNum() >= 0))) ||
(strcmp(sorted_teams[i].name, cl.players[cl.playernum].team) == 0) )
{
s_team = sorted_teams[i].frags;
n_team = sorted_teams[i].name;
if(n_teams > 1)
{
s_enemy = sorted_teams[i == 0 ? 1 : 0].frags;
n_enemy = sorted_teams[i == 0 ? 1 : 0].name;
}
s_difference = s_team - s_enemy;
break;
}
}
}
else if(cl.deathmatch)
{
for(i = 0; i < n_players; i++)
{
if( (cls.demoplayback && !cl.spectator && !cls.mvdplayback && strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) ||
((cls.demoplayback || cl.spectator) && ((strcmp(cl.players[spec_track].name, cl.players[sorted_players[i].playernum].name) == 0) && (Cam_TrackNum() >= 0))) ||
(strcmp(cl.players[sorted_players[i].playernum].name, cl.players[cl.playernum].name) == 0) )
{
s_team = cl.players[sorted_players[i].playernum].frags;
if(n_players > 1)
{
s_enemy = cl.players[sorted_players[i == 0 ? 1 : 0].playernum].frags;
}
s_difference = s_team - s_enemy;
break;
}
}
}
// two pots of delicious customized copypasta from math_tools.c
switch(style->ival)
{
// Big
case 1:
in = TP_ParseFunChars(format_big->string, false);
buf[0] = 0;
out = buf;
while((c = *in++) && (out - buf < sizeof(buf) - 1))
{
if((c == '%') && *in)
{
switch((c = *in++))
{
// c = colorize, r = reset
case 'd':
temp = va("%d", s_difference);
width += (s_difference >= 0) ? strlen(temp) * 24 : ((strlen(temp) - 1) * 24) + 16;
break;
case 'D':
temp = va("c%dr", s_difference);
width += (s_difference >= 0) ? (strlen(temp) - 2) * 24 : ((strlen(temp) - 3) * 24) + 16;
break;
case 'e':
temp = va("%d", s_enemy);
width += (s_enemy >= 0) ? strlen(temp) * 24 : ((strlen(temp) - 1) * 24) + 16;
break;
case 'E':
temp = va("c%dr", s_enemy);
width += (s_enemy >= 0) ? (strlen(temp) - 2) * 24 : ((strlen(temp) - 3) * 24) + 16;
break;
case 'p':
temp = va("%d", i + 1);
width += 24;
break;
case 't':
temp = va("%d", s_team);
width += (s_team >= 0) ? strlen(temp) * 24 : ((strlen(temp) - 1) * 24) + 16;
break;
case 'T':
temp = va("c%dr", s_team);
width += (s_team >= 0) ? (strlen(temp) - 2) * 24 : ((strlen(temp) - 3) * 24) + 16;
break;
case 'z':
if(s_difference >= 0)
{
temp = va("%d", s_difference);
width += strlen(temp) * 24;
}
else
{
temp = va("c%dr", -(s_difference));
width += (strlen(temp) - 2) * 24;
}
break;
case 'Z':
if(s_difference >= 0)
{
temp = va("c%dr", s_difference);
width += (strlen(temp) - 2) * 24;
}
else
{
temp = va("%d", -(s_difference));
width += strlen(temp) * 24;
}
break;
default:
temp = NULL;
break;
}
if(temp != NULL)
{
strlcpy(out, temp, sizeof(buf) - (out - buf));
out += strlen(temp);
}
}
else if (c == ':' || c == '/' || c == '-' || c == ' ')
{
width += 16;
*out++ = c;
}
}
*out = 0;
break;
// Small
case 0:
default:
in = TP_ParseFunChars(format_small->string, false);
buf[0] = 0;
out = buf;
while((c = *in++) && (out - buf < sizeof(buf) - 1))
{
if((c == '%') && *in)
{
switch((c = *in++))
{
case '%':
temp = "%";
break;
case 't':
temp = va("%d", s_team);
break;
case 'e':
temp = va("%d", s_enemy);
break;
case 'd':
temp = va("%d", s_difference);
break;
case 'p':
temp = va("%d", i + 1);
break;
case 'T':
temp = n_team;
break;
case 'E':
temp = n_enemy;
break;
case 'D':
temp = va("%+d", s_difference);
break;
default:
temp = va("%%%c", c);
break;
}
strlcpy(out, temp, sizeof(buf) - (out - buf));
out += strlen(temp);
}
else
{
*out++ = c;
}
}
*out = 0;
break;
}
switch(style->ival)
{
// Big
case 1:
width *= scale->value;
height = 24 * scale->value;
if(HUD_PrepareDraw(hud, width, height, &x, &y))
{
SCR_DrawWadString(x, y, scale->value, buf);
}
break;
// Small
case 0:
default:
width = 8 * strlen_color(buf) * scale->value;
height = 8 * scale->value;
if(HUD_PrepareDraw(hud, width, height, &x, &y))
{
Draw_SString(x, y, buf, scale->value);
}
break;
}
}
void SCR_HUD_DrawBarArmor(hud_t *hud)
{
static cvar_t *width = NULL, *height, *direction, *color_noarmor, *color_ga, *color_ya, *color_ra, *color_unnatural;
int x, y;
int armor = HUD_Stats(STAT_ARMOR);
qbool alive = cl.stats[STAT_HEALTH] > 0;
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
direction = HUD_FindVar(hud, "direction");
color_noarmor = HUD_FindVar(hud, "color_noarmor");
color_ga = HUD_FindVar(hud, "color_ga");
color_ya = HUD_FindVar(hud, "color_ya");
color_ra = HUD_FindVar(hud, "color_ra");
color_unnatural = HUD_FindVar(hud, "color_unnatural");
}
if(HUD_PrepareDraw(hud, width->ival, height->ival, &x, &y))
{
if(!width->ival || !height->ival)
return;
if(HUD_Stats(STAT_ITEMS) & IT_INVULNERABILITY && alive)
{
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_unnatural->vec4, x, y, width->ival, height->ival);
}
else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR3 && alive)
{
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival);
SCR_HUD_DrawBar(direction->ival, armor, 200.0, color_ra->vec4, x, y, width->ival, height->ival);
}
else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR2 && alive)
{
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival);
SCR_HUD_DrawBar(direction->ival, armor, 150.0, color_ya->vec4, x, y, width->ival, height->ival);
}
else if (HUD_Stats(STAT_ITEMS) & IT_ARMOR1 && alive)
{
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival);
SCR_HUD_DrawBar(direction->ival, armor, 100.0, color_ga->vec4, x, y, width->ival, height->ival);
}
else
{
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_noarmor->vec4, x, y, width->ival, height->ival);
}
}
}
void SCR_HUD_DrawBarHealth(hud_t *hud)
{
static cvar_t *width = NULL, *height, *direction, *color_nohealth, *color_normal, *color_mega, *color_twomega, *color_unnatural;
int x, y;
int health = cl.stats[STAT_HEALTH];
if (width == NULL) // first time called
{
width = HUD_FindVar(hud, "width");
height = HUD_FindVar(hud, "height");
direction = HUD_FindVar(hud, "direction");
color_nohealth = HUD_FindVar(hud, "color_nohealth");
color_normal = HUD_FindVar(hud, "color_normal");
color_mega = HUD_FindVar(hud, "color_mega");
color_twomega = HUD_FindVar(hud, "color_twomega");
color_unnatural = HUD_FindVar(hud, "color_unnatural");
}
if(HUD_PrepareDraw(hud, width->ival, height->ival, &x, &y))
{
if(!width->ival || !height->ival)
return;
if(health > 250)
{
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_unnatural->vec4, x, y, width->ival, height->ival);
}
else if(health > 200)
{
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_normal->vec4, x, y, width->ival, height->ival);
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_mega->vec4, x, y, width->ival, height->ival);
SCR_HUD_DrawBar(direction->ival, health - 200, 100.0, color_twomega->vec4, x, y, width->ival, height->ival);
}
else if(health > 100)
{
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_normal->vec4, x, y, width->ival, height->ival);
SCR_HUD_DrawBar(direction->ival, health - 100, 100.0, color_mega->vec4, x, y, width->ival, height->ival);
}
else if(health > 0)
{
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_nohealth->vec4, x, y, width->ival, height->ival);
SCR_HUD_DrawBar(direction->ival, health, 100.0, color_normal->vec4, x, y, width->ival, height->ival);
}
else
{
SCR_HUD_DrawBar(direction->ival, 100, 100.0, color_nohealth->vec4, x, y, width->ival, height->ival);
}
}
}
void SCR_HUD_DrawOwnFrags(hud_t *hud)
{
// not implemented yet: scale, color
// fixme: add appropriate opengl functions that will add alpha, scale and color
char ownfragtext[256];
float age;
int width;
int height = 8;
int x, y;
double alpha;
static cvar_t
*hud_ownfrags_timeout = NULL,
*hud_ownfrags_scale = NULL;
// *hud_ownfrags_color = NULL;
extern qbool hud_editor;
if (hud_ownfrags_timeout == NULL) // first time
{
hud_ownfrags_scale = HUD_FindVar(hud, "scale");
// hud_ownfrags_color = HUD_FindVar(hud, "color");
hud_ownfrags_timeout = HUD_FindVar(hud, "timeout");
}
if (hud_editor)
{
strcpy(ownfragtext, "Own Frags");
age = 0;
}
else if (clientfuncs->GetTrackerOwnFrags)
age = clientfuncs->GetTrackerOwnFrags(0, ownfragtext, sizeof(ownfragtext));
else
age = 999999;
width = strlen(ownfragtext)*8;
width *= hud_ownfrags_scale->value;
height *= hud_ownfrags_scale->value;
if (age >= hud_ownfrags_timeout->value)
width = 0;
alpha = 2 - age / hud_ownfrags_timeout->value * 2;
alpha = bound(0, alpha, 1);
if (!width)
{
HUD_PrepareDraw(hud, width, height, NULL, NULL);
return;
}
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
drawfuncs->Colour4f(1, 1, 1, alpha);
Draw_SString(x, y, ownfragtext, hud_ownfrags_scale->value);
drawfuncs->Colour4f(1, 1, 1, 1);
}
#ifdef QUAKEHUD
static struct wstats_s *findweapon(struct wstats_s *w, size_t wc, char *wn)
{
for (; wc>0; wc--, w++)
{
if (!strcmp(wn, w->wname))
return w;
}
return NULL;
}
static void SCR_HUD_DrawWeaponStats(hud_t *hud)
{
char line[1024], *o, *i;
int width;
int height = 8;
int x, y;
static cvar_t *hud_weaponstats_scale = NULL;
static cvar_t *hud_weaponstats_fmt = NULL;
extern qbool hud_editor;
int ws;
struct wstats_s wstats[16];
ws = clientfuncs->GetWeaponStats?clientfuncs->GetWeaponStats(-1, wstats, countof(wstats)):0;
if (hud_editor)
{
ws = 0;
strcpy(wstats[ws].wname, "axe");
wstats[ws].hit = 20;
wstats[ws].total = 100;
ws++;
strcpy(wstats[ws].wname, "rl");
wstats[ws].hit = 60;
wstats[ws].total = 120;
ws++;
strcpy(wstats[ws].wname, "lg");
wstats[ws].hit = 20;
wstats[ws].total = 100;
ws++;
}
if (hud_weaponstats_scale == NULL) // first time
{
hud_weaponstats_scale = HUD_FindVar(hud, "scale");
hud_weaponstats_fmt = HUD_FindVar(hud, "fmt");
// "&c990sg&r:[%sg] &c099ssg&r:[%ssg] &c900rl&r:[#rl] &c009lg&r:[%lg]"
}
height = 8;
for (o = line, i = hud_weaponstats_fmt->string; ws && *i && o < line+countof(line)-1; )
{
if (i[0] == '[' && (i[1] == '%' || i[1] == '#'))
{
struct wstats_s *w;
char wname[16];
int pct = i[1]=='%', j;
i+=2;
for (j = 0; *i && j < countof(wname)-1; j++)
{
if (*i == ']')
{
i++;
break;
}
wname[j] = *i++;
}
wname[j] = 0;
w = findweapon(wstats, ws, wname);
if (pct && w && w->total)
snprintf(wname, sizeof(wname), "%.1f", (100.0 * w->hit) / w->total);
else if (pct)
snprintf(wname, sizeof(wname), "%.1f", 0.0);
else if (w)
snprintf(wname, sizeof(wname), "%u", w->hit);
else
snprintf(wname, sizeof(wname), "%u", 0);
for (j = 0; wname[j] && o < line+countof(line)-1; j++)
*o++ = wname[j];
}
else if (*i == '\n')
{
height += 8;
*o++ = *i++;
}
else
*o++ = *i++;
}
*o++ = 0;
width = 8*strlen_color(line);
width *= hud_weaponstats_scale->value;
height *= hud_weaponstats_scale->value;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
Draw_SString(x, y, line, hud_weaponstats_scale->value);
}
#endif
void SCR_HUD_DrawKeys(hud_t *hud)
{
char line1[32], line2[32];
int width, height, x, y;
usercmd_t b;
static cvar_t* vscale = NULL;
float scale;
memset(&b, 0, sizeof(b));
clientfuncs->GetLastInputFrame(0, &b);
if (!vscale) {
vscale = HUD_FindVar(hud, "scale");
}
scale = vscale->value;
scale = max(0, scale);
snprintf(line1, sizeof(line1), "^{%x}^{%x}^{%x}",
0xe000 + 'x' + ((b.buttons & 1)?0x80:0),
0xe000 + '^' + ((b.forwardmove > 0)?0x80:0),
0xe000 + 'J' + ((b.buttons & 2)?0x80:0));
snprintf(line2, sizeof(line2), "^{%x}^{%x}^{%x}",
0xe000 + '<' + ((b.sidemove < 0)?0x80:0),
0xe000 + '_' + ((b.forwardmove < 0)?0x80:0),
0xe000 + '>' + ((b.sidemove > 0)?0x80:0));
width = 8 * 3 * scale;
height = 8 * 2 * scale;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
Draw_SString(x, y, line1, scale);
Draw_SString(x, y + 8*scale, line2, scale);
}
#ifdef WITH_PNG
// What stats to draw.
#define HUD_RADAR_STATS_NONE 0
#define HUD_RADAR_STATS_BOTH_TEAMS_HOLD 1
#define HUD_RADAR_STATS_TEAM1_HOLD 2
#define HUD_RADAR_STATS_TEAM2_HOLD 3
#define HUD_RADAR_STATS_BOTH_TEAMS_DEATHS 4
#define HUD_RADAR_STATS_TEAM1_DEATHS 5
#define HUD_RADAR_STATS_TEAM2_DEATHS 6
void Radar_DrawGrid(stats_weight_grid_t *grid, int x, int y, float scale, int pic_width, int pic_height, int style)
{
int row, col;
// Don't try to draw anything if we got no data.
if(grid == NULL || grid->cells == NULL || style == HUD_RADAR_STATS_NONE)
{
return;
}
// Go through all the cells and draw them based on their weight.
for(row = 0; row < grid->row_count; row++)
{
// Just to be safe if something went wrong with the allocation.
if(grid->cells[row] == NULL)
{
continue;
}
for(col = 0; col < grid->col_count; col++)
{
float weight = 0.0;
int color = 0;
float tl_x, tl_y; // The pixel coordinate of the top left corner of a grid cell.
float p_cell_length_x; // The pixel length of a cell.
float p_cell_length_y; // The pixel "length" on the Y-axis. We calculate this
// seperatly because we'll get errors when converting from
// quake coordinates -> pixel coordinates.
// Calculate the pixel coordinates of the top left corner of the current cell.
// (This is times 8 because the conversion formula was calculated from a .loc-file)
tl_x = (map_x_slope * (8.0 * grid->cells[row][col].tl_x) + map_x_intercept) * scale;
tl_y = (map_y_slope * (8.0 * grid->cells[row][col].tl_y) + map_y_intercept) * scale;
// Calculate the cell length in pixel length.
p_cell_length_x = map_x_slope*(8.0 * grid->cell_length) * scale;
p_cell_length_y = map_y_slope*(8.0 * grid->cell_length) * scale;
// Add rounding errors (so that we don't get weird gaps in the grid).
p_cell_length_x += tl_x - Q_rint(tl_x);
p_cell_length_y += tl_y - Q_rint(tl_y);
// Don't draw the stats stuff outside the picture.
if(tl_x + p_cell_length_x > pic_width || tl_y + p_cell_length_y > pic_height || x + tl_x < x || y + tl_y < y)
{
continue;
}
//
// Death stats.
//
if(grid->cells[row][col].teams[STATS_TEAM1].death_weight + grid->cells[row][col].teams[STATS_TEAM2].death_weight > 0)
{
weight = 0;
if(style == HUD_RADAR_STATS_BOTH_TEAMS_DEATHS || style == HUD_RADAR_STATS_TEAM1_DEATHS)
{
weight = grid->cells[row][col].teams[STATS_TEAM1].death_weight;
}
if(style == HUD_RADAR_STATS_BOTH_TEAMS_DEATHS || style == HUD_RADAR_STATS_TEAM2_DEATHS)
{
weight += grid->cells[row][col].teams[STATS_TEAM2].death_weight;
}
color = 79;
}
//
// Team stats.
//
{
// No point in drawing if we have no weight.
if(grid->cells[row][col].teams[STATS_TEAM1].weight + grid->cells[row][col].teams[STATS_TEAM2].weight <= 0
&& (style == HUD_RADAR_STATS_BOTH_TEAMS_HOLD
|| style == HUD_RADAR_STATS_TEAM1_HOLD
|| style == HUD_RADAR_STATS_TEAM2_HOLD))
{
continue;
}
// Get the team with the highest weight for this cell.
if(grid->cells[row][col].teams[STATS_TEAM1].weight > grid->cells[row][col].teams[STATS_TEAM2].weight
&& (style == HUD_RADAR_STATS_BOTH_TEAMS_HOLD
|| style == HUD_RADAR_STATS_TEAM1_HOLD))
{
weight = grid->cells[row][col].teams[STATS_TEAM1].weight;
color = stats_grid->teams[STATS_TEAM1].color;
}
else if(style == HUD_RADAR_STATS_BOTH_TEAMS_HOLD || style == HUD_RADAR_STATS_TEAM2_HOLD)
{
weight = grid->cells[row][col].teams[STATS_TEAM2].weight;
color = stats_grid->teams[STATS_TEAM2].color;
}
}
// Draw the cell in the color of the team with the
// biggest weight for this cell. Or draw deaths.
Draw_AlphaFill(
x + Q_rint(tl_x), // X.
y + Q_rint(tl_y), // Y.
Q_rint(p_cell_length_x), // Width.
Q_rint(p_cell_length_y), // Height.
color, // Color.
weight); // Alpha.
}
}
}
// The skinnum property in the entity_s structure is used
// for determening what type of armor to draw on the radar.
#define HUD_RADAR_GA 0
#define HUD_RADAR_YA 1
#define HUD_RADAR_RA 2
// Radar filters.
#define RADAR_SHOW_WEAPONS (radar_show_ssg || radar_show_ng || radar_show_sng || radar_show_gl || radar_show_rl || radar_show_lg)
static qbool radar_show_ssg = false;
static qbool radar_show_ng = false;
static qbool radar_show_sng = false;
static qbool radar_show_gl = false;
static qbool radar_show_rl = false;
static qbool radar_show_lg = false;
#define RADAR_SHOW_ITEMS (radar_show_backpacks || radar_show_health || radar_show_ra || radar_show_ya || radar_show_ga || radar_show_rockets || radar_show_nails || radar_show_cells || radar_show_shells || radar_show_quad || radar_show_pent || radar_show_ring || radar_show_suit)
static qbool radar_show_backpacks = false;
static qbool radar_show_health = false;
static qbool radar_show_ra = false;
static qbool radar_show_ya = false;
static qbool radar_show_ga = false;
static qbool radar_show_rockets = false;
static qbool radar_show_nails = false;
static qbool radar_show_cells = false;
static qbool radar_show_shells = false;
static qbool radar_show_quad = false;
static qbool radar_show_pent = false;
static qbool radar_show_ring = false;
static qbool radar_show_suit = false;
static qbool radar_show_mega = false;
#define RADAR_SHOW_OTHER (radar_show_gibs || radar_show_explosions || radar_show_nails_p || radar_show_rockets_p || radar_show_shaft_p || radar_show_teleport || radar_show_shotgun)
static qbool radar_show_nails_p = false;
static qbool radar_show_rockets_p = false;
static qbool radar_show_shaft_p = false;
static qbool radar_show_gibs = false;
static qbool radar_show_explosions = false;
static qbool radar_show_teleport = false;
static qbool radar_show_shotgun = false;
void Radar_OnChangeWeaponFilter(cvar_t *var, char *oldval)
{
// Parse the weapon filter.
radar_show_ssg = Utils_RegExpMatch("SSG|SUPERSHOTGUN|ALL", var->string);
radar_show_ng = Utils_RegExpMatch("([^S]|^)NG|NAILGUN|ALL", var->string); // Yes very ugly, but we don't want to match SNG.
radar_show_sng = Utils_RegExpMatch("SNG|SUPERNAILGUN|ALL", var->string);
radar_show_rl = Utils_RegExpMatch("RL|ROCKETLAUNCHER|ALL", var->string);
radar_show_gl = Utils_RegExpMatch("GL|GRENADELAUNCHER|ALL", var->string);
radar_show_lg = Utils_RegExpMatch("LG|SHAFT|LIGHTNING|ALL", var->string);
}
void Radar_OnChangeItemFilter(cvar_t *var, char *oldval)
{
// Parse the item filter.
radar_show_backpacks = Utils_RegExpMatch("BP|BACKPACK|ALL", var->string);
radar_show_health = Utils_RegExpMatch("HP|HEALTH|ALL", var->string);
radar_show_ra = Utils_RegExpMatch("RA|REDARMOR|ARMOR|ALL", var->string);
radar_show_ya = Utils_RegExpMatch("YA|YELLOWARMOR|ARMOR|ALL", var->string);
radar_show_ga = Utils_RegExpMatch("GA|GREENARMOR|ARMOR|ALL", var->string);
radar_show_rockets = Utils_RegExpMatch("ROCKETS|ROCKS|AMMO|ALL", var->string);
radar_show_nails = Utils_RegExpMatch("NAILS|SPIKES|AMMO|ALL", var->string);
radar_show_cells = Utils_RegExpMatch("CELLS|BATTERY|AMMO|ALL", var->string);
radar_show_shells = Utils_RegExpMatch("SHELLS|AMMO|ALL", var->string);
radar_show_quad = Utils_RegExpMatch("QUAD|POWERUPS|ALL", var->string);
radar_show_pent = Utils_RegExpMatch("PENT|PENTAGRAM|666|POWERUPS|ALL", var->string);
radar_show_ring = Utils_RegExpMatch("RING|INVISIBLE|EYES|POWERUPS|ALL", var->string);
radar_show_suit = Utils_RegExpMatch("SUIT|POWERUPS|ALL", var->string);
radar_show_mega = Utils_RegExpMatch("MH|MEGA|MEGAHEALTH|100\\+|ALL", var->string);
}
void Radar_OnChangeOtherFilter(cvar_t *var, char *oldval)
{
// Parse the "other" filter.
radar_show_nails_p = Utils_RegExpMatch("NAILS|PROJECTILES|ALL", var->string);
radar_show_rockets_p = Utils_RegExpMatch("ROCKETS|PROJECTILES|ALL", var->string);
radar_show_shaft_p = Utils_RegExpMatch("SHAFT|PROJECTILES|ALL", var->string);
radar_show_gibs = Utils_RegExpMatch("GIBS|ALL", var->string);
radar_show_explosions = Utils_RegExpMatch("EXPLOSIONS|ALL", var->string);
radar_show_teleport = Utils_RegExpMatch("TELE|ALL", var->string);
radar_show_shotgun = Utils_RegExpMatch("SHOTGUN|SG|BUCK|ALL", var->string);
}
#define HUD_COLOR_DEFAULT_TRANSPARENCY 75
byte hud_radar_highlight_color[4] = {255, 255, 0, HUD_COLOR_DEFAULT_TRANSPARENCY};
void Radar_OnChangeHighlightColor(cvar_t *var, char *newval, qbool *cancel)
{
char *new_color;
char buf[MAX_COM_TOKEN];
// Translate a colors name to RGB values.
new_color = ColorNameToRGBString(newval);
// Parse the colors.
//color = StringToRGB(new_color);
strlcpy(buf,new_color,sizeof(buf));
memcpy(hud_radar_highlight_color, StringToRGB(buf), sizeof(byte) * 4);
// Set the cvar to contain the new color string
// (if the user entered "red" it will be "255 0 0").
Cvar_Set(var, new_color);
}
void Radar_DrawEntities(int x, int y, float scale, float player_size, int show_hold_areas)
{
int i;
// Entities (weapons and such). cl_main.c
extern visentlist_t cl_visents;
// Go through all the entities and draw the ones we're supposed to.
for (i = 0; i < cl_visents.count; i++)
{
int entity_q_x = 0;
int entity_q_y = 0;
int entity_p_x = 0;
int entity_p_y = 0;
// Get quake coordinates (times 8 to get them in the same format as .locs).
entity_q_x = cl_visents.list[i].origin[0]*8;
entity_q_y = cl_visents.list[i].origin[1]*8;
// Convert from quake coordiantes -> pixel coordinates.
entity_p_x = x + Q_rint((map_x_slope*entity_q_x + map_x_intercept) * scale);
entity_p_y = y + Q_rint((map_y_slope*entity_q_y + map_y_intercept) * scale);
// TODO: Replace all model name comparison below with MOD_HINT's instead for less comparisons (create new ones in Mod_LoadAliasModel() in r_model.c and gl_model.c/.h for the ones that don't have one already).
//
// Powerups.
//
if(radar_show_pent && !strcmp(cl_visents.list[i].model->name, "progs/invulner.mdl"))
{
// Pentagram.
Draw_ColoredString(entity_p_x, entity_p_y, "&cf00P", 0);
}
else if(radar_show_quad && !strcmp(cl_visents.list[i].model->name, "progs/quaddama.mdl"))
{
// Quad.
Draw_ColoredString(entity_p_x, entity_p_y, "&c0ffQ", 0);
}
else if(radar_show_ring && !strcmp(cl_visents.list[i].model->name, "progs/invisibl.mdl"))
{
// Ring.
Draw_ColoredString(entity_p_x, entity_p_y, "&cff0R", 0);
}
else if(radar_show_suit && !strcmp(cl_visents.list[i].model->name, "progs/suit.mdl"))
{
// Suit.
Draw_ColoredString(entity_p_x, entity_p_y, "&c0f0S", 0);
}
//
// Show RL, LG and backpacks.
//
if(radar_show_rl && !strcmp(cl_visents.list[i].model->name, "progs/g_rock2.mdl"))
{
// RL.
Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "RL");
}
else if(radar_show_lg && !strcmp(cl_visents.list[i].model->name, "progs/g_light.mdl"))
{
// LG.
Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "LG");
}
else if(radar_show_backpacks && cl_visents.list[i].model->modhint == MOD_BACKPACK)
{
// Back packs.
float back_pack_size = 0;
back_pack_size = max(player_size * 0.5, 0.05);
Draw_AlphaCircleFill (entity_p_x, entity_p_y, back_pack_size, 114, 1);
Draw_AlphaCircleOutline (entity_p_x, entity_p_y, back_pack_size, 1.0, 0, 1);
}
if(!strcmp(cl_visents.list[i].model->name, "progs/armor.mdl"))
{
//
// Show armors.
//
if(radar_show_ga && cl_visents.list[i].skinnum == HUD_RADAR_GA)
{
// GA.
Draw_AlphaCircleFill (entity_p_x, entity_p_y, 3.0, 178, 1.0);
}
else if(radar_show_ya && cl_visents.list[i].skinnum == HUD_RADAR_YA)
{
// YA.
Draw_AlphaCircleFill (entity_p_x, entity_p_y, 3.0, 192, 1.0);
}
else if(radar_show_ra && cl_visents.list[i].skinnum == HUD_RADAR_RA)
{
// RA.
Draw_AlphaCircleFill (entity_p_x, entity_p_y, 3.0, 251, 1.0);
}
Draw_AlphaCircleOutline (entity_p_x, entity_p_y, 3.0, 1.0, 0, 1.0);
}
if(radar_show_mega && !strcmp(cl_visents.list[i].model->name, "maps/b_bh100.bsp"))
{
//
// Show megahealth.
//
// Draw a red border around the cross.
Draw_AlphaRectangleRGB(entity_p_x - 3, entity_p_y - 3, 8, 8, 1, false, RGBA_TO_COLOR(200, 0, 0, 200));
// Draw a black outline cross.
Draw_AlphaFill(entity_p_x - 3, entity_p_y - 1, 8, 4, 0, 1);
Draw_AlphaFill(entity_p_x - 1, entity_p_y - 3, 4, 8, 0, 1);
// Draw a 2 pixel cross.
Draw_AlphaFill(entity_p_x - 2, entity_p_y, 6, 2, 79, 1);
Draw_AlphaFill(entity_p_x, entity_p_y - 2, 2, 6, 79, 1);
}
if(radar_show_ssg && !strcmp(cl_visents.list[i].model->name, "progs/g_shot.mdl"))
{
// SSG.
Draw_String(entity_p_x - (3*8)/2, entity_p_y - 4, "SSG");
}
else if(radar_show_ng && !strcmp(cl_visents.list[i].model->name, "progs/g_nail.mdl"))
{
// NG.
Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "NG");
}
else if(radar_show_sng && !strcmp(cl_visents.list[i].model->name, "progs/g_nail2.mdl"))
{
// SNG.
Draw_String(entity_p_x - (3*8)/2, entity_p_y - 4, "SNG");
}
else if(radar_show_gl && !strcmp(cl_visents.list[i].model->name, "progs/g_rock.mdl"))
{
// GL.
Draw_String(entity_p_x - (2*8)/2, entity_p_y - 4, "GL");
}
if(radar_show_gibs
&&(!strcmp(cl_visents.list[i].model->name, "progs/gib1.mdl")
|| !strcmp(cl_visents.list[i].model->name, "progs/gib2.mdl")
|| !strcmp(cl_visents.list[i].model->name, "progs/gib3.mdl")))
{
//
// Gibs.
//
Draw_AlphaCircleFill(entity_p_x, entity_p_y, 2.0, 251, 1);
}
if(radar_show_health
&&(!strcmp(cl_visents.list[i].model->name, "maps/b_bh25.bsp")
|| !strcmp(cl_visents.list[i].model->name, "maps/b_bh10.bsp")))
{
//
// Health.
//
// Draw a black outline cross.
Draw_AlphaFill (entity_p_x - 3, entity_p_y - 1, 7, 3, 0, 1);
Draw_AlphaFill (entity_p_x - 1, entity_p_y - 3, 3, 7, 0, 1);
// Draw a cross.
Draw_AlphaFill (entity_p_x - 2, entity_p_y, 5, 1, 79, 1);
Draw_AlphaFill (entity_p_x, entity_p_y - 2, 1, 5, 79, 1);
}
//
// Ammo.
//
if(radar_show_rockets
&&(!strcmp(cl_visents.list[i].model->name, "maps/b_rock0.bsp")
|| !strcmp(cl_visents.list[i].model->name, "maps/b_rock1.bsp")))
{
//
// Rockets.
//
// Draw a black outline.
Draw_AlphaFill (entity_p_x - 1, entity_p_y - 6, 3, 5, 0, 1);
Draw_AlphaFill (entity_p_x - 2, entity_p_y - 1, 5, 5, 0, 1);
// The brown rocket.
Draw_AlphaFill (entity_p_x, entity_p_y - 5, 1, 5, 120, 1);
Draw_AlphaFill (entity_p_x - 1, entity_p_y, 1, 3, 120, 1);
Draw_AlphaFill (entity_p_x + 1, entity_p_y, 1, 3, 120, 1);
}
if(radar_show_cells
&&(!strcmp(cl_visents.list[i].model->name, "maps/b_batt0.bsp")
|| !strcmp(cl_visents.list[i].model->name, "maps/b_batt1.bsp")))
{
//
// Cells.
//
// Draw a black outline.
Draw_AlphaLine(entity_p_x - 3, entity_p_y, entity_p_x + 4, entity_p_y - 5, 3, 0, 1);
Draw_AlphaLine(entity_p_x - 3, entity_p_y, entity_p_x + 3 , entity_p_y, 3, 0, 1);
Draw_AlphaLine(entity_p_x + 3, entity_p_y, entity_p_x - 3, entity_p_y + 4, 3, 0, 1);
// Draw a yellow lightning!
Draw_AlphaLine(entity_p_x - 2, entity_p_y, entity_p_x + 3, entity_p_y - 4, 1, 111, 1);
Draw_AlphaLine(entity_p_x - 2, entity_p_y, entity_p_x + 2 , entity_p_y, 1, 111, 1);
Draw_AlphaLine(entity_p_x + 2, entity_p_y, entity_p_x - 2, entity_p_y + 3, 1, 111, 1);
}
if(radar_show_nails
&&(!strcmp(cl_visents.list[i].model->name, "maps/b_nail0.bsp")
|| !strcmp(cl_visents.list[i].model->name, "maps/b_nail1.bsp")))
{
//
// Nails.
//
// Draw a black outline.
Draw_AlphaFill (entity_p_x - 3, entity_p_y - 3, 7, 3, 0, 1);
Draw_AlphaFill (entity_p_x - 2, entity_p_y - 2, 5, 3, 0, 0.5);
Draw_AlphaFill (entity_p_x - 1, entity_p_y, 3, 3, 0, 1);
Draw_AlphaFill (entity_p_x - 1, entity_p_y + 3, 1, 1, 0, 0.5);
Draw_AlphaFill (entity_p_x + 1, entity_p_y + 3, 1, 1, 0, 0.5);
Draw_AlphaFill (entity_p_x, entity_p_y + 4, 1, 1, 0, 1);
Draw_AlphaFill (entity_p_x - 2, entity_p_y - 2, 5, 1, 6, 1);
Draw_AlphaFill (entity_p_x - 1, entity_p_y - 1, 3, 1, 6, 0.5);
Draw_AlphaFill (entity_p_x, entity_p_y, 1, 4, 6, 1);
}
if(radar_show_shells
&&(!strcmp(cl_visents.list[i].model->name, "maps/b_shell0.bsp")
|| !strcmp(cl_visents.list[i].model->name, "maps/b_shell1.bsp")))
{
//
// Shells.
//
// Draw a black outline.
Draw_AlphaFill (entity_p_x - 2, entity_p_y - 3, 5, 9, 0, 1);
// Draw 2 shotgun shells.
Draw_AlphaFill (entity_p_x - 1, entity_p_y - 2, 1, 4, 73, 1);
Draw_AlphaFill (entity_p_x - 1, entity_p_y - 2 + 5, 1, 2, 104, 1);
Draw_AlphaFill (entity_p_x + 1, entity_p_y - 2, 1, 4, 73, 1);
Draw_AlphaFill (entity_p_x + 1, entity_p_y - 2 + 5, 1, 2, 104, 1);
}
//
// Show projectiles (rockets, grenades, nails, shaft).
//
if(radar_show_nails_p
&& (!strcmp(cl_visents.list[i].model->name, "progs/s_spike.mdl")
|| !strcmp(cl_visents.list[i].model->name, "progs/spike.mdl")))
{
//
// Spikes from SNG and NG.
//
Draw_AlphaFill(entity_p_x, entity_p_y, 1, 1, 254, 1);
}
else if(radar_show_rockets_p
&& (!strcmp(cl_visents.list[i].model->name, "progs/missile.mdl")
|| !strcmp(cl_visents.list[i].model->name, "progs/grenade.mdl")))
{
//
// Rockets and grenades.
//
float entity_angle = 0;
int x_line_end = 0;
int y_line_end = 0;
// Get the entity angle in radians.
entity_angle = DEG2RAD(cl_visents.list[i].angles[1]);
x_line_end = entity_p_x + 5 * cos(entity_angle) * scale;
y_line_end = entity_p_y - 5 * sin(entity_angle) * scale;
// Draw the rocket/grenade showing it's angle also.
Draw_AlphaLine (entity_p_x, entity_p_y, x_line_end, y_line_end, 1.0, 254, 1);
}
else if(radar_show_shaft_p
&& (!strcmp(cl_visents.list[i].model->name, "progs/bolt.mdl")
|| !strcmp(cl_visents.list[i].model->name, "progs/bolt2.mdl")
|| !strcmp(cl_visents.list[i].model->name, "progs/bolt3.mdl")))
{
//
// Shaft beam.
//
float entity_angle = 0;
float shaft_length = 0;
float x_line_end = 0;
float y_line_end = 0;
// Get the length and angle of the shaft.
shaft_length = cl_visents.list[i].model->maxs[1];
entity_angle = (cl_visents.list[i].angles[1]*M_PI)/180;
// Calculate where the shaft beam's ending point.
x_line_end = entity_p_x + shaft_length * cos(entity_angle);
y_line_end = entity_p_y - shaft_length * sin(entity_angle);
// Draw the shaft beam.
Draw_AlphaLine (entity_p_x, entity_p_y, x_line_end, y_line_end, 1.0, 254, 1);
}
}
// Draw a circle around "hold areas", the grid cells within this circle
// are the ones that are counted for that particular hold area. The team
// that has the most percentage of these cells is considered to hold that area.
if(show_hold_areas && stats_important_ents != NULL && stats_important_ents->list != NULL)
{
int entity_p_x = 0;
int entity_p_y = 0;
for(i = 0; i < stats_important_ents->count; i++)
{
entity_p_x = x + Q_rint((map_x_slope*8*stats_important_ents->list[i].origin[0] + map_x_intercept) * scale);
entity_p_y = y + Q_rint((map_y_slope*8*stats_important_ents->list[i].origin[1] + map_y_intercept) * scale);
Draw_ColoredString(entity_p_x - (8 * strlen(stats_important_ents->list[i].name)) / 2.0, entity_p_y - 4,
va("&c55f%s", stats_important_ents->list[i].name), 0);
Draw_AlphaCircleOutline(entity_p_x , entity_p_y, map_x_slope * 8 * stats_important_ents->hold_radius * scale, 1.0, 15, 0.2);
}
}
//
// Draw temp entities (explosions, blood, teleport effects).
//
for(i = 0; i < MAX_TEMP_ENTITIES; i++)
{
float time_diff = 0.0;
int entity_q_x = 0;
int entity_q_y = 0;
int entity_p_x = 0;
int entity_p_y = 0;
// Get the time since the entity spawned.
if(cls.demoplayback)
{
time_diff = cls.demotime - temp_entities.list[i].time;
}
else
{
time_diff = cls.realtime - temp_entities.list[i].time;
}
// Don't show temp entities for long.
if(time_diff < 0.25)
{
float radius = 0.0;
radius = (time_diff < 0.125) ? (time_diff * 32.0) : (time_diff * 32.0) - time_diff;
radius *= scale;
radius = min(max(radius, 0), 200);
// Get quake coordinates (times 8 to get them in the same format as .locs).
entity_q_x = temp_entities.list[i].pos[0]*8;
entity_q_y = temp_entities.list[i].pos[1]*8;
entity_p_x = x + Q_rint((map_x_slope*entity_q_x + map_x_intercept) * scale);
entity_p_y = y + Q_rint((map_y_slope*entity_q_y + map_y_intercept) * scale);
if(radar_show_explosions
&& (temp_entities.list[i].type == TE_EXPLOSION
|| temp_entities.list[i].type == TE_TAREXPLOSION))
{
//
// Explosions.
//
Draw_AlphaCircleFill (entity_p_x, entity_p_y, radius, 235, 0.8);
}
else if(radar_show_teleport && temp_entities.list[i].type == TE_TELEPORT)
{
//
// Teleport effect.
//
radius *= 1.5;
Draw_AlphaCircleFill (entity_p_x, entity_p_y, radius, 244, 0.8);
}
else if(radar_show_shotgun && temp_entities.list[i].type == TE_GUNSHOT)
{
//
// Shotgun fire.
//
#define SHOTGUN_SPREAD 10
int spread_x = 0;
int spread_y = 0;
int n = 0;
for(n = 0; n < 10; n++)
{
spread_x = (int)(rand() / (((double)RAND_MAX + 1) / SHOTGUN_SPREAD));
spread_y = (int)(rand() / (((double)RAND_MAX + 1) / SHOTGUN_SPREAD));
Draw_AlphaFill (entity_p_x + spread_x - (SHOTGUN_SPREAD/2), entity_p_y + spread_y - (SHOTGUN_SPREAD/2), 1, 1, 8, 0.9);
}
}
}
}
}
void Radar_DrawPlayers(int x, int y, int width, int height, float scale,
float show_height, float show_powerups,
float player_size, float show_names,
float fade_players, float highlight,
char *highlight_color)
{
int i;
player_state_t *state;
player_info_t *info;
// Get player state so we can know where he is (or on rare occassions, she).
state = cl.frames[cl.oldparsecount & UPDATE_MASK].playerstate;
// Get the info for the player.
info = cl.players;
//
// Draw the players.
//
for (i = 0; i < MAX_CLIENTS; i++, info++, state++)
{
// Players quake coordinates
// (these are multiplied by 8, since the conversion formula was
// calculated using the coordinates in a .loc-file, which are in
// the format quake-coordainte*8).
int player_q_x = 0;
int player_q_y = 0;
// The height of the player.
float player_z = 1.0;
float player_z_relative = 1.0;
// Players pixel coordinates.
int player_p_x = 0;
int player_p_y = 0;
// Used for drawing the the direction the
// player is looking at.
float player_angle = 0;
int x_line_start = 0;
int y_line_start = 0;
int x_line_end = 0;
int y_line_end = 0;
// Color and opacity of the player.
int player_color = 0;
float player_alpha = 1.0;
// Make sure we're not drawing any ghosts.
if(!info->name[0])
{
continue;
}
if (state->messagenum == cl.oldparsecount)
{
// TODO: Implement lerping to get smoother drawing.
// Get the quake coordinates. Multiply by 8 since
// the conversion formula has been calculated using
// a .loc-file which is in that format.
player_q_x = state->origin[0]*8;
player_q_y = state->origin[1]*8;
// Get the players view angle.
player_angle = cls.demoplayback ? state->viewangles[1] : cl.simangles[1];
// Convert from quake coordiantes -> pixel coordinates.
player_p_x = Q_rint((map_x_slope*player_q_x + map_x_intercept) * scale);
player_p_y = Q_rint((map_y_slope*player_q_y + map_y_intercept) * scale);
player_color = Sbar_BottomColor(info);
// Calculate the height of the player.
if(show_height)
{
player_z = state->origin[2];
player_z += (player_z >= 0) ? fabs(cl.worldmodel->mins[2]) : fabs(cl.worldmodel->maxs[2]);
player_z_relative = min(fabs(player_z / map_height_diff), 1.0);
player_z_relative = max(player_z_relative, 0.2);
}
// Make the players fade out as they get less armor/health.
if(fade_players)
{
int armor_strength = 0;
armor_strength = (info->stats[STAT_ITEMS] & IT_ARMOR1) ? 100 :
((info->stats[STAT_ITEMS] & IT_ARMOR2) ? 150 :
((info->stats[STAT_ITEMS] & IT_ARMOR3) ? 200 : 0));
// Don't let the players get completly transparent so add 0.2 to the final value.
player_alpha = ((info->stats[STAT_HEALTH] + (info->stats[STAT_ARMOR] * armor_strength)) / 100.0) + 0.2;
}
// Turn dead people red.
if(info->stats[STAT_HEALTH] <= 0)
{
player_alpha = 1.0;
player_color = 79;
}
// Draw a ring around players with powerups if it's enabled.
if(show_powerups)
{
if(info->stats[STAT_ITEMS] & IT_INVISIBILITY)
{
Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size*2*player_z_relative, 161, 0.2);
}
if(info->stats[STAT_ITEMS] & IT_INVULNERABILITY)
{
Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size*2*player_z_relative, 79, 0.5);
}
if(info->stats[STAT_ITEMS] & IT_QUAD)
{
Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size*2*player_z_relative, 244, 0.2);
}
}
#define HUD_RADAR_HIGHLIGHT_NONE 0
#define HUD_RADAR_HIGHLIGHT_TEXT_ONLY 1
#define HUD_RADAR_HIGHLIGHT_OUTLINE 2
#define HUD_RADAR_HIGHLIGHT_FIXED_OUTLINE 3
#define HUD_RADAR_HIGHLIGHT_CIRCLE 4
#define HUD_RADAR_HIGHLIGHT_FIXED_CIRCLE 5
#define HUD_RADAR_HIGHLIGHT_ARROW_BOTTOM 6
#define HUD_RADAR_HIGHLIGHT_ARROW_CENTER 7
#define HUD_RADAR_HIGHLIGHT_ARROW_TOP 8
#define HUD_RADAR_HIGHLIGHT_CROSS_CORNERS 9
// Draw a circle around the tracked player.
if (highlight != HUD_RADAR_HIGHLIGHT_NONE && Cam_TrackNum() >= 0 && info->userid == cl.players[Cam_TrackNum()].userid)
{
color_t higlight_color = RGBAVECT_TO_COLOR(hud_radar_highlight_color);
// Draw the highlight.
switch ((int)highlight)
{
case HUD_RADAR_HIGHLIGHT_CROSS_CORNERS :
{
// Top left
Draw_AlphaLineRGB (x, y, x + player_p_x, y + player_p_y, 2, higlight_color);
// Top right.
Draw_AlphaLineRGB (x + width, y, x + player_p_x, y + player_p_y, 2, higlight_color);
// Bottom left.
Draw_AlphaLineRGB (x, y + height, x + player_p_x, y + player_p_y, 2, higlight_color);
// Bottom right.
Draw_AlphaLineRGB (x + width, y + height, x + player_p_x, y + player_p_y, 2, higlight_color);
break;
}
case HUD_RADAR_HIGHLIGHT_ARROW_TOP :
{
// Top center.
Draw_AlphaLineRGB (x + width / 2, y, x + player_p_x, y + player_p_y, 2, higlight_color);
break;
}
case HUD_RADAR_HIGHLIGHT_ARROW_CENTER :
{
// Center.
Draw_AlphaLineRGB (x + width / 2, y + height / 2, x + player_p_x, y + player_p_y, 2, higlight_color);
break;
}
case HUD_RADAR_HIGHLIGHT_ARROW_BOTTOM :
{
// Bottom center.
Draw_AlphaLineRGB (x + width / 2, y + height, x + player_p_x, y + player_p_y, 2, higlight_color);
break;
}
case HUD_RADAR_HIGHLIGHT_FIXED_CIRCLE :
{
Draw_AlphaCircleRGB (x + player_p_x, y + player_p_y, player_size * 1.5, 1.0, true, higlight_color);
break;
}
case HUD_RADAR_HIGHLIGHT_CIRCLE :
{
Draw_AlphaCircleRGB (x + player_p_x, y + player_p_y, player_size * player_z_relative * 2.0, 1.0, true, higlight_color);
break;
}
case HUD_RADAR_HIGHLIGHT_FIXED_OUTLINE :
{
Draw_AlphaCircleOutlineRGB (x + player_p_x, y + player_p_y, player_size * 1.5, 1.0, higlight_color);
break;
}
case HUD_RADAR_HIGHLIGHT_OUTLINE :
{
Draw_AlphaCircleOutlineRGB (x + player_p_x, y + player_p_y, player_size * player_z_relative * 2.0, 1.0, higlight_color);
break;
}
case HUD_RADAR_HIGHLIGHT_TEXT_ONLY :
default :
{
break;
}
}
}
// Draw the actual player and a line showing what direction the player is looking in.
{
float relative_x = 0;
float relative_y = 0;
x_line_start = x + player_p_x;
y_line_start = y + player_p_y;
// Translate the angle into radians.
player_angle = DEG2RAD(player_angle);
relative_x = cos(player_angle);
relative_y = sin(player_angle);
// Draw a slightly larger line behind the colored one
// so that it get's an outline.
x_line_end = x_line_start + (player_size * 2 * player_z_relative + 1) * relative_x;
y_line_end = y_line_start - (player_size * 2 * player_z_relative + 1) * relative_y;
Draw_AlphaLine (x_line_start, y_line_start, x_line_end, y_line_end, 4.0, 0, 1.0);
// Draw the colored line.
x_line_end = x_line_start + (player_size * 2 * player_z_relative) * relative_x;
y_line_end = y_line_start - (player_size * 2 * player_z_relative) * relative_y;
Draw_AlphaLine (x_line_start, y_line_start, x_line_end, y_line_end, 2.0, player_color, player_alpha);
// Draw the player on the map.
Draw_AlphaCircleFill (x + player_p_x, y + player_p_y, player_size * player_z_relative, player_color, player_alpha);
Draw_AlphaCircleOutline (x + player_p_x, y + player_p_y, player_size * player_z_relative, 1.0, 0, 1.0);
}
// Draw the players name.
if(show_names)
{
int name_x = 0;
int name_y = 0;
name_x = x + player_p_x;
name_y = y + player_p_y;
// Make sure we're not too far right.
while(name_x + 8 * strlen(info->name) > x + width)
{
name_x--;
}
// Make sure we're not outside the radar to the left.
name_x = max(name_x, x);
// Draw the name.
if (highlight >= HUD_RADAR_HIGHLIGHT_TEXT_ONLY
&& info->userid == cl.players[Cam_TrackNum()].userid)
{
// Draw the tracked players name in the user specified color.
Draw_ColoredString (name_x, name_y,
va("&c%x%x%x%s",
(unsigned int)(hud_radar_highlight_color[0] * 15),
(unsigned int)(hud_radar_highlight_color[1] * 15),
(unsigned int)(hud_radar_highlight_color[2] * 15), info->name), 0);
}
else
{
// Draw other players in normal character color.
Draw_String (name_x, name_y, info->name);
}
}
// Show if a person lost an RL-pack.
if(info->stats[STAT_HEALTH] <= 0 && info->stats[STAT_ACTIVEWEAPON] == IT_ROCKET_LAUNCHER)
{
Draw_AlphaCircleOutline (x + player_p_x, y + player_p_y, player_size*player_z_relative*2, 1.0, 254, player_alpha);
Draw_ColoredString (x + player_p_x, y + player_p_y, va("&cf00PACK!"), 1);
}
}
}
}
//
// Draws a map of the current level and plots player movements on it.
//
void SCR_HUD_DrawRadar(hud_t *hud)
{
int width, height, x, y;
float width_limit, height_limit;
float scale;
float x_scale;
float y_scale;
static cvar_t
*hud_radar_opacity = NULL,
*hud_radar_width,
*hud_radar_height,
*hud_radar_autosize,
*hud_radar_fade_players,
*hud_radar_show_powerups,
*hud_radar_show_names,
*hud_radar_highlight,
*hud_radar_highlight_color,
*hud_radar_player_size,
*hud_radar_show_height,
*hud_radar_show_stats,
*hud_radar_show_hold,
*hud_radar_weaponfilter,
*hud_radar_itemfilter,
*hud_radar_onlytp,
*hud_radar_otherfilter;
if (hud_radar_opacity == NULL) // first time
{
char checkval[256];
hud_radar_opacity = HUD_FindVar(hud, "opacity");
hud_radar_width = HUD_FindVar(hud, "width");
hud_radar_height = HUD_FindVar(hud, "height");
hud_radar_autosize = HUD_FindVar(hud, "autosize");
hud_radar_fade_players = HUD_FindVar(hud, "fade_players");
hud_radar_show_powerups = HUD_FindVar(hud, "show_powerups");
hud_radar_show_names = HUD_FindVar(hud, "show_names");
hud_radar_player_size = HUD_FindVar(hud, "player_size");
hud_radar_show_height = HUD_FindVar(hud, "show_height");
hud_radar_show_stats = HUD_FindVar(hud, "show_stats");
hud_radar_show_hold = HUD_FindVar(hud, "show_hold");
hud_radar_weaponfilter = HUD_FindVar(hud, "weaponfilter");
hud_radar_itemfilter = HUD_FindVar(hud, "itemfilter");
hud_radar_otherfilter = HUD_FindVar(hud, "otherfilter");
hud_radar_onlytp = HUD_FindVar(hud, "onlytp");
hud_radar_highlight = HUD_FindVar(hud, "highlight");
hud_radar_highlight_color = HUD_FindVar(hud, "highlight_color");
//
// Only parse the the filters when they change, not on each frame.
//
// Weapon filter.
hud_radar_weaponfilter->OnChange = Radar_OnChangeWeaponFilter;
strlcpy(checkval, hud_radar_weaponfilter->string, sizeof(checkval));
Cvar_Set(hud_radar_weaponfilter, checkval);
// Item filter.
hud_radar_itemfilter->OnChange = Radar_OnChangeItemFilter;
strlcpy(checkval, hud_radar_itemfilter->string, sizeof(checkval));
Cvar_Set(hud_radar_itemfilter, checkval);
// Other filter.
hud_radar_otherfilter->OnChange = Radar_OnChangeOtherFilter;
strlcpy(checkval, hud_radar_otherfilter->string, sizeof(checkval));
Cvar_Set(hud_radar_otherfilter, checkval);
// Highlight color.
hud_radar_highlight_color->OnChange = Radar_OnChangeHighlightColor;
strlcpy(checkval, hud_radar_highlight_color->string, sizeof(checkval));
Cvar_Set(hud_radar_highlight_color, checkval);
}
// Don't show anything if it's a normal player.
if(!(cls.demoplayback || cl.spectator))
{
HUD_PrepareDraw(hud, hud_radar_width->value, hud_radar_height->value, &x, &y);
return;
}
// Don't show when not in teamplay/demoplayback.
if(!HUD_ShowInDemoplayback(hud_radar_onlytp->value))
{
HUD_PrepareDraw(hud, hud_radar_width->value, hud_radar_height->value, &x, &y);
return;
}
// Save the width and height of the HUD. We're using these because
// if autosize is on these will be altered and we don't want to change
// the settings that the user set, if we try, and the user turns off
// autosize again the size of the HUD will remain "autosized" until the user
// resets it by hand again.
width_limit = hud_radar_width->value;
height_limit = hud_radar_height->value;
// we support also sizes specified as a percentage of total screen width/height
if (strchr(hud_radar_width->string, '%'))
width_limit = width_limit * vid.conwidth / 100.0;
if (strchr(hud_radar_height->string, '%'))
height_limit = hud_radar_height->value * vid.conheight / 100.0;
// This map doesn't have a map pic.
if(!radar_pic_found)
{
if(HUD_PrepareDraw(hud, Q_rint(width_limit), Q_rint(height_limit), &x, &y))
{
Draw_String(x, y, "No radar picture found!");
}
return;
}
// Make sure we can translate the coordinates.
if(!conversion_formula_found)
{
if(HUD_PrepareDraw(hud, Q_rint(width_limit), Q_rint(height_limit), &x, &y))
{
Draw_String(x, y, "No conversion formula found!");
}
return;
}
x = 0;
y = 0;
scale = 1;
if(hud_radar_autosize->value)
{
//
// Autosize the hud element based on the size of the radar picture.
//
width = width_limit = radar_pic.width;
height = height_limit = radar_pic.height;
}
else
{
//
// Size the picture so that it fits inside the hud element.
//
// Set the scaling based on the picture dimensions.
x_scale = (width_limit / radar_pic.width);
y_scale = (height_limit / radar_pic.height);
scale = (x_scale < y_scale) ? x_scale : y_scale;
width = radar_pic.width * scale;
height = radar_pic.height * scale;
}
if (HUD_PrepareDraw(hud, Q_rint(width_limit), Q_rint(height_limit), &x, &y))
{
float player_size = 1.0;
static int lastframecount = -1;
// Place the map picture in the center of the HUD element.
x += Q_rint((width_limit / 2.0) - (width / 2.0));
x = max(0, x);
x = min(x + width, x);
y += Q_rint((height_limit / 2.0) - (height / 2.0));
y = max(0, y);
y = min(y + height, y);
// Draw the radar background.
Draw_SAlphaPic (x, y, &radar_pic, hud_radar_opacity->value, scale);
// Only draw once per frame.
if (cls.framecount == lastframecount)
{
return;
}
lastframecount = cls.framecount;
if (!cl.oldparsecount || !cl.parsecount || cls.state < ca_active)
{
return;
}
// Scale the player size after the size of the radar.
player_size = hud_radar_player_size->value * scale;
// Draw team stats.
if(hud_radar_show_stats->value)
{
Radar_DrawGrid(stats_grid, x, y, scale, width, height, hud_radar_show_stats->value);
}
// Draw entities such as powerups, weapons and backpacks.
if(RADAR_SHOW_WEAPONS || RADAR_SHOW_ITEMS || RADAR_SHOW_OTHER)
{
Radar_DrawEntities(x, y, scale,
player_size,
hud_radar_show_hold->value);
}
// Draw the players.
Radar_DrawPlayers(x, y, width, height, scale,
hud_radar_show_height->value,
hud_radar_show_powerups->value,
player_size,
hud_radar_show_names->value,
hud_radar_fade_players->value,
hud_radar_highlight->value,
hud_radar_highlight_color->string);
}
}
#endif // WITH_PNG
//
// Run before HUD elements are drawn.
// Place stuff that is common for HUD elements here.
//
void HUD_BeforeDraw()
{
// Only sort once per draw.
HUD_Sort_Scoreboard (HUD_SCOREBOARD_ALL);
}
//
// Run after HUD elements are drawn.
// Place stuff that is common for HUD elements here.
//
void HUD_AfterDraw()
{
}
#ifndef HAXX
static void SCR_HUD_DrawNotImplemented(hud_t *hud)
{
char line1[64];
int width, height, x, y;
snprintf(line1, sizeof(line1), "%s not implemented", hud->name);
width = 8 * strlen(line1);
height = 8;
if (!HUD_PrepareDraw(hud, width, height, &x, &y))
return;
Draw_SString(x, y, line1, 1);
}
#define SCR_HUD_DrawTeamHoldBar SCR_HUD_DrawNotImplemented
#define SCR_HUD_DrawTeamHoldInfo SCR_HUD_DrawNotImplemented
#define SCR_HUD_DrawItemsClock SCR_HUD_DrawNotImplemented
#endif
// ----------------
// Init
// and add some common elements to hud (clock etc)
//
void CommonDraw_Init(void)
{
int i;
HUD_InitSbarImages();
// variables
hud_planmode = cvarfuncs->GetNVFDG("hud_planmode", "0", 0, NULL, "ezhud");
hud_tp_need = cvarfuncs->GetNVFDG("hud_tp_need", "0", 0, NULL, "ezhud");
hud_digits_trim = cvarfuncs->GetNVFDG("hud_digits_trim", "1", 0, NULL, "ezhud");
mvd_autohud = cvarfuncs->GetNVFDG("mvd_autohud", "0", 0, NULL, "ezhud");
cl_weaponpreselect = cvarfuncs->GetNVFDG("cl_weaponpreselect", "0", 0, NULL, "ezhud");
cl_multiview = cvarfuncs->GetNVFDG("cl_multiview", "0", 0, NULL, "ezhud");
tp_need_health = cvarfuncs->GetNVFDG("tp_need_health", "50", 0, NULL, "ezhud");
tp_need_ra = cvarfuncs->GetNVFDG("tp_need_ra", "50", 0, NULL, "ezhud");
tp_need_ya = cvarfuncs->GetNVFDG("tp_need_ya", "50", 0, NULL, "ezhud");
tp_need_ga = cvarfuncs->GetNVFDG("tp_need_ga", "50", 0, NULL, "ezhud");
tp_weapon_order = cvarfuncs->GetNVFDG("tp_weapon_order", "78654321", 0, NULL, "ezhud");
tp_need_weapon = cvarfuncs->GetNVFDG("tp_need_weapon", "35687", 0, NULL, "ezhud");
tp_need_shells = cvarfuncs->GetNVFDG("tp_need_shells", "10", 0, NULL, "ezhud");
tp_need_nails = cvarfuncs->GetNVFDG("tp_need_nails", "40", 0, NULL, "ezhud");
tp_need_rockets = cvarfuncs->GetNVFDG("tp_need_rockets", "5", 0, NULL, "ezhud");
tp_need_cells = cvarfuncs->GetNVFDG("tp_need_cells", "20", 0, NULL, "ezhud");
// init HUD STAT table
for (i=0; i < MAX_CL_STATS; i++)
hud_stats[i] = 0;
hud_stats[STAT_HEALTH] = 200;
hud_stats[STAT_AMMO] = 100;
hud_stats[STAT_ARMOR] = 200;
hud_stats[STAT_SHELLS] = 100;
hud_stats[STAT_NAILS] = 200;
hud_stats[STAT_ROCKETS] = 100;
hud_stats[STAT_CELLS] = 100;
hud_stats[STAT_ACTIVEWEAPON] = 32;
hud_stats[STAT_ITEMS] = 0xffffffff - IT_ARMOR2 - IT_ARMOR1;
autohud.active = 0;
// init gameclock
HUD_Register("gameclock", NULL, "Shows current game time (hh:mm:ss).",
HUD_PLUSMINUS, ca_disconnected, 8, SCR_HUD_DrawGameClock,
"1", "top", "right", "console", "0", "0", "0", "0 0 0", NULL,
"big", "1",
"style", "0",
"scale", "1",
"blink", "1",
"countdown","0",
"offset","0",
NULL);
HUD_Register("notify", NULL, "Shows last console lines",
HUD_PLUSMINUS, ca_disconnected, 8, SCR_HUD_DrawNotify,
"0", "top", "left", "top", "0", "0", "0", "0 0 0", NULL,
"rows", "4",
"cols", "30",
"scale", "1",
"time", "4",
NULL);
// fps
HUD_Register("fps", NULL,
"Shows your current framerate in frames per second (fps)."
"This can also show the minimum framerate that occured in the last measured period.",
HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawFPS,
"1", "gameclock", "center", "after", "0", "0", "0", "0 0 0", NULL,
"show_min", "0",
"style", "0",
"title", "1",
"drop", "70",
NULL);
HUD_Register("vidlag", NULL,
"Shows the delay between the time a frame is rendered and the time it's displayed.",
HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawVidLag,
"0", "top", "right", "top", "0", "0", "0", "0 0 0", NULL,
"style", "0",
NULL);
HUD_Register("mouserate", NULL, "Show your current mouse input rate", HUD_PLUSMINUS, ca_active, 9,
SCR_HUD_DrawMouserate,
"0", "screen", "left", "bottom", "0", "0", "0", "0 0 0", NULL,
"title", "1",
"interval", "1",
"style", "0",
NULL);
// init clock
HUD_Register("clock", NULL, "Shows current local time (hh:mm:ss).",
HUD_PLUSMINUS, ca_disconnected, 8, SCR_HUD_DrawClock,
"0", "top", "right", "console", "0", "0", "0", "0 0 0", NULL,
"big", "1",
"style", "0",
"scale", "1",
"blink", "1",
"format", "0",
NULL);
// init democlock
HUD_Register("democlock", NULL, "Shows current demo time (hh:mm:ss).",
HUD_PLUSMINUS, ca_disconnected, 7, SCR_HUD_DrawDemoClock,
"1", "top", "right", "console", "0", "8", "0", "0 0 0", NULL,
"big", "0",
"style", "0",
"scale", "1",
"blink", "0",
NULL);
// init ping
HUD_Register("ping", NULL, "Shows most important net conditions, like ping and pl. Shown only when you are connected to a server.",
HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawPing,
"0", "screen", "left", "bottom", "0", "0", "0", "0 0 0", NULL,
"period", "1",
"show_pl", "1",
"show_min", "0",
"show_max", "0",
"show_dev", "0",
"style", "0",
"blink", "1",
NULL);
// init net
HUD_Register("net", NULL, "Shows network statistics, like latency, packet loss, average packet sizes and bandwidth. Shown only when you are connected to a server.",
HUD_PLUSMINUS, ca_active, 7, SCR_HUD_DrawNetStats,
"0", "top", "left", "center", "0", "0", "0.2", "0 0 0", NULL,
"period", "1",
NULL);
// init speed
HUD_Register("speed", NULL, "Shows your current running speed. It is measured over XY or XYZ axis depending on \'xyz\' property.",
HUD_PLUSMINUS, ca_active, 7, SCR_HUD_DrawSpeed,
"0", "top", "center", "bottom", "0", "-5", "0", "0 0 0", NULL,
"xyz", "0",
"width", "160",
"height", "15",
"opacity", "1.0",
"tick_spacing", "0.2",
"color_stopped", SPEED_STOPPED,
"color_normal", SPEED_NORMAL,
"color_fast", SPEED_FAST,
"color_fastest", SPEED_FASTEST,
"color_insane", SPEED_INSANE,
"vertical", "0",
"vertical_text", "1",
"text_align", "1",
"style", "0",
"scale", "1",
NULL);
// Init speed2 (half circle thingie).
HUD_Register("speed2", NULL, "Shows your current running speed. It is measured over XY or XYZ axis depending on \'xyz\' property.",
HUD_PLUSMINUS, ca_active, 7, SCR_HUD_DrawSpeed2,
"0", "top", "center", "bottom", "0", "0", "0", "0 0 0", NULL,
"xyz", "0",
"opacity", "1.0",
"color_stopped", SPEED_STOPPED,
"color_normal", SPEED_NORMAL,
"color_fast", SPEED_FAST,
"color_fastest", SPEED_FASTEST,
"color_insane", SPEED_INSANE,
"radius", "50.0",
"wrapspeed", "500",
"orientation", "0",
NULL);
// init guns
HUD_Register("gun", NULL, "Part of your inventory - current weapon.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGunCurrent,
"0", "ibar", "center", "bottom", "0", "0", "0", "0 0 0", NULL,
"wide", "0",
"style", "0",
"scale", "1",
NULL);
HUD_Register("gun2", NULL, "Part of your inventory - shotgun.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun2,
"1", "ibar", "left", "bottom", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("gun3", NULL, "Part of your inventory - super shotgun.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun3,
"1", "gun2", "after", "center", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("gun4", NULL, "Part of your inventory - nailgun.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun4,
"1", "gun3", "after", "center", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("gun5", NULL, "Part of your inventory - super nailgun.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun5,
"1", "gun4", "after", "center", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("gun6", NULL, "Part of your inventory - grenade launcher.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun6,
"1", "gun5", "after", "center", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("gun7", NULL, "Part of your inventory - rocket launcher.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun7,
"1", "gun6", "after", "center", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("gun8", NULL, "Part of your inventory - thunderbolt.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawGun8,
"1", "gun7", "after", "center", "0", "0", "0", "0 0 0", NULL,
"wide", "0",
"style", "0",
"scale", "1",
NULL);
// init powerzz
HUD_Register("key1", NULL, "Part of your inventory - silver key.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawKey1,
"1", "ibar", "top", "left", "0", "64", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("key2", NULL, "Part of your inventory - gold key.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawKey2,
"1", "key1", "left", "after", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("ring", NULL, "Part of your inventory - invisibility.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawRing,
"1", "key2", "left", "after", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("pent", NULL, "Part of your inventory - invulnerability.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawPent,
"1", "ring", "left", "after", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("suit", NULL, "Part of your inventory - biosuit.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSuit,
"1", "pent", "left", "after", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("quad", NULL, "Part of your inventory - quad damage.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawQuad,
"1", "suit", "left", "after", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
// netproblem icon
HUD_Register("netproblem", NULL, "Shows an icon if you are experiencing network problems",
HUD_NO_FRAME, ca_active, 0, SCR_HUD_NetProblem,
"1", "top", "left", "top", "0", "0", "0", "0 0 0", NULL,
"scale", "1",
NULL);
// sigilzz
HUD_Register("sigil1", NULL, "Part of your inventory - sigil 1.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil1,
"0", "ibar", "left", "top", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("sigil2", NULL, "Part of your inventory - sigil 2.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil2,
"0", "sigil1", "after", "top", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("sigil3", NULL, "Part of your inventory - sigil 3.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil3,
"0", "sigil2", "after", "top", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("sigil4", NULL, "Part of your inventory - sigil 4.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawSigil4,
"0", "sigil3", "after", "top", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
// player face (health indicator)
HUD_Register("face", NULL, "Your bloody face.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawFace,
"1", "screen", "center", "bottom", "0", "0", "0", "0 0 0", NULL,
"scale", "1",
NULL);
// health
HUD_Register("health", NULL, "Part of your status - health level.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawHealth,
"1", "face", "after", "center", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "3",
NULL);
// ammo/s
HUD_Register("ammo", NULL, "Part of your inventory - ammo for active weapon.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoCurrent,
"1", "health", "after", "center", "32", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "3",
NULL);
HUD_Register("ammo1", NULL, "Part of your inventory - ammo - shells.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo1,
"0", "ibar", "left", "top", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "3",
NULL);
HUD_Register("ammo2", NULL, "Part of your inventory - ammo - nails.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo2,
"0", "ammo1", "after", "top", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "3",
NULL);
HUD_Register("ammo3", NULL, "Part of your inventory - ammo - rockets.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo3,
"0", "ammo2", "after", "top", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "3",
NULL);
HUD_Register("ammo4", NULL, "Part of your inventory - ammo - cells.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmo4,
"0", "ammo3", "after", "top", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "3",
NULL);
// ammo icon/s
HUD_Register("iammo", NULL, "Part of your inventory - ammo icon.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIconCurrent,
"1", "ammo", "before", "center", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
HUD_Register("iammo1", NULL, "Part of your inventory - ammo icon.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon1,
"0", "ibar", "left", "top", "0", "0", "0", "0 0 0", NULL,
"style", "2",
"scale", "1",
NULL);
HUD_Register("iammo2", NULL, "Part of your inventory - ammo icon.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon2,
"0", "iammo1", "after", "top", "0", "0", "0", "0 0 0", NULL,
"style", "2",
"scale", "1",
NULL);
HUD_Register("iammo3", NULL, "Part of your inventory - ammo icon.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon3,
"0", "iammo2", "after", "top", "0", "0", "0", "0 0 0", NULL,
"style", "2",
"scale", "1",
NULL);
HUD_Register("iammo4", NULL, "Part of your inventory - ammo icon.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawAmmoIcon4,
"0", "iammo3", "after", "top", "0", "0", "0", "0 0 0", NULL,
"style", "2",
"scale", "1",
NULL);
// armor count
HUD_Register("armor", NULL, "Part of your inventory - armor level.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawArmor,
"1", "face", "before", "center", "-32", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "3",
"pent_666", "1", // Show 666 instead of armor value
NULL);
// armor icon
HUD_Register("iarmor", NULL, "Part of your inventory - armor icon.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawArmorIcon,
"1", "armor", "before", "center", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
NULL);
// Tracking JohnNy_cz (Contains name of the player who's player we're watching at the moment)
HUD_Register("tracking", NULL, "Shows the name of tracked player.",
HUD_PLUSMINUS, ca_active, 9, SCR_HUD_DrawTracking,
"1", "face", "center", "before", "0", "0", "0", "0 0 0", NULL,
"format", "^mTracking:^m %t %n"/*, ^mJUMP^m for next"*/, //"Tracking: team name, JUMP for next", "Tracking:" and "JUMP" are brown. default: "Tracking %t %n, [JUMP] for next"
"scale", "1",
NULL);
// groups
HUD_Register("group1", NULL, "Group element.",
HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group1,
"0", "screen", "left", "top", "0", "0", ".5", "0 0 0", NULL,
"name", "group1",
"width", "64",
"height", "64",
"picture", "",
"pic_alpha", "1.0",
"pic_scalemode", "0",
NULL);
HUD_Register("group2", NULL, "Group element.",
HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group2,
"0", "screen", "center", "top", "0", "0", ".5", "0 0 0", NULL,
"name", "group2",
"width", "64",
"height", "64",
"picture", "",
"pic_alpha", "1.0",
"pic_scalemode", "0",
NULL);
HUD_Register("group3", NULL, "Group element.",
HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group3,
"0", "screen", "right", "top", "0", "0", ".5", "0 0 0", NULL,
"name", "group3",
"width", "64",
"height", "64",
"picture", "",
"pic_alpha", "1.0",
"pic_scalemode", "0",
NULL);
HUD_Register("group4", NULL, "Group element.",
HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group4,
"0", "screen", "left", "center", "0", "0", ".5", "0 0 0", NULL,
"name", "group4",
"width", "64",
"height", "64",
"picture", "",
"pic_alpha", "1.0",
"pic_scalemode", "0",
NULL);
HUD_Register("group5", NULL, "Group element.",
HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group5,
"0", "screen", "center", "center", "0", "0", ".5", "0 0 0", NULL,
"name", "group5",
"width", "64",
"height", "64",
"picture", "",
"pic_alpha", "1.0",
"pic_scalemode", "0",
NULL);
HUD_Register("group6", NULL, "Group element.",
HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group6,
"0", "screen", "right", "center", "0", "0", ".5", "0 0 0", NULL,
"name", "group6",
"width", "64",
"height", "64",
"picture", "",
"pic_alpha", "1.0",
"pic_scalemode", "0",
NULL);
HUD_Register("group7", NULL, "Group element.",
HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group7,
"0", "screen", "left", "bottom", "0", "0", ".5", "0 0 0", NULL,
"name", "group7",
"width", "64",
"height", "64",
"picture", "",
"pic_alpha", "1.0",
"pic_scalemode", "0",
NULL);
HUD_Register("group8", NULL, "Group element.",
HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group8,
"0", "screen", "center", "bottom", "0", "0", ".5", "0 0 0", NULL,
"name", "group8",
"width", "64",
"height", "64",
"picture", "",
"pic_alpha", "1.0",
"pic_scalemode", "0",
NULL);
HUD_Register("group9", NULL, "Group element.",
HUD_NO_GROW, ca_disconnected, 0, SCR_HUD_Group9,
"0", "screen", "right", "bottom", "0", "0", ".5", "0 0 0", NULL,
"name", "group9",
"width", "64",
"height", "64",
"picture", "",
"pic_alpha", "1.0",
"pic_scalemode", "0",
NULL);
// healthdamage
HUD_Register("healthdamage", NULL, "Shows amount of damage done to your health.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawHealthDamage,
"0", "health", "left", "before", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "3",
"duration", "0.8",
NULL);
// armordamage
HUD_Register("armordamage", NULL, "Shows amount of damage done to your armour.",
HUD_INVENTORY, ca_active, 0, SCR_HUD_DrawArmorDamage,
"0", "armor", "left", "before", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "3",
"duration", "0.8",
NULL);
HUD_Register("frags", NULL, "Show list of player frags in short form.",
0, ca_active, 0, SCR_HUD_DrawFrags,
"0", "top", "right", "bottom", "0", "0", "0", "0 0 0", NULL,
"cell_width", "32",
"cell_height", "8",
"rows", "1",
"cols", "4",
"space_x", "1",
"space_y", "1",
"teamsort", "0",
"strip", "1",
"vertical", "0",
"shownames", "0",
"showteams", "0",
"padtext", "1",
"showself_always", "1",
"extra_spec_info", "ALL",
"fliptext", "0",
"style", "0",
"bignum", "0",
"colors_alpha", "1.0",
"maxname", "16",
"notintp", "0",
NULL);
HUD_Register("teamfrags", NULL, "Show list of team frags in short form.",
0, ca_active, 0, SCR_HUD_DrawTeamFrags,
"1", "ibar", "center", "before", "0", "0", "0", "0 0 0", NULL,
"cell_width", "32",
"cell_height", "8",
"rows", "1",
"cols", "2",
"space_x", "1",
"space_y", "1",
"strip", "1",
"vertical", "0",
"shownames", "0",
"padtext", "1",
"fliptext", "1",
"style", "0",
"extra_spec_info", "1",
"onlytp", "0",
"bignum", "0",
"colors_alpha", "1.0",
"maxname", "16",
NULL);
HUD_Register("teaminfo", NULL, "Show information about your team in short form.",
0, ca_active, 0, SCR_HUD_DrawTeamInfo,
"0", "", "right", "center", "0", "0", "0.2", "20 20 20", NULL,
"layout", "%p%n $x10%l$x11 %a/%H %w",
"align_right","0",
"loc_width","5",
"name_width","6",
"low_health","25",
"armor_style","3",
"weapon_style","0",
"show_enemies","0",
"show_self","1",
"scale","1",
"powerup_style","1",
NULL);
HUD_Register("mp3_title", NULL, "Shows current mp3 playing.",
HUD_PLUSMINUS, ca_disconnected, 0, SCR_HUD_DrawMP3_Title,
"0", "top", "right", "bottom", "0", "0", "0", "0 0 0", NULL,
"style", "2",
"width", "512",
"height", "8",
"scroll", "1",
"scroll_delay", "0.5",
"on_scoreboard", "0",
"wordwrap", "0",
NULL);
HUD_Register("mp3_time", NULL, "Shows the time of the current mp3 playing.",
HUD_PLUSMINUS, ca_disconnected, 0, SCR_HUD_DrawMP3_Time,
"0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL,
"style", "0",
"on_scoreboard", "0",
NULL);
#ifdef WITH_PNG
HUD_Register("radar", NULL, "Plots the players on a picture of the map. (Only when watching MVD's or QTV).",
HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawRadar,
"0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL,
"opacity", "0.5",
"width", "30%",
"height", "25%",
"autosize", "0",
"show_powerups", "1",
"show_names", "0",
"highlight_color", "yellow",
"highlight", "0",
"player_size", "10",
"show_height", "1",
"show_stats", "1",
"fade_players", "1",
"show_hold", "0",
"weaponfilter", "gl rl lg",
"itemfilter", "backpack quad pent armor mega",
"otherfilter", "projectiles gibs explosions shotgun",
"onlytp", "0",
NULL);
#endif // WITH_PNG
HUD_Register("teamholdbar", NULL, "Shows how much of the level (in percent) that is currently being held by either team.",
HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawTeamHoldBar,
"0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL,
"opacity", "0.8",
"width", "200",
"height", "8",
"vertical", "0",
"vertical_text", "0",
"show_text", "1",
"onlytp", "0",
NULL);
HUD_Register("teamholdinfo", NULL, "Shows which important items in the level that are being held by the teams.",
HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawTeamHoldInfo,
"0", "top", "left", "bottom", "0", "0", "0", "0 0 0", NULL,
"opacity", "0.8",
"width", "200",
"height", "8",
"onlytp", "0",
"style", "1",
"itemfilter", "quad ra ya ga mega pent rl quad",
NULL);
HUD_Register("ownfrags" /* jeez someone give me a better name please */, NULL, "Highlights your own frags",
0, ca_active, 1, SCR_HUD_DrawOwnFrags,
"1", "screen", "center", "top", "0", "50", "0.2", "0 0 100", NULL,
/*
"color", "255 255 255",
*/
"timeout", "3",
"scale", "1.5",
NULL
);
HUD_Register("keys", NULL, "Shows which keys user does press at the moment",
0, ca_active, 1, SCR_HUD_DrawKeys,
"0", "screen", "right", "center", "0", "0", "0.5", "20 20 20", NULL,
"scale", "2",
NULL
);
HUD_Register("itemsclock", NULL, "Displays upcoming item respawns",
0, ca_active, 1, SCR_HUD_DrawItemsClock,
"0", "screen", "right", "center", "0", "0", "0", "0 0 0", NULL,
"timelimit", "5",
"style", "0",
NULL
);
HUD_Register("score_team", NULL, "Own scores or team scores.",
0, ca_active, 0, SCR_HUD_DrawScoresTeam,
"0", "screen", "left", "bottom", "0", "0", "0.5", "4 8 32", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "0",
"colorize", "0",
NULL
);
HUD_Register("score_enemy", NULL, "Scores of enemy or enemy team.",
0, ca_active, 0, SCR_HUD_DrawScoresEnemy,
"0", "score_team", "after", "bottom", "0", "0", "0.5", "32 4 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "0",
"colorize", "0",
NULL
);
HUD_Register("score_difference", NULL, "Difference between teamscores and enemyscores.",
0, ca_active, 0, SCR_HUD_DrawScoresDifference,
"0", "score_enemy", "after", "bottom", "0", "0", "0.5", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "0",
"colorize", "1",
NULL
);
HUD_Register("score_position", NULL, "Position on scoreboard.",
0, ca_active, 0, SCR_HUD_DrawScoresPosition,
"0", "score_difference", "after", "bottom", "0", "0", "0.5", "0 0 0", NULL,
"style", "0",
"scale", "1",
"align", "right",
"digits", "0",
"colorize", "1",
NULL
);
HUD_Register("score_bar", NULL, "Team, enemy, and difference scores together.",
HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawScoresBar,
"0", "screen", "center", "console", "0", "0", "0.5", "0 0 0", NULL,
"style", "0",
"scale", "1",
"format_small", "&c69f%T&r:%t &cf10%E&r:%e $[%D$]",
"format_big", "%t:%e:%Z",
NULL
);
HUD_Register("bar_armor", NULL, "Armor bar.",
HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawBarArmor,
"0", "armor", "left", "center", "0", "0", "0", "0 0 0", NULL,
"height", "16",
"width", "64",
"direction", "1",
"color_noarmor", "128 128 128 64",
"color_ga", "32 128 0 128",
"color_ya", "192 128 0 128",
"color_ra", "128 0 0 128",
"color_unnatural", "255 255 255 128",
NULL
);
HUD_Register("bar_health", NULL, "Health bar.",
HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawBarHealth,
"0", "health", "right", "center", "0", "0", "0", "0 0 0", NULL,
"height", "16",
"width", "64",
"direction", "0",
"color_nohealth", "128 128 128 64",
"color_normal", "32 64 128 128",
"color_mega", "64 96 128 128",
"color_twomega", "128 128 255 128",
"color_unnatural", "255 255 255 128",
NULL
);
#ifdef QUAKEHUD
HUD_Register("weaponstats", NULL, "Weapon Stats",
HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawWeaponStats,
"0", "screen", "right", "center", "0", "0", "0", "0 0 0", NULL,
"scale", "1",
"fmt", "&c990sg&r:[%sg] &c099ssg&r:[%ssg] &c900rl&r:[#rl] &c009lg&r:[%lg]",
NULL
);
#endif
/* hexum -> FIXME? this is used only for debug purposes, I wont bother to port it (it shouldnt be too difficult if anyone cares)
#ifdef _DEBUG
HUD_Register("framegraph", NULL, "Shows different frame times for debug/profiling purposes.",
HUD_PLUSMINUS | HUD_ON_SCORES, ca_disconnected, 0, SCR_HUD_DrawFrameGraph,
"0", "top", "left", "bottom", "0", "0", "2",
"swap_x", "0",
"swap_y", "0",
"scale", "14",
"width", "256",
"height", "64",
"alpha", "1",
NULL);
#endif
*/
}