2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // sbar.c -- status bar code
24 #include "cl_collision.h"
29 #define STAT_MINUS 10 // num frame for '-' stats digit
30 cachepic_t *sb_nums[2][11];
31 cachepic_t *sb_colon, *sb_slash;
34 cachepic_t *sb_scorebar;
35 // AK only used by NEX
36 cachepic_t *sb_sbar_minimal;
37 cachepic_t *sb_sbar_overlay;
39 // AK changed the bound to 9
40 cachepic_t *sb_weapons[7][9]; // 0 is active, 1 is owned, 2-5 are flashes
41 cachepic_t *sb_ammo[4];
42 cachepic_t *sb_sigil[4];
43 cachepic_t *sb_armor[3];
44 cachepic_t *sb_items[32];
46 // 0-4 are based on health (in 20 increments)
47 // 0 is static, 1 is temporary animation
48 cachepic_t *sb_faces[5][2];
49 cachepic_t *sb_health; // GAME_NEXUIZ
51 cachepic_t *sb_face_invis;
52 cachepic_t *sb_face_quad;
53 cachepic_t *sb_face_invuln;
54 cachepic_t *sb_face_invis_invuln;
58 int sb_lines; // scan lines to draw
60 cachepic_t *rsb_invbar[2];
61 cachepic_t *rsb_weapons[5];
62 cachepic_t *rsb_items[2];
63 cachepic_t *rsb_ammo[3];
64 cachepic_t *rsb_teambord; // PGM 01/19/97 - team color border
66 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
67 cachepic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
68 //MED 01/04/97 added array to simplify weapon parsing
69 int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
70 //MED 01/04/97 added hipnotic items array
71 cachepic_t *hsb_items[2];
73 cachepic_t *zymsb_crosshair_center;
74 cachepic_t *zymsb_crosshair_line;
75 cachepic_t *zymsb_crosshair_health;
76 cachepic_t *zymsb_crosshair_ammo;
77 cachepic_t *zymsb_crosshair_clip;
78 cachepic_t *zymsb_crosshair_background;
79 cachepic_t *zymsb_crosshair_left1;
80 cachepic_t *zymsb_crosshair_left2;
81 cachepic_t *zymsb_crosshair_right;
83 cachepic_t *sb_ranking;
84 cachepic_t *sb_complete;
86 cachepic_t *sb_finale;
88 cvar_t cl_showfps = {CF_CLIENT | CF_ARCHIVE, "cl_showfps", "0", "shows your rendered fps (frames per second)"};
89 cvar_t cl_showsound = {CF_CLIENT | CF_ARCHIVE, "cl_showsound", "0", "shows number of active sound sources, sound latency, and other statistics"};
90 cvar_t cl_showblur = {CF_CLIENT | CF_ARCHIVE, "cl_showblur", "0", "shows the current alpha level of motionblur"};
91 cvar_t cl_showspeed = {CF_CLIENT | CF_ARCHIVE, "cl_showspeed", "0", "shows your current speed (qu per second); number selects unit: 1 = qu/s, 2 = m/s, 3 = km/h, 4 = mph, 5 = knots"};
92 cvar_t cl_showspeed_factor = {CF_CLIENT | CF_ARCHIVE, "cl_showspeed_factor", "2.54", "multiplier of the centimeter for cl_showspeed. 1 unit = 1 inch in Quake, so this should be 2.54 for Quake, etc"};
93 cvar_t cl_showtopspeed = {CF_CLIENT | CF_ARCHIVE, "cl_showtopspeed", "0", "shows your top speed (kept on screen for max 3 seconds); value -1 takes over the unit from cl_showspeed, otherwise it's an unit number just like in cl_showspeed"};
94 cvar_t cl_showtime = {CF_CLIENT | CF_ARCHIVE, "cl_showtime", "0", "shows current time of day (useful on screenshots)"};
95 cvar_t cl_showtime_format = {CF_CLIENT | CF_ARCHIVE, "cl_showtime_format", "%H:%M:%S", "format string for time of day"};
96 cvar_t cl_showdate = {CF_CLIENT | CF_ARCHIVE, "cl_showdate", "0", "shows current date (useful on screenshots)"};
97 cvar_t cl_showdate_format = {CF_CLIENT | CF_ARCHIVE, "cl_showdate_format", "%Y-%m-%d", "format string for date"};
98 cvar_t cl_showtex = {CF_CLIENT, "cl_showtex", "0", "shows the name of the texture on the crosshair (for map debugging)"};
100 cvar_t sbar_alpha_bg = {CF_CLIENT | CF_ARCHIVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
101 cvar_t sbar_alpha_fg = {CF_CLIENT | CF_ARCHIVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
102 cvar_t sbar_hudselector = {CF_CLIENT | CF_ARCHIVE, "sbar_hudselector", "0", "selects which of the builtin hud layouts to use (meaning is somewhat dependent on gamemode, so nexuiz has a very different set of hud layouts than quake for example)"};
103 cvar_t sbar_scorerank = {CF_CLIENT | CF_ARCHIVE, "sbar_scorerank", "1", "shows an overlay for your score (or team score) and rank in the scoreboard"};
104 cvar_t sbar_gametime = {CF_CLIENT | CF_ARCHIVE, "sbar_gametime", "1", "shows an overlay for the time left in the current match/level (or current game time if there is no timelimit set)"};
105 cvar_t sbar_miniscoreboard_size = {CF_CLIENT | CF_ARCHIVE, "sbar_miniscoreboard_size", "-1", "sets the size of the mini deathmatch overlay in items, or disables it when set to 0, or sets it to a sane default when set to -1"};
106 cvar_t sbar_flagstatus_right = {CF_CLIENT | CF_ARCHIVE, "sbar_flagstatus_right", "0", "moves Nexuiz flag status icons to the right"};
107 cvar_t sbar_flagstatus_pos = {CF_CLIENT | CF_ARCHIVE, "sbar_flagstatus_pos", "115", "pixel position of the Nexuiz flag status icons, from the bottom"};
108 cvar_t sbar_info_pos = {CF_CLIENT | CF_ARCHIVE, "sbar_info_pos", "0", "pixel position of the info strings (such as showfps), from the bottom"};
110 cvar_t cl_deathscoreboard = {CF_CLIENT, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
112 cvar_t crosshair_color_red = {CF_CLIENT | CF_ARCHIVE, "crosshair_color_red", "1", "customizable crosshair color"};
113 cvar_t crosshair_color_green = {CF_CLIENT | CF_ARCHIVE, "crosshair_color_green", "0", "customizable crosshair color"};
114 cvar_t crosshair_color_blue = {CF_CLIENT | CF_ARCHIVE, "crosshair_color_blue", "0", "customizable crosshair color"};
115 cvar_t crosshair_color_alpha = {CF_CLIENT | CF_ARCHIVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
116 cvar_t crosshair_size = {CF_CLIENT | CF_ARCHIVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
118 static void Sbar_MiniDeathmatchOverlay (int x, int y);
119 static void Sbar_DeathmatchOverlay (void);
120 static void Sbar_IntermissionOverlay (void);
121 static void Sbar_FinaleOverlay (void);
132 static void Sbar_ShowScores_f(cmd_state_t *cmd)
136 sb_showscores = true;
137 CL_VM_UpdateShowingScoresState(sb_showscores);
147 static void Sbar_DontShowScores_f(cmd_state_t *cmd)
149 sb_showscores = false;
150 CL_VM_UpdateShowingScoresState(sb_showscores);
153 static void sbar_start(void)
158 if (gamemode == GAME_DELUXEQUAKE || gamemode == GAME_BLOODOMNICIDE)
161 else if (IS_OLDNEXUIZ_DERIVED(gamemode))
163 for (i = 0;i < 10;i++)
164 sb_nums[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/num_%i",i), CACHEPICFLAG_QUIET);
165 sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET);
166 sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET | CACHEPICFLAG_FAILONMISSING);
168 sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
169 sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_bullets", CACHEPICFLAG_QUIET);
170 sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
171 sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
173 sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor", CACHEPICFLAG_QUIET);
177 sb_health = Draw_CachePic_Flags ("gfx/sb_health", CACHEPICFLAG_QUIET);
179 sb_items[2] = Draw_CachePic_Flags ("gfx/sb_slowmo", CACHEPICFLAG_QUIET);
180 sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invinc", CACHEPICFLAG_QUIET);
181 sb_items[4] = Draw_CachePic_Flags ("gfx/sb_energy", CACHEPICFLAG_QUIET);
182 sb_items[5] = Draw_CachePic_Flags ("gfx/sb_str", CACHEPICFLAG_QUIET);
184 sb_items[11] = Draw_CachePic_Flags ("gfx/sb_flag_red_taken", CACHEPICFLAG_QUIET);
185 sb_items[12] = Draw_CachePic_Flags ("gfx/sb_flag_red_lost", CACHEPICFLAG_QUIET);
186 sb_items[13] = Draw_CachePic_Flags ("gfx/sb_flag_red_carrying", CACHEPICFLAG_QUIET);
187 sb_items[14] = Draw_CachePic_Flags ("gfx/sb_key_carrying", CACHEPICFLAG_QUIET);
188 sb_items[15] = Draw_CachePic_Flags ("gfx/sb_flag_blue_taken", CACHEPICFLAG_QUIET);
189 sb_items[16] = Draw_CachePic_Flags ("gfx/sb_flag_blue_lost", CACHEPICFLAG_QUIET);
190 sb_items[17] = Draw_CachePic_Flags ("gfx/sb_flag_blue_carrying", CACHEPICFLAG_QUIET);
192 sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET);
193 sb_sbar_minimal = Draw_CachePic_Flags ("gfx/sbar_minimal", CACHEPICFLAG_QUIET);
194 sb_sbar_overlay = Draw_CachePic_Flags ("gfx/sbar_overlay", CACHEPICFLAG_QUIET);
196 for(i = 0; i < 9;i++)
197 sb_weapons[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inv_weapon%i",i), CACHEPICFLAG_QUIET);
199 else if (gamemode == GAME_ZYMOTIC)
201 zymsb_crosshair_center = Draw_CachePic_Flags ("gfx/hud/crosshair_center", CACHEPICFLAG_QUIET);
202 zymsb_crosshair_line = Draw_CachePic_Flags ("gfx/hud/crosshair_line", CACHEPICFLAG_QUIET);
203 zymsb_crosshair_health = Draw_CachePic_Flags ("gfx/hud/crosshair_health", CACHEPICFLAG_QUIET);
204 zymsb_crosshair_clip = Draw_CachePic_Flags ("gfx/hud/crosshair_clip", CACHEPICFLAG_QUIET);
205 zymsb_crosshair_ammo = Draw_CachePic_Flags ("gfx/hud/crosshair_ammo", CACHEPICFLAG_QUIET);
206 zymsb_crosshair_background = Draw_CachePic_Flags ("gfx/hud/crosshair_background", CACHEPICFLAG_QUIET);
207 zymsb_crosshair_left1 = Draw_CachePic_Flags ("gfx/hud/crosshair_left1", CACHEPICFLAG_QUIET);
208 zymsb_crosshair_left2 = Draw_CachePic_Flags ("gfx/hud/crosshair_left2", CACHEPICFLAG_QUIET);
209 zymsb_crosshair_right = Draw_CachePic_Flags ("gfx/hud/crosshair_right", CACHEPICFLAG_QUIET);
213 sb_disc = Draw_CachePic_Flags ("gfx/disc", CACHEPICFLAG_QUIET);
215 for (i = 0;i < 10;i++)
217 sb_nums[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/num_%i",i), CACHEPICFLAG_QUIET);
218 sb_nums[1][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/anum_%i",i), CACHEPICFLAG_QUIET);
221 sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET);
222 sb_nums[1][10] = Draw_CachePic_Flags ("gfx/anum_minus", CACHEPICFLAG_QUIET);
224 sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET | CACHEPICFLAG_FAILONMISSING);
225 sb_slash = Draw_CachePic_Flags ("gfx/num_slash", CACHEPICFLAG_QUIET);
227 sb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_shotgun", CACHEPICFLAG_QUIET);
228 sb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_sshotgun", CACHEPICFLAG_QUIET);
229 sb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_nailgun", CACHEPICFLAG_QUIET);
230 sb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_snailgun", CACHEPICFLAG_QUIET);
231 sb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_rlaunch", CACHEPICFLAG_QUIET);
232 sb_weapons[0][5] = Draw_CachePic_Flags ("gfx/inv_srlaunch", CACHEPICFLAG_QUIET);
233 sb_weapons[0][6] = Draw_CachePic_Flags ("gfx/inv_lightng", CACHEPICFLAG_QUIET);
235 sb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_shotgun", CACHEPICFLAG_QUIET);
236 sb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_sshotgun", CACHEPICFLAG_QUIET);
237 sb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_nailgun", CACHEPICFLAG_QUIET);
238 sb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_snailgun", CACHEPICFLAG_QUIET);
239 sb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_rlaunch", CACHEPICFLAG_QUIET);
240 sb_weapons[1][5] = Draw_CachePic_Flags ("gfx/inv2_srlaunch", CACHEPICFLAG_QUIET);
241 sb_weapons[1][6] = Draw_CachePic_Flags ("gfx/inv2_lightng", CACHEPICFLAG_QUIET);
243 for (i = 0;i < 5;i++)
245 sb_weapons[2+i][0] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_shotgun",i+1), CACHEPICFLAG_QUIET);
246 sb_weapons[2+i][1] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_sshotgun",i+1), CACHEPICFLAG_QUIET);
247 sb_weapons[2+i][2] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_nailgun",i+1), CACHEPICFLAG_QUIET);
248 sb_weapons[2+i][3] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_snailgun",i+1), CACHEPICFLAG_QUIET);
249 sb_weapons[2+i][4] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_rlaunch",i+1), CACHEPICFLAG_QUIET);
250 sb_weapons[2+i][5] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_srlaunch",i+1), CACHEPICFLAG_QUIET);
251 sb_weapons[2+i][6] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_lightng",i+1), CACHEPICFLAG_QUIET);
254 sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
255 sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_nails", CACHEPICFLAG_QUIET);
256 sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
257 sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
259 sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor1", CACHEPICFLAG_QUIET);
260 sb_armor[1] = Draw_CachePic_Flags ("gfx/sb_armor2", CACHEPICFLAG_QUIET);
261 sb_armor[2] = Draw_CachePic_Flags ("gfx/sb_armor3", CACHEPICFLAG_QUIET);
263 sb_items[0] = Draw_CachePic_Flags ("gfx/sb_key1", CACHEPICFLAG_QUIET);
264 sb_items[1] = Draw_CachePic_Flags ("gfx/sb_key2", CACHEPICFLAG_QUIET);
265 sb_items[2] = Draw_CachePic_Flags ("gfx/sb_invis", CACHEPICFLAG_QUIET);
266 sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invuln", CACHEPICFLAG_QUIET);
267 sb_items[4] = Draw_CachePic_Flags ("gfx/sb_suit", CACHEPICFLAG_QUIET);
268 sb_items[5] = Draw_CachePic_Flags ("gfx/sb_quad", CACHEPICFLAG_QUIET);
270 sb_sigil[0] = Draw_CachePic_Flags ("gfx/sb_sigil1", CACHEPICFLAG_QUIET);
271 sb_sigil[1] = Draw_CachePic_Flags ("gfx/sb_sigil2", CACHEPICFLAG_QUIET);
272 sb_sigil[2] = Draw_CachePic_Flags ("gfx/sb_sigil3", CACHEPICFLAG_QUIET);
273 sb_sigil[3] = Draw_CachePic_Flags ("gfx/sb_sigil4", CACHEPICFLAG_QUIET);
275 sb_faces[4][0] = Draw_CachePic_Flags ("gfx/face1", CACHEPICFLAG_QUIET);
276 sb_faces[4][1] = Draw_CachePic_Flags ("gfx/face_p1", CACHEPICFLAG_QUIET);
277 sb_faces[3][0] = Draw_CachePic_Flags ("gfx/face2", CACHEPICFLAG_QUIET);
278 sb_faces[3][1] = Draw_CachePic_Flags ("gfx/face_p2", CACHEPICFLAG_QUIET);
279 sb_faces[2][0] = Draw_CachePic_Flags ("gfx/face3", CACHEPICFLAG_QUIET);
280 sb_faces[2][1] = Draw_CachePic_Flags ("gfx/face_p3", CACHEPICFLAG_QUIET);
281 sb_faces[1][0] = Draw_CachePic_Flags ("gfx/face4", CACHEPICFLAG_QUIET);
282 sb_faces[1][1] = Draw_CachePic_Flags ("gfx/face_p4", CACHEPICFLAG_QUIET);
283 sb_faces[0][0] = Draw_CachePic_Flags ("gfx/face5", CACHEPICFLAG_QUIET);
284 sb_faces[0][1] = Draw_CachePic_Flags ("gfx/face_p5", CACHEPICFLAG_QUIET);
286 sb_face_invis = Draw_CachePic_Flags ("gfx/face_invis", CACHEPICFLAG_QUIET);
287 sb_face_invuln = Draw_CachePic_Flags ("gfx/face_invul2", CACHEPICFLAG_QUIET);
288 sb_face_invis_invuln = Draw_CachePic_Flags ("gfx/face_inv2", CACHEPICFLAG_QUIET);
289 sb_face_quad = Draw_CachePic_Flags ("gfx/face_quad", CACHEPICFLAG_QUIET);
291 sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET);
292 sb_ibar = Draw_CachePic_Flags ("gfx/ibar", CACHEPICFLAG_QUIET);
293 sb_scorebar = Draw_CachePic_Flags ("gfx/scorebar", CACHEPICFLAG_QUIET);
295 //MED 01/04/97 added new hipnotic weapons
296 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
298 hsb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_laser", CACHEPICFLAG_QUIET);
299 hsb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_mjolnir", CACHEPICFLAG_QUIET);
300 hsb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_gren_prox", CACHEPICFLAG_QUIET);
301 hsb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_prox_gren", CACHEPICFLAG_QUIET);
302 hsb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_prox", CACHEPICFLAG_QUIET);
304 hsb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_laser", CACHEPICFLAG_QUIET);
305 hsb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_mjolnir", CACHEPICFLAG_QUIET);
306 hsb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_gren_prox", CACHEPICFLAG_QUIET);
307 hsb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_prox_gren", CACHEPICFLAG_QUIET);
308 hsb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_prox", CACHEPICFLAG_QUIET);
310 for (i = 0;i < 5;i++)
312 hsb_weapons[2+i][0] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_laser",i+1), CACHEPICFLAG_QUIET);
313 hsb_weapons[2+i][1] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_mjolnir",i+1), CACHEPICFLAG_QUIET);
314 hsb_weapons[2+i][2] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_gren_prox",i+1), CACHEPICFLAG_QUIET);
315 hsb_weapons[2+i][3] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_prox_gren",i+1), CACHEPICFLAG_QUIET);
316 hsb_weapons[2+i][4] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_prox",i+1), CACHEPICFLAG_QUIET);
319 hsb_items[0] = Draw_CachePic_Flags ("gfx/sb_wsuit", CACHEPICFLAG_QUIET);
320 hsb_items[1] = Draw_CachePic_Flags ("gfx/sb_eshld", CACHEPICFLAG_QUIET);
322 else if (gamemode == GAME_ROGUE)
324 rsb_invbar[0] = Draw_CachePic_Flags ("gfx/r_invbar1", CACHEPICFLAG_QUIET);
325 rsb_invbar[1] = Draw_CachePic_Flags ("gfx/r_invbar2", CACHEPICFLAG_QUIET);
327 rsb_weapons[0] = Draw_CachePic_Flags ("gfx/r_lava", CACHEPICFLAG_QUIET);
328 rsb_weapons[1] = Draw_CachePic_Flags ("gfx/r_superlava", CACHEPICFLAG_QUIET);
329 rsb_weapons[2] = Draw_CachePic_Flags ("gfx/r_gren", CACHEPICFLAG_QUIET);
330 rsb_weapons[3] = Draw_CachePic_Flags ("gfx/r_multirock", CACHEPICFLAG_QUIET);
331 rsb_weapons[4] = Draw_CachePic_Flags ("gfx/r_plasma", CACHEPICFLAG_QUIET);
333 rsb_items[0] = Draw_CachePic_Flags ("gfx/r_shield1", CACHEPICFLAG_QUIET);
334 rsb_items[1] = Draw_CachePic_Flags ("gfx/r_agrav1", CACHEPICFLAG_QUIET);
336 // PGM 01/19/97 - team color border
337 rsb_teambord = Draw_CachePic_Flags ("gfx/r_teambord", CACHEPICFLAG_QUIET);
338 // PGM 01/19/97 - team color border
340 rsb_ammo[0] = Draw_CachePic_Flags ("gfx/r_ammolava", CACHEPICFLAG_QUIET);
341 rsb_ammo[1] = Draw_CachePic_Flags ("gfx/r_ammomulti", CACHEPICFLAG_QUIET);
342 rsb_ammo[2] = Draw_CachePic_Flags ("gfx/r_ammoplasma", CACHEPICFLAG_QUIET);
346 sb_ranking = Draw_CachePic_Flags ("gfx/ranking", CACHEPICFLAG_QUIET);
347 sb_complete = Draw_CachePic_Flags ("gfx/complete", CACHEPICFLAG_QUIET);
348 sb_inter = Draw_CachePic_Flags ("gfx/inter", CACHEPICFLAG_QUIET);
349 sb_finale = Draw_CachePic_Flags ("gfx/finale", CACHEPICFLAG_QUIET);
352 static void sbar_shutdown(void)
356 static void sbar_newmap(void)
360 void Sbar_Init (void)
362 if(gamemode == GAME_NORMAL) // Workaround so Quake doesn't trample on Xonotic.
364 Cmd_AddCommand(CF_CLIENT, "+showscores", Sbar_ShowScores_f, "show scoreboard");
365 Cmd_AddCommand(CF_CLIENT, "-showscores", Sbar_DontShowScores_f, "hide scoreboard");
367 Cvar_RegisterVariable(&cl_showfps);
368 Cvar_RegisterVariable(&cl_showsound);
369 Cvar_RegisterVariable(&cl_showblur);
370 Cvar_RegisterVariable(&cl_showspeed);
371 Cvar_RegisterVariable(&cl_showspeed_factor);
372 Cvar_RegisterVariable(&cl_showtopspeed);
373 Cvar_RegisterVariable(&cl_showtime);
374 Cvar_RegisterVariable(&cl_showtime_format);
375 Cvar_RegisterVariable(&cl_showdate);
376 Cvar_RegisterVariable(&cl_showdate_format);
377 Cvar_RegisterVariable(&cl_showtex);
379 Cvar_RegisterAlias(&cl_showfps, "showfps");
380 Cvar_RegisterAlias(&cl_showsound, "showsound");
381 Cvar_RegisterAlias(&cl_showblur, "showblur");
382 Cvar_RegisterAlias(&cl_showspeed, "showspeed");
383 Cvar_RegisterAlias(&cl_showtopspeed, "showtopspeed");
384 Cvar_RegisterAlias(&cl_showtime, "showtime");
385 Cvar_RegisterAlias(&cl_showtime_format, "showtime_format");
386 Cvar_RegisterAlias(&cl_showdate, "showdate");
387 Cvar_RegisterAlias(&cl_showdate_format, "showdate_format");
388 Cvar_RegisterAlias(&cl_showtex, "showtex");
390 Cvar_RegisterVariable(&sbar_alpha_bg);
391 Cvar_RegisterVariable(&sbar_alpha_fg);
392 Cvar_RegisterVariable(&sbar_hudselector);
393 Cvar_RegisterVariable(&sbar_scorerank);
394 Cvar_RegisterVariable(&sbar_gametime);
395 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
396 Cvar_RegisterVariable(&sbar_info_pos);
397 Cvar_RegisterVariable(&cl_deathscoreboard);
399 Cvar_RegisterVariable(&crosshair_color_red);
400 Cvar_RegisterVariable(&crosshair_color_green);
401 Cvar_RegisterVariable(&crosshair_color_blue);
402 Cvar_RegisterVariable(&crosshair_color_alpha);
403 Cvar_RegisterVariable(&crosshair_size);
405 Cvar_RegisterVariable(&sbar_flagstatus_right); // (GAME_NEXUZI ONLY)
406 Cvar_RegisterVariable(&sbar_flagstatus_pos); // (GAME_NEXUIZ ONLY)
408 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap, NULL, NULL);
412 //=============================================================================
414 // drawing routines are relative to the status bar location
423 static void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
425 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
428 static void Sbar_DrawPic (int x, int y, cachepic_t *pic)
430 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
433 static void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
435 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
442 Draws one solid graphics character
445 static void Sbar_DrawCharacter (int x, int y, int num)
448 DrawQ_String (sbar_x + x + 4 , sbar_y + y, va(vabuf, sizeof(vabuf), "%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, true, FONT_SBAR);
456 static void Sbar_DrawString (int x, int y, char *str)
458 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR);
466 static void Sbar_DrawNum (int x, int y, int num, int digits, int color)
471 l = dpsnprintf(str, sizeof(str), "%i", num);
485 Sbar_DrawPic (x, y, sb_nums[color][frame]);
498 static void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
506 l = dpsnprintf(str, sizeof(str), "%0*i", digits, num);
509 l = dpsnprintf(str, sizeof(str), "%i", num);
514 x += (digits-l) * lettersize;
523 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
530 //=============================================================================
533 static int Sbar_IsTeammatch(void)
535 // currently only nexuiz uses the team score board
536 return (IS_OLDNEXUIZ_DERIVED(gamemode)
537 && (teamplay.integer > 0));
545 static int fragsort[MAX_SCOREBOARD];
546 static int scoreboardlines;
548 int Sbar_GetSortedPlayerIndex (int index)
550 return index >= 0 && index < scoreboardlines ? fragsort[index] : -1;
553 static scoreboard_t teams[MAX_SCOREBOARD];
554 static int teamsort[MAX_SCOREBOARD];
555 static int teamlines;
556 void Sbar_SortFrags (void)
562 for (i=0 ; i<cl.maxclients ; i++)
564 if (cl.scores[i].name[0])
566 fragsort[scoreboardlines] = i;
571 for (i=0 ; i<scoreboardlines ; i++)
572 for (j=0 ; j<scoreboardlines-1-i ; j++)
573 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
576 fragsort[j] = fragsort[j+1];
581 if (Sbar_IsTeammatch ())
583 // now sort players by teams.
584 for (i=0 ; i<scoreboardlines ; i++)
586 for (j=0 ; j<scoreboardlines-1-i ; j++)
588 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
591 fragsort[j] = fragsort[j+1];
597 // calculate team scores
599 for (i=0 ; i<scoreboardlines ; i++)
601 if (color != (cl.scores[fragsort[i]].colors & 15))
603 const char* teamname;
605 color = cl.scores[fragsort[i]].colors & 15;
611 teamname = "^1Red Team";
614 teamname = "^4Blue Team";
617 teamname = "^6Pink Team";
620 teamname = "^3Yellow Team";
623 teamname = "Total Team Score";
626 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
628 teams[teamlines-1].frags = 0;
629 teams[teamlines-1].colors = color + 16 * color;
632 if (cl.scores[fragsort[i]].frags != -666)
634 // do not add spedcators
635 // (ugly hack for nexuiz)
636 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
640 // now sort teams by scores.
641 for (i=0 ; i<teamlines ; i++)
643 for (i=0 ; i<teamlines ; i++)
645 for (j=0 ; j<teamlines-1-i ; j++)
647 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
650 teamsort[j] = teamsort[j+1];
663 static void Sbar_SoloScoreboard (void)
666 char str[80], timestr[40];
668 int minutes, seconds;
672 t = (cl.intermission ? cl.completed_time : cl.time);
673 minutes = (int)(t / 60);
674 seconds = (int)(t - 60*floor(t/60));
676 // monsters and secrets are now both on the top row
677 if (cl.stats[STAT_TOTALMONSTERS])
678 Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
679 else if (cl.stats[STAT_MONSTERS]) // LA: Display something if monsters_killed is non-zero, but total_monsters is zero
680 Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i", cl.stats[STAT_MONSTERS]));
682 if (cl.stats[STAT_TOTALSECRETS])
683 Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
684 else if (cl.stats[STAT_SECRETS]) // LA: And similarly for secrets
685 Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i", cl.stats[STAT_SECRETS]));
687 // format is like this: e1m1:The Sligpate Complex
688 dpsnprintf(str, sizeof(str), "%s:%s", cl.worldbasename, cl.worldmessage);
690 // if there's a newline character, terminate the string there
691 if (strchr(str, '\n'))
692 *(strchr(str, '\n')) = 0;
694 // make the time string
695 timelen = dpsnprintf(timestr, sizeof(timestr), " %i:%02i", minutes, seconds);
697 // truncate the level name if necessary to make room for time
699 if ((int)strlen(str) > max)
702 // print the filename and message
703 Sbar_DrawString(8, 12, str);
706 Sbar_DrawString(8 + max*8, 12, timestr);
710 int minutes, seconds, tens, units;
713 if (IS_OLDNEXUIZ_DERIVED(gamemode)) {
714 dpsnprintf (str, sizeof(str), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
715 Sbar_DrawString (8, 4, str);
717 dpsnprintf (str, sizeof(str), "Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
718 Sbar_DrawString (8, 12, str);
722 minutes = (int)(cl.time / 60);
723 seconds = (int)(cl.time - 60*minutes);
725 units = seconds - 10*tens;
726 dpsnprintf (str, sizeof(str), "Time :%3i:%i%i", minutes, tens, units);
727 Sbar_DrawString (184, 4, str);
730 if (IS_OLDNEXUIZ_DERIVED(gamemode)) {
731 l = (int) strlen (cl.worldname);
732 Sbar_DrawString (232 - l*4, 12, cl.worldname);
734 l = (int) strlen (cl.worldmessage);
735 Sbar_DrawString (232 - l*4, 12, cl.worldmessage);
745 static void Sbar_DrawScoreboard (void)
747 Sbar_SoloScoreboard ();
748 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
749 //if (cl.gametype == GAME_DEATHMATCH)
751 Sbar_DeathmatchOverlay ();
754 //=============================================================================
756 // AK to make DrawInventory smaller
757 static void Sbar_DrawWeapon(int nr, float fade, int active)
760 if (sbar_hudselector.integer == 1)
762 // width = 300, height = 100
763 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
765 DrawQ_Pic((vid_conwidth.integer - w_width * 9) * 0.5 + w_width * nr, vid_conheight.integer - w_height, sb_weapons[0][nr], w_width, w_height, (active) ? 1 : 0.6, active ? 1 : 0.6, active ? 1 : 0.6, (active ? 1 : 0.6) * fade * sbar_alpha_fg.value, DRAWFLAG_NORMAL);
767 DrawQ_String((vid_conwidth.integer - w_width * 9) * 0.5 + w_width * nr + w_space, vid_conheight.integer - w_height + w_space, va(vabuf, sizeof(vabuf), "%i",nr+1), 0, font_size, font_size, 1, 1, 0, sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT);
771 // width = 300, height = 100
772 const int w_width = 300, w_height = 100, w_space = 10;
773 const float w_scale = 0.4;
775 DrawQ_Pic(vid_conwidth.integer - (w_width + w_space) * w_scale, (w_height + w_space) * w_scale * nr + w_space, sb_weapons[0][nr], w_width * w_scale, w_height * w_scale, (active) ? 1 : 0.6, active ? 1 : 0.6, active ? 1 : 1, fade * sbar_alpha_fg.value, DRAWFLAG_NORMAL);
776 //DrawQ_String(vid_conwidth.integer - (w_space + font_size ), (w_height + w_space) * w_scale * nr + w_space, va(vabuf, sizeof(vabuf), "%i",nr+1), 0, font_size, font_size, 1, 0, 0, fade, 0, NULL, true, FONT_DEFAULT);
785 static void Sbar_DrawInventory (void)
792 if (gamemode == GAME_ROGUE)
794 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
795 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
797 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
800 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
803 for (i=0 ; i<7 ; i++)
805 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
807 time = cl.item_gettime[i];
808 flashon = (int)(max(0, cl.time - time)*10);
811 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
817 flashon = (flashon%5) + 2;
819 Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
825 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
827 int grenadeflashing=0;
828 for (i=0 ; i<4 ; i++)
830 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
832 time = max(0, cl.item_gettime[hipweapons[i]]);
833 flashon = (int)((cl.time - time)*10);
836 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
842 flashon = (flashon%5) + 2;
844 // check grenade launcher
847 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
852 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
858 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
860 if (!grenadeflashing)
861 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
864 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
867 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
872 if (gamemode == GAME_ROGUE)
874 // check for powered up weapon.
875 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
877 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
878 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
882 for (i=0 ; i<4 ; i++)
884 dpsnprintf (num, sizeof(num), "%4i",cl.stats[STAT_SHELLS+i] );
886 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
888 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
890 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
892 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
896 for (i=0 ; i<6 ; i++)
897 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
899 //MED 01/04/97 changed keys
900 if (!(gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH) || (i>1))
901 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
904 //MED 01/04/97 added hipnotic items
906 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
908 for (i=0 ; i<2 ; i++)
909 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
910 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
913 if (gamemode == GAME_ROGUE)
916 for (i=0 ; i<2 ; i++)
917 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
918 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
923 for (i=0 ; i<4 ; i++)
924 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
925 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
929 //=============================================================================
936 static void Sbar_DrawFrags (void)
946 l = min(scoreboardlines, 4);
950 for (i = 0;i < l;i++)
956 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
957 DrawQ_Fill (sbar_x + x + 10, sbar_y - 23, 28, 4, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
958 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
959 DrawQ_Fill (sbar_x + x + 10, sbar_y + 4 - 23, 28, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
963 dpsnprintf (num, sizeof(num), "%3i",f);
965 if (k == cl.viewentity - 1)
967 Sbar_DrawCharacter ( x + 2, -24, 16);
968 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
970 Sbar_DrawCharacter (x + 8, -24, num[0]);
971 Sbar_DrawCharacter (x + 16, -24, num[1]);
972 Sbar_DrawCharacter (x + 24, -24, num[2]);
977 //=============================================================================
985 static void Sbar_DrawFace (void)
989 // PGM 01/19/97 - team color drawing
990 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
991 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
997 s = &cl.scores[cl.viewentity - 1];
999 Sbar_DrawPic (112, 0, rsb_teambord);
1000 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1001 DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+3, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1002 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1003 DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+12, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1007 dpsnprintf (num, sizeof(num), "%3i",f);
1009 if ((s->colors & 0xf0)==0)
1012 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1014 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1016 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1020 Sbar_DrawCharacter ( 109, 3, num[0]);
1021 Sbar_DrawCharacter ( 116, 3, num[1]);
1022 Sbar_DrawCharacter ( 123, 3, num[2]);
1027 // PGM 01/19/97 - team color drawing
1029 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1030 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1031 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1032 Sbar_DrawPic (112, 0, sb_face_quad );
1033 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1034 Sbar_DrawPic (112, 0, sb_face_invis );
1035 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1036 Sbar_DrawPic (112, 0, sb_face_invuln);
1039 f = cl.stats[STAT_HEALTH] / 20;
1041 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1044 double topspeed = 0;
1045 double topspeedxy = 0;
1046 time_t current_time = 3;
1047 time_t top_time = 0;
1048 time_t topxy_time = 0;
1050 static void get_showspeed_unit(int unitnumber, double *conversion_factor, const char **unit)
1053 unitnumber = cl_showspeed.integer;
1059 *conversion_factor = 1.0;
1063 *conversion_factor = 1.0 * cl_showspeed_factor.value * 0.01;
1067 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01) * 3.6;
1071 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01 * 3.6) * 0.6213711922;
1075 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01 * 3.6) * 0.539957;
1080 static double showfps_nexttime = 0, showfps_lasttime = -1;
1081 static double showfps_framerate = 0;
1082 static int showfps_framecount = 0;
1084 void Sbar_ShowFPS_Update(void)
1086 double interval = 1;
1088 newtime = host.realtime;
1089 if (newtime >= showfps_nexttime)
1091 showfps_framerate = showfps_framecount / (newtime - showfps_lasttime);
1092 if (showfps_nexttime < newtime - interval * 1.5)
1093 showfps_nexttime = newtime;
1094 showfps_lasttime = newtime;
1095 showfps_nexttime += interval;
1096 showfps_framecount = 0;
1098 showfps_framecount++;
1101 void Sbar_ShowFPS(void)
1103 float fps_x, fps_y, fps_scalex, fps_scaley, fps_strings = 0;
1104 char soundstring[32];
1106 char timestring[32];
1107 char datestring[32];
1108 char timedemostring1[32];
1109 char timedemostring2[32];
1110 char speedstring[32];
1111 char blurstring[32];
1112 char topspeedstring[48];
1113 char texstring[MAX_QPATH];
1118 timedemostring1[0] = 0;
1119 timedemostring2[0] = 0;
1124 topspeedstring[0] = 0;
1127 if (cl_showfps.integer)
1129 red = (showfps_framerate < 1.0f);
1130 if(cl_showfps.integer == 2)
1131 dpsnprintf(fpsstring, sizeof(fpsstring), "%7.3f mspf", (1000.0 / showfps_framerate));
1133 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0 / showfps_framerate + 0.5));
1135 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(showfps_framerate + 0.5));
1139 dpsnprintf(timedemostring1, sizeof(timedemostring1), "frame%4i %f", cls.td_frames, host.realtime - cls.td_starttime);
1140 dpsnprintf(timedemostring2, sizeof(timedemostring2), "%i seconds %3.0f/%3.0f/%3.0f fps", cls.td_onesecondavgcount, cls.td_onesecondminfps, cls.td_onesecondavgfps / max(1, cls.td_onesecondavgcount), cls.td_onesecondmaxfps);
1145 if (cl_showtime.integer)
1147 strlcpy(timestring, Sys_TimeString(cl_showtime_format.string), sizeof(timestring));
1150 if (cl_showdate.integer)
1152 strlcpy(datestring, Sys_TimeString(cl_showdate_format.string), sizeof(datestring));
1155 if (cl_showblur.integer)
1157 dpsnprintf(blurstring, sizeof(blurstring), "%3i%% blur", (int)(cl.motionbluralpha * 100));
1160 if (cl_showsound.integer)
1162 dpsnprintf(soundstring, sizeof(soundstring), "%4i/4%i at %3ims", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds);
1165 if (cl_showspeed.integer || cl_showtopspeed.integer)
1167 double speed, speedxy, f;
1169 speed = VectorLength(cl.movement_velocity);
1170 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1171 if (cl_showspeed.integer)
1173 get_showspeed_unit(cl_showspeed.integer, &f, &unit);
1174 dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1177 if (cl_showtopspeed.integer)
1179 qbool topspeed_latched = false, topspeedxy_latched = false;
1180 get_showspeed_unit(cl_showtopspeed.integer, &f, &unit);
1181 if (speed >= topspeed || current_time - top_time > 3)
1187 topspeed_latched = true;
1188 if (speedxy >= topspeedxy || current_time - topxy_time > 3)
1190 topspeedxy = speedxy;
1194 topspeedxy_latched = true;
1195 dpsnprintf(topspeedstring, sizeof(topspeedstring), "%s%.0f%s (%s%.0f%s) %s",
1196 topspeed_latched ? "^1" : "^xf88", f*topspeed, "^xf88",
1197 topspeedxy_latched ? "^1" : "^xf88", f*topspeedxy, "^xf88",
1199 time(¤t_time);
1203 if (cl_showtex.integer)
1208 trace_t svtrace, cltrace;
1209 int hitnetentity = -1;
1211 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, org);
1212 VectorSet(temp, 65536, 0, 0);
1213 Matrix4x4_Transform(&r_refdef.view.matrix, temp, dest);
1214 // clear the traces as we may or may not fill them out, and mark them with an invalid fraction so we know if we did
1215 memset(&svtrace, 0, sizeof(svtrace));
1216 memset(&cltrace, 0, sizeof(cltrace));
1217 svtrace.fraction = 2.0;
1218 cltrace.fraction = 2.0;
1219 // ray hits models (even animated ones) and ignores translucent materials
1220 if (SVVM_prog != NULL)
1221 svtrace = SV_TraceLine(org, dest, MOVE_HITMODEL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value);
1222 cltrace = CL_TraceLine(org, dest, MOVE_HITMODEL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, &hitnetentity, true, true);
1223 if (cltrace.hittexture)
1224 strlcpy(texstring, cltrace.hittexture->name, sizeof(texstring));
1226 strlcpy(texstring, "(no texture hit)", sizeof(texstring));
1228 if (svtrace.fraction < cltrace.fraction)
1230 if (svtrace.ent != NULL)
1232 prvm_prog_t *prog = SVVM_prog;
1233 dpsnprintf(entstring, sizeof(entstring), "server entity %i", (int)PRVM_EDICT_TO_PROG(svtrace.ent));
1236 strlcpy(entstring, "(no entity hit)", sizeof(entstring));
1240 if (CLVM_prog != NULL && cltrace.ent != NULL)
1242 prvm_prog_t *prog = CLVM_prog;
1243 dpsnprintf(entstring, sizeof(entstring), "client entity %i", (int)PRVM_EDICT_TO_PROG(cltrace.ent));
1245 else if (hitnetentity > 0)
1246 dpsnprintf(entstring, sizeof(entstring), "network entity %i", hitnetentity);
1247 else if (hitnetentity == 0)
1248 strlcpy(entstring, "world entity", sizeof(entstring));
1250 strlcpy(entstring, "(no entity hit)", sizeof(entstring));
1258 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1259 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_strings*fps_scaley);
1260 fps_y = vid_conheight.integer - sbar_info_pos.integer - fps_strings*fps_scaley;
1263 fps_x = vid_conwidth.integer - DrawQ_TextWidth(soundstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1264 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1265 DrawQ_String(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1266 fps_y += fps_scaley;
1270 r_draw2d_force = true;
1271 fps_x = vid_conwidth.integer - DrawQ_TextWidth(fpsstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1272 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1274 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1276 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1277 fps_y += fps_scaley;
1278 r_draw2d_force = false;
1280 if (timedemostring1[0])
1282 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring1, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1283 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1284 DrawQ_String(fps_x, fps_y, timedemostring1, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1285 fps_y += fps_scaley;
1287 if (timedemostring2[0])
1289 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring2, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1290 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1291 DrawQ_String(fps_x, fps_y, timedemostring2, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1292 fps_y += fps_scaley;
1296 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1297 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1298 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1299 fps_y += fps_scaley;
1303 fps_x = vid_conwidth.integer - DrawQ_TextWidth(datestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1304 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1305 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1306 fps_y += fps_scaley;
1310 fps_x = vid_conwidth.integer - DrawQ_TextWidth(speedstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1311 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1312 DrawQ_String(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1313 fps_y += fps_scaley;
1315 if (topspeedstring[0])
1317 fps_x = vid_conwidth.integer - DrawQ_TextWidth(topspeedstring, 0, fps_scalex, fps_scaley, false, FONT_INFOBAR);
1318 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1319 DrawQ_String(fps_x, fps_y, topspeedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR);
1320 fps_y += fps_scaley;
1324 fps_x = vid_conwidth.integer - DrawQ_TextWidth(blurstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1325 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1326 DrawQ_String(fps_x, fps_y, blurstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1327 fps_y += fps_scaley;
1331 fps_x = vid_conwidth.integer - DrawQ_TextWidth(texstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1332 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1333 DrawQ_String(fps_x, fps_y, texstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1334 fps_y += fps_scaley;
1338 fps_x = vid_conwidth.integer - DrawQ_TextWidth(entstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1339 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1340 DrawQ_String(fps_x, fps_y, entstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1341 fps_y += fps_scaley;
1346 static void Sbar_DrawGauge(float x, float y, cachepic_t *pic, float width, float height, float rangey, float rangeheight, float c1, float c2, float c1r, float c1g, float c1b, float c1a, float c2r, float c2g, float c2b, float c2a, float c3r, float c3g, float c3b, float c3a, int drawflags)
1349 c2 = bound(0, c2, 1);
1350 c1 = bound(0, c1, 1 - c2);
1352 r[1] = rangey + rangeheight * (c2 + c1);
1353 r[2] = rangey + rangeheight * (c2);
1357 DrawQ_SuperPic(x, y + r[0], pic, width, (r[1] - r[0]), 0,(r[0] / height), c3r,c3g,c3b,c3a, 1,(r[0] / height), c3r,c3g,c3b,c3a, 0,(r[1] / height), c3r,c3g,c3b,c3a, 1,(r[1] / height), c3r,c3g,c3b,c3a, drawflags);
1359 DrawQ_SuperPic(x, y + r[1], pic, width, (r[2] - r[1]), 0,(r[1] / height), c1r,c1g,c1b,c1a, 1,(r[1] / height), c1r,c1g,c1b,c1a, 0,(r[2] / height), c1r,c1g,c1b,c1a, 1,(r[2] / height), c1r,c1g,c1b,c1a, drawflags);
1361 DrawQ_SuperPic(x, y + r[2], pic, width, (r[3] - r[2]), 0,(r[2] / height), c2r,c2g,c2b,c2a, 1,(r[2] / height), c2r,c2g,c2b,c2a, 0,(r[3] / height), c2r,c2g,c2b,c2a, 1,(r[3] / height), c2r,c2g,c2b,c2a, drawflags);
1363 DrawQ_SuperPic(x, y + r[3], pic, width, (r[4] - r[3]), 0,(r[3] / height), c3r,c3g,c3b,c3a, 1,(r[3] / height), c3r,c3g,c3b,c3a, 0,(r[4] / height), c3r,c3g,c3b,c3a, 1,(r[4] / height), c3r,c3g,c3b,c3a, drawflags);
1371 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1372 extern cvar_t v_kicktime;
1373 void Sbar_Score (int margin);
1374 void Sbar_Draw (void)
1379 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1382 Sbar_DrawScoreboard ();
1383 else if (cl.intermission == 1)
1385 if(IS_OLDNEXUIZ_DERIVED(gamemode)) // display full scoreboard (that is, show scores + map name)
1387 Sbar_DrawScoreboard();
1390 Sbar_IntermissionOverlay();
1392 else if (cl.intermission == 2)
1393 Sbar_FinaleOverlay();
1394 else if (gamemode == GAME_DELUXEQUAKE)
1397 else if (IS_OLDNEXUIZ_DERIVED(gamemode))
1399 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1401 sbar_x = (vid_conwidth.integer - 640)/2;
1402 sbar_y = vid_conheight.integer - 47;
1403 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1404 Sbar_DrawScoreboard ();
1406 else if (sb_lines && sbar_hudselector.integer == 1)
1410 int redflag, blueflag;
1413 sbar_x = (vid_conwidth.integer - 320)/2;
1414 sbar_y = vid_conheight.integer - 24 - 16;
1416 // calculate intensity to draw weapons bar at
1417 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1418 fade = bound(0.7, fade, 1);
1419 for (i = 0; i < 8;i++)
1420 if (cl.stats[STAT_ITEMS] & (1 << i))
1421 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1422 if((cl.stats[STAT_ITEMS] & (1<<12)))
1423 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1426 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1427 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1428 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1429 if (redflag == 3 && blueflag == 3)
1431 // The Impossible Combination[tm]
1432 // Can only happen in Key Hunt mode...
1433 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[14]);
1438 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64)), sb_items[redflag+10]);
1440 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[blueflag+14]);
1444 if (cl.stats[STAT_ARMOR] > 0)
1446 Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1447 if(cl.stats[STAT_ARMOR] > 200)
1448 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1449 else if(cl.stats[STAT_ARMOR] > 100)
1450 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1451 else if(cl.stats[STAT_ARMOR] > 50)
1452 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1453 else if(cl.stats[STAT_ARMOR] > 25)
1454 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1456 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1460 if (cl.stats[STAT_HEALTH] != 0)
1462 Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1463 if(cl.stats[STAT_HEALTH] > 200)
1464 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1465 else if(cl.stats[STAT_HEALTH] > 100)
1466 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1467 else if(cl.stats[STAT_HEALTH] > 50)
1468 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1469 else if(cl.stats[STAT_HEALTH] > 25)
1470 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1472 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1476 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1478 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1479 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1480 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1481 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1482 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1483 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1484 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1485 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1486 if(cl.stats[STAT_AMMO] > 10)
1487 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1489 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1492 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1493 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1496 // The margin can be at most 8 to support 640x480 console size:
1497 // 320 + 2 * (144 + 16) = 640
1503 int redflag, blueflag;
1506 sbar_x = (vid_conwidth.integer - 640)/2;
1507 sbar_y = vid_conheight.integer - 47;
1509 // calculate intensity to draw weapons bar at
1510 fade = 3 - 2 * (cl.time - cl.weapontime);
1513 fade = min(fade, 1);
1514 for (i = 0; i < 8;i++)
1515 if (cl.stats[STAT_ITEMS] & (1 << i))
1516 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1518 if((cl.stats[STAT_ITEMS] & (1<<12)))
1519 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1522 //if (!cl.islocalgame)
1523 // Sbar_DrawFrags ();
1526 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1528 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1531 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1532 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1533 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1534 if (redflag == 3 && blueflag == 3)
1536 // The Impossible Combination[tm]
1537 // Can only happen in Key Hunt mode...
1538 Sbar_DrawPic ((int) x, -179, sb_items[14]);
1543 Sbar_DrawPic ((int) x, -117, sb_items[redflag+10]);
1545 Sbar_DrawPic ((int) x, -177, sb_items[blueflag+14]);
1549 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1552 if(cl.stats[STAT_HEALTH] > 100)
1553 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1554 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1555 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1557 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1559 // AK dont draw ammo for the laser
1560 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1562 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1563 Sbar_DrawPic (519, 0, sb_ammo[0]);
1564 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1565 Sbar_DrawPic (519, 0, sb_ammo[1]);
1566 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1567 Sbar_DrawPic (519, 0, sb_ammo[2]);
1568 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1569 Sbar_DrawPic (519, 0, sb_ammo[3]);
1571 if(cl.stats[STAT_AMMO] <= 10)
1572 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1574 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1579 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1581 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1582 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1587 // Mini scoreboard uses 12*4 per other team, that is, 144
1588 // pixels when there are four teams...
1589 // Nexuiz by default sets vid_conwidth to 800... makes
1591 // so we need to shift it by 64 pixels to the right to fit
1592 // BUT: then it overlaps with the image that gets drawn
1593 // for viewsize 100! Therefore, just account for 3 teams,
1594 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1598 else if (gamemode == GAME_ZYMOTIC)
1601 float scale = 64.0f / 256.0f;
1602 float kickoffset[3];
1603 VectorClear(kickoffset);
1606 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1607 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1609 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1610 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1611 // left1 16, 48 : 126 -66
1612 // left2 16, 128 : 196 -66
1613 // right 176, 48 : 196 -136
1614 Sbar_DrawGauge(sbar_x + 16 * scale, sbar_y + 48 * scale, zymsb_crosshair_left1, 64*scale, 80*scale, 78*scale, -66*scale, cl.stats[STAT_AMMO] * (1.0 / 200.0), cl.stats[STAT_SHELLS] * (1.0 / 200.0), 0.8f,0.8f,0.0f,1.0f, 0.8f,0.5f,0.0f,1.0f, 0.3f,0.3f,0.3f,1.0f, DRAWFLAG_NORMAL);
1615 Sbar_DrawGauge(sbar_x + 16 * scale, sbar_y + 128 * scale, zymsb_crosshair_left2, 64*scale, 80*scale, 68*scale, -66*scale, cl.stats[STAT_NAILS] * (1.0 / 200.0), cl.stats[STAT_ROCKETS] * (1.0 / 200.0), 0.8f,0.8f,0.0f,1.0f, 0.8f,0.5f,0.0f,1.0f, 0.3f,0.3f,0.3f,1.0f, DRAWFLAG_NORMAL);
1616 Sbar_DrawGauge(sbar_x + 176 * scale, sbar_y + 48 * scale, zymsb_crosshair_right, 64*scale, 160*scale, 148*scale, -136*scale, cl.stats[STAT_ARMOR] * (1.0 / 300.0), cl.stats[STAT_HEALTH] * (1.0 / 300.0), 0.0f,0.5f,1.0f,1.0f, 1.0f,0.0f,0.0f,1.0f, 0.3f,0.3f,0.3f,1.0f, DRAWFLAG_NORMAL);
1617 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1619 float scale = 128.0f / 256.0f;
1620 float healthstart, healthheight, healthstarttc, healthendtc;
1621 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1622 float ammostart, ammoheight, ammostarttc, ammoendtc;
1623 float clipstart, clipheight, clipstarttc, clipendtc;
1624 float kickoffset[3], offset;
1625 VectorClear(kickoffset);
1628 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1629 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1631 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1632 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1633 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1634 DrawQ_SuperPic(sbar_x + 120 * scale, sbar_y + ( 88 - offset) * scale, zymsb_crosshair_line, 16 * scale, 36 * scale, 0,0, 1,1,1,1, 1,0, 1,1,1,1, 0,1, 1,1,1,1, 1,1, 1,1,1,1, 0);
1635 DrawQ_SuperPic(sbar_x + (132 + offset) * scale, sbar_y + 120 * scale, zymsb_crosshair_line, 36 * scale, 16 * scale, 0,1, 1,1,1,1, 0,0, 1,1,1,1, 1,1, 1,1,1,1, 1,0, 1,1,1,1, 0);
1636 DrawQ_SuperPic(sbar_x + 120 * scale, sbar_y + (132 + offset) * scale, zymsb_crosshair_line, 16 * scale, 36 * scale, 1,1, 1,1,1,1, 0,1, 1,1,1,1, 1,0, 1,1,1,1, 0,0, 1,1,1,1, 0);
1637 DrawQ_SuperPic(sbar_x + ( 88 - offset) * scale, sbar_y + 120 * scale, zymsb_crosshair_line, 36 * scale, 16 * scale, 1,0, 1,1,1,1, 1,1, 1,1,1,1, 0,0, 1,1,1,1, 0,1, 1,1,1,1, 0);
1638 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1639 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1640 healthstart = 204 - healthheight;
1641 shieldstart = healthstart - shieldheight;
1642 healthstarttc = healthstart * (1.0f / 256.0f);
1643 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1644 shieldstarttc = shieldstart * (1.0f / 256.0f);
1645 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1646 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1647 ammostart = 114 - ammoheight;
1648 ammostarttc = ammostart * (1.0f / 256.0f);
1649 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1650 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1651 clipstart = 190 - clipheight;
1652 clipstarttc = clipstart * (1.0f / 256.0f);
1653 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1654 if (healthheight > 0) DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + healthstart * scale, zymsb_crosshair_health, 256 * scale, healthheight * scale, 0,healthstarttc, 1.0f,0.0f,0.0f,1.0f, 1,healthstarttc, 1.0f,0.0f,0.0f,1.0f, 0,healthendtc, 1.0f,0.0f,0.0f,1.0f, 1,healthendtc, 1.0f,0.0f,0.0f,1.0f, DRAWFLAG_NORMAL);
1655 if (shieldheight > 0) DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + shieldstart * scale, zymsb_crosshair_health, 256 * scale, shieldheight * scale, 0,shieldstarttc, 0.0f,0.5f,1.0f,1.0f, 1,shieldstarttc, 0.0f,0.5f,1.0f,1.0f, 0,shieldendtc, 0.0f,0.5f,1.0f,1.0f, 1,shieldendtc, 0.0f,0.5f,1.0f,1.0f, DRAWFLAG_NORMAL);
1656 if (ammoheight > 0) DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + ammostart * scale, zymsb_crosshair_ammo, 256 * scale, ammoheight * scale, 0,ammostarttc, 0.8f,0.8f,0.0f,1.0f, 1,ammostarttc, 0.8f,0.8f,0.0f,1.0f, 0,ammoendtc, 0.8f,0.8f,0.0f,1.0f, 1,ammoendtc, 0.8f,0.8f,0.0f,1.0f, DRAWFLAG_NORMAL);
1657 if (clipheight > 0) DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + clipstart * scale, zymsb_crosshair_clip, 256 * scale, clipheight * scale, 0,clipstarttc, 1.0f,1.0f,0.0f,1.0f, 1,clipstarttc, 1.0f,1.0f,0.0f,1.0f, 0,clipendtc, 1.0f,1.0f,0.0f,1.0f, 1,clipendtc, 1.0f,1.0f,0.0f,1.0f, DRAWFLAG_NORMAL);
1658 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1659 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1662 else // Quake and others
1664 sbar_x = (vid_conwidth.integer - 320)/2;
1665 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1666 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1667 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1671 if (gamemode != GAME_GOODVSBAD2)
1672 Sbar_DrawInventory ();
1673 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1677 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1679 if (gamemode != GAME_GOODVSBAD2)
1680 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1681 Sbar_DrawScoreboard ();
1685 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1687 // keys (hipnotic only)
1688 //MED 01/04/97 moved keys here so they would not be overwritten
1689 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
1691 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1692 Sbar_DrawPic (209, 3, sb_items[0]);
1693 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1694 Sbar_DrawPic (209, 12, sb_items[1]);
1697 if (gamemode != GAME_GOODVSBAD2)
1699 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1701 Sbar_DrawNum (24, 0, 666, 3, 1);
1702 Sbar_DrawPic (0, 0, sb_disc);
1706 if (gamemode == GAME_ROGUE)
1708 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1709 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1710 Sbar_DrawPic (0, 0, sb_armor[2]);
1711 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1712 Sbar_DrawPic (0, 0, sb_armor[1]);
1713 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1714 Sbar_DrawPic (0, 0, sb_armor[0]);
1718 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1719 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1720 Sbar_DrawPic (0, 0, sb_armor[2]);
1721 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1722 Sbar_DrawPic (0, 0, sb_armor[1]);
1723 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1724 Sbar_DrawPic (0, 0, sb_armor[0]);
1733 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1736 if (gamemode == GAME_ROGUE)
1738 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1739 Sbar_DrawPic (224, 0, sb_ammo[0]);
1740 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1741 Sbar_DrawPic (224, 0, sb_ammo[1]);
1742 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1743 Sbar_DrawPic (224, 0, sb_ammo[2]);
1744 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1745 Sbar_DrawPic (224, 0, sb_ammo[3]);
1746 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1747 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1748 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1749 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1750 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1751 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1755 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1756 Sbar_DrawPic (224, 0, sb_ammo[0]);
1757 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1758 Sbar_DrawPic (224, 0, sb_ammo[1]);
1759 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1760 Sbar_DrawPic (224, 0, sb_ammo[2]);
1761 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1762 Sbar_DrawPic (224, 0, sb_ammo[3]);
1765 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1767 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1768 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1770 if (gamemode == GAME_TRANSFUSION)
1771 Sbar_MiniDeathmatchOverlay (0, 0);
1773 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1780 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1782 pic = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/crosshair%i", crosshair.integer));
1783 DrawQ_Pic((vid_conwidth.integer - Draw_GetPicWidth(pic) * crosshair_size.value) * 0.5f, (vid_conheight.integer - Draw_GetPicHeight(pic) * crosshair_size.value) * 0.5f, pic, Draw_GetPicWidth(pic) * crosshair_size.value, Draw_GetPicHeight(pic) * crosshair_size.value, crosshair_color_red.value, crosshair_color_green.value, crosshair_color_blue.value, crosshair_color_alpha.value, 0);
1786 if (cl_prydoncursor.integer > 0)
1787 DrawQ_Pic((cl.cmd.cursor_screen[0] + 1) * 0.5 * vid_conwidth.integer, (cl.cmd.cursor_screen[1] + 1) * 0.5 * vid_conheight.integer, Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/prydoncursor%03i", cl_prydoncursor.integer)), 0, 0, 1, 1, 1, 1, 0);
1790 //=============================================================================
1794 Sbar_DeathmatchOverlay
1798 static float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1801 qbool myself = false;
1804 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1806 if((s - cl.scores) == cl.playerentity - 1)
1808 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1809 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1812 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1814 if (s->qw_spectator)
1816 if (s->qw_ping || s->qw_packetloss)
1817 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i %4i spectator %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1819 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), " %4i spectator %c%s", minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1823 // draw colors behind score
1829 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1830 DrawQ_Fill(x + 14*8*FONT_SBAR->maxwidth, y+1, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1831 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1832 DrawQ_Fill(x + 14*8*FONT_SBAR->maxwidth, y+4, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1834 //DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%c%4i %s", myself ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT);
1835 if (s->qw_ping || s->qw_packetloss)
1836 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i %4i %5i %-4s %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1838 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), " %4i %5i %-4s %c%s", minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1843 if (s->qw_spectator)
1845 if (s->qw_ping || s->qw_packetloss)
1846 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i spect %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1848 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), " spect %c%s", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1852 // draw colors behind score
1853 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1854 DrawQ_Fill(x + 9*8*FONT_SBAR->maxwidth, y+1, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1855 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1856 DrawQ_Fill(x + 9*8*FONT_SBAR->maxwidth, y+4, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1858 //DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%c%4i %s", myself ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT);
1859 if (s->qw_ping || s->qw_packetloss)
1860 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i %5i %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1862 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), " %5i %c%s", (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1868 void Sbar_DeathmatchOverlay (void)
1870 int i, y, xmin, xmax, ymin, ymax;
1873 // request new ping times every two second
1874 if (cl.last_ping_request < host.realtime - 2 && cls.netcon)
1876 cl.last_ping_request = host.realtime;
1877 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1879 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1880 MSG_WriteString(&cls.netcon->message, "pings");
1882 else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6/* || cls.protocol == PROTOCOL_DARKPLACES7*/)
1884 // these servers usually lack the pings command and so a less efficient "ping" command must be sent, which on modern DP servers will also reply with a pingplreport command after the ping listing
1885 static int ping_anyway_counter = 0;
1886 if(cl.parsingtextexpectingpingforscores == 1)
1888 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1889 if(++ping_anyway_counter >= 5)
1890 cl.parsingtextexpectingpingforscores = 0;
1892 if(cl.parsingtextexpectingpingforscores != 1)
1894 ping_anyway_counter = 0;
1895 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1896 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1897 MSG_WriteString(&cls.netcon->message, "ping");
1902 // newer server definitely has pings command, so use it for more efficiency, avoids ping reports spamming the console if they are misparsed, and saves a little bandwidth
1903 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1904 MSG_WriteString(&cls.netcon->message, "pings");
1912 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1914 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1915 xmin = (int) (vid_conwidth.integer - (26 + 15) * 8 * FONT_SBAR->maxwidth) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1917 xmin = (int) (vid_conwidth.integer - (16 + 25) * 8 * FONT_SBAR->maxwidth) / 2; // 16 characters until name, then we assume 25 character names (they can be longer but usually aren't)
1918 xmax = vid_conwidth.integer - xmin;
1920 if(IS_OLDNEXUIZ_DERIVED(gamemode))
1921 DrawQ_Pic (xmin - 8, ymin - 8, 0, xmax-xmin+1 + 2*8, ymax-ymin+1 + 2*8, 0, 0, 0, sbar_alpha_bg.value, 0);
1923 DrawQ_Pic ((vid_conwidth.integer - Draw_GetPicWidth(sb_ranking))/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1927 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1929 DrawQ_String(xmin, y, va(vabuf, sizeof(vabuf), "ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1933 DrawQ_String(xmin, y, va(vabuf, sizeof(vabuf), "ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1937 if (Sbar_IsTeammatch ())
1939 // show team scores first
1940 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1941 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1945 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1946 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1951 Sbar_MiniDeathmatchOverlay
1955 void Sbar_MiniDeathmatchOverlay (int x, int y)
1957 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1959 // do not draw this if sbar_miniscoreboard_size is zero
1960 if(sbar_miniscoreboard_size.value == 0)
1962 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1963 if(sbar_miniscoreboard_size.value > 0)
1964 y = (int) (vid_conheight.integer - sbar_miniscoreboard_size.value * 8);
1969 // decide where to print
1970 if (gamemode == GAME_TRANSFUSION)
1971 numlines = (vid_conwidth.integer - x + 127) / 128;
1973 numlines = (vid_conheight.integer - y + 7) / 8;
1975 // give up if there isn't room
1976 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1980 for (i = 0; i < scoreboardlines; i++)
1981 if (fragsort[i] == cl.playerentity - 1)
1985 range_end = scoreboardlines;
1988 if (gamemode != GAME_TRANSFUSION)
1989 if (Sbar_IsTeammatch ())
1991 // reserve space for the team scores
1992 numlines -= teamlines;
1994 // find first and last player of my team (only draw the team totals and my own team)
1995 range_begin = range_end = i;
1996 myteam = cl.scores[fragsort[i]].colors & 15;
1997 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1999 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
2002 // looks better than two players
2012 i = min(i, range_end - numlines);
2013 i = max(i, range_begin);
2015 if (gamemode == GAME_TRANSFUSION)
2017 for (;i < range_end && x < vid_conwidth.integer;i++)
2018 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2022 if(range_end - i < numlines) // won't draw to bottom?
2023 y += 8 * (numlines - (range_end - i)); // bottom align
2024 // show team scores first
2025 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
2026 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
2028 for (;i < range_end && y < vid_conheight.integer;i++)
2029 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2033 static int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
2035 static int const sortorder[16] =
2054 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
2055 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
2056 int tc1 = sortorder[t1->colors & 15];
2057 int tc2 = sortorder[t2->colors & 15];
2061 void Sbar_Score (int margin)
2063 int i, me, score, otherleader, place, distribution, minutes, seconds;
2065 int sbar_x_save = sbar_x;
2066 int sbar_y_save = sbar_y;
2069 sbar_y = (int) (vid_conheight.value - (32+12));
2072 me = cl.playerentity - 1;
2073 if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients)
2075 if(Sbar_IsTeammatch())
2079 // team1 team3 team4
2083 scoreboard_t *teamcolorsort[16];
2086 for(i = 0; i < teamlines; ++i)
2087 teamcolorsort[i] = &(teams[i]);
2089 // Now sort them by color
2090 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
2093 // -12*4: four digits space
2094 place = (teamlines - 1) * (-12 * 4);
2096 for(i = 0; i < teamlines; ++i)
2098 int cindex = teamcolorsort[i]->colors & 15;
2099 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
2100 float cm = max(max(c[0], c[1]), c[2]);
2101 float cr = c[0] / cm;
2102 float cg = c[1] / cm;
2103 float cb = c[2] / cm;
2104 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
2106 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
2110 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
2123 // find leading score other than ourselves, to calculate distribution
2124 // find our place in the scoreboard
2125 score = cl.scores[me].frags;
2126 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
2128 if (cl.scores[i].name[0] && i != me)
2130 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
2132 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
2136 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
2138 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2139 else if (place == 2)
2140 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2142 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2143 if (otherleader < 0)
2144 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2145 if (distribution >= 0)
2147 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2148 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2150 else if (distribution >= -5)
2152 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2153 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2157 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2158 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2163 if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT])
2165 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2166 minutes = (int)floor(timeleft / 60);
2167 seconds = (int)(floor(timeleft) - minutes * 60);
2170 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2171 if (Draw_IsPicLoaded(sb_colon))
2172 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2173 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2175 else if (minutes >= 1)
2177 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2178 if (Draw_IsPicLoaded(sb_colon))
2179 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2180 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2182 else if ((int)(timeleft * 4) & 1)
2183 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2185 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2187 else if (sbar_gametime.integer)
2189 minutes = (int)floor(cl.time / 60);
2190 seconds = (int)(floor(cl.time) - minutes * 60);
2191 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2192 if (Draw_IsPicLoaded(sb_colon))
2193 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2194 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2197 sbar_x = sbar_x_save;
2198 sbar_y = sbar_y_save;
2203 Sbar_IntermissionOverlay
2207 void Sbar_IntermissionOverlay (void)
2212 if (cl.gametype == GAME_DEATHMATCH)
2214 Sbar_DeathmatchOverlay ();
2218 sbar_x = (vid_conwidth.integer - 320) >> 1;
2219 sbar_y = (vid_conheight.integer - 200) >> 1;
2221 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2222 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2225 dig = (int)cl.completed_time / 60;
2226 Sbar_DrawNum (160, 64, dig, 3, 0);
2227 num = (int)cl.completed_time - dig*60;
2228 Sbar_DrawPic (234,64,sb_colon);
2229 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2230 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2232 // LA: Display as "a" instead of "a/b" if b is 0
2233 if(cl.stats[STAT_TOTALSECRETS])
2235 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2236 if (!IS_OLDNEXUIZ_DERIVED(gamemode))
2237 Sbar_DrawPic (232, 104, sb_slash);
2238 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2242 Sbar_DrawNum (240, 104, cl.stats[STAT_SECRETS], 3, 0);
2245 if(cl.stats[STAT_TOTALMONSTERS])
2247 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2248 if (!IS_OLDNEXUIZ_DERIVED(gamemode))
2249 Sbar_DrawPic (232, 144, sb_slash);
2250 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2254 Sbar_DrawNum (240, 144, cl.stats[STAT_MONSTERS], 3, 0);
2265 void Sbar_FinaleOverlay (void)
2267 DrawQ_Pic((vid_conwidth.integer - Draw_GetPicWidth(sb_finale))/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);