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
27 #define STAT_MINUS 10 // num frame for '-' stats digit
28 cachepic_t *sb_nums[2][11];
29 cachepic_t *sb_colon, *sb_slash;
32 cachepic_t *sb_scorebar;
33 // AK only used by NEX
34 cachepic_t *sb_sbar_minimal;
35 cachepic_t *sb_sbar_overlay;
37 // AK changed the bound to 9
38 cachepic_t *sb_weapons[7][9]; // 0 is active, 1 is owned, 2-5 are flashes
39 cachepic_t *sb_ammo[4];
40 cachepic_t *sb_sigil[4];
41 cachepic_t *sb_armor[3];
42 cachepic_t *sb_items[32];
44 // 0-4 are based on health (in 20 increments)
45 // 0 is static, 1 is temporary animation
46 cachepic_t *sb_faces[5][2];
47 cachepic_t *sb_health; // GAME_NEXUIZ
49 cachepic_t *sb_face_invis;
50 cachepic_t *sb_face_quad;
51 cachepic_t *sb_face_invuln;
52 cachepic_t *sb_face_invis_invuln;
54 qboolean sb_showscores;
56 int sb_lines; // scan lines to draw
58 cachepic_t *rsb_invbar[2];
59 cachepic_t *rsb_weapons[5];
60 cachepic_t *rsb_items[2];
61 cachepic_t *rsb_ammo[3];
62 cachepic_t *rsb_teambord; // PGM 01/19/97 - team color border
64 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
65 cachepic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
66 //MED 01/04/97 added array to simplify weapon parsing
67 int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
68 //MED 01/04/97 added hipnotic items array
69 cachepic_t *hsb_items[2];
72 cachepic_t *somsb_health;
73 cachepic_t *somsb_ammo[4];
74 cachepic_t *somsb_armor[3];
76 cachepic_t *zymsb_crosshair_center;
77 cachepic_t *zymsb_crosshair_line;
78 cachepic_t *zymsb_crosshair_health;
79 cachepic_t *zymsb_crosshair_ammo;
80 cachepic_t *zymsb_crosshair_clip;
81 cachepic_t *zymsb_crosshair_background;
82 cachepic_t *zymsb_crosshair_left1;
83 cachepic_t *zymsb_crosshair_left2;
84 cachepic_t *zymsb_crosshair_right;
86 cachepic_t *sb_ranking;
87 cachepic_t *sb_complete;
89 cachepic_t *sb_finale;
91 cvar_t showfps = {CVAR_SAVE, "showfps", "0", "shows your rendered fps (frames per second)"};
92 cvar_t showsound = {CVAR_SAVE, "showsound", "0", "shows number of active sound sources, sound latency, and other statistics"};
93 cvar_t showblur = {CVAR_SAVE, "showblur", "0", "shows the current alpha level of motionblur"};
94 cvar_t showspeed = {CVAR_SAVE, "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"};
95 cvar_t showtopspeed = {CVAR_SAVE, "showtopspeed", "0", "shows your top speed (kept on screen for max 3 seconds); value -1 takes over the unit from showspeed, otherwise it's an unit number just like in showspeed"};
96 cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"};
97 cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"};
98 cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"};
99 cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"};
100 cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
101 cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
102 cvar_t sbar_hudselector = {CVAR_SAVE, "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 = {CVAR_SAVE, "sbar_scorerank", "1", "shows an overlay for your score (or team score) and rank in the scoreboard"};
104 cvar_t sbar_gametime = {CVAR_SAVE, "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 = {CVAR_SAVE, "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 = {CVAR_SAVE, "sbar_flagstatus_right", "0", "moves Nexuiz flag status icons to the right"};
107 cvar_t sbar_flagstatus_pos = {CVAR_SAVE, "sbar_flagstatus_pos", "115", "pixel position of the Nexuiz flag status icons, from the bottom"};
108 cvar_t sbar_info_pos = {CVAR_SAVE, "sbar_info_pos", "0", "pixel position of the info strings (such as showfps), from the bottom"};
110 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
112 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
113 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
114 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
115 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
116 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
118 void Sbar_MiniDeathmatchOverlay (int x, int y);
119 void Sbar_DeathmatchOverlay (void);
120 void Sbar_IntermissionOverlay (void);
121 void Sbar_FinaleOverlay (void);
123 void CL_VM_UpdateShowingScoresState (int showingscores);
133 void Sbar_ShowScores (void)
137 sb_showscores = true;
138 CL_VM_UpdateShowingScoresState(sb_showscores);
148 void Sbar_DontShowScores (void)
150 sb_showscores = false;
151 CL_VM_UpdateShowingScoresState(sb_showscores);
154 void sbar_start(void)
158 if (gamemode == GAME_DELUXEQUAKE || gamemode == GAME_BLOODOMNICIDE)
161 else if (gamemode == GAME_SOM)
163 sb_disc = Draw_CachePic_Flags ("gfx/disc", CACHEPICFLAG_QUIET);
165 for (i = 0;i < 10;i++)
166 sb_nums[0][i] = Draw_CachePic_Flags (va("gfx/num_%i",i), CACHEPICFLAG_QUIET);
168 somsb_health = Draw_CachePic_Flags ("gfx/hud_health", CACHEPICFLAG_QUIET);
169 somsb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
170 somsb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_nails", CACHEPICFLAG_QUIET);
171 somsb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
172 somsb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
173 somsb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor1", CACHEPICFLAG_QUIET);
174 somsb_armor[1] = Draw_CachePic_Flags ("gfx/sb_armor2", CACHEPICFLAG_QUIET);
175 somsb_armor[2] = Draw_CachePic_Flags ("gfx/sb_armor3", CACHEPICFLAG_QUIET);
177 else if (gamemode == GAME_NEXUIZ)
179 for (i = 0;i < 10;i++)
180 sb_nums[0][i] = Draw_CachePic_Flags (va("gfx/num_%i",i), CACHEPICFLAG_QUIET);
181 sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET);
182 sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET);
184 sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
185 sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_bullets", CACHEPICFLAG_QUIET);
186 sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
187 sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
189 sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor", CACHEPICFLAG_QUIET);
193 sb_health = Draw_CachePic_Flags ("gfx/sb_health", CACHEPICFLAG_QUIET);
195 sb_items[2] = Draw_CachePic_Flags ("gfx/sb_slowmo", CACHEPICFLAG_QUIET);
196 sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invinc", CACHEPICFLAG_QUIET);
197 sb_items[4] = Draw_CachePic_Flags ("gfx/sb_energy", CACHEPICFLAG_QUIET);
198 sb_items[5] = Draw_CachePic_Flags ("gfx/sb_str", CACHEPICFLAG_QUIET);
200 sb_items[11] = Draw_CachePic_Flags ("gfx/sb_flag_red_taken", CACHEPICFLAG_QUIET);
201 sb_items[12] = Draw_CachePic_Flags ("gfx/sb_flag_red_lost", CACHEPICFLAG_QUIET);
202 sb_items[13] = Draw_CachePic_Flags ("gfx/sb_flag_red_carrying", CACHEPICFLAG_QUIET);
203 sb_items[14] = Draw_CachePic_Flags ("gfx/sb_key_carrying", CACHEPICFLAG_QUIET);
204 sb_items[15] = Draw_CachePic_Flags ("gfx/sb_flag_blue_taken", CACHEPICFLAG_QUIET);
205 sb_items[16] = Draw_CachePic_Flags ("gfx/sb_flag_blue_lost", CACHEPICFLAG_QUIET);
206 sb_items[17] = Draw_CachePic_Flags ("gfx/sb_flag_blue_carrying", CACHEPICFLAG_QUIET);
208 sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET);
209 sb_sbar_minimal = Draw_CachePic_Flags ("gfx/sbar_minimal", CACHEPICFLAG_QUIET);
210 sb_sbar_overlay = Draw_CachePic_Flags ("gfx/sbar_overlay", CACHEPICFLAG_QUIET);
212 for(i = 0; i < 9;i++)
213 sb_weapons[0][i] = Draw_CachePic_Flags (va("gfx/inv_weapon%i",i), CACHEPICFLAG_QUIET);
215 else if (gamemode == GAME_ZYMOTIC)
217 zymsb_crosshair_center = Draw_CachePic_Flags ("gfx/hud/crosshair_center", CACHEPICFLAG_QUIET);
218 zymsb_crosshair_line = Draw_CachePic_Flags ("gfx/hud/crosshair_line", CACHEPICFLAG_QUIET);
219 zymsb_crosshair_health = Draw_CachePic_Flags ("gfx/hud/crosshair_health", CACHEPICFLAG_QUIET);
220 zymsb_crosshair_clip = Draw_CachePic_Flags ("gfx/hud/crosshair_clip", CACHEPICFLAG_QUIET);
221 zymsb_crosshair_ammo = Draw_CachePic_Flags ("gfx/hud/crosshair_ammo", CACHEPICFLAG_QUIET);
222 zymsb_crosshair_background = Draw_CachePic_Flags ("gfx/hud/crosshair_background", CACHEPICFLAG_QUIET);
223 zymsb_crosshair_left1 = Draw_CachePic_Flags ("gfx/hud/crosshair_left1", CACHEPICFLAG_QUIET);
224 zymsb_crosshair_left2 = Draw_CachePic_Flags ("gfx/hud/crosshair_left2", CACHEPICFLAG_QUIET);
225 zymsb_crosshair_right = Draw_CachePic_Flags ("gfx/hud/crosshair_right", CACHEPICFLAG_QUIET);
229 sb_disc = Draw_CachePic_Flags ("gfx/disc", CACHEPICFLAG_QUIET);
231 for (i = 0;i < 10;i++)
233 sb_nums[0][i] = Draw_CachePic_Flags (va("gfx/num_%i",i), CACHEPICFLAG_QUIET);
234 sb_nums[1][i] = Draw_CachePic_Flags (va("gfx/anum_%i",i), CACHEPICFLAG_QUIET);
237 sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET);
238 sb_nums[1][10] = Draw_CachePic_Flags ("gfx/anum_minus", CACHEPICFLAG_QUIET);
240 sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET);
241 sb_slash = Draw_CachePic_Flags ("gfx/num_slash", CACHEPICFLAG_QUIET);
243 sb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_shotgun", CACHEPICFLAG_QUIET);
244 sb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_sshotgun", CACHEPICFLAG_QUIET);
245 sb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_nailgun", CACHEPICFLAG_QUIET);
246 sb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_snailgun", CACHEPICFLAG_QUIET);
247 sb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_rlaunch", CACHEPICFLAG_QUIET);
248 sb_weapons[0][5] = Draw_CachePic_Flags ("gfx/inv_srlaunch", CACHEPICFLAG_QUIET);
249 sb_weapons[0][6] = Draw_CachePic_Flags ("gfx/inv_lightng", CACHEPICFLAG_QUIET);
251 sb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_shotgun", CACHEPICFLAG_QUIET);
252 sb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_sshotgun", CACHEPICFLAG_QUIET);
253 sb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_nailgun", CACHEPICFLAG_QUIET);
254 sb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_snailgun", CACHEPICFLAG_QUIET);
255 sb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_rlaunch", CACHEPICFLAG_QUIET);
256 sb_weapons[1][5] = Draw_CachePic_Flags ("gfx/inv2_srlaunch", CACHEPICFLAG_QUIET);
257 sb_weapons[1][6] = Draw_CachePic_Flags ("gfx/inv2_lightng", CACHEPICFLAG_QUIET);
259 for (i = 0;i < 5;i++)
261 sb_weapons[2+i][0] = Draw_CachePic_Flags (va("gfx/inva%i_shotgun",i+1), CACHEPICFLAG_QUIET);
262 sb_weapons[2+i][1] = Draw_CachePic_Flags (va("gfx/inva%i_sshotgun",i+1), CACHEPICFLAG_QUIET);
263 sb_weapons[2+i][2] = Draw_CachePic_Flags (va("gfx/inva%i_nailgun",i+1), CACHEPICFLAG_QUIET);
264 sb_weapons[2+i][3] = Draw_CachePic_Flags (va("gfx/inva%i_snailgun",i+1), CACHEPICFLAG_QUIET);
265 sb_weapons[2+i][4] = Draw_CachePic_Flags (va("gfx/inva%i_rlaunch",i+1), CACHEPICFLAG_QUIET);
266 sb_weapons[2+i][5] = Draw_CachePic_Flags (va("gfx/inva%i_srlaunch",i+1), CACHEPICFLAG_QUIET);
267 sb_weapons[2+i][6] = Draw_CachePic_Flags (va("gfx/inva%i_lightng",i+1), CACHEPICFLAG_QUIET);
270 sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
271 sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_nails", CACHEPICFLAG_QUIET);
272 sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
273 sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
275 sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor1", CACHEPICFLAG_QUIET);
276 sb_armor[1] = Draw_CachePic_Flags ("gfx/sb_armor2", CACHEPICFLAG_QUIET);
277 sb_armor[2] = Draw_CachePic_Flags ("gfx/sb_armor3", CACHEPICFLAG_QUIET);
279 sb_items[0] = Draw_CachePic_Flags ("gfx/sb_key1", CACHEPICFLAG_QUIET);
280 sb_items[1] = Draw_CachePic_Flags ("gfx/sb_key2", CACHEPICFLAG_QUIET);
281 sb_items[2] = Draw_CachePic_Flags ("gfx/sb_invis", CACHEPICFLAG_QUIET);
282 sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invuln", CACHEPICFLAG_QUIET);
283 sb_items[4] = Draw_CachePic_Flags ("gfx/sb_suit", CACHEPICFLAG_QUIET);
284 sb_items[5] = Draw_CachePic_Flags ("gfx/sb_quad", CACHEPICFLAG_QUIET);
286 sb_sigil[0] = Draw_CachePic_Flags ("gfx/sb_sigil1", CACHEPICFLAG_QUIET);
287 sb_sigil[1] = Draw_CachePic_Flags ("gfx/sb_sigil2", CACHEPICFLAG_QUIET);
288 sb_sigil[2] = Draw_CachePic_Flags ("gfx/sb_sigil3", CACHEPICFLAG_QUIET);
289 sb_sigil[3] = Draw_CachePic_Flags ("gfx/sb_sigil4", CACHEPICFLAG_QUIET);
291 sb_faces[4][0] = Draw_CachePic_Flags ("gfx/face1", CACHEPICFLAG_QUIET);
292 sb_faces[4][1] = Draw_CachePic_Flags ("gfx/face_p1", CACHEPICFLAG_QUIET);
293 sb_faces[3][0] = Draw_CachePic_Flags ("gfx/face2", CACHEPICFLAG_QUIET);
294 sb_faces[3][1] = Draw_CachePic_Flags ("gfx/face_p2", CACHEPICFLAG_QUIET);
295 sb_faces[2][0] = Draw_CachePic_Flags ("gfx/face3", CACHEPICFLAG_QUIET);
296 sb_faces[2][1] = Draw_CachePic_Flags ("gfx/face_p3", CACHEPICFLAG_QUIET);
297 sb_faces[1][0] = Draw_CachePic_Flags ("gfx/face4", CACHEPICFLAG_QUIET);
298 sb_faces[1][1] = Draw_CachePic_Flags ("gfx/face_p4", CACHEPICFLAG_QUIET);
299 sb_faces[0][0] = Draw_CachePic_Flags ("gfx/face5", CACHEPICFLAG_QUIET);
300 sb_faces[0][1] = Draw_CachePic_Flags ("gfx/face_p5", CACHEPICFLAG_QUIET);
302 sb_face_invis = Draw_CachePic_Flags ("gfx/face_invis", CACHEPICFLAG_QUIET);
303 sb_face_invuln = Draw_CachePic_Flags ("gfx/face_invul2", CACHEPICFLAG_QUIET);
304 sb_face_invis_invuln = Draw_CachePic_Flags ("gfx/face_inv2", CACHEPICFLAG_QUIET);
305 sb_face_quad = Draw_CachePic_Flags ("gfx/face_quad", CACHEPICFLAG_QUIET);
307 sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET);
308 sb_ibar = Draw_CachePic_Flags ("gfx/ibar", CACHEPICFLAG_QUIET);
309 sb_scorebar = Draw_CachePic_Flags ("gfx/scorebar", CACHEPICFLAG_QUIET);
311 //MED 01/04/97 added new hipnotic weapons
312 if (gamemode == GAME_HIPNOTIC)
314 hsb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_laser", CACHEPICFLAG_QUIET);
315 hsb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_mjolnir", CACHEPICFLAG_QUIET);
316 hsb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_gren_prox", CACHEPICFLAG_QUIET);
317 hsb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_prox_gren", CACHEPICFLAG_QUIET);
318 hsb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_prox", CACHEPICFLAG_QUIET);
320 hsb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_laser", CACHEPICFLAG_QUIET);
321 hsb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_mjolnir", CACHEPICFLAG_QUIET);
322 hsb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_gren_prox", CACHEPICFLAG_QUIET);
323 hsb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_prox_gren", CACHEPICFLAG_QUIET);
324 hsb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_prox", CACHEPICFLAG_QUIET);
326 for (i = 0;i < 5;i++)
328 hsb_weapons[2+i][0] = Draw_CachePic_Flags (va("gfx/inva%i_laser",i+1), CACHEPICFLAG_QUIET);
329 hsb_weapons[2+i][1] = Draw_CachePic_Flags (va("gfx/inva%i_mjolnir",i+1), CACHEPICFLAG_QUIET);
330 hsb_weapons[2+i][2] = Draw_CachePic_Flags (va("gfx/inva%i_gren_prox",i+1), CACHEPICFLAG_QUIET);
331 hsb_weapons[2+i][3] = Draw_CachePic_Flags (va("gfx/inva%i_prox_gren",i+1), CACHEPICFLAG_QUIET);
332 hsb_weapons[2+i][4] = Draw_CachePic_Flags (va("gfx/inva%i_prox",i+1), CACHEPICFLAG_QUIET);
335 hsb_items[0] = Draw_CachePic_Flags ("gfx/sb_wsuit", CACHEPICFLAG_QUIET);
336 hsb_items[1] = Draw_CachePic_Flags ("gfx/sb_eshld", CACHEPICFLAG_QUIET);
338 else if (gamemode == GAME_ROGUE)
340 rsb_invbar[0] = Draw_CachePic_Flags ("gfx/r_invbar1", CACHEPICFLAG_QUIET);
341 rsb_invbar[1] = Draw_CachePic_Flags ("gfx/r_invbar2", CACHEPICFLAG_QUIET);
343 rsb_weapons[0] = Draw_CachePic_Flags ("gfx/r_lava", CACHEPICFLAG_QUIET);
344 rsb_weapons[1] = Draw_CachePic_Flags ("gfx/r_superlava", CACHEPICFLAG_QUIET);
345 rsb_weapons[2] = Draw_CachePic_Flags ("gfx/r_gren", CACHEPICFLAG_QUIET);
346 rsb_weapons[3] = Draw_CachePic_Flags ("gfx/r_multirock", CACHEPICFLAG_QUIET);
347 rsb_weapons[4] = Draw_CachePic_Flags ("gfx/r_plasma", CACHEPICFLAG_QUIET);
349 rsb_items[0] = Draw_CachePic_Flags ("gfx/r_shield1", CACHEPICFLAG_QUIET);
350 rsb_items[1] = Draw_CachePic_Flags ("gfx/r_agrav1", CACHEPICFLAG_QUIET);
352 // PGM 01/19/97 - team color border
353 rsb_teambord = Draw_CachePic_Flags ("gfx/r_teambord", CACHEPICFLAG_QUIET);
354 // PGM 01/19/97 - team color border
356 rsb_ammo[0] = Draw_CachePic_Flags ("gfx/r_ammolava", CACHEPICFLAG_QUIET);
357 rsb_ammo[1] = Draw_CachePic_Flags ("gfx/r_ammomulti", CACHEPICFLAG_QUIET);
358 rsb_ammo[2] = Draw_CachePic_Flags ("gfx/r_ammoplasma", CACHEPICFLAG_QUIET);
362 sb_ranking = Draw_CachePic_Flags ("gfx/ranking", CACHEPICFLAG_QUIET);
363 sb_complete = Draw_CachePic_Flags ("gfx/complete", CACHEPICFLAG_QUIET);
364 sb_inter = Draw_CachePic_Flags ("gfx/inter", CACHEPICFLAG_QUIET);
365 sb_finale = Draw_CachePic_Flags ("gfx/finale", CACHEPICFLAG_QUIET);
368 void sbar_shutdown(void)
372 void sbar_newmap(void)
376 void Sbar_Init (void)
378 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
379 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
380 Cvar_RegisterVariable(&showfps);
381 Cvar_RegisterVariable(&showsound);
382 Cvar_RegisterVariable(&showblur);
383 Cvar_RegisterVariable(&showspeed);
384 Cvar_RegisterVariable(&showtopspeed);
385 Cvar_RegisterVariable(&showtime);
386 Cvar_RegisterVariable(&showtime_format);
387 Cvar_RegisterVariable(&showdate);
388 Cvar_RegisterVariable(&showdate_format);
389 Cvar_RegisterVariable(&sbar_alpha_bg);
390 Cvar_RegisterVariable(&sbar_alpha_fg);
391 Cvar_RegisterVariable(&sbar_hudselector);
392 Cvar_RegisterVariable(&sbar_scorerank);
393 Cvar_RegisterVariable(&sbar_gametime);
394 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
395 Cvar_RegisterVariable(&sbar_info_pos);
396 Cvar_RegisterVariable(&cl_deathscoreboard);
398 Cvar_RegisterVariable(&crosshair_color_red);
399 Cvar_RegisterVariable(&crosshair_color_green);
400 Cvar_RegisterVariable(&crosshair_color_blue);
401 Cvar_RegisterVariable(&crosshair_color_alpha);
402 Cvar_RegisterVariable(&crosshair_size);
404 Cvar_RegisterVariable(&sbar_flagstatus_right); // (GAME_NEXUZI ONLY)
405 Cvar_RegisterVariable(&sbar_flagstatus_pos); // (GAME_NEXUIZ ONLY)
407 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap, NULL, NULL);
411 //=============================================================================
413 // drawing routines are relative to the status bar location
422 void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
424 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
427 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
429 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
432 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
434 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
441 Draws one solid graphics character
444 void Sbar_DrawCharacter (int x, int y, int num)
446 DrawQ_String (sbar_x + x + 4 , sbar_y + y, va("%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, true, FONT_SBAR);
454 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 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 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 int Sbar_IsTeammatch(void)
533 // currently only nexuiz uses the team score board
534 return ((gamemode == GAME_NEXUIZ)
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 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 void Sbar_SoloScoreboard (void)
664 char str[80], timestr[40];
666 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("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("Monsters:%3i", cl.stats[STAT_MONSTERS]));
679 if (cl.stats[STAT_TOTALSECRETS])
680 Sbar_DrawString(8+22*8, 4, va("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("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 (gamemode != GAME_NEXUIZ) {
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 (gamemode == GAME_NEXUIZ) {
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 void Sbar_DrawScoreboard (void)
744 Sbar_SoloScoreboard ();
745 // LordHavoc: 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)
756 if (sbar_hudselector.integer == 1)
758 // width = 300, height = 100
759 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
761 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);
763 DrawQ_String((vid_conwidth.integer - w_width * 9) * 0.5 + w_width * nr + w_space, vid_conheight.integer - w_height + w_space, va("%i",nr+1), 0, font_size, font_size, 1, 1, 0, sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT);
767 // width = 300, height = 100
768 const int w_width = 300, w_height = 100, w_space = 10;
769 const float w_scale = 0.4;
771 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);
772 //DrawQ_String(vid_conwidth.integer - (w_space + font_size ), (w_height + w_space) * w_scale * nr + w_space, va("%i",nr+1), 0, font_size, font_size, 1, 0, 0, fade, 0, NULL, true, FONT_DEFAULT);
781 void Sbar_DrawInventory (void)
788 if (gamemode == GAME_ROGUE)
790 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
791 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
793 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
796 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
799 for (i=0 ; i<7 ; i++)
801 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
803 time = cl.item_gettime[i];
804 flashon = (int)(max(0, cl.time - time)*10);
807 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
813 flashon = (flashon%5) + 2;
815 Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
821 if (gamemode == GAME_HIPNOTIC)
823 int grenadeflashing=0;
824 for (i=0 ; i<4 ; i++)
826 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
828 time = max(0, cl.item_gettime[hipweapons[i]]);
829 flashon = (int)((cl.time - time)*10);
832 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
838 flashon = (flashon%5) + 2;
840 // check grenade launcher
843 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
848 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
854 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
856 if (!grenadeflashing)
857 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
860 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
863 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
868 if (gamemode == GAME_ROGUE)
870 // check for powered up weapon.
871 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
873 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
874 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
878 for (i=0 ; i<4 ; i++)
880 dpsnprintf (num, sizeof(num), "%4i",cl.stats[STAT_SHELLS+i] );
882 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
884 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
886 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
888 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
892 for (i=0 ; i<6 ; i++)
893 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
895 //MED 01/04/97 changed keys
896 if (gamemode != GAME_HIPNOTIC || (i>1))
897 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
900 //MED 01/04/97 added hipnotic items
902 if (gamemode == GAME_HIPNOTIC)
904 for (i=0 ; i<2 ; i++)
905 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
906 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
909 if (gamemode == GAME_ROGUE)
912 for (i=0 ; i<2 ; i++)
913 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
914 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
919 for (i=0 ; i<4 ; i++)
920 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
921 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
925 //=============================================================================
932 void Sbar_DrawFrags (void)
942 l = min(scoreboardlines, 4);
946 for (i = 0;i < l;i++)
952 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
953 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);
954 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
955 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);
959 dpsnprintf (num, sizeof(num), "%3i",f);
961 if (k == cl.viewentity - 1)
963 Sbar_DrawCharacter ( x + 2, -24, 16);
964 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
966 Sbar_DrawCharacter (x + 8, -24, num[0]);
967 Sbar_DrawCharacter (x + 16, -24, num[1]);
968 Sbar_DrawCharacter (x + 24, -24, num[2]);
973 //=============================================================================
981 void Sbar_DrawFace (void)
985 // PGM 01/19/97 - team color drawing
986 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
987 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
993 s = &cl.scores[cl.viewentity - 1];
995 Sbar_DrawPic (112, 0, rsb_teambord);
996 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
997 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);
998 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
999 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);
1003 dpsnprintf (num, sizeof(num), "%3i",f);
1005 if ((s->colors & 0xf0)==0)
1008 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1010 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1012 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1016 Sbar_DrawCharacter ( 109, 3, num[0]);
1017 Sbar_DrawCharacter ( 116, 3, num[1]);
1018 Sbar_DrawCharacter ( 123, 3, num[2]);
1023 // PGM 01/19/97 - team color drawing
1025 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1026 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1027 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1028 Sbar_DrawPic (112, 0, sb_face_quad );
1029 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1030 Sbar_DrawPic (112, 0, sb_face_invis );
1031 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1032 Sbar_DrawPic (112, 0, sb_face_invuln);
1035 f = cl.stats[STAT_HEALTH] / 20;
1037 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1040 double topspeed = 0;
1041 double topspeedxy = 0;
1042 time_t current_time = 3;
1043 time_t top_time = 0;
1044 time_t topxy_time = 0;
1046 static void get_showspeed_unit(int unitnumber, double *conversion_factor, const char **unit)
1049 unitnumber = showspeed.integer;
1054 if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC)
1058 *conversion_factor = 1.0;
1062 *conversion_factor = 0.0254;
1063 if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1064 // 1qu=1.5in is for non-Nexuiz/Xonotic only - Nexuiz/Xonotic players are overly large, but 1qu=1in fixes that
1068 *conversion_factor = 0.0254 * 3.6;
1069 if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1073 *conversion_factor = 0.0254 * 3.6 * 0.6213711922;
1074 if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1078 *conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
1079 if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1084 static double showfps_nexttime = 0, showfps_lasttime = -1;
1085 static double showfps_framerate = 0;
1086 static int showfps_framecount = 0;
1088 void Sbar_ShowFPS_Update(void)
1090 double interval = 1;
1093 if (newtime >= showfps_nexttime)
1095 showfps_framerate = showfps_framecount / (newtime - showfps_lasttime);
1096 if (showfps_nexttime < newtime - interval * 1.5)
1097 showfps_nexttime = newtime;
1098 showfps_lasttime = newtime;
1099 showfps_nexttime += interval;
1100 showfps_framecount = 0;
1102 showfps_framecount++;
1105 void Sbar_ShowFPS(void)
1107 float fps_x, fps_y, fps_scalex, fps_scaley, fps_strings = 0;
1108 char soundstring[32];
1110 char timestring[32];
1111 char datestring[32];
1112 char timedemostring1[32];
1113 char timedemostring2[32];
1114 char speedstring[32];
1115 char blurstring[32];
1116 char topspeedstring[48];
1117 qboolean red = false;
1120 timedemostring1[0] = 0;
1121 timedemostring2[0] = 0;
1126 topspeedstring[0] = 0;
1127 if (showfps.integer)
1129 red = (showfps_framerate < 1.0f);
1130 if(showfps.integer == 2)
1131 dpsnprintf(fpsstring, sizeof(fpsstring), "%7.3f mspf", (1000.0 / showfps_framerate));
1133 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0 / showfps_framerate + 0.5));
1135 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(showfps_framerate + 0.5));
1139 dpsnprintf(timedemostring1, sizeof(timedemostring1), "frame%4i %f", cls.td_frames, realtime - cls.td_starttime);
1140 dpsnprintf(timedemostring2, sizeof(timedemostring2), "%i seconds %3.0f/%3.0f/%3.0f fps", cls.td_onesecondavgcount, cls.td_onesecondminfps, cls.td_onesecondavgfps / max(1, cls.td_onesecondavgcount), cls.td_onesecondmaxfps);
1145 if (showtime.integer)
1147 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1150 if (showdate.integer)
1152 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1155 if (showblur.integer)
1157 dpsnprintf(blurstring, sizeof(blurstring), "%3i%% blur", (int)(cl.motionbluralpha * 100));
1160 if (showsound.integer)
1162 dpsnprintf(soundstring, sizeof(soundstring), "%4i/4%i at %3ims", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds);
1165 if (showspeed.integer || showtopspeed.integer)
1167 double speed, speedxy, f;
1169 speed = VectorLength(cl.movement_velocity);
1170 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1171 if (showspeed.integer)
1173 get_showspeed_unit(showspeed.integer, &f, &unit);
1174 dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1177 if (showtopspeed.integer)
1179 qboolean topspeed_latched = false, topspeedxy_latched = false;
1180 get_showspeed_unit(showtopspeed.integer, &f, &unit);
1181 if (speed >= topspeed || current_time - top_time > 3)
1187 topspeed_latched = true;
1188 if (speedxy >= topspeedxy || current_time - topxy_time > 3)
1190 topspeedxy = speedxy;
1194 topspeedxy_latched = true;
1195 dpsnprintf(topspeedstring, sizeof(topspeedstring), "%s%.0f%s (%s%.0f%s) %s",
1196 topspeed_latched ? "^1" : "^xf88", f*topspeed, "^xf88",
1197 topspeedxy_latched ? "^1" : "^xf88", f*topspeedxy, "^xf88",
1199 time(¤t_time);
1207 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1208 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_strings*fps_scaley);
1209 fps_y = vid_conheight.integer - sbar_info_pos.integer - fps_strings*fps_scaley;
1212 fps_x = vid_conwidth.integer - DrawQ_TextWidth(soundstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1213 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1214 DrawQ_String(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1215 fps_y += fps_scaley;
1219 r_draw2d_force = true;
1220 fps_x = vid_conwidth.integer - DrawQ_TextWidth(fpsstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1221 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1223 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1225 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1226 fps_y += fps_scaley;
1227 r_draw2d_force = false;
1229 if (timedemostring1[0])
1231 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring1, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1232 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1233 DrawQ_String(fps_x, fps_y, timedemostring1, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1234 fps_y += fps_scaley;
1236 if (timedemostring2[0])
1238 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring2, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1239 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1240 DrawQ_String(fps_x, fps_y, timedemostring2, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1241 fps_y += fps_scaley;
1245 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1246 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1247 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1248 fps_y += fps_scaley;
1252 fps_x = vid_conwidth.integer - DrawQ_TextWidth(datestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1253 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1254 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1255 fps_y += fps_scaley;
1259 fps_x = vid_conwidth.integer - DrawQ_TextWidth(speedstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1260 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1261 DrawQ_String(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1262 fps_y += fps_scaley;
1264 if (topspeedstring[0])
1266 fps_x = vid_conwidth.integer - DrawQ_TextWidth(topspeedstring, 0, fps_scalex, fps_scaley, false, FONT_INFOBAR);
1267 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1268 DrawQ_String(fps_x, fps_y, topspeedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR);
1269 fps_y += fps_scaley;
1273 fps_x = vid_conwidth.integer - DrawQ_TextWidth(blurstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1274 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1275 DrawQ_String(fps_x, fps_y, blurstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1276 fps_y += fps_scaley;
1281 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)
1284 c2 = bound(0, c2, 1);
1285 c1 = bound(0, c1, 1 - c2);
1287 r[1] = rangey + rangeheight * (c2 + c1);
1288 r[2] = rangey + rangeheight * (c2);
1292 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);
1294 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);
1296 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);
1298 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);
1306 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1307 extern cvar_t v_kicktime;
1308 void Sbar_Score (int margin);
1309 void Sbar_Draw (void)
1313 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1316 Sbar_DrawScoreboard ();
1317 else if (cl.intermission == 1)
1319 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1321 Sbar_DrawScoreboard();
1324 Sbar_IntermissionOverlay();
1326 else if (cl.intermission == 2)
1327 Sbar_FinaleOverlay();
1328 else if (gamemode == GAME_DELUXEQUAKE)
1331 else if (gamemode == GAME_SOM)
1333 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1334 Sbar_DrawScoreboard ();
1337 // this is the top left of the sbar area
1339 sbar_y = vid_conheight.integer - 24*3;
1342 if (cl.stats[STAT_ARMOR])
1344 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1345 Sbar_DrawPic(0, 0, somsb_armor[2]);
1346 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1347 Sbar_DrawPic(0, 0, somsb_armor[1]);
1348 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1349 Sbar_DrawPic(0, 0, somsb_armor[0]);
1350 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1354 Sbar_DrawPic(0, 24, somsb_health);
1355 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1358 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1359 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1360 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1361 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1362 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1363 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1364 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1365 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1366 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1367 if (cl.stats[STAT_SHELLS])
1368 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1371 else if (gamemode == GAME_NEXUIZ)
1373 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1375 sbar_x = (vid_conwidth.integer - 640)/2;
1376 sbar_y = vid_conheight.integer - 47;
1377 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1378 Sbar_DrawScoreboard ();
1380 else if (sb_lines && sbar_hudselector.integer == 1)
1384 int redflag, blueflag;
1387 sbar_x = (vid_conwidth.integer - 320)/2;
1388 sbar_y = vid_conheight.integer - 24 - 16;
1390 // calculate intensity to draw weapons bar at
1391 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1392 fade = bound(0.7, fade, 1);
1393 for (i = 0; i < 8;i++)
1394 if (cl.stats[STAT_ITEMS] & (1 << i))
1395 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1396 if((cl.stats[STAT_ITEMS] & (1<<12)))
1397 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1400 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1401 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1402 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1403 if (redflag == 3 && blueflag == 3)
1405 // The Impossible Combination[tm]
1406 // Can only happen in Key Hunt mode...
1407 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[14]);
1412 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64)), sb_items[redflag+10]);
1414 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[blueflag+14]);
1418 if (cl.stats[STAT_ARMOR] > 0)
1420 Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1421 if(cl.stats[STAT_ARMOR] > 200)
1422 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1423 else if(cl.stats[STAT_ARMOR] > 100)
1424 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1425 else if(cl.stats[STAT_ARMOR] > 50)
1426 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1427 else if(cl.stats[STAT_ARMOR] > 25)
1428 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1430 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1434 if (cl.stats[STAT_HEALTH] != 0)
1436 Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1437 if(cl.stats[STAT_HEALTH] > 200)
1438 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1439 else if(cl.stats[STAT_HEALTH] > 100)
1440 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1441 else if(cl.stats[STAT_HEALTH] > 50)
1442 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1443 else if(cl.stats[STAT_HEALTH] > 25)
1444 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1446 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1450 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1452 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1453 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1454 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1455 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1456 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1457 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1458 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1459 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1460 if(cl.stats[STAT_AMMO] > 10)
1461 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1463 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1466 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1467 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1470 // The margin can be at most 8 to support 640x480 console size:
1471 // 320 + 2 * (144 + 16) = 640
1477 int redflag, blueflag;
1480 sbar_x = (vid_conwidth.integer - 640)/2;
1481 sbar_y = vid_conheight.integer - 47;
1483 // calculate intensity to draw weapons bar at
1484 fade = 3 - 2 * (cl.time - cl.weapontime);
1487 fade = min(fade, 1);
1488 for (i = 0; i < 8;i++)
1489 if (cl.stats[STAT_ITEMS] & (1 << i))
1490 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1492 if((cl.stats[STAT_ITEMS] & (1<<12)))
1493 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1496 //if (!cl.islocalgame)
1497 // Sbar_DrawFrags ();
1500 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1502 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1505 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1506 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1507 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1508 if (redflag == 3 && blueflag == 3)
1510 // The Impossible Combination[tm]
1511 // Can only happen in Key Hunt mode...
1512 Sbar_DrawPic ((int) x, -179, sb_items[14]);
1517 Sbar_DrawPic ((int) x, -117, sb_items[redflag+10]);
1519 Sbar_DrawPic ((int) x, -177, sb_items[blueflag+14]);
1523 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1526 if(cl.stats[STAT_HEALTH] > 100)
1527 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1528 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1529 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1531 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1533 // AK dont draw ammo for the laser
1534 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1536 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1537 Sbar_DrawPic (519, 0, sb_ammo[0]);
1538 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1539 Sbar_DrawPic (519, 0, sb_ammo[1]);
1540 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1541 Sbar_DrawPic (519, 0, sb_ammo[2]);
1542 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1543 Sbar_DrawPic (519, 0, sb_ammo[3]);
1545 if(cl.stats[STAT_AMMO] <= 10)
1546 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1548 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1553 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1555 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1556 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1561 // Mini scoreboard uses 12*4 per other team, that is, 144
1562 // pixels when there are four teams...
1563 // Nexuiz by default sets vid_conwidth to 800... makes
1565 // so we need to shift it by 64 pixels to the right to fit
1566 // BUT: then it overlaps with the image that gets drawn
1567 // for viewsize 100! Therefore, just account for 3 teams,
1568 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1572 else if (gamemode == GAME_ZYMOTIC)
1575 float scale = 64.0f / 256.0f;
1576 float kickoffset[3];
1577 VectorClear(kickoffset);
1580 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1581 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1583 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1584 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1585 // left1 16, 48 : 126 -66
1586 // left2 16, 128 : 196 -66
1587 // right 176, 48 : 196 -136
1588 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);
1589 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);
1590 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);
1591 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1593 float scale = 128.0f / 256.0f;
1594 float healthstart, healthheight, healthstarttc, healthendtc;
1595 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1596 float ammostart, ammoheight, ammostarttc, ammoendtc;
1597 float clipstart, clipheight, clipstarttc, clipendtc;
1598 float kickoffset[3], offset;
1599 VectorClear(kickoffset);
1602 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1603 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1605 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1606 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1607 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1608 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);
1609 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);
1610 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);
1611 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);
1612 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1613 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1614 healthstart = 204 - healthheight;
1615 shieldstart = healthstart - shieldheight;
1616 healthstarttc = healthstart * (1.0f / 256.0f);
1617 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1618 shieldstarttc = shieldstart * (1.0f / 256.0f);
1619 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1620 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1621 ammostart = 114 - ammoheight;
1622 ammostarttc = ammostart * (1.0f / 256.0f);
1623 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1624 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1625 clipstart = 190 - clipheight;
1626 clipstarttc = clipstart * (1.0f / 256.0f);
1627 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1628 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);
1629 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);
1630 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);
1631 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);
1632 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1633 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1636 else // Quake and others
1638 sbar_x = (vid_conwidth.integer - 320)/2;
1639 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1640 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1641 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1645 if (gamemode != GAME_GOODVSBAD2)
1646 Sbar_DrawInventory ();
1647 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1651 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1653 if (gamemode != GAME_GOODVSBAD2)
1654 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1655 Sbar_DrawScoreboard ();
1659 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1661 // keys (hipnotic only)
1662 //MED 01/04/97 moved keys here so they would not be overwritten
1663 if (gamemode == GAME_HIPNOTIC)
1665 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1666 Sbar_DrawPic (209, 3, sb_items[0]);
1667 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1668 Sbar_DrawPic (209, 12, sb_items[1]);
1671 if (gamemode != GAME_GOODVSBAD2)
1673 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1675 Sbar_DrawNum (24, 0, 666, 3, 1);
1676 Sbar_DrawPic (0, 0, sb_disc);
1680 if (gamemode == GAME_ROGUE)
1682 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1683 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1684 Sbar_DrawPic (0, 0, sb_armor[2]);
1685 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1686 Sbar_DrawPic (0, 0, sb_armor[1]);
1687 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1688 Sbar_DrawPic (0, 0, sb_armor[0]);
1692 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1693 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1694 Sbar_DrawPic (0, 0, sb_armor[2]);
1695 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1696 Sbar_DrawPic (0, 0, sb_armor[1]);
1697 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1698 Sbar_DrawPic (0, 0, sb_armor[0]);
1707 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1710 if (gamemode == GAME_ROGUE)
1712 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1713 Sbar_DrawPic (224, 0, sb_ammo[0]);
1714 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1715 Sbar_DrawPic (224, 0, sb_ammo[1]);
1716 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1717 Sbar_DrawPic (224, 0, sb_ammo[2]);
1718 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1719 Sbar_DrawPic (224, 0, sb_ammo[3]);
1720 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1721 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1722 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1723 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1724 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1725 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1729 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1730 Sbar_DrawPic (224, 0, sb_ammo[0]);
1731 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1732 Sbar_DrawPic (224, 0, sb_ammo[1]);
1733 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1734 Sbar_DrawPic (224, 0, sb_ammo[2]);
1735 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1736 Sbar_DrawPic (224, 0, sb_ammo[3]);
1739 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1741 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1742 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1744 if (gamemode == GAME_TRANSFUSION)
1745 Sbar_MiniDeathmatchOverlay (0, 0);
1747 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1754 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1756 pic = Draw_CachePic (va("gfx/crosshair%i", crosshair.integer));
1757 DrawQ_Pic((vid_conwidth.integer - pic->width * crosshair_size.value) * 0.5f, (vid_conheight.integer - pic->height * crosshair_size.value) * 0.5f, pic, pic->width * crosshair_size.value, pic->height * crosshair_size.value, crosshair_color_red.value, crosshair_color_green.value, crosshair_color_blue.value, crosshair_color_alpha.value, 0);
1760 if (cl_prydoncursor.integer > 0)
1761 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("gfx/prydoncursor%03i", cl_prydoncursor.integer)), 0, 0, 1, 1, 1, 1, 0);
1764 //=============================================================================
1768 Sbar_DeathmatchOverlay
1772 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1775 qboolean myself = false;
1777 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1779 if((s - cl.scores) == cl.playerentity - 1)
1781 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1782 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1785 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1787 if (s->qw_spectator)
1789 if (s->qw_ping || s->qw_packetloss)
1790 DrawQ_String(x, y, va("%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 );
1792 DrawQ_String(x, y, va(" %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 );
1796 // draw colors behind score
1802 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1803 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);
1804 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1805 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);
1807 //DrawQ_String(x, y, va("%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);
1808 if (s->qw_ping || s->qw_packetloss)
1809 DrawQ_String(x, y, va("%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 );
1811 DrawQ_String(x, y, va(" %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 );
1816 if (s->qw_spectator)
1818 if (s->qw_ping || s->qw_packetloss)
1819 DrawQ_String(x, y, va("%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 );
1821 DrawQ_String(x, y, va(" spect %c%s", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1825 // draw colors behind score
1826 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1827 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);
1828 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1829 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);
1831 //DrawQ_String(x, y, va("%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("%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 );
1835 DrawQ_String(x, y, va(" %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 );
1841 void Sbar_DeathmatchOverlay (void)
1843 int i, y, xmin, xmax, ymin, ymax;
1845 // request new ping times every two second
1846 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1848 cl.last_ping_request = realtime;
1849 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1851 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1852 MSG_WriteString(&cls.netcon->message, "pings");
1854 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*/)
1856 // 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
1857 static int ping_anyway_counter = 0;
1858 if(cl.parsingtextexpectingpingforscores == 1)
1860 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1861 if(++ping_anyway_counter >= 5)
1862 cl.parsingtextexpectingpingforscores = 0;
1864 if(cl.parsingtextexpectingpingforscores != 1)
1866 ping_anyway_counter = 0;
1867 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1868 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1869 MSG_WriteString(&cls.netcon->message, "ping");
1874 // 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
1875 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1876 MSG_WriteString(&cls.netcon->message, "pings");
1884 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1886 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1887 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)
1889 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)
1890 xmax = vid_conwidth.integer - xmin;
1892 if(gamemode == GAME_NEXUIZ)
1893 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);
1895 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1899 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1901 DrawQ_String(xmin, y, va("ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1905 DrawQ_String(xmin, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1909 if (Sbar_IsTeammatch ())
1911 // show team scores first
1912 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1913 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1917 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1918 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1923 Sbar_MiniDeathmatchOverlay
1927 void Sbar_MiniDeathmatchOverlay (int x, int y)
1929 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1931 // do not draw this if sbar_miniscoreboard_size is zero
1932 if(sbar_miniscoreboard_size.value == 0)
1934 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1935 if(sbar_miniscoreboard_size.value > 0)
1936 y = (int) (vid_conheight.integer - sbar_miniscoreboard_size.value * 8);
1941 // decide where to print
1942 if (gamemode == GAME_TRANSFUSION)
1943 numlines = (vid_conwidth.integer - x + 127) / 128;
1945 numlines = (vid_conheight.integer - y + 7) / 8;
1947 // give up if there isn't room
1948 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1952 for (i = 0; i < scoreboardlines; i++)
1953 if (fragsort[i] == cl.playerentity - 1)
1957 range_end = scoreboardlines;
1960 if (gamemode != GAME_TRANSFUSION)
1961 if (Sbar_IsTeammatch ())
1963 // reserve space for the team scores
1964 numlines -= teamlines;
1966 // find first and last player of my team (only draw the team totals and my own team)
1967 range_begin = range_end = i;
1968 myteam = cl.scores[fragsort[i]].colors & 15;
1969 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1971 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1974 // looks better than two players
1984 i = min(i, range_end - numlines);
1985 i = max(i, range_begin);
1987 if (gamemode == GAME_TRANSFUSION)
1989 for (;i < range_end && x < vid_conwidth.integer;i++)
1990 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1994 if(range_end - i < numlines) // won't draw to bottom?
1995 y += 8 * (numlines - (range_end - i)); // bottom align
1996 // show team scores first
1997 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1998 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
2000 for (;i < range_end && y < vid_conheight.integer;i++)
2001 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2005 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
2007 static int const sortorder[16] =
2026 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
2027 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
2028 int tc1 = sortorder[t1->colors & 15];
2029 int tc2 = sortorder[t2->colors & 15];
2033 void Sbar_Score (int margin)
2035 int i, me, score, otherleader, place, distribution, minutes, seconds;
2037 int sbar_x_save = sbar_x;
2038 int sbar_y_save = sbar_y;
2041 sbar_y = (int) (vid_conheight.value - (32+12));
2044 me = cl.playerentity - 1;
2045 if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients)
2047 if(Sbar_IsTeammatch())
2051 // team1 team3 team4
2055 scoreboard_t *teamcolorsort[16];
2058 for(i = 0; i < teamlines; ++i)
2059 teamcolorsort[i] = &(teams[i]);
2061 // Now sort them by color
2062 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
2065 // -12*4: four digits space
2066 place = (teamlines - 1) * (-12 * 4);
2068 for(i = 0; i < teamlines; ++i)
2070 int cindex = teamcolorsort[i]->colors & 15;
2071 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
2072 float cm = max(max(c[0], c[1]), c[2]);
2073 float cr = c[0] / cm;
2074 float cg = c[1] / cm;
2075 float cb = c[2] / cm;
2076 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
2078 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
2082 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
2095 // find leading score other than ourselves, to calculate distribution
2096 // find our place in the scoreboard
2097 score = cl.scores[me].frags;
2098 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
2100 if (cl.scores[i].name[0] && i != me)
2102 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
2104 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
2108 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
2110 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2111 else if (place == 2)
2112 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2114 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2115 if (otherleader < 0)
2116 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2117 if (distribution >= 0)
2119 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2120 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2122 else if (distribution >= -5)
2124 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2125 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2129 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2130 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2135 if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT])
2137 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2138 minutes = (int)floor(timeleft / 60);
2139 seconds = (int)(floor(timeleft) - minutes * 60);
2142 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2143 if(sb_colon && sb_colon->tex != r_texture_notexture)
2144 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2145 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2147 else if (minutes >= 1)
2149 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2150 if(sb_colon && sb_colon->tex != r_texture_notexture)
2151 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2152 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2154 else if ((int)(timeleft * 4) & 1)
2155 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2157 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2159 else if (sbar_gametime.integer)
2161 minutes = (int)floor(cl.time / 60);
2162 seconds = (int)(floor(cl.time) - minutes * 60);
2163 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2164 if(sb_colon && sb_colon->tex != r_texture_notexture)
2165 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2166 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2169 sbar_x = sbar_x_save;
2170 sbar_y = sbar_y_save;
2175 Sbar_IntermissionOverlay
2179 void Sbar_IntermissionOverlay (void)
2184 if (cl.gametype == GAME_DEATHMATCH)
2186 Sbar_DeathmatchOverlay ();
2190 sbar_x = (vid_conwidth.integer - 320) >> 1;
2191 sbar_y = (vid_conheight.integer - 200) >> 1;
2193 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2194 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2197 dig = (int)cl.completed_time / 60;
2198 Sbar_DrawNum (160, 64, dig, 3, 0);
2199 num = (int)cl.completed_time - dig*60;
2200 Sbar_DrawPic (234,64,sb_colon);
2201 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2202 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2204 // LA: Display as "a" instead of "a/b" if b is 0
2205 if(cl.stats[STAT_TOTALSECRETS])
2207 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2208 if (gamemode != GAME_NEXUIZ)
2209 Sbar_DrawPic (232, 104, sb_slash);
2210 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2214 Sbar_DrawNum (240, 104, cl.stats[STAT_SECRETS], 3, 0);
2217 if(cl.stats[STAT_TOTALMONSTERS])
2219 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2220 if (gamemode != GAME_NEXUIZ)
2221 Sbar_DrawPic (232, 144, sb_slash);
2222 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2226 Sbar_DrawNum (240, 144, cl.stats[STAT_MONSTERS], 3, 0);
2237 void Sbar_FinaleOverlay (void)
2239 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);