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_IntermissionOverlay (void);
120 static void Sbar_FinaleOverlay (void);
131 static void Sbar_ShowScores_f(cmd_state_t *cmd)
135 sb_showscores = true;
136 CL_VM_UpdateShowingScoresState(sb_showscores);
146 static void Sbar_DontShowScores_f(cmd_state_t *cmd)
148 sb_showscores = false;
149 CL_VM_UpdateShowingScoresState(sb_showscores);
152 static void sbar_start(void)
157 if (gamemode == GAME_DELUXEQUAKE || gamemode == GAME_BLOODOMNICIDE)
160 else if (IS_OLDNEXUIZ_DERIVED(gamemode))
162 for (i = 0;i < 10;i++)
163 sb_nums[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/num_%i",i), CACHEPICFLAG_QUIET);
164 sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET);
165 sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET | CACHEPICFLAG_FAILONMISSING);
167 sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
168 sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_bullets", CACHEPICFLAG_QUIET);
169 sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
170 sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
172 sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor", CACHEPICFLAG_QUIET);
176 sb_health = Draw_CachePic_Flags ("gfx/sb_health", CACHEPICFLAG_QUIET);
178 sb_items[2] = Draw_CachePic_Flags ("gfx/sb_slowmo", CACHEPICFLAG_QUIET);
179 sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invinc", CACHEPICFLAG_QUIET);
180 sb_items[4] = Draw_CachePic_Flags ("gfx/sb_energy", CACHEPICFLAG_QUIET);
181 sb_items[5] = Draw_CachePic_Flags ("gfx/sb_str", CACHEPICFLAG_QUIET);
183 sb_items[11] = Draw_CachePic_Flags ("gfx/sb_flag_red_taken", CACHEPICFLAG_QUIET);
184 sb_items[12] = Draw_CachePic_Flags ("gfx/sb_flag_red_lost", CACHEPICFLAG_QUIET);
185 sb_items[13] = Draw_CachePic_Flags ("gfx/sb_flag_red_carrying", CACHEPICFLAG_QUIET);
186 sb_items[14] = Draw_CachePic_Flags ("gfx/sb_key_carrying", CACHEPICFLAG_QUIET);
187 sb_items[15] = Draw_CachePic_Flags ("gfx/sb_flag_blue_taken", CACHEPICFLAG_QUIET);
188 sb_items[16] = Draw_CachePic_Flags ("gfx/sb_flag_blue_lost", CACHEPICFLAG_QUIET);
189 sb_items[17] = Draw_CachePic_Flags ("gfx/sb_flag_blue_carrying", CACHEPICFLAG_QUIET);
191 sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET);
192 sb_sbar_minimal = Draw_CachePic_Flags ("gfx/sbar_minimal", CACHEPICFLAG_QUIET);
193 sb_sbar_overlay = Draw_CachePic_Flags ("gfx/sbar_overlay", CACHEPICFLAG_QUIET);
195 for(i = 0; i < 9;i++)
196 sb_weapons[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inv_weapon%i",i), CACHEPICFLAG_QUIET);
198 else if (gamemode == GAME_ZYMOTIC)
200 zymsb_crosshair_center = Draw_CachePic_Flags ("gfx/hud/crosshair_center", CACHEPICFLAG_QUIET);
201 zymsb_crosshair_line = Draw_CachePic_Flags ("gfx/hud/crosshair_line", CACHEPICFLAG_QUIET);
202 zymsb_crosshair_health = Draw_CachePic_Flags ("gfx/hud/crosshair_health", CACHEPICFLAG_QUIET);
203 zymsb_crosshair_clip = Draw_CachePic_Flags ("gfx/hud/crosshair_clip", CACHEPICFLAG_QUIET);
204 zymsb_crosshair_ammo = Draw_CachePic_Flags ("gfx/hud/crosshair_ammo", CACHEPICFLAG_QUIET);
205 zymsb_crosshair_background = Draw_CachePic_Flags ("gfx/hud/crosshair_background", CACHEPICFLAG_QUIET);
206 zymsb_crosshair_left1 = Draw_CachePic_Flags ("gfx/hud/crosshair_left1", CACHEPICFLAG_QUIET);
207 zymsb_crosshair_left2 = Draw_CachePic_Flags ("gfx/hud/crosshair_left2", CACHEPICFLAG_QUIET);
208 zymsb_crosshair_right = Draw_CachePic_Flags ("gfx/hud/crosshair_right", CACHEPICFLAG_QUIET);
212 sb_disc = Draw_CachePic_Flags ("gfx/disc", CACHEPICFLAG_QUIET);
214 for (i = 0;i < 10;i++)
216 sb_nums[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/num_%i",i), CACHEPICFLAG_QUIET);
217 sb_nums[1][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/anum_%i",i), CACHEPICFLAG_QUIET);
220 sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET);
221 sb_nums[1][10] = Draw_CachePic_Flags ("gfx/anum_minus", CACHEPICFLAG_QUIET);
223 sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET | CACHEPICFLAG_FAILONMISSING);
224 sb_slash = Draw_CachePic_Flags ("gfx/num_slash", CACHEPICFLAG_QUIET);
226 sb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_shotgun", CACHEPICFLAG_QUIET);
227 sb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_sshotgun", CACHEPICFLAG_QUIET);
228 sb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_nailgun", CACHEPICFLAG_QUIET);
229 sb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_snailgun", CACHEPICFLAG_QUIET);
230 sb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_rlaunch", CACHEPICFLAG_QUIET);
231 sb_weapons[0][5] = Draw_CachePic_Flags ("gfx/inv_srlaunch", CACHEPICFLAG_QUIET);
232 sb_weapons[0][6] = Draw_CachePic_Flags ("gfx/inv_lightng", CACHEPICFLAG_QUIET);
234 sb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_shotgun", CACHEPICFLAG_QUIET);
235 sb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_sshotgun", CACHEPICFLAG_QUIET);
236 sb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_nailgun", CACHEPICFLAG_QUIET);
237 sb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_snailgun", CACHEPICFLAG_QUIET);
238 sb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_rlaunch", CACHEPICFLAG_QUIET);
239 sb_weapons[1][5] = Draw_CachePic_Flags ("gfx/inv2_srlaunch", CACHEPICFLAG_QUIET);
240 sb_weapons[1][6] = Draw_CachePic_Flags ("gfx/inv2_lightng", CACHEPICFLAG_QUIET);
242 for (i = 0;i < 5;i++)
244 sb_weapons[2+i][0] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_shotgun",i+1), CACHEPICFLAG_QUIET);
245 sb_weapons[2+i][1] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_sshotgun",i+1), CACHEPICFLAG_QUIET);
246 sb_weapons[2+i][2] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_nailgun",i+1), CACHEPICFLAG_QUIET);
247 sb_weapons[2+i][3] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_snailgun",i+1), CACHEPICFLAG_QUIET);
248 sb_weapons[2+i][4] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_rlaunch",i+1), CACHEPICFLAG_QUIET);
249 sb_weapons[2+i][5] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_srlaunch",i+1), CACHEPICFLAG_QUIET);
250 sb_weapons[2+i][6] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_lightng",i+1), CACHEPICFLAG_QUIET);
253 sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
254 sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_nails", CACHEPICFLAG_QUIET);
255 sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
256 sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
258 sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor1", CACHEPICFLAG_QUIET);
259 sb_armor[1] = Draw_CachePic_Flags ("gfx/sb_armor2", CACHEPICFLAG_QUIET);
260 sb_armor[2] = Draw_CachePic_Flags ("gfx/sb_armor3", CACHEPICFLAG_QUIET);
262 sb_items[0] = Draw_CachePic_Flags ("gfx/sb_key1", CACHEPICFLAG_QUIET);
263 sb_items[1] = Draw_CachePic_Flags ("gfx/sb_key2", CACHEPICFLAG_QUIET);
264 sb_items[2] = Draw_CachePic_Flags ("gfx/sb_invis", CACHEPICFLAG_QUIET);
265 sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invuln", CACHEPICFLAG_QUIET);
266 sb_items[4] = Draw_CachePic_Flags ("gfx/sb_suit", CACHEPICFLAG_QUIET);
267 sb_items[5] = Draw_CachePic_Flags ("gfx/sb_quad", CACHEPICFLAG_QUIET);
269 sb_sigil[0] = Draw_CachePic_Flags ("gfx/sb_sigil1", CACHEPICFLAG_QUIET);
270 sb_sigil[1] = Draw_CachePic_Flags ("gfx/sb_sigil2", CACHEPICFLAG_QUIET);
271 sb_sigil[2] = Draw_CachePic_Flags ("gfx/sb_sigil3", CACHEPICFLAG_QUIET);
272 sb_sigil[3] = Draw_CachePic_Flags ("gfx/sb_sigil4", CACHEPICFLAG_QUIET);
274 sb_faces[4][0] = Draw_CachePic_Flags ("gfx/face1", CACHEPICFLAG_QUIET);
275 sb_faces[4][1] = Draw_CachePic_Flags ("gfx/face_p1", CACHEPICFLAG_QUIET);
276 sb_faces[3][0] = Draw_CachePic_Flags ("gfx/face2", CACHEPICFLAG_QUIET);
277 sb_faces[3][1] = Draw_CachePic_Flags ("gfx/face_p2", CACHEPICFLAG_QUIET);
278 sb_faces[2][0] = Draw_CachePic_Flags ("gfx/face3", CACHEPICFLAG_QUIET);
279 sb_faces[2][1] = Draw_CachePic_Flags ("gfx/face_p3", CACHEPICFLAG_QUIET);
280 sb_faces[1][0] = Draw_CachePic_Flags ("gfx/face4", CACHEPICFLAG_QUIET);
281 sb_faces[1][1] = Draw_CachePic_Flags ("gfx/face_p4", CACHEPICFLAG_QUIET);
282 sb_faces[0][0] = Draw_CachePic_Flags ("gfx/face5", CACHEPICFLAG_QUIET);
283 sb_faces[0][1] = Draw_CachePic_Flags ("gfx/face_p5", CACHEPICFLAG_QUIET);
285 sb_face_invis = Draw_CachePic_Flags ("gfx/face_invis", CACHEPICFLAG_QUIET);
286 sb_face_invuln = Draw_CachePic_Flags ("gfx/face_invul2", CACHEPICFLAG_QUIET);
287 sb_face_invis_invuln = Draw_CachePic_Flags ("gfx/face_inv2", CACHEPICFLAG_QUIET);
288 sb_face_quad = Draw_CachePic_Flags ("gfx/face_quad", CACHEPICFLAG_QUIET);
290 sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET);
291 sb_ibar = Draw_CachePic_Flags ("gfx/ibar", CACHEPICFLAG_QUIET);
292 sb_scorebar = Draw_CachePic_Flags ("gfx/scorebar", CACHEPICFLAG_QUIET);
294 //MED 01/04/97 added new hipnotic weapons
295 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
297 hsb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_laser", CACHEPICFLAG_QUIET);
298 hsb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_mjolnir", CACHEPICFLAG_QUIET);
299 hsb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_gren_prox", CACHEPICFLAG_QUIET);
300 hsb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_prox_gren", CACHEPICFLAG_QUIET);
301 hsb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_prox", CACHEPICFLAG_QUIET);
303 hsb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_laser", CACHEPICFLAG_QUIET);
304 hsb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_mjolnir", CACHEPICFLAG_QUIET);
305 hsb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_gren_prox", CACHEPICFLAG_QUIET);
306 hsb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_prox_gren", CACHEPICFLAG_QUIET);
307 hsb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_prox", CACHEPICFLAG_QUIET);
309 for (i = 0;i < 5;i++)
311 hsb_weapons[2+i][0] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_laser",i+1), CACHEPICFLAG_QUIET);
312 hsb_weapons[2+i][1] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_mjolnir",i+1), CACHEPICFLAG_QUIET);
313 hsb_weapons[2+i][2] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_gren_prox",i+1), CACHEPICFLAG_QUIET);
314 hsb_weapons[2+i][3] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_prox_gren",i+1), CACHEPICFLAG_QUIET);
315 hsb_weapons[2+i][4] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_prox",i+1), CACHEPICFLAG_QUIET);
318 hsb_items[0] = Draw_CachePic_Flags ("gfx/sb_wsuit", CACHEPICFLAG_QUIET);
319 hsb_items[1] = Draw_CachePic_Flags ("gfx/sb_eshld", CACHEPICFLAG_QUIET);
321 else if (gamemode == GAME_ROGUE)
323 rsb_invbar[0] = Draw_CachePic_Flags ("gfx/r_invbar1", CACHEPICFLAG_QUIET);
324 rsb_invbar[1] = Draw_CachePic_Flags ("gfx/r_invbar2", CACHEPICFLAG_QUIET);
326 rsb_weapons[0] = Draw_CachePic_Flags ("gfx/r_lava", CACHEPICFLAG_QUIET);
327 rsb_weapons[1] = Draw_CachePic_Flags ("gfx/r_superlava", CACHEPICFLAG_QUIET);
328 rsb_weapons[2] = Draw_CachePic_Flags ("gfx/r_gren", CACHEPICFLAG_QUIET);
329 rsb_weapons[3] = Draw_CachePic_Flags ("gfx/r_multirock", CACHEPICFLAG_QUIET);
330 rsb_weapons[4] = Draw_CachePic_Flags ("gfx/r_plasma", CACHEPICFLAG_QUIET);
332 rsb_items[0] = Draw_CachePic_Flags ("gfx/r_shield1", CACHEPICFLAG_QUIET);
333 rsb_items[1] = Draw_CachePic_Flags ("gfx/r_agrav1", CACHEPICFLAG_QUIET);
335 // PGM 01/19/97 - team color border
336 rsb_teambord = Draw_CachePic_Flags ("gfx/r_teambord", CACHEPICFLAG_QUIET);
337 // PGM 01/19/97 - team color border
339 rsb_ammo[0] = Draw_CachePic_Flags ("gfx/r_ammolava", CACHEPICFLAG_QUIET);
340 rsb_ammo[1] = Draw_CachePic_Flags ("gfx/r_ammomulti", CACHEPICFLAG_QUIET);
341 rsb_ammo[2] = Draw_CachePic_Flags ("gfx/r_ammoplasma", CACHEPICFLAG_QUIET);
345 sb_ranking = Draw_CachePic_Flags ("gfx/ranking", CACHEPICFLAG_QUIET);
346 sb_complete = Draw_CachePic_Flags ("gfx/complete", CACHEPICFLAG_QUIET);
347 sb_inter = Draw_CachePic_Flags ("gfx/inter", CACHEPICFLAG_QUIET);
348 sb_finale = Draw_CachePic_Flags ("gfx/finale", CACHEPICFLAG_QUIET);
351 static void sbar_shutdown(void)
355 static void sbar_newmap(void)
359 void Sbar_Init (void)
361 Cmd_AddCommand(CF_CLIENT, "+showscores", Sbar_ShowScores_f, "show scoreboard");
362 Cmd_AddCommand(CF_CLIENT, "-showscores", Sbar_DontShowScores_f, "hide scoreboard");
363 Cvar_RegisterVariable(&cl_showfps);
364 Cvar_RegisterVariable(&cl_showsound);
365 Cvar_RegisterVariable(&cl_showblur);
366 Cvar_RegisterVariable(&cl_showspeed);
367 Cvar_RegisterVariable(&cl_showspeed_factor);
368 Cvar_RegisterVariable(&cl_showtopspeed);
369 Cvar_RegisterVariable(&cl_showtime);
370 Cvar_RegisterVariable(&cl_showtime_format);
371 Cvar_RegisterVariable(&cl_showdate);
372 Cvar_RegisterVariable(&cl_showdate_format);
373 Cvar_RegisterVariable(&cl_showtex);
375 Cvar_RegisterVirtual(&cl_showfps, "showfps");
376 Cvar_RegisterVirtual(&cl_showsound, "showsound");
377 Cvar_RegisterVirtual(&cl_showblur, "showblur");
378 Cvar_RegisterVirtual(&cl_showspeed, "showspeed");
379 Cvar_RegisterVirtual(&cl_showtopspeed, "showtopspeed");
380 Cvar_RegisterVirtual(&cl_showtime, "showtime");
381 Cvar_RegisterVirtual(&cl_showtime_format, "showtime_format");
382 Cvar_RegisterVirtual(&cl_showdate, "showdate");
383 Cvar_RegisterVirtual(&cl_showdate_format, "showdate_format");
384 Cvar_RegisterVirtual(&cl_showtex, "showtex");
386 Cvar_RegisterVariable(&sbar_alpha_bg);
387 Cvar_RegisterVariable(&sbar_alpha_fg);
388 Cvar_RegisterVariable(&sbar_hudselector);
389 Cvar_RegisterVariable(&sbar_scorerank);
390 Cvar_RegisterVariable(&sbar_gametime);
391 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
392 Cvar_RegisterVariable(&sbar_info_pos);
393 Cvar_RegisterVariable(&cl_deathscoreboard);
394 // This name is used by QuakeSpasm-based engines and is read by the Alkaline 1.2 CSQC
395 Cvar_RegisterVirtual(&sbar_alpha_bg, "scr_sbaralpha");
397 Cvar_RegisterVariable(&crosshair_color_red);
398 Cvar_RegisterVariable(&crosshair_color_green);
399 Cvar_RegisterVariable(&crosshair_color_blue);
400 Cvar_RegisterVariable(&crosshair_color_alpha);
401 Cvar_RegisterVariable(&crosshair_size);
403 Cvar_RegisterVariable(&sbar_flagstatus_right); // (GAME_NEXUZI ONLY)
404 Cvar_RegisterVariable(&sbar_flagstatus_pos); // (GAME_NEXUIZ ONLY)
406 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap, NULL, NULL);
410 //=============================================================================
412 // drawing routines are relative to the status bar location
421 static void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
423 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
426 static void Sbar_DrawPic (int x, int y, cachepic_t *pic)
428 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
431 static void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
433 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
440 Draws one solid graphics character
443 static void Sbar_DrawCharacter (int x, int y, int num)
446 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);
454 static void Sbar_DrawString (int x, int y, char *str)
456 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR);
464 static void Sbar_DrawNum (int x, int y, int num, int digits, int color)
469 l = dpsnprintf(str, sizeof(str), "%i", num);
483 Sbar_DrawPic (x, y, sb_nums[color][frame]);
496 static void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
504 l = dpsnprintf(str, sizeof(str), "%0*i", digits, num);
507 l = dpsnprintf(str, sizeof(str), "%i", num);
512 x += (digits-l) * lettersize;
521 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
528 //=============================================================================
531 static int Sbar_IsTeammatch(void)
533 // currently only nexuiz uses the team score board
534 return (IS_OLDNEXUIZ_DERIVED(gamemode)
535 && (teamplay.integer > 0));
543 static int fragsort[MAX_SCOREBOARD];
544 static int scoreboardlines;
546 int Sbar_GetSortedPlayerIndex (int index)
548 return index >= 0 && index < scoreboardlines ? fragsort[index] : -1;
551 static scoreboard_t teams[MAX_SCOREBOARD];
552 static int teamsort[MAX_SCOREBOARD];
553 static int teamlines;
554 void Sbar_SortFrags (void)
560 for (i=0 ; i<cl.maxclients ; i++)
562 if (cl.scores[i].name[0])
564 fragsort[scoreboardlines] = i;
569 for (i=0 ; i<scoreboardlines ; i++)
570 for (j=0 ; j<scoreboardlines-1-i ; j++)
571 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
574 fragsort[j] = fragsort[j+1];
579 if (Sbar_IsTeammatch ())
581 // now sort players by teams.
582 for (i=0 ; i<scoreboardlines ; i++)
584 for (j=0 ; j<scoreboardlines-1-i ; j++)
586 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
589 fragsort[j] = fragsort[j+1];
595 // calculate team scores
597 for (i=0 ; i<scoreboardlines ; i++)
599 if (color != (cl.scores[fragsort[i]].colors & 15))
601 const char* teamname;
603 color = cl.scores[fragsort[i]].colors & 15;
609 teamname = "^1Red Team";
612 teamname = "^4Blue Team";
615 teamname = "^6Pink Team";
618 teamname = "^3Yellow Team";
621 teamname = "Total Team Score";
624 dp_strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
626 teams[teamlines-1].frags = 0;
627 teams[teamlines-1].colors = color + 16 * color;
630 if (cl.scores[fragsort[i]].frags != -666)
632 // do not add spedcators
633 // (ugly hack for nexuiz)
634 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
638 // now sort teams by scores.
639 for (i=0 ; i<teamlines ; i++)
641 for (i=0 ; i<teamlines ; i++)
643 for (j=0 ; j<teamlines-1-i ; j++)
645 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
648 teamsort[j] = teamsort[j+1];
661 static void Sbar_SoloScoreboard (void)
664 char str[80], timestr[40];
666 int minutes, seconds;
670 t = (cl.intermission ? cl.completed_time : cl.time);
671 minutes = (int)(t / 60);
672 seconds = (int)(t - 60*floor(t/60));
674 // monsters and secrets are now both on the top row
675 if (cl.stats[STAT_TOTALMONSTERS])
676 Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
677 else if (cl.stats[STAT_MONSTERS]) // LA: Display something if monsters_killed is non-zero, but total_monsters is zero
678 Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i", cl.stats[STAT_MONSTERS]));
680 if (cl.stats[STAT_TOTALSECRETS])
681 Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
682 else if (cl.stats[STAT_SECRETS]) // LA: And similarly for secrets
683 Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i", cl.stats[STAT_SECRETS]));
685 // format is like this: e1m1:The Sligpate Complex
686 dpsnprintf(str, sizeof(str), "%s:%.39s", cl.worldbasename, cl.worldmessage);
688 // if there's a newline character, terminate the string there
689 if (strchr(str, '\n'))
690 *(strchr(str, '\n')) = 0;
692 // make the time string
693 timelen = dpsnprintf(timestr, sizeof(timestr), " %i:%02i", minutes, seconds);
695 // truncate the level name if necessary to make room for time
697 if ((int)strlen(str) > max)
700 // print the filename and message
701 Sbar_DrawString(8, 12, str);
704 Sbar_DrawString(8 + max*8, 12, timestr);
708 int minutes, seconds, tens, units;
711 if (IS_OLDNEXUIZ_DERIVED(gamemode)) {
712 dpsnprintf (str, sizeof(str), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
713 Sbar_DrawString (8, 4, str);
715 dpsnprintf (str, sizeof(str), "Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
716 Sbar_DrawString (8, 12, str);
720 minutes = (int)(cl.time / 60);
721 seconds = (int)(cl.time - 60*minutes);
723 units = seconds - 10*tens;
724 dpsnprintf (str, sizeof(str), "Time :%3i:%i%i", minutes, tens, units);
725 Sbar_DrawString (184, 4, str);
728 if (IS_OLDNEXUIZ_DERIVED(gamemode)) {
729 l = (int) strlen (cl.worldname);
730 Sbar_DrawString (232 - l*4, 12, cl.worldname);
732 l = (int) strlen (cl.worldmessage);
733 Sbar_DrawString (232 - l*4, 12, cl.worldmessage);
743 static void Sbar_DrawScoreboard (void)
745 Sbar_SoloScoreboard ();
746 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
747 //if (cl.gametype == GAME_DEATHMATCH)
749 Sbar_DeathmatchOverlay ();
752 //=============================================================================
754 // AK to make DrawInventory smaller
755 static void Sbar_DrawWeapon(int nr, float fade, int active)
758 if (sbar_hudselector.integer == 1)
760 // width = 300, height = 100
761 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
763 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);
765 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);
769 // width = 300, height = 100
770 const int w_width = 300, w_height = 100, w_space = 10;
771 const float w_scale = 0.4;
773 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);
774 //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);
783 static void Sbar_DrawInventory (void)
790 if (gamemode == GAME_ROGUE)
792 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
793 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
795 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
798 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
801 for (i=0 ; i<7 ; i++)
803 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
805 time = cl.item_gettime[i];
806 flashon = (int)(max(0, cl.time - time)*10);
809 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
815 flashon = (flashon%5) + 2;
817 Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
823 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
825 int grenadeflashing=0;
826 for (i=0 ; i<4 ; i++)
828 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
830 time = max(0, cl.item_gettime[hipweapons[i]]);
831 flashon = (int)((cl.time - time)*10);
834 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
840 flashon = (flashon%5) + 2;
842 // check grenade launcher
845 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
850 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
856 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
858 if (!grenadeflashing)
859 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
862 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
865 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
870 if (gamemode == GAME_ROGUE)
872 // check for powered up weapon.
873 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
875 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
876 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
880 for (i=0 ; i<4 ; i++)
882 dpsnprintf (num, sizeof(num), "%4i",cl.stats[STAT_SHELLS+i] );
884 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
886 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
888 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
890 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
894 for (i=0 ; i<6 ; i++)
895 if (cl.stats[STAT_ITEMS] & (1u<<(17+i)))
897 //MED 01/04/97 changed keys
898 if (!(gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH) || (i>1))
899 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
902 //MED 01/04/97 added hipnotic items
904 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
906 for (i=0 ; i<2 ; i++)
907 if (cl.stats[STAT_ITEMS] & (1u<<(24+i)))
908 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
911 if (gamemode == GAME_ROGUE)
914 for (i=0 ; i<2 ; i++)
915 if (cl.stats[STAT_ITEMS] & (1u<<(29+i)))
916 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
921 for (i=0 ; i<4 ; i++)
922 if (cl.stats[STAT_ITEMS] & (1u<<(28+i)))
923 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
927 //=============================================================================
934 static void Sbar_DrawFrags (void)
944 l = min(scoreboardlines, 4);
948 for (i = 0;i < l;i++)
954 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
955 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);
956 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
957 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);
961 dpsnprintf (num, sizeof(num), "%3i",f);
963 if (k == cl.viewentity - 1)
965 Sbar_DrawCharacter ( x + 2, -24, 16);
966 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
968 Sbar_DrawCharacter (x + 8, -24, num[0]);
969 Sbar_DrawCharacter (x + 16, -24, num[1]);
970 Sbar_DrawCharacter (x + 24, -24, num[2]);
975 //=============================================================================
983 static void Sbar_DrawFace (void)
987 // PGM 01/19/97 - team color drawing
988 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
989 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
995 s = &cl.scores[cl.viewentity - 1];
997 Sbar_DrawPic (112, 0, rsb_teambord);
998 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
999 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);
1000 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1001 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);
1005 dpsnprintf (num, sizeof(num), "%3i",f);
1007 if ((s->colors & 0xf0)==0)
1010 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1012 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1014 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1018 Sbar_DrawCharacter ( 109, 3, num[0]);
1019 Sbar_DrawCharacter ( 116, 3, num[1]);
1020 Sbar_DrawCharacter ( 123, 3, num[2]);
1025 // PGM 01/19/97 - team color drawing
1027 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1028 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1029 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1030 Sbar_DrawPic (112, 0, sb_face_quad );
1031 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1032 Sbar_DrawPic (112, 0, sb_face_invis );
1033 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1034 Sbar_DrawPic (112, 0, sb_face_invuln);
1037 f = cl.stats[STAT_HEALTH] / 20;
1039 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1042 double topspeed = 0;
1043 double topspeedxy = 0;
1044 time_t current_time = 3;
1045 time_t top_time = 0;
1046 time_t topxy_time = 0;
1048 static void get_showspeed_unit(int unitnumber, double *conversion_factor, const char **unit)
1051 unitnumber = cl_showspeed.integer;
1057 *conversion_factor = 1.0;
1061 *conversion_factor = 1.0 * cl_showspeed_factor.value * 0.01;
1065 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01) * 3.6;
1069 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01 * 3.6) * 0.6213711922;
1073 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01 * 3.6) * 0.539957;
1078 static double showfps_nexttime = 0, showfps_lasttime = -1;
1079 static double showfps_framerate = 0;
1080 static int showfps_framecount = 0;
1082 void Sbar_ShowFPS_Update(void)
1084 double interval = 1;
1086 newtime = host.realtime;
1087 if (newtime >= showfps_nexttime)
1089 showfps_framerate = showfps_framecount / (newtime - showfps_lasttime);
1090 if (showfps_nexttime < newtime - interval * 1.5)
1091 showfps_nexttime = newtime;
1092 showfps_lasttime = newtime;
1093 showfps_nexttime += interval;
1094 showfps_framecount = 0;
1096 showfps_framecount++;
1099 void Sbar_ShowFPS(void)
1101 float fps_x, fps_y, fps_scalex, fps_scaley, fps_strings = 0;
1102 char soundstring[32];
1104 char timestring[32];
1105 char datestring[32];
1106 char timedemostring1[32];
1107 char timedemostring2[32];
1108 char speedstring[32];
1109 char blurstring[32];
1110 char topspeedstring[48];
1111 char texstring[MAX_QPATH];
1116 timedemostring1[0] = 0;
1117 timedemostring2[0] = 0;
1122 topspeedstring[0] = 0;
1125 if (cl_showfps.integer)
1127 red = (showfps_framerate < 1.0f);
1128 if(cl_showfps.integer == 2)
1129 dpsnprintf(fpsstring, sizeof(fpsstring), "%7.3f mspf", (1000.0 / showfps_framerate));
1131 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0 / showfps_framerate + 0.5));
1133 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(showfps_framerate + 0.5));
1137 dpsnprintf(timedemostring1, sizeof(timedemostring1), "frame%4i %f", cls.td_frames, host.realtime - cls.td_starttime);
1138 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);
1143 if (cl_showtime.integer)
1145 dp_strlcpy(timestring, Sys_TimeString(cl_showtime_format.string), sizeof(timestring));
1148 if (cl_showdate.integer)
1150 dp_strlcpy(datestring, Sys_TimeString(cl_showdate_format.string), sizeof(datestring));
1153 if (cl_showblur.integer)
1155 dpsnprintf(blurstring, sizeof(blurstring), "%3i%% blur", (int)(cl.motionbluralpha * 100));
1158 if (cl_showsound.integer)
1160 dpsnprintf(soundstring, sizeof(soundstring), "%4i/4%i at %3ims", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds);
1163 if (cl_showspeed.integer || cl_showtopspeed.integer)
1165 double speed, speedxy, f;
1167 speed = VectorLength(cl.movement_velocity);
1168 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1169 if (cl_showspeed.integer)
1171 get_showspeed_unit(cl_showspeed.integer, &f, &unit);
1172 dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1175 if (cl_showtopspeed.integer)
1177 qbool topspeed_latched = false, topspeedxy_latched = false;
1178 get_showspeed_unit(cl_showtopspeed.integer, &f, &unit);
1179 if (speed >= topspeed || current_time - top_time > 3)
1185 topspeed_latched = true;
1186 if (speedxy >= topspeedxy || current_time - topxy_time > 3)
1188 topspeedxy = speedxy;
1192 topspeedxy_latched = true;
1193 dpsnprintf(topspeedstring, sizeof(topspeedstring), "%s%.0f%s (%s%.0f%s) %s",
1194 topspeed_latched ? "^1" : "^xf88", f*topspeed, "^xf88",
1195 topspeedxy_latched ? "^1" : "^xf88", f*topspeedxy, "^xf88",
1197 time(¤t_time);
1201 if (cl_showtex.integer)
1206 trace_t svtrace, cltrace;
1207 int hitnetentity = -1;
1209 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, org);
1210 VectorSet(temp, 65536, 0, 0);
1211 Matrix4x4_Transform(&r_refdef.view.matrix, temp, dest);
1212 // 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
1213 memset(&svtrace, 0, sizeof(svtrace));
1214 memset(&cltrace, 0, sizeof(cltrace));
1215 svtrace.fraction = 2.0;
1216 cltrace.fraction = 2.0;
1217 // ray hits models (even animated ones) and ignores translucent materials
1219 svtrace = SV_TraceLine(org, dest, MOVE_HITMODEL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value);
1220 cltrace = CL_TraceLine(org, dest, MOVE_HITMODEL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, &hitnetentity, true, true);
1221 if (cltrace.hittexture)
1222 dp_strlcpy(texstring, cltrace.hittexture->name, sizeof(texstring));
1224 dp_strlcpy(texstring, "(no texture hit)", sizeof(texstring));
1226 if (svtrace.fraction < cltrace.fraction)
1228 if (svtrace.ent != NULL)
1230 prvm_prog_t *prog = SVVM_prog;
1231 dpsnprintf(entstring, sizeof(entstring), "server entity %i", (int)PRVM_EDICT_TO_PROG(svtrace.ent));
1234 dp_strlcpy(entstring, "(no entity hit)", sizeof(entstring));
1238 if (cltrace.ent != NULL)
1240 prvm_prog_t *prog = CLVM_prog;
1241 dpsnprintf(entstring, sizeof(entstring), "client entity %i", (int)PRVM_EDICT_TO_PROG(cltrace.ent));
1243 else if (hitnetentity > 0)
1244 dpsnprintf(entstring, sizeof(entstring), "network entity %i", hitnetentity);
1245 else if (hitnetentity == 0)
1246 dp_strlcpy(entstring, "world entity", sizeof(entstring));
1248 dp_strlcpy(entstring, "(no entity hit)", sizeof(entstring));
1256 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1257 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_strings*fps_scaley);
1258 fps_y = vid_conheight.integer - sbar_info_pos.integer - fps_strings*fps_scaley;
1261 fps_x = vid_conwidth.integer - DrawQ_TextWidth(soundstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1262 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1263 DrawQ_String(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1264 fps_y += fps_scaley;
1268 r_draw2d_force = true;
1269 fps_x = vid_conwidth.integer - DrawQ_TextWidth(fpsstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1270 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1272 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1274 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1275 fps_y += fps_scaley;
1276 r_draw2d_force = false;
1278 if (timedemostring1[0])
1280 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring1, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1281 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1282 DrawQ_String(fps_x, fps_y, timedemostring1, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1283 fps_y += fps_scaley;
1285 if (timedemostring2[0])
1287 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring2, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1288 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1289 DrawQ_String(fps_x, fps_y, timedemostring2, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1290 fps_y += fps_scaley;
1294 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1295 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1296 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1297 fps_y += fps_scaley;
1301 fps_x = vid_conwidth.integer - DrawQ_TextWidth(datestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1302 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1303 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1304 fps_y += fps_scaley;
1308 fps_x = vid_conwidth.integer - DrawQ_TextWidth(speedstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1309 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1310 DrawQ_String(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1311 fps_y += fps_scaley;
1313 if (topspeedstring[0])
1315 fps_x = vid_conwidth.integer - DrawQ_TextWidth(topspeedstring, 0, fps_scalex, fps_scaley, false, FONT_INFOBAR);
1316 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1317 DrawQ_String(fps_x, fps_y, topspeedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR);
1318 fps_y += fps_scaley;
1322 fps_x = vid_conwidth.integer - DrawQ_TextWidth(blurstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1323 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1324 DrawQ_String(fps_x, fps_y, blurstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1325 fps_y += fps_scaley;
1329 fps_x = vid_conwidth.integer - DrawQ_TextWidth(texstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1330 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1331 DrawQ_String(fps_x, fps_y, texstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1332 fps_y += fps_scaley;
1336 fps_x = vid_conwidth.integer - DrawQ_TextWidth(entstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1337 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1338 DrawQ_String(fps_x, fps_y, entstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1339 fps_y += fps_scaley;
1344 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)
1347 c2 = bound(0, c2, 1);
1348 c1 = bound(0, c1, 1 - c2);
1350 r[1] = rangey + rangeheight * (c2 + c1);
1351 r[2] = rangey + rangeheight * (c2);
1355 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);
1357 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);
1359 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);
1361 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);
1369 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1370 extern cvar_t v_kicktime;
1371 void Sbar_Score (int margin);
1372 void Sbar_Draw (void)
1377 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1380 Sbar_DrawScoreboard ();
1381 else if (cl.intermission == 1)
1383 if(IS_OLDNEXUIZ_DERIVED(gamemode)) // display full scoreboard (that is, show scores + map name)
1385 Sbar_DrawScoreboard();
1388 Sbar_IntermissionOverlay();
1390 else if (cl.intermission == 2)
1391 Sbar_FinaleOverlay();
1392 else if (gamemode == GAME_DELUXEQUAKE)
1395 else if (IS_OLDNEXUIZ_DERIVED(gamemode))
1397 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1399 sbar_x = (vid_conwidth.integer - 640)/2;
1400 sbar_y = vid_conheight.integer - 47;
1401 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1402 Sbar_DrawScoreboard ();
1404 else if (sb_lines && sbar_hudselector.integer == 1)
1408 int redflag, blueflag;
1411 sbar_x = (vid_conwidth.integer - 320)/2;
1412 sbar_y = vid_conheight.integer - 24 - 16;
1414 // calculate intensity to draw weapons bar at
1415 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1416 fade = bound(0.7, fade, 1);
1417 for (i = 0; i < 8;i++)
1418 if (cl.stats[STAT_ITEMS] & (1 << i))
1419 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1420 if((cl.stats[STAT_ITEMS] & (1<<12)))
1421 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1424 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1425 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1426 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1427 if (redflag == 3 && blueflag == 3)
1429 // The Impossible Combination[tm]
1430 // Can only happen in Key Hunt mode...
1431 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[14]);
1436 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64)), sb_items[redflag+10]);
1438 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[blueflag+14]);
1442 if (cl.stats[STAT_ARMOR] > 0)
1444 Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1445 if(cl.stats[STAT_ARMOR] > 200)
1446 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1447 else if(cl.stats[STAT_ARMOR] > 100)
1448 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1449 else if(cl.stats[STAT_ARMOR] > 50)
1450 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1451 else if(cl.stats[STAT_ARMOR] > 25)
1452 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1454 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1458 if (cl.stats[STAT_HEALTH] != 0)
1460 Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1461 if(cl.stats[STAT_HEALTH] > 200)
1462 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1463 else if(cl.stats[STAT_HEALTH] > 100)
1464 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1465 else if(cl.stats[STAT_HEALTH] > 50)
1466 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1467 else if(cl.stats[STAT_HEALTH] > 25)
1468 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1470 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1474 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1476 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1477 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1478 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1479 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1480 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1481 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1482 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1483 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1484 if(cl.stats[STAT_AMMO] > 10)
1485 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1487 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1490 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1491 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1494 // The margin can be at most 8 to support 640x480 console size:
1495 // 320 + 2 * (144 + 16) = 640
1501 int redflag, blueflag;
1504 sbar_x = (vid_conwidth.integer - 640)/2;
1505 sbar_y = vid_conheight.integer - 47;
1507 // calculate intensity to draw weapons bar at
1508 fade = 3 - 2 * (cl.time - cl.weapontime);
1511 fade = min(fade, 1);
1512 for (i = 0; i < 8;i++)
1513 if (cl.stats[STAT_ITEMS] & (1 << i))
1514 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1516 if((cl.stats[STAT_ITEMS] & (1<<12)))
1517 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1520 //if (!cl.islocalgame)
1521 // Sbar_DrawFrags ();
1524 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1526 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1529 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1530 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1531 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1532 if (redflag == 3 && blueflag == 3)
1534 // The Impossible Combination[tm]
1535 // Can only happen in Key Hunt mode...
1536 Sbar_DrawPic ((int) x, -179, sb_items[14]);
1541 Sbar_DrawPic ((int) x, -117, sb_items[redflag+10]);
1543 Sbar_DrawPic ((int) x, -177, sb_items[blueflag+14]);
1547 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1550 if(cl.stats[STAT_HEALTH] > 100)
1551 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1552 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1553 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1555 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1557 // AK dont draw ammo for the laser
1558 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1560 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1561 Sbar_DrawPic (519, 0, sb_ammo[0]);
1562 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1563 Sbar_DrawPic (519, 0, sb_ammo[1]);
1564 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1565 Sbar_DrawPic (519, 0, sb_ammo[2]);
1566 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1567 Sbar_DrawPic (519, 0, sb_ammo[3]);
1569 if(cl.stats[STAT_AMMO] <= 10)
1570 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1572 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1577 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1579 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1580 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1585 // Mini scoreboard uses 12*4 per other team, that is, 144
1586 // pixels when there are four teams...
1587 // Nexuiz by default sets vid_conwidth to 800... makes
1589 // so we need to shift it by 64 pixels to the right to fit
1590 // BUT: then it overlaps with the image that gets drawn
1591 // for viewsize 100! Therefore, just account for 3 teams,
1592 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1596 else if (gamemode == GAME_ZYMOTIC)
1599 float scale = 64.0f / 256.0f;
1600 float kickoffset[3];
1601 VectorClear(kickoffset);
1604 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1605 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1607 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1608 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1609 // left1 16, 48 : 126 -66
1610 // left2 16, 128 : 196 -66
1611 // right 176, 48 : 196 -136
1612 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);
1613 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);
1614 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);
1615 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1617 float scale = 128.0f / 256.0f;
1618 float healthstart, healthheight, healthstarttc, healthendtc;
1619 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1620 float ammostart, ammoheight, ammostarttc, ammoendtc;
1621 float clipstart, clipheight, clipstarttc, clipendtc;
1622 float kickoffset[3], offset;
1623 VectorClear(kickoffset);
1626 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1627 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1629 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1630 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1631 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1632 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);
1633 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);
1634 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);
1635 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);
1636 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1637 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1638 healthstart = 204 - healthheight;
1639 shieldstart = healthstart - shieldheight;
1640 healthstarttc = healthstart * (1.0f / 256.0f);
1641 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1642 shieldstarttc = shieldstart * (1.0f / 256.0f);
1643 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1644 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1645 ammostart = 114 - ammoheight;
1646 ammostarttc = ammostart * (1.0f / 256.0f);
1647 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1648 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1649 clipstart = 190 - clipheight;
1650 clipstarttc = clipstart * (1.0f / 256.0f);
1651 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1652 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);
1653 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);
1654 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);
1655 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);
1656 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1657 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1660 else // Quake and others
1662 sbar_x = (vid_conwidth.integer - 320)/2;
1663 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1664 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1665 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1669 if (gamemode != GAME_GOODVSBAD2)
1670 Sbar_DrawInventory ();
1671 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1675 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1677 if (gamemode != GAME_GOODVSBAD2)
1678 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1679 Sbar_DrawScoreboard ();
1683 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1685 // keys (hipnotic only)
1686 //MED 01/04/97 moved keys here so they would not be overwritten
1687 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
1689 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1690 Sbar_DrawPic (209, 3, sb_items[0]);
1691 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1692 Sbar_DrawPic (209, 12, sb_items[1]);
1695 if (gamemode != GAME_GOODVSBAD2)
1697 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1699 Sbar_DrawNum (24, 0, 666, 3, 1);
1700 Sbar_DrawPic (0, 0, sb_disc);
1704 if (gamemode == GAME_ROGUE)
1706 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1707 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1708 Sbar_DrawPic (0, 0, sb_armor[2]);
1709 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1710 Sbar_DrawPic (0, 0, sb_armor[1]);
1711 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1712 Sbar_DrawPic (0, 0, sb_armor[0]);
1716 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1717 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1718 Sbar_DrawPic (0, 0, sb_armor[2]);
1719 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1720 Sbar_DrawPic (0, 0, sb_armor[1]);
1721 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1722 Sbar_DrawPic (0, 0, sb_armor[0]);
1731 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1734 if (gamemode == GAME_ROGUE)
1736 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1737 Sbar_DrawPic (224, 0, sb_ammo[0]);
1738 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1739 Sbar_DrawPic (224, 0, sb_ammo[1]);
1740 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1741 Sbar_DrawPic (224, 0, sb_ammo[2]);
1742 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1743 Sbar_DrawPic (224, 0, sb_ammo[3]);
1744 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1745 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1746 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1747 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1748 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1749 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1753 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1754 Sbar_DrawPic (224, 0, sb_ammo[0]);
1755 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1756 Sbar_DrawPic (224, 0, sb_ammo[1]);
1757 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1758 Sbar_DrawPic (224, 0, sb_ammo[2]);
1759 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1760 Sbar_DrawPic (224, 0, sb_ammo[3]);
1763 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1765 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1766 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1768 if (gamemode == GAME_TRANSFUSION)
1769 Sbar_MiniDeathmatchOverlay (0, 0);
1771 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1778 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1780 pic = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/crosshair%i", crosshair.integer));
1781 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);
1784 if (cl_prydoncursor.integer > 0)
1785 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);
1788 //=============================================================================
1792 Sbar_DeathmatchOverlay
1796 static float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1799 qbool myself = false;
1802 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1804 if((s - cl.scores) == cl.playerentity - 1)
1806 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1807 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1810 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1812 if (s->qw_spectator)
1814 if (s->qw_ping || s->qw_packetloss)
1815 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 );
1817 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 );
1821 // draw colors behind score
1827 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1828 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);
1829 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1830 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);
1832 //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);
1833 if (s->qw_ping || s->qw_packetloss)
1834 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 );
1836 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 );
1841 if (s->qw_spectator)
1843 if (s->qw_ping || s->qw_packetloss)
1844 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 );
1846 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 );
1850 // draw colors behind score
1851 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1852 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);
1853 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1854 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);
1856 //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);
1857 if (s->qw_ping || s->qw_packetloss)
1858 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 );
1860 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 );
1866 void Sbar_DeathmatchOverlay (void)
1868 int i, y, xmin, xmax, ymin, ymax;
1871 // request new ping times every two second
1872 if (cl.last_ping_request < host.realtime - 2 && cls.netcon)
1874 cl.last_ping_request = host.realtime;
1875 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1877 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1878 MSG_WriteString(&cls.netcon->message, "pings");
1880 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*/)
1882 // 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
1883 static int ping_anyway_counter = 0;
1884 if(cl.parsingtextexpectingpingforscores == 1)
1886 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1887 if(++ping_anyway_counter >= 5)
1888 cl.parsingtextexpectingpingforscores = 0;
1890 if(cl.parsingtextexpectingpingforscores != 1)
1892 ping_anyway_counter = 0;
1893 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1894 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1895 MSG_WriteString(&cls.netcon->message, "ping");
1900 // 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
1901 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1902 MSG_WriteString(&cls.netcon->message, "pings");
1910 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1912 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1913 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)
1915 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)
1916 xmax = vid_conwidth.integer - xmin;
1918 if(IS_OLDNEXUIZ_DERIVED(gamemode))
1919 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);
1921 DrawQ_Pic ((vid_conwidth.integer - Draw_GetPicWidth(sb_ranking))/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1925 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1927 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 );
1931 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 );
1935 if (Sbar_IsTeammatch ())
1937 // show team scores first
1938 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1939 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1943 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1944 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1949 Sbar_MiniDeathmatchOverlay
1953 void Sbar_MiniDeathmatchOverlay (int x, int y)
1955 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1957 // do not draw this if sbar_miniscoreboard_size is zero
1958 if(sbar_miniscoreboard_size.value == 0)
1960 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1961 if(sbar_miniscoreboard_size.value > 0)
1962 y = (int) (vid_conheight.integer - sbar_miniscoreboard_size.value * 8);
1967 // decide where to print
1968 if (gamemode == GAME_TRANSFUSION)
1969 numlines = (vid_conwidth.integer - x + 127) / 128;
1971 numlines = (vid_conheight.integer - y + 7) / 8;
1973 // give up if there isn't room
1974 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1978 for (i = 0; i < scoreboardlines; i++)
1979 if (fragsort[i] == cl.playerentity - 1)
1983 range_end = scoreboardlines;
1986 if (gamemode != GAME_TRANSFUSION)
1987 if (Sbar_IsTeammatch ())
1989 // reserve space for the team scores
1990 numlines -= teamlines;
1992 // find first and last player of my team (only draw the team totals and my own team)
1993 range_begin = range_end = i;
1994 myteam = cl.scores[fragsort[i]].colors & 15;
1995 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1997 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
2000 // looks better than two players
2010 i = min(i, range_end - numlines);
2011 i = max(i, range_begin);
2013 if (gamemode == GAME_TRANSFUSION)
2015 for (;i < range_end && x < vid_conwidth.integer;i++)
2016 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2020 if(range_end - i < numlines) // won't draw to bottom?
2021 y += 8 * (numlines - (range_end - i)); // bottom align
2022 // show team scores first
2023 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
2024 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
2026 for (;i < range_end && y < vid_conheight.integer;i++)
2027 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2031 static int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
2033 static int const sortorder[16] =
2052 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
2053 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
2054 int tc1 = sortorder[t1->colors & 15];
2055 int tc2 = sortorder[t2->colors & 15];
2059 void Sbar_Score (int margin)
2061 int i, me, score, otherleader, place, distribution, minutes, seconds;
2063 int sbar_x_save = sbar_x;
2064 int sbar_y_save = sbar_y;
2067 sbar_y = (int) (vid_conheight.value - (32+12));
2070 me = cl.playerentity - 1;
2071 if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients)
2073 if(Sbar_IsTeammatch())
2077 // team1 team3 team4
2081 scoreboard_t *teamcolorsort[16];
2084 for(i = 0; i < teamlines; ++i)
2085 teamcolorsort[i] = &(teams[i]);
2087 // Now sort them by color
2088 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
2091 // -12*4: four digits space
2092 place = (teamlines - 1) * (-12 * 4);
2094 for(i = 0; i < teamlines; ++i)
2096 int cindex = teamcolorsort[i]->colors & 15;
2097 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
2098 float cm = max(max(c[0], c[1]), c[2]);
2099 float cr = c[0] / cm;
2100 float cg = c[1] / cm;
2101 float cb = c[2] / cm;
2102 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
2104 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
2108 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
2121 // find leading score other than ourselves, to calculate distribution
2122 // find our place in the scoreboard
2123 score = cl.scores[me].frags;
2124 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
2126 if (cl.scores[i].name[0] && i != me)
2128 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
2130 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
2134 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
2136 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2137 else if (place == 2)
2138 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2140 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2141 if (otherleader < 0)
2142 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2143 if (distribution >= 0)
2145 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2146 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2148 else if (distribution >= -5)
2150 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2151 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2155 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2156 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2161 if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT])
2163 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2164 minutes = (int)floor(timeleft / 60);
2165 seconds = (int)(floor(timeleft) - minutes * 60);
2168 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2169 if (Draw_IsPicLoaded(sb_colon))
2170 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2171 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2173 else if (minutes >= 1)
2175 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2176 if (Draw_IsPicLoaded(sb_colon))
2177 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2178 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2180 else if ((int)(timeleft * 4) & 1)
2181 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2183 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2185 else if (sbar_gametime.integer)
2187 minutes = (int)floor(cl.time / 60);
2188 seconds = (int)(floor(cl.time) - minutes * 60);
2189 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2190 if (Draw_IsPicLoaded(sb_colon))
2191 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2192 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2195 sbar_x = sbar_x_save;
2196 sbar_y = sbar_y_save;
2201 Sbar_IntermissionOverlay
2205 void Sbar_IntermissionOverlay (void)
2210 if (cl.gametype == GAME_DEATHMATCH)
2212 Sbar_DeathmatchOverlay ();
2216 sbar_x = (vid_conwidth.integer - 320) >> 1;
2217 sbar_y = (vid_conheight.integer - 200) >> 1;
2219 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2220 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2223 dig = (int)cl.completed_time / 60;
2224 Sbar_DrawNum (160, 64, dig, 3, 0);
2225 num = (int)cl.completed_time - dig*60;
2226 Sbar_DrawPic (234,64,sb_colon);
2227 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2228 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2230 // LA: Display as "a" instead of "a/b" if b is 0
2231 if(cl.stats[STAT_TOTALSECRETS])
2233 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2234 if (!IS_OLDNEXUIZ_DERIVED(gamemode))
2235 Sbar_DrawPic (232, 104, sb_slash);
2236 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2240 Sbar_DrawNum (240, 104, cl.stats[STAT_SECRETS], 3, 0);
2243 if(cl.stats[STAT_TOTALMONSTERS])
2245 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2246 if (!IS_OLDNEXUIZ_DERIVED(gamemode))
2247 Sbar_DrawPic (232, 144, sb_slash);
2248 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2252 Sbar_DrawNum (240, 144, cl.stats[STAT_MONSTERS], 3, 0);
2263 void Sbar_FinaleOverlay (void)
2265 DrawQ_Pic((vid_conwidth.integer - Draw_GetPicWidth(sb_finale))/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);