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 // FIXME: Don't know what game we're running until after cvars are initialized.
363 // So we're not doing this in our Init_Commands function yet.
364 if(gamemode == GAME_NORMAL) // Workaround so Quake doesn't trample on Xonotic.
366 Cmd_AddCommand(CF_CLIENT, "+showscores", Sbar_ShowScores_f, "show scoreboard");
367 Cmd_AddCommand(CF_CLIENT, "-showscores", Sbar_DontShowScores_f, "hide scoreboard");
369 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap, NULL, NULL);
372 void Sbar_Init_Commands(void)
374 Cvar_RegisterVariable(&cl_showfps);
375 Cvar_RegisterVariable(&cl_showsound);
376 Cvar_RegisterVariable(&cl_showblur);
377 Cvar_RegisterVariable(&cl_showspeed);
378 Cvar_RegisterVariable(&cl_showspeed_factor);
379 Cvar_RegisterVariable(&cl_showtopspeed);
380 Cvar_RegisterVariable(&cl_showtime);
381 Cvar_RegisterVariable(&cl_showtime_format);
382 Cvar_RegisterVariable(&cl_showdate);
383 Cvar_RegisterVariable(&cl_showdate_format);
384 Cvar_RegisterVariable(&cl_showtex);
386 Cvar_RegisterAlias(&cl_showfps, "showfps");
387 Cvar_RegisterAlias(&cl_showsound, "showsound");
388 Cvar_RegisterAlias(&cl_showblur, "showblur");
389 Cvar_RegisterAlias(&cl_showspeed, "showspeed");
390 Cvar_RegisterAlias(&cl_showtopspeed, "showtopspeed");
391 Cvar_RegisterAlias(&cl_showtime, "showtime");
392 Cvar_RegisterAlias(&cl_showtime_format, "showtime_format");
393 Cvar_RegisterAlias(&cl_showdate, "showdate");
394 Cvar_RegisterAlias(&cl_showdate_format, "showdate_format");
395 Cvar_RegisterAlias(&cl_showtex, "showtex");
397 Cvar_RegisterVariable(&sbar_alpha_bg);
398 Cvar_RegisterVariable(&sbar_alpha_fg);
399 Cvar_RegisterVariable(&sbar_hudselector);
400 Cvar_RegisterVariable(&sbar_scorerank);
401 Cvar_RegisterVariable(&sbar_gametime);
402 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
403 Cvar_RegisterVariable(&sbar_info_pos);
404 Cvar_RegisterVariable(&cl_deathscoreboard);
406 Cvar_RegisterVariable(&crosshair_color_red);
407 Cvar_RegisterVariable(&crosshair_color_green);
408 Cvar_RegisterVariable(&crosshair_color_blue);
409 Cvar_RegisterVariable(&crosshair_color_alpha);
410 Cvar_RegisterVariable(&crosshair_size);
412 Cvar_RegisterVariable(&sbar_flagstatus_right); // (GAME_NEXUZI ONLY)
413 Cvar_RegisterVariable(&sbar_flagstatus_pos); // (GAME_NEXUIZ ONLY)
416 //=============================================================================
418 // drawing routines are relative to the status bar location
427 static void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
429 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
432 static void Sbar_DrawPic (int x, int y, cachepic_t *pic)
434 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
437 static void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
439 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
446 Draws one solid graphics character
449 static void Sbar_DrawCharacter (int x, int y, int num)
452 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);
460 static void Sbar_DrawString (int x, int y, char *str)
462 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR);
470 static void Sbar_DrawNum (int x, int y, int num, int digits, int color)
475 l = dpsnprintf(str, sizeof(str), "%i", num);
489 Sbar_DrawPic (x, y, sb_nums[color][frame]);
502 static void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
510 l = dpsnprintf(str, sizeof(str), "%0*i", digits, num);
513 l = dpsnprintf(str, sizeof(str), "%i", num);
518 x += (digits-l) * lettersize;
527 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
534 //=============================================================================
537 static int Sbar_IsTeammatch(void)
539 // currently only nexuiz uses the team score board
540 return (IS_OLDNEXUIZ_DERIVED(gamemode)
541 && (teamplay.integer > 0));
549 static int fragsort[MAX_SCOREBOARD];
550 static int scoreboardlines;
552 int Sbar_GetSortedPlayerIndex (int index)
554 return index >= 0 && index < scoreboardlines ? fragsort[index] : -1;
557 static scoreboard_t teams[MAX_SCOREBOARD];
558 static int teamsort[MAX_SCOREBOARD];
559 static int teamlines;
560 void Sbar_SortFrags (void)
566 for (i=0 ; i<cl.maxclients ; i++)
568 if (cl.scores[i].name[0])
570 fragsort[scoreboardlines] = i;
575 for (i=0 ; i<scoreboardlines ; i++)
576 for (j=0 ; j<scoreboardlines-1-i ; j++)
577 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
580 fragsort[j] = fragsort[j+1];
585 if (Sbar_IsTeammatch ())
587 // now sort players by teams.
588 for (i=0 ; i<scoreboardlines ; i++)
590 for (j=0 ; j<scoreboardlines-1-i ; j++)
592 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
595 fragsort[j] = fragsort[j+1];
601 // calculate team scores
603 for (i=0 ; i<scoreboardlines ; i++)
605 if (color != (cl.scores[fragsort[i]].colors & 15))
607 const char* teamname;
609 color = cl.scores[fragsort[i]].colors & 15;
615 teamname = "^1Red Team";
618 teamname = "^4Blue Team";
621 teamname = "^6Pink Team";
624 teamname = "^3Yellow Team";
627 teamname = "Total Team Score";
630 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
632 teams[teamlines-1].frags = 0;
633 teams[teamlines-1].colors = color + 16 * color;
636 if (cl.scores[fragsort[i]].frags != -666)
638 // do not add spedcators
639 // (ugly hack for nexuiz)
640 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
644 // now sort teams by scores.
645 for (i=0 ; i<teamlines ; i++)
647 for (i=0 ; i<teamlines ; i++)
649 for (j=0 ; j<teamlines-1-i ; j++)
651 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
654 teamsort[j] = teamsort[j+1];
667 static void Sbar_SoloScoreboard (void)
670 char str[80], timestr[40];
672 int minutes, seconds;
676 t = (cl.intermission ? cl.completed_time : cl.time);
677 minutes = (int)(t / 60);
678 seconds = (int)(t - 60*floor(t/60));
680 // monsters and secrets are now both on the top row
681 if (cl.stats[STAT_TOTALMONSTERS])
682 Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
683 else if (cl.stats[STAT_MONSTERS]) // LA: Display something if monsters_killed is non-zero, but total_monsters is zero
684 Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i", cl.stats[STAT_MONSTERS]));
686 if (cl.stats[STAT_TOTALSECRETS])
687 Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
688 else if (cl.stats[STAT_SECRETS]) // LA: And similarly for secrets
689 Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i", cl.stats[STAT_SECRETS]));
691 // format is like this: e1m1:The Sligpate Complex
692 dpsnprintf(str, sizeof(str), "%s:%s", cl.worldbasename, cl.worldmessage);
694 // if there's a newline character, terminate the string there
695 if (strchr(str, '\n'))
696 *(strchr(str, '\n')) = 0;
698 // make the time string
699 timelen = dpsnprintf(timestr, sizeof(timestr), " %i:%02i", minutes, seconds);
701 // truncate the level name if necessary to make room for time
703 if ((int)strlen(str) > max)
706 // print the filename and message
707 Sbar_DrawString(8, 12, str);
710 Sbar_DrawString(8 + max*8, 12, timestr);
714 int minutes, seconds, tens, units;
717 if (IS_OLDNEXUIZ_DERIVED(gamemode)) {
718 dpsnprintf (str, sizeof(str), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
719 Sbar_DrawString (8, 4, str);
721 dpsnprintf (str, sizeof(str), "Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
722 Sbar_DrawString (8, 12, str);
726 minutes = (int)(cl.time / 60);
727 seconds = (int)(cl.time - 60*minutes);
729 units = seconds - 10*tens;
730 dpsnprintf (str, sizeof(str), "Time :%3i:%i%i", minutes, tens, units);
731 Sbar_DrawString (184, 4, str);
734 if (IS_OLDNEXUIZ_DERIVED(gamemode)) {
735 l = (int) strlen (cl.worldname);
736 Sbar_DrawString (232 - l*4, 12, cl.worldname);
738 l = (int) strlen (cl.worldmessage);
739 Sbar_DrawString (232 - l*4, 12, cl.worldmessage);
749 static void Sbar_DrawScoreboard (void)
751 Sbar_SoloScoreboard ();
752 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
753 //if (cl.gametype == GAME_DEATHMATCH)
755 Sbar_DeathmatchOverlay ();
758 //=============================================================================
760 // AK to make DrawInventory smaller
761 static void Sbar_DrawWeapon(int nr, float fade, int active)
764 if (sbar_hudselector.integer == 1)
766 // width = 300, height = 100
767 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
769 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);
771 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);
775 // width = 300, height = 100
776 const int w_width = 300, w_height = 100, w_space = 10;
777 const float w_scale = 0.4;
779 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);
780 //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);
789 static void Sbar_DrawInventory (void)
796 if (gamemode == GAME_ROGUE)
798 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
799 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
801 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
804 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
807 for (i=0 ; i<7 ; i++)
809 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
811 time = cl.item_gettime[i];
812 flashon = (int)(max(0, cl.time - time)*10);
815 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
821 flashon = (flashon%5) + 2;
823 Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
829 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
831 int grenadeflashing=0;
832 for (i=0 ; i<4 ; i++)
834 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
836 time = max(0, cl.item_gettime[hipweapons[i]]);
837 flashon = (int)((cl.time - time)*10);
840 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
846 flashon = (flashon%5) + 2;
848 // check grenade launcher
851 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
856 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
862 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
864 if (!grenadeflashing)
865 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
868 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
871 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
876 if (gamemode == GAME_ROGUE)
878 // check for powered up weapon.
879 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
881 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
882 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
886 for (i=0 ; i<4 ; i++)
888 dpsnprintf (num, sizeof(num), "%4i",cl.stats[STAT_SHELLS+i] );
890 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
892 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
894 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
896 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
900 for (i=0 ; i<6 ; i++)
901 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
903 //MED 01/04/97 changed keys
904 if (!(gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH) || (i>1))
905 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
908 //MED 01/04/97 added hipnotic items
910 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
912 for (i=0 ; i<2 ; i++)
913 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
914 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
917 if (gamemode == GAME_ROGUE)
920 for (i=0 ; i<2 ; i++)
921 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
922 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
927 for (i=0 ; i<4 ; i++)
928 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
929 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
933 //=============================================================================
940 static void Sbar_DrawFrags (void)
950 l = min(scoreboardlines, 4);
954 for (i = 0;i < l;i++)
960 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
961 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);
962 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
963 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);
967 dpsnprintf (num, sizeof(num), "%3i",f);
969 if (k == cl.viewentity - 1)
971 Sbar_DrawCharacter ( x + 2, -24, 16);
972 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
974 Sbar_DrawCharacter (x + 8, -24, num[0]);
975 Sbar_DrawCharacter (x + 16, -24, num[1]);
976 Sbar_DrawCharacter (x + 24, -24, num[2]);
981 //=============================================================================
989 static void Sbar_DrawFace (void)
993 // PGM 01/19/97 - team color drawing
994 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
995 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
1001 s = &cl.scores[cl.viewentity - 1];
1003 Sbar_DrawPic (112, 0, rsb_teambord);
1004 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1005 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);
1006 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1007 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);
1011 dpsnprintf (num, sizeof(num), "%3i",f);
1013 if ((s->colors & 0xf0)==0)
1016 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1018 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1020 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1024 Sbar_DrawCharacter ( 109, 3, num[0]);
1025 Sbar_DrawCharacter ( 116, 3, num[1]);
1026 Sbar_DrawCharacter ( 123, 3, num[2]);
1031 // PGM 01/19/97 - team color drawing
1033 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1034 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1035 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1036 Sbar_DrawPic (112, 0, sb_face_quad );
1037 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1038 Sbar_DrawPic (112, 0, sb_face_invis );
1039 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1040 Sbar_DrawPic (112, 0, sb_face_invuln);
1043 f = cl.stats[STAT_HEALTH] / 20;
1045 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1048 double topspeed = 0;
1049 double topspeedxy = 0;
1050 time_t current_time = 3;
1051 time_t top_time = 0;
1052 time_t topxy_time = 0;
1054 static void get_showspeed_unit(int unitnumber, double *conversion_factor, const char **unit)
1057 unitnumber = cl_showspeed.integer;
1063 *conversion_factor = 1.0;
1067 *conversion_factor = 1.0 * cl_showspeed_factor.value * 0.01;
1071 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01) * 3.6;
1075 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01 * 3.6) * 0.6213711922;
1079 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01 * 3.6) * 0.539957;
1084 static double showfps_nexttime = 0, showfps_lasttime = -1;
1085 static double showfps_framerate = 0;
1086 static int showfps_framecount = 0;
1088 void Sbar_ShowFPS_Update(void)
1090 double interval = 1;
1092 newtime = host.realtime;
1093 if (newtime >= showfps_nexttime)
1095 showfps_framerate = showfps_framecount / (newtime - showfps_lasttime);
1096 if (showfps_nexttime < newtime - interval * 1.5)
1097 showfps_nexttime = newtime;
1098 showfps_lasttime = newtime;
1099 showfps_nexttime += interval;
1100 showfps_framecount = 0;
1102 showfps_framecount++;
1105 void Sbar_ShowFPS(void)
1107 float fps_x, fps_y, fps_scalex, fps_scaley, fps_strings = 0;
1108 char soundstring[32];
1110 char timestring[32];
1111 char datestring[32];
1112 char timedemostring1[32];
1113 char timedemostring2[32];
1114 char speedstring[32];
1115 char blurstring[32];
1116 char topspeedstring[48];
1117 char texstring[MAX_QPATH];
1122 timedemostring1[0] = 0;
1123 timedemostring2[0] = 0;
1128 topspeedstring[0] = 0;
1131 if (cl_showfps.integer)
1133 red = (showfps_framerate < 1.0f);
1134 if(cl_showfps.integer == 2)
1135 dpsnprintf(fpsstring, sizeof(fpsstring), "%7.3f mspf", (1000.0 / showfps_framerate));
1137 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0 / showfps_framerate + 0.5));
1139 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(showfps_framerate + 0.5));
1143 dpsnprintf(timedemostring1, sizeof(timedemostring1), "frame%4i %f", cls.td_frames, host.realtime - cls.td_starttime);
1144 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);
1149 if (cl_showtime.integer)
1151 strlcpy(timestring, Sys_TimeString(cl_showtime_format.string), sizeof(timestring));
1154 if (cl_showdate.integer)
1156 strlcpy(datestring, Sys_TimeString(cl_showdate_format.string), sizeof(datestring));
1159 if (cl_showblur.integer)
1161 dpsnprintf(blurstring, sizeof(blurstring), "%3i%% blur", (int)(cl.motionbluralpha * 100));
1164 if (cl_showsound.integer)
1166 dpsnprintf(soundstring, sizeof(soundstring), "%4i/4%i at %3ims", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds);
1169 if (cl_showspeed.integer || cl_showtopspeed.integer)
1171 double speed, speedxy, f;
1173 speed = VectorLength(cl.movement_velocity);
1174 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1175 if (cl_showspeed.integer)
1177 get_showspeed_unit(cl_showspeed.integer, &f, &unit);
1178 dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1181 if (cl_showtopspeed.integer)
1183 qbool topspeed_latched = false, topspeedxy_latched = false;
1184 get_showspeed_unit(cl_showtopspeed.integer, &f, &unit);
1185 if (speed >= topspeed || current_time - top_time > 3)
1191 topspeed_latched = true;
1192 if (speedxy >= topspeedxy || current_time - topxy_time > 3)
1194 topspeedxy = speedxy;
1198 topspeedxy_latched = true;
1199 dpsnprintf(topspeedstring, sizeof(topspeedstring), "%s%.0f%s (%s%.0f%s) %s",
1200 topspeed_latched ? "^1" : "^xf88", f*topspeed, "^xf88",
1201 topspeedxy_latched ? "^1" : "^xf88", f*topspeedxy, "^xf88",
1203 time(¤t_time);
1207 if (cl_showtex.integer)
1212 trace_t svtrace, cltrace;
1213 int hitnetentity = -1;
1215 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, org);
1216 VectorSet(temp, 65536, 0, 0);
1217 Matrix4x4_Transform(&r_refdef.view.matrix, temp, dest);
1218 // 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
1219 memset(&svtrace, 0, sizeof(svtrace));
1220 memset(&cltrace, 0, sizeof(cltrace));
1221 svtrace.fraction = 2.0;
1222 cltrace.fraction = 2.0;
1223 // ray hits models (even animated ones) and ignores translucent materials
1224 if (SVVM_prog != NULL)
1225 svtrace = SV_TraceLine(org, dest, MOVE_HITMODEL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value);
1226 cltrace = CL_TraceLine(org, dest, MOVE_HITMODEL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, &hitnetentity, true, true);
1227 if (cltrace.hittexture)
1228 strlcpy(texstring, cltrace.hittexture->name, sizeof(texstring));
1230 strlcpy(texstring, "(no texture hit)", sizeof(texstring));
1232 if (svtrace.fraction < cltrace.fraction)
1234 if (svtrace.ent != NULL)
1236 prvm_prog_t *prog = SVVM_prog;
1237 dpsnprintf(entstring, sizeof(entstring), "server entity %i", (int)PRVM_EDICT_TO_PROG(svtrace.ent));
1240 strlcpy(entstring, "(no entity hit)", sizeof(entstring));
1244 if (CLVM_prog != NULL && cltrace.ent != NULL)
1246 prvm_prog_t *prog = CLVM_prog;
1247 dpsnprintf(entstring, sizeof(entstring), "client entity %i", (int)PRVM_EDICT_TO_PROG(cltrace.ent));
1249 else if (hitnetentity > 0)
1250 dpsnprintf(entstring, sizeof(entstring), "network entity %i", hitnetentity);
1251 else if (hitnetentity == 0)
1252 strlcpy(entstring, "world entity", sizeof(entstring));
1254 strlcpy(entstring, "(no entity hit)", sizeof(entstring));
1262 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1263 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_strings*fps_scaley);
1264 fps_y = vid_conheight.integer - sbar_info_pos.integer - fps_strings*fps_scaley;
1267 fps_x = vid_conwidth.integer - DrawQ_TextWidth(soundstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1268 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1269 DrawQ_String(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1270 fps_y += fps_scaley;
1274 r_draw2d_force = true;
1275 fps_x = vid_conwidth.integer - DrawQ_TextWidth(fpsstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1276 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1278 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1280 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1281 fps_y += fps_scaley;
1282 r_draw2d_force = false;
1284 if (timedemostring1[0])
1286 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring1, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1287 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1288 DrawQ_String(fps_x, fps_y, timedemostring1, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1289 fps_y += fps_scaley;
1291 if (timedemostring2[0])
1293 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring2, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1294 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1295 DrawQ_String(fps_x, fps_y, timedemostring2, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1296 fps_y += fps_scaley;
1300 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1301 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1302 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1303 fps_y += fps_scaley;
1307 fps_x = vid_conwidth.integer - DrawQ_TextWidth(datestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1308 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1309 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1310 fps_y += fps_scaley;
1314 fps_x = vid_conwidth.integer - DrawQ_TextWidth(speedstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1315 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1316 DrawQ_String(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1317 fps_y += fps_scaley;
1319 if (topspeedstring[0])
1321 fps_x = vid_conwidth.integer - DrawQ_TextWidth(topspeedstring, 0, fps_scalex, fps_scaley, false, FONT_INFOBAR);
1322 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1323 DrawQ_String(fps_x, fps_y, topspeedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR);
1324 fps_y += fps_scaley;
1328 fps_x = vid_conwidth.integer - DrawQ_TextWidth(blurstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1329 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1330 DrawQ_String(fps_x, fps_y, blurstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1331 fps_y += fps_scaley;
1335 fps_x = vid_conwidth.integer - DrawQ_TextWidth(texstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1336 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1337 DrawQ_String(fps_x, fps_y, texstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1338 fps_y += fps_scaley;
1342 fps_x = vid_conwidth.integer - DrawQ_TextWidth(entstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1343 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1344 DrawQ_String(fps_x, fps_y, entstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1345 fps_y += fps_scaley;
1350 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)
1353 c2 = bound(0, c2, 1);
1354 c1 = bound(0, c1, 1 - c2);
1356 r[1] = rangey + rangeheight * (c2 + c1);
1357 r[2] = rangey + rangeheight * (c2);
1361 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);
1363 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);
1365 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);
1367 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);
1375 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1376 extern cvar_t v_kicktime;
1377 void Sbar_Score (int margin);
1378 void Sbar_Draw (void)
1383 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1386 Sbar_DrawScoreboard ();
1387 else if (cl.intermission == 1)
1389 if(IS_OLDNEXUIZ_DERIVED(gamemode)) // display full scoreboard (that is, show scores + map name)
1391 Sbar_DrawScoreboard();
1394 Sbar_IntermissionOverlay();
1396 else if (cl.intermission == 2)
1397 Sbar_FinaleOverlay();
1398 else if (gamemode == GAME_DELUXEQUAKE)
1401 else if (IS_OLDNEXUIZ_DERIVED(gamemode))
1403 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1405 sbar_x = (vid_conwidth.integer - 640)/2;
1406 sbar_y = vid_conheight.integer - 47;
1407 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1408 Sbar_DrawScoreboard ();
1410 else if (sb_lines && sbar_hudselector.integer == 1)
1414 int redflag, blueflag;
1417 sbar_x = (vid_conwidth.integer - 320)/2;
1418 sbar_y = vid_conheight.integer - 24 - 16;
1420 // calculate intensity to draw weapons bar at
1421 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1422 fade = bound(0.7, fade, 1);
1423 for (i = 0; i < 8;i++)
1424 if (cl.stats[STAT_ITEMS] & (1 << i))
1425 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1426 if((cl.stats[STAT_ITEMS] & (1<<12)))
1427 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1430 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1431 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1432 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1433 if (redflag == 3 && blueflag == 3)
1435 // The Impossible Combination[tm]
1436 // Can only happen in Key Hunt mode...
1437 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[14]);
1442 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64)), sb_items[redflag+10]);
1444 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[blueflag+14]);
1448 if (cl.stats[STAT_ARMOR] > 0)
1450 Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1451 if(cl.stats[STAT_ARMOR] > 200)
1452 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1453 else if(cl.stats[STAT_ARMOR] > 100)
1454 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1455 else if(cl.stats[STAT_ARMOR] > 50)
1456 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1457 else if(cl.stats[STAT_ARMOR] > 25)
1458 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1460 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1464 if (cl.stats[STAT_HEALTH] != 0)
1466 Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1467 if(cl.stats[STAT_HEALTH] > 200)
1468 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1469 else if(cl.stats[STAT_HEALTH] > 100)
1470 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1471 else if(cl.stats[STAT_HEALTH] > 50)
1472 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1473 else if(cl.stats[STAT_HEALTH] > 25)
1474 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1476 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1480 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1482 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1483 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1484 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1485 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1486 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1487 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1488 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1489 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1490 if(cl.stats[STAT_AMMO] > 10)
1491 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1493 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1496 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1497 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1500 // The margin can be at most 8 to support 640x480 console size:
1501 // 320 + 2 * (144 + 16) = 640
1507 int redflag, blueflag;
1510 sbar_x = (vid_conwidth.integer - 640)/2;
1511 sbar_y = vid_conheight.integer - 47;
1513 // calculate intensity to draw weapons bar at
1514 fade = 3 - 2 * (cl.time - cl.weapontime);
1517 fade = min(fade, 1);
1518 for (i = 0; i < 8;i++)
1519 if (cl.stats[STAT_ITEMS] & (1 << i))
1520 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1522 if((cl.stats[STAT_ITEMS] & (1<<12)))
1523 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1526 //if (!cl.islocalgame)
1527 // Sbar_DrawFrags ();
1530 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1532 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1535 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1536 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1537 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1538 if (redflag == 3 && blueflag == 3)
1540 // The Impossible Combination[tm]
1541 // Can only happen in Key Hunt mode...
1542 Sbar_DrawPic ((int) x, -179, sb_items[14]);
1547 Sbar_DrawPic ((int) x, -117, sb_items[redflag+10]);
1549 Sbar_DrawPic ((int) x, -177, sb_items[blueflag+14]);
1553 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1556 if(cl.stats[STAT_HEALTH] > 100)
1557 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1558 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1559 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1561 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1563 // AK dont draw ammo for the laser
1564 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1566 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1567 Sbar_DrawPic (519, 0, sb_ammo[0]);
1568 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1569 Sbar_DrawPic (519, 0, sb_ammo[1]);
1570 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1571 Sbar_DrawPic (519, 0, sb_ammo[2]);
1572 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1573 Sbar_DrawPic (519, 0, sb_ammo[3]);
1575 if(cl.stats[STAT_AMMO] <= 10)
1576 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1578 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1583 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1585 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1586 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1591 // Mini scoreboard uses 12*4 per other team, that is, 144
1592 // pixels when there are four teams...
1593 // Nexuiz by default sets vid_conwidth to 800... makes
1595 // so we need to shift it by 64 pixels to the right to fit
1596 // BUT: then it overlaps with the image that gets drawn
1597 // for viewsize 100! Therefore, just account for 3 teams,
1598 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1602 else if (gamemode == GAME_ZYMOTIC)
1605 float scale = 64.0f / 256.0f;
1606 float kickoffset[3];
1607 VectorClear(kickoffset);
1610 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1611 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1613 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1614 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1615 // left1 16, 48 : 126 -66
1616 // left2 16, 128 : 196 -66
1617 // right 176, 48 : 196 -136
1618 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);
1619 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);
1620 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);
1621 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1623 float scale = 128.0f / 256.0f;
1624 float healthstart, healthheight, healthstarttc, healthendtc;
1625 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1626 float ammostart, ammoheight, ammostarttc, ammoendtc;
1627 float clipstart, clipheight, clipstarttc, clipendtc;
1628 float kickoffset[3], offset;
1629 VectorClear(kickoffset);
1632 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1633 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1635 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1636 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1637 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1638 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);
1639 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);
1640 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);
1641 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);
1642 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1643 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1644 healthstart = 204 - healthheight;
1645 shieldstart = healthstart - shieldheight;
1646 healthstarttc = healthstart * (1.0f / 256.0f);
1647 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1648 shieldstarttc = shieldstart * (1.0f / 256.0f);
1649 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1650 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1651 ammostart = 114 - ammoheight;
1652 ammostarttc = ammostart * (1.0f / 256.0f);
1653 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1654 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1655 clipstart = 190 - clipheight;
1656 clipstarttc = clipstart * (1.0f / 256.0f);
1657 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1658 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);
1659 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);
1660 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);
1661 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);
1662 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1663 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1666 else // Quake and others
1668 sbar_x = (vid_conwidth.integer - 320)/2;
1669 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1670 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1671 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1675 if (gamemode != GAME_GOODVSBAD2)
1676 Sbar_DrawInventory ();
1677 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1681 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1683 if (gamemode != GAME_GOODVSBAD2)
1684 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1685 Sbar_DrawScoreboard ();
1689 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1691 // keys (hipnotic only)
1692 //MED 01/04/97 moved keys here so they would not be overwritten
1693 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
1695 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1696 Sbar_DrawPic (209, 3, sb_items[0]);
1697 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1698 Sbar_DrawPic (209, 12, sb_items[1]);
1701 if (gamemode != GAME_GOODVSBAD2)
1703 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1705 Sbar_DrawNum (24, 0, 666, 3, 1);
1706 Sbar_DrawPic (0, 0, sb_disc);
1710 if (gamemode == GAME_ROGUE)
1712 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1713 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1714 Sbar_DrawPic (0, 0, sb_armor[2]);
1715 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1716 Sbar_DrawPic (0, 0, sb_armor[1]);
1717 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1718 Sbar_DrawPic (0, 0, sb_armor[0]);
1722 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1723 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1724 Sbar_DrawPic (0, 0, sb_armor[2]);
1725 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1726 Sbar_DrawPic (0, 0, sb_armor[1]);
1727 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1728 Sbar_DrawPic (0, 0, sb_armor[0]);
1737 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1740 if (gamemode == GAME_ROGUE)
1742 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1743 Sbar_DrawPic (224, 0, sb_ammo[0]);
1744 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1745 Sbar_DrawPic (224, 0, sb_ammo[1]);
1746 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1747 Sbar_DrawPic (224, 0, sb_ammo[2]);
1748 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1749 Sbar_DrawPic (224, 0, sb_ammo[3]);
1750 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1751 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1752 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1753 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1754 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1755 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1759 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1760 Sbar_DrawPic (224, 0, sb_ammo[0]);
1761 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1762 Sbar_DrawPic (224, 0, sb_ammo[1]);
1763 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1764 Sbar_DrawPic (224, 0, sb_ammo[2]);
1765 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1766 Sbar_DrawPic (224, 0, sb_ammo[3]);
1769 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1771 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1772 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1774 if (gamemode == GAME_TRANSFUSION)
1775 Sbar_MiniDeathmatchOverlay (0, 0);
1777 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1784 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1786 pic = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/crosshair%i", crosshair.integer));
1787 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);
1790 if (cl_prydoncursor.integer > 0)
1791 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);
1794 //=============================================================================
1798 Sbar_DeathmatchOverlay
1802 static float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1805 qbool myself = false;
1808 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1810 if((s - cl.scores) == cl.playerentity - 1)
1812 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1813 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1816 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1818 if (s->qw_spectator)
1820 if (s->qw_ping || s->qw_packetloss)
1821 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 );
1823 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 );
1827 // draw colors behind score
1833 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1834 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);
1835 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1836 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);
1838 //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);
1839 if (s->qw_ping || s->qw_packetloss)
1840 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 );
1842 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 );
1847 if (s->qw_spectator)
1849 if (s->qw_ping || s->qw_packetloss)
1850 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 );
1852 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 );
1856 // draw colors behind score
1857 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1858 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);
1859 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1860 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);
1862 //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);
1863 if (s->qw_ping || s->qw_packetloss)
1864 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 );
1866 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 );
1872 void Sbar_DeathmatchOverlay (void)
1874 int i, y, xmin, xmax, ymin, ymax;
1877 // request new ping times every two second
1878 if (cl.last_ping_request < host.realtime - 2 && cls.netcon)
1880 cl.last_ping_request = host.realtime;
1881 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1883 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1884 MSG_WriteString(&cls.netcon->message, "pings");
1886 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*/)
1888 // 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
1889 static int ping_anyway_counter = 0;
1890 if(cl.parsingtextexpectingpingforscores == 1)
1892 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1893 if(++ping_anyway_counter >= 5)
1894 cl.parsingtextexpectingpingforscores = 0;
1896 if(cl.parsingtextexpectingpingforscores != 1)
1898 ping_anyway_counter = 0;
1899 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1900 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1901 MSG_WriteString(&cls.netcon->message, "ping");
1906 // 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
1907 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1908 MSG_WriteString(&cls.netcon->message, "pings");
1916 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1918 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1919 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)
1921 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)
1922 xmax = vid_conwidth.integer - xmin;
1924 if(IS_OLDNEXUIZ_DERIVED(gamemode))
1925 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);
1927 DrawQ_Pic ((vid_conwidth.integer - Draw_GetPicWidth(sb_ranking))/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1931 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1933 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 );
1937 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 );
1941 if (Sbar_IsTeammatch ())
1943 // show team scores first
1944 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1945 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1949 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1950 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1955 Sbar_MiniDeathmatchOverlay
1959 void Sbar_MiniDeathmatchOverlay (int x, int y)
1961 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1963 // do not draw this if sbar_miniscoreboard_size is zero
1964 if(sbar_miniscoreboard_size.value == 0)
1966 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1967 if(sbar_miniscoreboard_size.value > 0)
1968 y = (int) (vid_conheight.integer - sbar_miniscoreboard_size.value * 8);
1973 // decide where to print
1974 if (gamemode == GAME_TRANSFUSION)
1975 numlines = (vid_conwidth.integer - x + 127) / 128;
1977 numlines = (vid_conheight.integer - y + 7) / 8;
1979 // give up if there isn't room
1980 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1984 for (i = 0; i < scoreboardlines; i++)
1985 if (fragsort[i] == cl.playerentity - 1)
1989 range_end = scoreboardlines;
1992 if (gamemode != GAME_TRANSFUSION)
1993 if (Sbar_IsTeammatch ())
1995 // reserve space for the team scores
1996 numlines -= teamlines;
1998 // find first and last player of my team (only draw the team totals and my own team)
1999 range_begin = range_end = i;
2000 myteam = cl.scores[fragsort[i]].colors & 15;
2001 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
2003 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
2006 // looks better than two players
2016 i = min(i, range_end - numlines);
2017 i = max(i, range_begin);
2019 if (gamemode == GAME_TRANSFUSION)
2021 for (;i < range_end && x < vid_conwidth.integer;i++)
2022 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2026 if(range_end - i < numlines) // won't draw to bottom?
2027 y += 8 * (numlines - (range_end - i)); // bottom align
2028 // show team scores first
2029 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
2030 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
2032 for (;i < range_end && y < vid_conheight.integer;i++)
2033 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2037 static int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
2039 static int const sortorder[16] =
2058 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
2059 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
2060 int tc1 = sortorder[t1->colors & 15];
2061 int tc2 = sortorder[t2->colors & 15];
2065 void Sbar_Score (int margin)
2067 int i, me, score, otherleader, place, distribution, minutes, seconds;
2069 int sbar_x_save = sbar_x;
2070 int sbar_y_save = sbar_y;
2073 sbar_y = (int) (vid_conheight.value - (32+12));
2076 me = cl.playerentity - 1;
2077 if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients)
2079 if(Sbar_IsTeammatch())
2083 // team1 team3 team4
2087 scoreboard_t *teamcolorsort[16];
2090 for(i = 0; i < teamlines; ++i)
2091 teamcolorsort[i] = &(teams[i]);
2093 // Now sort them by color
2094 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
2097 // -12*4: four digits space
2098 place = (teamlines - 1) * (-12 * 4);
2100 for(i = 0; i < teamlines; ++i)
2102 int cindex = teamcolorsort[i]->colors & 15;
2103 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
2104 float cm = max(max(c[0], c[1]), c[2]);
2105 float cr = c[0] / cm;
2106 float cg = c[1] / cm;
2107 float cb = c[2] / cm;
2108 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
2110 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
2114 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
2127 // find leading score other than ourselves, to calculate distribution
2128 // find our place in the scoreboard
2129 score = cl.scores[me].frags;
2130 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
2132 if (cl.scores[i].name[0] && i != me)
2134 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
2136 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
2140 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
2142 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2143 else if (place == 2)
2144 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2146 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2147 if (otherleader < 0)
2148 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2149 if (distribution >= 0)
2151 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2152 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2154 else if (distribution >= -5)
2156 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2157 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2161 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2162 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2167 if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT])
2169 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2170 minutes = (int)floor(timeleft / 60);
2171 seconds = (int)(floor(timeleft) - minutes * 60);
2174 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2175 if (Draw_IsPicLoaded(sb_colon))
2176 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2177 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2179 else if (minutes >= 1)
2181 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2182 if (Draw_IsPicLoaded(sb_colon))
2183 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2184 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2186 else if ((int)(timeleft * 4) & 1)
2187 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2189 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2191 else if (sbar_gametime.integer)
2193 minutes = (int)floor(cl.time / 60);
2194 seconds = (int)(floor(cl.time) - minutes * 60);
2195 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2196 if (Draw_IsPicLoaded(sb_colon))
2197 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2198 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2201 sbar_x = sbar_x_save;
2202 sbar_y = sbar_y_save;
2207 Sbar_IntermissionOverlay
2211 void Sbar_IntermissionOverlay (void)
2216 if (cl.gametype == GAME_DEATHMATCH)
2218 Sbar_DeathmatchOverlay ();
2222 sbar_x = (vid_conwidth.integer - 320) >> 1;
2223 sbar_y = (vid_conheight.integer - 200) >> 1;
2225 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2226 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2229 dig = (int)cl.completed_time / 60;
2230 Sbar_DrawNum (160, 64, dig, 3, 0);
2231 num = (int)cl.completed_time - dig*60;
2232 Sbar_DrawPic (234,64,sb_colon);
2233 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2234 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2236 // LA: Display as "a" instead of "a/b" if b is 0
2237 if(cl.stats[STAT_TOTALSECRETS])
2239 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2240 if (!IS_OLDNEXUIZ_DERIVED(gamemode))
2241 Sbar_DrawPic (232, 104, sb_slash);
2242 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2246 Sbar_DrawNum (240, 104, cl.stats[STAT_SECRETS], 3, 0);
2249 if(cl.stats[STAT_TOTALMONSTERS])
2251 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2252 if (!IS_OLDNEXUIZ_DERIVED(gamemode))
2253 Sbar_DrawPic (232, 144, sb_slash);
2254 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2258 Sbar_DrawNum (240, 144, cl.stats[STAT_MONSTERS], 3, 0);
2269 void Sbar_FinaleOverlay (void)
2271 DrawQ_Pic((vid_conwidth.integer - Draw_GetPicWidth(sb_finale))/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);