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 Cmd_AddCommand(CF_CLIENT, "+showscores", Sbar_ShowScores_f, "show scoreboard");
363 Cmd_AddCommand(CF_CLIENT, "-showscores", Sbar_DontShowScores_f, "hide scoreboard");
364 Cvar_RegisterVariable(&cl_showfps);
365 Cvar_RegisterVariable(&cl_showsound);
366 Cvar_RegisterVariable(&cl_showblur);
367 Cvar_RegisterVariable(&cl_showspeed);
368 Cvar_RegisterVariable(&cl_showspeed_factor);
369 Cvar_RegisterVariable(&cl_showtopspeed);
370 Cvar_RegisterVariable(&cl_showtime);
371 Cvar_RegisterVariable(&cl_showtime_format);
372 Cvar_RegisterVariable(&cl_showdate);
373 Cvar_RegisterVariable(&cl_showdate_format);
374 Cvar_RegisterVariable(&cl_showtex);
376 Cvar_RegisterVirtual(&cl_showfps, "showfps");
377 Cvar_RegisterVirtual(&cl_showsound, "showsound");
378 Cvar_RegisterVirtual(&cl_showblur, "showblur");
379 Cvar_RegisterVirtual(&cl_showspeed, "showspeed");
380 Cvar_RegisterVirtual(&cl_showtopspeed, "showtopspeed");
381 Cvar_RegisterVirtual(&cl_showtime, "showtime");
382 Cvar_RegisterVirtual(&cl_showtime_format, "showtime_format");
383 Cvar_RegisterVirtual(&cl_showdate, "showdate");
384 Cvar_RegisterVirtual(&cl_showdate_format, "showdate_format");
385 Cvar_RegisterVirtual(&cl_showtex, "showtex");
387 Cvar_RegisterVariable(&sbar_alpha_bg);
388 Cvar_RegisterVariable(&sbar_alpha_fg);
389 Cvar_RegisterVariable(&sbar_hudselector);
390 Cvar_RegisterVariable(&sbar_scorerank);
391 Cvar_RegisterVariable(&sbar_gametime);
392 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
393 Cvar_RegisterVariable(&sbar_info_pos);
394 Cvar_RegisterVariable(&cl_deathscoreboard);
396 Cvar_RegisterVariable(&crosshair_color_red);
397 Cvar_RegisterVariable(&crosshair_color_green);
398 Cvar_RegisterVariable(&crosshair_color_blue);
399 Cvar_RegisterVariable(&crosshair_color_alpha);
400 Cvar_RegisterVariable(&crosshair_size);
402 Cvar_RegisterVariable(&sbar_flagstatus_right); // (GAME_NEXUZI ONLY)
403 Cvar_RegisterVariable(&sbar_flagstatus_pos); // (GAME_NEXUIZ ONLY)
405 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap, NULL, NULL);
409 //=============================================================================
411 // drawing routines are relative to the status bar location
420 static void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
422 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
425 static void Sbar_DrawPic (int x, int y, cachepic_t *pic)
427 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
430 static void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
432 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
439 Draws one solid graphics character
442 static void Sbar_DrawCharacter (int x, int y, int num)
445 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);
453 static void Sbar_DrawString (int x, int y, char *str)
455 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR);
463 static void Sbar_DrawNum (int x, int y, int num, int digits, int color)
468 l = dpsnprintf(str, sizeof(str), "%i", num);
482 Sbar_DrawPic (x, y, sb_nums[color][frame]);
495 static void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
503 l = dpsnprintf(str, sizeof(str), "%0*i", digits, num);
506 l = dpsnprintf(str, sizeof(str), "%i", num);
511 x += (digits-l) * lettersize;
520 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
527 //=============================================================================
530 static int Sbar_IsTeammatch(void)
532 // currently only nexuiz uses the team score board
533 return (IS_OLDNEXUIZ_DERIVED(gamemode)
534 && (teamplay.integer > 0));
542 static int fragsort[MAX_SCOREBOARD];
543 static int scoreboardlines;
545 int Sbar_GetSortedPlayerIndex (int index)
547 return index >= 0 && index < scoreboardlines ? fragsort[index] : -1;
550 static scoreboard_t teams[MAX_SCOREBOARD];
551 static int teamsort[MAX_SCOREBOARD];
552 static int teamlines;
553 void Sbar_SortFrags (void)
559 for (i=0 ; i<cl.maxclients ; i++)
561 if (cl.scores[i].name[0])
563 fragsort[scoreboardlines] = i;
568 for (i=0 ; i<scoreboardlines ; i++)
569 for (j=0 ; j<scoreboardlines-1-i ; j++)
570 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
573 fragsort[j] = fragsort[j+1];
578 if (Sbar_IsTeammatch ())
580 // now sort players by teams.
581 for (i=0 ; i<scoreboardlines ; i++)
583 for (j=0 ; j<scoreboardlines-1-i ; j++)
585 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
588 fragsort[j] = fragsort[j+1];
594 // calculate team scores
596 for (i=0 ; i<scoreboardlines ; i++)
598 if (color != (cl.scores[fragsort[i]].colors & 15))
600 const char* teamname;
602 color = cl.scores[fragsort[i]].colors & 15;
608 teamname = "^1Red Team";
611 teamname = "^4Blue Team";
614 teamname = "^6Pink Team";
617 teamname = "^3Yellow Team";
620 teamname = "Total Team Score";
623 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
625 teams[teamlines-1].frags = 0;
626 teams[teamlines-1].colors = color + 16 * color;
629 if (cl.scores[fragsort[i]].frags != -666)
631 // do not add spedcators
632 // (ugly hack for nexuiz)
633 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
637 // now sort teams by scores.
638 for (i=0 ; i<teamlines ; i++)
640 for (i=0 ; i<teamlines ; i++)
642 for (j=0 ; j<teamlines-1-i ; j++)
644 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
647 teamsort[j] = teamsort[j+1];
660 static void Sbar_SoloScoreboard (void)
663 char str[80], timestr[40];
665 int minutes, seconds;
669 t = (cl.intermission ? cl.completed_time : cl.time);
670 minutes = (int)(t / 60);
671 seconds = (int)(t - 60*floor(t/60));
673 // monsters and secrets are now both on the top row
674 if (cl.stats[STAT_TOTALMONSTERS])
675 Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
676 else if (cl.stats[STAT_MONSTERS]) // LA: Display something if monsters_killed is non-zero, but total_monsters is zero
677 Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i", cl.stats[STAT_MONSTERS]));
679 if (cl.stats[STAT_TOTALSECRETS])
680 Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
681 else if (cl.stats[STAT_SECRETS]) // LA: And similarly for secrets
682 Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i", cl.stats[STAT_SECRETS]));
684 // format is like this: e1m1:The Sligpate Complex
685 dpsnprintf(str, sizeof(str), "%s:%s", cl.worldbasename, cl.worldmessage);
687 // if there's a newline character, terminate the string there
688 if (strchr(str, '\n'))
689 *(strchr(str, '\n')) = 0;
691 // make the time string
692 timelen = dpsnprintf(timestr, sizeof(timestr), " %i:%02i", minutes, seconds);
694 // truncate the level name if necessary to make room for time
696 if ((int)strlen(str) > max)
699 // print the filename and message
700 Sbar_DrawString(8, 12, str);
703 Sbar_DrawString(8 + max*8, 12, timestr);
707 int minutes, seconds, tens, units;
710 if (IS_OLDNEXUIZ_DERIVED(gamemode)) {
711 dpsnprintf (str, sizeof(str), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
712 Sbar_DrawString (8, 4, str);
714 dpsnprintf (str, sizeof(str), "Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
715 Sbar_DrawString (8, 12, str);
719 minutes = (int)(cl.time / 60);
720 seconds = (int)(cl.time - 60*minutes);
722 units = seconds - 10*tens;
723 dpsnprintf (str, sizeof(str), "Time :%3i:%i%i", minutes, tens, units);
724 Sbar_DrawString (184, 4, str);
727 if (IS_OLDNEXUIZ_DERIVED(gamemode)) {
728 l = (int) strlen (cl.worldname);
729 Sbar_DrawString (232 - l*4, 12, cl.worldname);
731 l = (int) strlen (cl.worldmessage);
732 Sbar_DrawString (232 - l*4, 12, cl.worldmessage);
742 static void Sbar_DrawScoreboard (void)
744 Sbar_SoloScoreboard ();
745 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
746 //if (cl.gametype == GAME_DEATHMATCH)
748 Sbar_DeathmatchOverlay ();
751 //=============================================================================
753 // AK to make DrawInventory smaller
754 static void Sbar_DrawWeapon(int nr, float fade, int active)
757 if (sbar_hudselector.integer == 1)
759 // width = 300, height = 100
760 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
762 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);
764 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);
768 // width = 300, height = 100
769 const int w_width = 300, w_height = 100, w_space = 10;
770 const float w_scale = 0.4;
772 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);
773 //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);
782 static void Sbar_DrawInventory (void)
789 if (gamemode == GAME_ROGUE)
791 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
792 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
794 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
797 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
800 for (i=0 ; i<7 ; i++)
802 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
804 time = cl.item_gettime[i];
805 flashon = (int)(max(0, cl.time - time)*10);
808 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
814 flashon = (flashon%5) + 2;
816 Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
822 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
824 int grenadeflashing=0;
825 for (i=0 ; i<4 ; i++)
827 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
829 time = max(0, cl.item_gettime[hipweapons[i]]);
830 flashon = (int)((cl.time - time)*10);
833 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
839 flashon = (flashon%5) + 2;
841 // check grenade launcher
844 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
849 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
855 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
857 if (!grenadeflashing)
858 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
861 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
864 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
869 if (gamemode == GAME_ROGUE)
871 // check for powered up weapon.
872 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
874 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
875 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
879 for (i=0 ; i<4 ; i++)
881 dpsnprintf (num, sizeof(num), "%4i",cl.stats[STAT_SHELLS+i] );
883 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
885 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
887 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
889 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
893 for (i=0 ; i<6 ; i++)
894 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
896 //MED 01/04/97 changed keys
897 if (!(gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH) || (i>1))
898 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
901 //MED 01/04/97 added hipnotic items
903 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
905 for (i=0 ; i<2 ; i++)
906 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
907 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
910 if (gamemode == GAME_ROGUE)
913 for (i=0 ; i<2 ; i++)
914 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
915 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
920 for (i=0 ; i<4 ; i++)
921 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
922 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
926 //=============================================================================
933 static void Sbar_DrawFrags (void)
943 l = min(scoreboardlines, 4);
947 for (i = 0;i < l;i++)
953 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
954 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);
955 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
956 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);
960 dpsnprintf (num, sizeof(num), "%3i",f);
962 if (k == cl.viewentity - 1)
964 Sbar_DrawCharacter ( x + 2, -24, 16);
965 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
967 Sbar_DrawCharacter (x + 8, -24, num[0]);
968 Sbar_DrawCharacter (x + 16, -24, num[1]);
969 Sbar_DrawCharacter (x + 24, -24, num[2]);
974 //=============================================================================
982 static void Sbar_DrawFace (void)
986 // PGM 01/19/97 - team color drawing
987 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
988 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
994 s = &cl.scores[cl.viewentity - 1];
996 Sbar_DrawPic (112, 0, rsb_teambord);
997 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
998 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);
999 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1000 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);
1004 dpsnprintf (num, sizeof(num), "%3i",f);
1006 if ((s->colors & 0xf0)==0)
1009 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1011 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1013 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1017 Sbar_DrawCharacter ( 109, 3, num[0]);
1018 Sbar_DrawCharacter ( 116, 3, num[1]);
1019 Sbar_DrawCharacter ( 123, 3, num[2]);
1024 // PGM 01/19/97 - team color drawing
1026 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1027 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1028 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1029 Sbar_DrawPic (112, 0, sb_face_quad );
1030 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1031 Sbar_DrawPic (112, 0, sb_face_invis );
1032 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1033 Sbar_DrawPic (112, 0, sb_face_invuln);
1036 f = cl.stats[STAT_HEALTH] / 20;
1038 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1041 double topspeed = 0;
1042 double topspeedxy = 0;
1043 time_t current_time = 3;
1044 time_t top_time = 0;
1045 time_t topxy_time = 0;
1047 static void get_showspeed_unit(int unitnumber, double *conversion_factor, const char **unit)
1050 unitnumber = cl_showspeed.integer;
1056 *conversion_factor = 1.0;
1060 *conversion_factor = 1.0 * cl_showspeed_factor.value * 0.01;
1064 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01) * 3.6;
1068 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01 * 3.6) * 0.6213711922;
1072 *conversion_factor = 1.0 * (cl_showspeed_factor.value * 0.01 * 3.6) * 0.539957;
1077 static double showfps_nexttime = 0, showfps_lasttime = -1;
1078 static double showfps_framerate = 0;
1079 static int showfps_framecount = 0;
1081 void Sbar_ShowFPS_Update(void)
1083 double interval = 1;
1085 newtime = host.realtime;
1086 if (newtime >= showfps_nexttime)
1088 showfps_framerate = showfps_framecount / (newtime - showfps_lasttime);
1089 if (showfps_nexttime < newtime - interval * 1.5)
1090 showfps_nexttime = newtime;
1091 showfps_lasttime = newtime;
1092 showfps_nexttime += interval;
1093 showfps_framecount = 0;
1095 showfps_framecount++;
1098 void Sbar_ShowFPS(void)
1100 float fps_x, fps_y, fps_scalex, fps_scaley, fps_strings = 0;
1101 char soundstring[32];
1103 char timestring[32];
1104 char datestring[32];
1105 char timedemostring1[32];
1106 char timedemostring2[32];
1107 char speedstring[32];
1108 char blurstring[32];
1109 char topspeedstring[48];
1110 char texstring[MAX_QPATH];
1115 timedemostring1[0] = 0;
1116 timedemostring2[0] = 0;
1121 topspeedstring[0] = 0;
1124 if (cl_showfps.integer)
1126 red = (showfps_framerate < 1.0f);
1127 if(cl_showfps.integer == 2)
1128 dpsnprintf(fpsstring, sizeof(fpsstring), "%7.3f mspf", (1000.0 / showfps_framerate));
1130 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0 / showfps_framerate + 0.5));
1132 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(showfps_framerate + 0.5));
1136 dpsnprintf(timedemostring1, sizeof(timedemostring1), "frame%4i %f", cls.td_frames, host.realtime - cls.td_starttime);
1137 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);
1142 if (cl_showtime.integer)
1144 strlcpy(timestring, Sys_TimeString(cl_showtime_format.string), sizeof(timestring));
1147 if (cl_showdate.integer)
1149 strlcpy(datestring, Sys_TimeString(cl_showdate_format.string), sizeof(datestring));
1152 if (cl_showblur.integer)
1154 dpsnprintf(blurstring, sizeof(blurstring), "%3i%% blur", (int)(cl.motionbluralpha * 100));
1157 if (cl_showsound.integer)
1159 dpsnprintf(soundstring, sizeof(soundstring), "%4i/4%i at %3ims", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds);
1162 if (cl_showspeed.integer || cl_showtopspeed.integer)
1164 double speed, speedxy, f;
1166 speed = VectorLength(cl.movement_velocity);
1167 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1168 if (cl_showspeed.integer)
1170 get_showspeed_unit(cl_showspeed.integer, &f, &unit);
1171 dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1174 if (cl_showtopspeed.integer)
1176 qbool topspeed_latched = false, topspeedxy_latched = false;
1177 get_showspeed_unit(cl_showtopspeed.integer, &f, &unit);
1178 if (speed >= topspeed || current_time - top_time > 3)
1184 topspeed_latched = true;
1185 if (speedxy >= topspeedxy || current_time - topxy_time > 3)
1187 topspeedxy = speedxy;
1191 topspeedxy_latched = true;
1192 dpsnprintf(topspeedstring, sizeof(topspeedstring), "%s%.0f%s (%s%.0f%s) %s",
1193 topspeed_latched ? "^1" : "^xf88", f*topspeed, "^xf88",
1194 topspeedxy_latched ? "^1" : "^xf88", f*topspeedxy, "^xf88",
1196 time(¤t_time);
1200 if (cl_showtex.integer)
1205 trace_t svtrace, cltrace;
1206 int hitnetentity = -1;
1208 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, org);
1209 VectorSet(temp, 65536, 0, 0);
1210 Matrix4x4_Transform(&r_refdef.view.matrix, temp, dest);
1211 // 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
1212 memset(&svtrace, 0, sizeof(svtrace));
1213 memset(&cltrace, 0, sizeof(cltrace));
1214 svtrace.fraction = 2.0;
1215 cltrace.fraction = 2.0;
1216 // ray hits models (even animated ones) and ignores translucent materials
1218 svtrace = SV_TraceLine(org, dest, MOVE_HITMODEL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value);
1219 cltrace = CL_TraceLine(org, dest, MOVE_HITMODEL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, &hitnetentity, true, true);
1220 if (cltrace.hittexture)
1221 strlcpy(texstring, cltrace.hittexture->name, sizeof(texstring));
1223 strlcpy(texstring, "(no texture hit)", sizeof(texstring));
1225 if (svtrace.fraction < cltrace.fraction)
1227 if (svtrace.ent != NULL)
1229 prvm_prog_t *prog = SVVM_prog;
1230 dpsnprintf(entstring, sizeof(entstring), "server entity %i", (int)PRVM_EDICT_TO_PROG(svtrace.ent));
1233 strlcpy(entstring, "(no entity hit)", sizeof(entstring));
1237 if (cltrace.ent != NULL)
1239 prvm_prog_t *prog = CLVM_prog;
1240 dpsnprintf(entstring, sizeof(entstring), "client entity %i", (int)PRVM_EDICT_TO_PROG(cltrace.ent));
1242 else if (hitnetentity > 0)
1243 dpsnprintf(entstring, sizeof(entstring), "network entity %i", hitnetentity);
1244 else if (hitnetentity == 0)
1245 strlcpy(entstring, "world entity", sizeof(entstring));
1247 strlcpy(entstring, "(no entity hit)", sizeof(entstring));
1255 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1256 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_strings*fps_scaley);
1257 fps_y = vid_conheight.integer - sbar_info_pos.integer - fps_strings*fps_scaley;
1260 fps_x = vid_conwidth.integer - DrawQ_TextWidth(soundstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1261 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1262 DrawQ_String(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1263 fps_y += fps_scaley;
1267 r_draw2d_force = true;
1268 fps_x = vid_conwidth.integer - DrawQ_TextWidth(fpsstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1269 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1271 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1273 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1274 fps_y += fps_scaley;
1275 r_draw2d_force = false;
1277 if (timedemostring1[0])
1279 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring1, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1280 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1281 DrawQ_String(fps_x, fps_y, timedemostring1, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1282 fps_y += fps_scaley;
1284 if (timedemostring2[0])
1286 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring2, 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, timedemostring2, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1289 fps_y += fps_scaley;
1293 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timestring, 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, timestring, 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(datestring, 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, datestring, 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(speedstring, 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, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1310 fps_y += fps_scaley;
1312 if (topspeedstring[0])
1314 fps_x = vid_conwidth.integer - DrawQ_TextWidth(topspeedstring, 0, fps_scalex, fps_scaley, false, 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, topspeedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR);
1317 fps_y += fps_scaley;
1321 fps_x = vid_conwidth.integer - DrawQ_TextWidth(blurstring, 0, fps_scalex, fps_scaley, true, 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, blurstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1324 fps_y += fps_scaley;
1328 fps_x = vid_conwidth.integer - DrawQ_TextWidth(texstring, 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, texstring, 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(entstring, 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, entstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1338 fps_y += fps_scaley;
1343 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)
1346 c2 = bound(0, c2, 1);
1347 c1 = bound(0, c1, 1 - c2);
1349 r[1] = rangey + rangeheight * (c2 + c1);
1350 r[2] = rangey + rangeheight * (c2);
1354 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);
1356 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);
1358 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);
1360 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);
1368 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1369 extern cvar_t v_kicktime;
1370 void Sbar_Score (int margin);
1371 void Sbar_Draw (void)
1376 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1379 Sbar_DrawScoreboard ();
1380 else if (cl.intermission == 1)
1382 if(IS_OLDNEXUIZ_DERIVED(gamemode)) // display full scoreboard (that is, show scores + map name)
1384 Sbar_DrawScoreboard();
1387 Sbar_IntermissionOverlay();
1389 else if (cl.intermission == 2)
1390 Sbar_FinaleOverlay();
1391 else if (gamemode == GAME_DELUXEQUAKE)
1394 else if (IS_OLDNEXUIZ_DERIVED(gamemode))
1396 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1398 sbar_x = (vid_conwidth.integer - 640)/2;
1399 sbar_y = vid_conheight.integer - 47;
1400 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1401 Sbar_DrawScoreboard ();
1403 else if (sb_lines && sbar_hudselector.integer == 1)
1407 int redflag, blueflag;
1410 sbar_x = (vid_conwidth.integer - 320)/2;
1411 sbar_y = vid_conheight.integer - 24 - 16;
1413 // calculate intensity to draw weapons bar at
1414 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1415 fade = bound(0.7, fade, 1);
1416 for (i = 0; i < 8;i++)
1417 if (cl.stats[STAT_ITEMS] & (1 << i))
1418 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1419 if((cl.stats[STAT_ITEMS] & (1<<12)))
1420 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1423 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1424 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1425 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1426 if (redflag == 3 && blueflag == 3)
1428 // The Impossible Combination[tm]
1429 // Can only happen in Key Hunt mode...
1430 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[14]);
1435 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64)), sb_items[redflag+10]);
1437 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[blueflag+14]);
1441 if (cl.stats[STAT_ARMOR] > 0)
1443 Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1444 if(cl.stats[STAT_ARMOR] > 200)
1445 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1446 else if(cl.stats[STAT_ARMOR] > 100)
1447 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1448 else if(cl.stats[STAT_ARMOR] > 50)
1449 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1450 else if(cl.stats[STAT_ARMOR] > 25)
1451 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1453 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1457 if (cl.stats[STAT_HEALTH] != 0)
1459 Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1460 if(cl.stats[STAT_HEALTH] > 200)
1461 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1462 else if(cl.stats[STAT_HEALTH] > 100)
1463 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1464 else if(cl.stats[STAT_HEALTH] > 50)
1465 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1466 else if(cl.stats[STAT_HEALTH] > 25)
1467 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1469 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1473 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1475 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1476 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1477 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1478 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1479 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1480 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1481 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1482 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1483 if(cl.stats[STAT_AMMO] > 10)
1484 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1486 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1489 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1490 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1493 // The margin can be at most 8 to support 640x480 console size:
1494 // 320 + 2 * (144 + 16) = 640
1500 int redflag, blueflag;
1503 sbar_x = (vid_conwidth.integer - 640)/2;
1504 sbar_y = vid_conheight.integer - 47;
1506 // calculate intensity to draw weapons bar at
1507 fade = 3 - 2 * (cl.time - cl.weapontime);
1510 fade = min(fade, 1);
1511 for (i = 0; i < 8;i++)
1512 if (cl.stats[STAT_ITEMS] & (1 << i))
1513 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1515 if((cl.stats[STAT_ITEMS] & (1<<12)))
1516 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1519 //if (!cl.islocalgame)
1520 // Sbar_DrawFrags ();
1523 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1525 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1528 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1529 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1530 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1531 if (redflag == 3 && blueflag == 3)
1533 // The Impossible Combination[tm]
1534 // Can only happen in Key Hunt mode...
1535 Sbar_DrawPic ((int) x, -179, sb_items[14]);
1540 Sbar_DrawPic ((int) x, -117, sb_items[redflag+10]);
1542 Sbar_DrawPic ((int) x, -177, sb_items[blueflag+14]);
1546 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1549 if(cl.stats[STAT_HEALTH] > 100)
1550 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1551 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1552 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1554 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1556 // AK dont draw ammo for the laser
1557 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1559 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1560 Sbar_DrawPic (519, 0, sb_ammo[0]);
1561 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1562 Sbar_DrawPic (519, 0, sb_ammo[1]);
1563 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1564 Sbar_DrawPic (519, 0, sb_ammo[2]);
1565 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1566 Sbar_DrawPic (519, 0, sb_ammo[3]);
1568 if(cl.stats[STAT_AMMO] <= 10)
1569 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1571 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1576 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1578 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1579 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1584 // Mini scoreboard uses 12*4 per other team, that is, 144
1585 // pixels when there are four teams...
1586 // Nexuiz by default sets vid_conwidth to 800... makes
1588 // so we need to shift it by 64 pixels to the right to fit
1589 // BUT: then it overlaps with the image that gets drawn
1590 // for viewsize 100! Therefore, just account for 3 teams,
1591 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1595 else if (gamemode == GAME_ZYMOTIC)
1598 float scale = 64.0f / 256.0f;
1599 float kickoffset[3];
1600 VectorClear(kickoffset);
1603 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1604 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1606 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1607 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1608 // left1 16, 48 : 126 -66
1609 // left2 16, 128 : 196 -66
1610 // right 176, 48 : 196 -136
1611 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);
1612 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);
1613 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);
1614 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1616 float scale = 128.0f / 256.0f;
1617 float healthstart, healthheight, healthstarttc, healthendtc;
1618 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1619 float ammostart, ammoheight, ammostarttc, ammoendtc;
1620 float clipstart, clipheight, clipstarttc, clipendtc;
1621 float kickoffset[3], offset;
1622 VectorClear(kickoffset);
1625 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1626 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1628 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1629 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1630 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1631 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);
1632 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);
1633 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);
1634 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);
1635 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1636 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1637 healthstart = 204 - healthheight;
1638 shieldstart = healthstart - shieldheight;
1639 healthstarttc = healthstart * (1.0f / 256.0f);
1640 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1641 shieldstarttc = shieldstart * (1.0f / 256.0f);
1642 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1643 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1644 ammostart = 114 - ammoheight;
1645 ammostarttc = ammostart * (1.0f / 256.0f);
1646 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1647 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1648 clipstart = 190 - clipheight;
1649 clipstarttc = clipstart * (1.0f / 256.0f);
1650 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1651 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);
1652 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);
1653 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);
1654 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);
1655 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1656 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1659 else // Quake and others
1661 sbar_x = (vid_conwidth.integer - 320)/2;
1662 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1663 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1664 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1668 if (gamemode != GAME_GOODVSBAD2)
1669 Sbar_DrawInventory ();
1670 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1674 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1676 if (gamemode != GAME_GOODVSBAD2)
1677 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1678 Sbar_DrawScoreboard ();
1682 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1684 // keys (hipnotic only)
1685 //MED 01/04/97 moved keys here so they would not be overwritten
1686 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
1688 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1689 Sbar_DrawPic (209, 3, sb_items[0]);
1690 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1691 Sbar_DrawPic (209, 12, sb_items[1]);
1694 if (gamemode != GAME_GOODVSBAD2)
1696 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1698 Sbar_DrawNum (24, 0, 666, 3, 1);
1699 Sbar_DrawPic (0, 0, sb_disc);
1703 if (gamemode == GAME_ROGUE)
1705 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1706 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1707 Sbar_DrawPic (0, 0, sb_armor[2]);
1708 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1709 Sbar_DrawPic (0, 0, sb_armor[1]);
1710 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1711 Sbar_DrawPic (0, 0, sb_armor[0]);
1715 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1716 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1717 Sbar_DrawPic (0, 0, sb_armor[2]);
1718 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1719 Sbar_DrawPic (0, 0, sb_armor[1]);
1720 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1721 Sbar_DrawPic (0, 0, sb_armor[0]);
1730 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1733 if (gamemode == GAME_ROGUE)
1735 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1736 Sbar_DrawPic (224, 0, sb_ammo[0]);
1737 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1738 Sbar_DrawPic (224, 0, sb_ammo[1]);
1739 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1740 Sbar_DrawPic (224, 0, sb_ammo[2]);
1741 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1742 Sbar_DrawPic (224, 0, sb_ammo[3]);
1743 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1744 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1745 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1746 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1747 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1748 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1752 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1753 Sbar_DrawPic (224, 0, sb_ammo[0]);
1754 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1755 Sbar_DrawPic (224, 0, sb_ammo[1]);
1756 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1757 Sbar_DrawPic (224, 0, sb_ammo[2]);
1758 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1759 Sbar_DrawPic (224, 0, sb_ammo[3]);
1762 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1764 // LadyHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1765 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1767 if (gamemode == GAME_TRANSFUSION)
1768 Sbar_MiniDeathmatchOverlay (0, 0);
1770 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1777 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1779 pic = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/crosshair%i", crosshair.integer));
1780 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);
1783 if (cl_prydoncursor.integer > 0)
1784 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);
1787 //=============================================================================
1791 Sbar_DeathmatchOverlay
1795 static float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1798 qbool myself = false;
1801 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1803 if((s - cl.scores) == cl.playerentity - 1)
1805 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1806 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1809 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1811 if (s->qw_spectator)
1813 if (s->qw_ping || s->qw_packetloss)
1814 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 );
1816 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 );
1820 // draw colors behind score
1826 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1827 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);
1828 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1829 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);
1831 //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);
1832 if (s->qw_ping || s->qw_packetloss)
1833 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 );
1835 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 );
1840 if (s->qw_spectator)
1842 if (s->qw_ping || s->qw_packetloss)
1843 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 );
1845 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 );
1849 // draw colors behind score
1850 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1851 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);
1852 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1853 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);
1855 //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);
1856 if (s->qw_ping || s->qw_packetloss)
1857 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 );
1859 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 );
1865 void Sbar_DeathmatchOverlay (void)
1867 int i, y, xmin, xmax, ymin, ymax;
1870 // request new ping times every two second
1871 if (cl.last_ping_request < host.realtime - 2 && cls.netcon)
1873 cl.last_ping_request = host.realtime;
1874 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1876 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1877 MSG_WriteString(&cls.netcon->message, "pings");
1879 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*/)
1881 // 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
1882 static int ping_anyway_counter = 0;
1883 if(cl.parsingtextexpectingpingforscores == 1)
1885 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1886 if(++ping_anyway_counter >= 5)
1887 cl.parsingtextexpectingpingforscores = 0;
1889 if(cl.parsingtextexpectingpingforscores != 1)
1891 ping_anyway_counter = 0;
1892 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1893 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1894 MSG_WriteString(&cls.netcon->message, "ping");
1899 // 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
1900 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1901 MSG_WriteString(&cls.netcon->message, "pings");
1909 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1911 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1912 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)
1914 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)
1915 xmax = vid_conwidth.integer - xmin;
1917 if(IS_OLDNEXUIZ_DERIVED(gamemode))
1918 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);
1920 DrawQ_Pic ((vid_conwidth.integer - Draw_GetPicWidth(sb_ranking))/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1924 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1926 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 );
1930 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 );
1934 if (Sbar_IsTeammatch ())
1936 // show team scores first
1937 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1938 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1942 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1943 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1948 Sbar_MiniDeathmatchOverlay
1952 void Sbar_MiniDeathmatchOverlay (int x, int y)
1954 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1956 // do not draw this if sbar_miniscoreboard_size is zero
1957 if(sbar_miniscoreboard_size.value == 0)
1959 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1960 if(sbar_miniscoreboard_size.value > 0)
1961 y = (int) (vid_conheight.integer - sbar_miniscoreboard_size.value * 8);
1966 // decide where to print
1967 if (gamemode == GAME_TRANSFUSION)
1968 numlines = (vid_conwidth.integer - x + 127) / 128;
1970 numlines = (vid_conheight.integer - y + 7) / 8;
1972 // give up if there isn't room
1973 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1977 for (i = 0; i < scoreboardlines; i++)
1978 if (fragsort[i] == cl.playerentity - 1)
1982 range_end = scoreboardlines;
1985 if (gamemode != GAME_TRANSFUSION)
1986 if (Sbar_IsTeammatch ())
1988 // reserve space for the team scores
1989 numlines -= teamlines;
1991 // find first and last player of my team (only draw the team totals and my own team)
1992 range_begin = range_end = i;
1993 myteam = cl.scores[fragsort[i]].colors & 15;
1994 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1996 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1999 // looks better than two players
2009 i = min(i, range_end - numlines);
2010 i = max(i, range_begin);
2012 if (gamemode == GAME_TRANSFUSION)
2014 for (;i < range_end && x < vid_conwidth.integer;i++)
2015 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2019 if(range_end - i < numlines) // won't draw to bottom?
2020 y += 8 * (numlines - (range_end - i)); // bottom align
2021 // show team scores first
2022 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
2023 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
2025 for (;i < range_end && y < vid_conheight.integer;i++)
2026 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2030 static int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
2032 static int const sortorder[16] =
2051 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
2052 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
2053 int tc1 = sortorder[t1->colors & 15];
2054 int tc2 = sortorder[t2->colors & 15];
2058 void Sbar_Score (int margin)
2060 int i, me, score, otherleader, place, distribution, minutes, seconds;
2062 int sbar_x_save = sbar_x;
2063 int sbar_y_save = sbar_y;
2066 sbar_y = (int) (vid_conheight.value - (32+12));
2069 me = cl.playerentity - 1;
2070 if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients)
2072 if(Sbar_IsTeammatch())
2076 // team1 team3 team4
2080 scoreboard_t *teamcolorsort[16];
2083 for(i = 0; i < teamlines; ++i)
2084 teamcolorsort[i] = &(teams[i]);
2086 // Now sort them by color
2087 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
2090 // -12*4: four digits space
2091 place = (teamlines - 1) * (-12 * 4);
2093 for(i = 0; i < teamlines; ++i)
2095 int cindex = teamcolorsort[i]->colors & 15;
2096 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
2097 float cm = max(max(c[0], c[1]), c[2]);
2098 float cr = c[0] / cm;
2099 float cg = c[1] / cm;
2100 float cb = c[2] / cm;
2101 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
2103 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
2107 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
2120 // find leading score other than ourselves, to calculate distribution
2121 // find our place in the scoreboard
2122 score = cl.scores[me].frags;
2123 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
2125 if (cl.scores[i].name[0] && i != me)
2127 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
2129 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
2133 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
2135 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2136 else if (place == 2)
2137 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2139 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2140 if (otherleader < 0)
2141 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2142 if (distribution >= 0)
2144 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2145 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2147 else if (distribution >= -5)
2149 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2150 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2154 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2155 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2160 if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT])
2162 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2163 minutes = (int)floor(timeleft / 60);
2164 seconds = (int)(floor(timeleft) - minutes * 60);
2167 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2168 if (Draw_IsPicLoaded(sb_colon))
2169 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2170 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2172 else if (minutes >= 1)
2174 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2175 if (Draw_IsPicLoaded(sb_colon))
2176 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2177 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2179 else if ((int)(timeleft * 4) & 1)
2180 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2182 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2184 else if (sbar_gametime.integer)
2186 minutes = (int)floor(cl.time / 60);
2187 seconds = (int)(floor(cl.time) - minutes * 60);
2188 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2189 if (Draw_IsPicLoaded(sb_colon))
2190 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2191 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2194 sbar_x = sbar_x_save;
2195 sbar_y = sbar_y_save;
2200 Sbar_IntermissionOverlay
2204 void Sbar_IntermissionOverlay (void)
2209 if (cl.gametype == GAME_DEATHMATCH)
2211 Sbar_DeathmatchOverlay ();
2215 sbar_x = (vid_conwidth.integer - 320) >> 1;
2216 sbar_y = (vid_conheight.integer - 200) >> 1;
2218 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2219 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2222 dig = (int)cl.completed_time / 60;
2223 Sbar_DrawNum (160, 64, dig, 3, 0);
2224 num = (int)cl.completed_time - dig*60;
2225 Sbar_DrawPic (234,64,sb_colon);
2226 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2227 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2229 // LA: Display as "a" instead of "a/b" if b is 0
2230 if(cl.stats[STAT_TOTALSECRETS])
2232 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2233 if (!IS_OLDNEXUIZ_DERIVED(gamemode))
2234 Sbar_DrawPic (232, 104, sb_slash);
2235 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2239 Sbar_DrawNum (240, 104, cl.stats[STAT_SECRETS], 3, 0);
2242 if(cl.stats[STAT_TOTALMONSTERS])
2244 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2245 if (!IS_OLDNEXUIZ_DERIVED(gamemode))
2246 Sbar_DrawPic (232, 144, sb_slash);
2247 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2251 Sbar_DrawNum (240, 144, cl.stats[STAT_MONSTERS], 3, 0);
2262 void Sbar_FinaleOverlay (void)
2264 DrawQ_Pic((vid_conwidth.integer - Draw_GetPicWidth(sb_finale))/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);