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"
28 #define STAT_MINUS 10 // num frame for '-' stats digit
29 cachepic_t *sb_nums[2][11];
30 cachepic_t *sb_colon, *sb_slash;
33 cachepic_t *sb_scorebar;
34 // AK only used by NEX
35 cachepic_t *sb_sbar_minimal;
36 cachepic_t *sb_sbar_overlay;
38 // AK changed the bound to 9
39 cachepic_t *sb_weapons[7][9]; // 0 is active, 1 is owned, 2-5 are flashes
40 cachepic_t *sb_ammo[4];
41 cachepic_t *sb_sigil[4];
42 cachepic_t *sb_armor[3];
43 cachepic_t *sb_items[32];
45 // 0-4 are based on health (in 20 increments)
46 // 0 is static, 1 is temporary animation
47 cachepic_t *sb_faces[5][2];
48 cachepic_t *sb_health; // GAME_NEXUIZ
50 cachepic_t *sb_face_invis;
51 cachepic_t *sb_face_quad;
52 cachepic_t *sb_face_invuln;
53 cachepic_t *sb_face_invis_invuln;
55 qboolean sb_showscores;
57 int sb_lines; // scan lines to draw
59 cachepic_t *rsb_invbar[2];
60 cachepic_t *rsb_weapons[5];
61 cachepic_t *rsb_items[2];
62 cachepic_t *rsb_ammo[3];
63 cachepic_t *rsb_teambord; // PGM 01/19/97 - team color border
65 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
66 cachepic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
67 //MED 01/04/97 added array to simplify weapon parsing
68 int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
69 //MED 01/04/97 added hipnotic items array
70 cachepic_t *hsb_items[2];
73 cachepic_t *somsb_health;
74 cachepic_t *somsb_ammo[4];
75 cachepic_t *somsb_armor[3];
77 cachepic_t *zymsb_crosshair_center;
78 cachepic_t *zymsb_crosshair_line;
79 cachepic_t *zymsb_crosshair_health;
80 cachepic_t *zymsb_crosshair_ammo;
81 cachepic_t *zymsb_crosshair_clip;
82 cachepic_t *zymsb_crosshair_background;
83 cachepic_t *zymsb_crosshair_left1;
84 cachepic_t *zymsb_crosshair_left2;
85 cachepic_t *zymsb_crosshair_right;
87 cachepic_t *sb_ranking;
88 cachepic_t *sb_complete;
90 cachepic_t *sb_finale;
92 cvar_t showfps = {CVAR_SAVE, "showfps", "0", "shows your rendered fps (frames per second)"};
93 cvar_t showsound = {CVAR_SAVE, "showsound", "0", "shows number of active sound sources, sound latency, and other statistics"};
94 cvar_t showblur = {CVAR_SAVE, "showblur", "0", "shows the current alpha level of motionblur"};
95 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"};
96 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"};
97 cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"};
98 cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"};
99 cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"};
100 cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"};
101 cvar_t showtex = {0, "showtex", "0", "shows the name of the texture on the crosshair (for map debugging)"};
102 cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
103 cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
104 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)"};
105 cvar_t sbar_scorerank = {CVAR_SAVE, "sbar_scorerank", "1", "shows an overlay for your score (or team score) and rank in the scoreboard"};
106 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)"};
107 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"};
108 cvar_t sbar_flagstatus_right = {CVAR_SAVE, "sbar_flagstatus_right", "0", "moves Nexuiz flag status icons to the right"};
109 cvar_t sbar_flagstatus_pos = {CVAR_SAVE, "sbar_flagstatus_pos", "115", "pixel position of the Nexuiz flag status icons, from the bottom"};
110 cvar_t sbar_info_pos = {CVAR_SAVE, "sbar_info_pos", "0", "pixel position of the info strings (such as showfps), from the bottom"};
112 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
114 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
115 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
116 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
117 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
118 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
120 void Sbar_MiniDeathmatchOverlay (int x, int y);
121 void Sbar_DeathmatchOverlay (void);
122 void Sbar_IntermissionOverlay (void);
123 void Sbar_FinaleOverlay (void);
125 void CL_VM_UpdateShowingScoresState (int showingscores);
135 void Sbar_ShowScores (void)
139 sb_showscores = true;
140 CL_VM_UpdateShowingScoresState(sb_showscores);
150 void Sbar_DontShowScores (void)
152 sb_showscores = false;
153 CL_VM_UpdateShowingScoresState(sb_showscores);
156 void sbar_start(void)
160 if (gamemode == GAME_DELUXEQUAKE || gamemode == GAME_BLOODOMNICIDE)
163 else if (gamemode == GAME_SOM)
165 sb_disc = Draw_CachePic_Flags ("gfx/disc", CACHEPICFLAG_QUIET);
167 for (i = 0;i < 10;i++)
168 sb_nums[0][i] = Draw_CachePic_Flags (va("gfx/num_%i",i), CACHEPICFLAG_QUIET);
170 somsb_health = Draw_CachePic_Flags ("gfx/hud_health", CACHEPICFLAG_QUIET);
171 somsb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
172 somsb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_nails", CACHEPICFLAG_QUIET);
173 somsb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
174 somsb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
175 somsb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor1", CACHEPICFLAG_QUIET);
176 somsb_armor[1] = Draw_CachePic_Flags ("gfx/sb_armor2", CACHEPICFLAG_QUIET);
177 somsb_armor[2] = Draw_CachePic_Flags ("gfx/sb_armor3", CACHEPICFLAG_QUIET);
179 else if (gamemode == GAME_NEXUIZ)
181 for (i = 0;i < 10;i++)
182 sb_nums[0][i] = Draw_CachePic_Flags (va("gfx/num_%i",i), CACHEPICFLAG_QUIET);
183 sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET);
184 sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET);
186 sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
187 sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_bullets", CACHEPICFLAG_QUIET);
188 sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
189 sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
191 sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor", CACHEPICFLAG_QUIET);
195 sb_health = Draw_CachePic_Flags ("gfx/sb_health", CACHEPICFLAG_QUIET);
197 sb_items[2] = Draw_CachePic_Flags ("gfx/sb_slowmo", CACHEPICFLAG_QUIET);
198 sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invinc", CACHEPICFLAG_QUIET);
199 sb_items[4] = Draw_CachePic_Flags ("gfx/sb_energy", CACHEPICFLAG_QUIET);
200 sb_items[5] = Draw_CachePic_Flags ("gfx/sb_str", CACHEPICFLAG_QUIET);
202 sb_items[11] = Draw_CachePic_Flags ("gfx/sb_flag_red_taken", CACHEPICFLAG_QUIET);
203 sb_items[12] = Draw_CachePic_Flags ("gfx/sb_flag_red_lost", CACHEPICFLAG_QUIET);
204 sb_items[13] = Draw_CachePic_Flags ("gfx/sb_flag_red_carrying", CACHEPICFLAG_QUIET);
205 sb_items[14] = Draw_CachePic_Flags ("gfx/sb_key_carrying", CACHEPICFLAG_QUIET);
206 sb_items[15] = Draw_CachePic_Flags ("gfx/sb_flag_blue_taken", CACHEPICFLAG_QUIET);
207 sb_items[16] = Draw_CachePic_Flags ("gfx/sb_flag_blue_lost", CACHEPICFLAG_QUIET);
208 sb_items[17] = Draw_CachePic_Flags ("gfx/sb_flag_blue_carrying", CACHEPICFLAG_QUIET);
210 sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET);
211 sb_sbar_minimal = Draw_CachePic_Flags ("gfx/sbar_minimal", CACHEPICFLAG_QUIET);
212 sb_sbar_overlay = Draw_CachePic_Flags ("gfx/sbar_overlay", CACHEPICFLAG_QUIET);
214 for(i = 0; i < 9;i++)
215 sb_weapons[0][i] = Draw_CachePic_Flags (va("gfx/inv_weapon%i",i), CACHEPICFLAG_QUIET);
217 else if (gamemode == GAME_ZYMOTIC)
219 zymsb_crosshair_center = Draw_CachePic_Flags ("gfx/hud/crosshair_center", CACHEPICFLAG_QUIET);
220 zymsb_crosshair_line = Draw_CachePic_Flags ("gfx/hud/crosshair_line", CACHEPICFLAG_QUIET);
221 zymsb_crosshair_health = Draw_CachePic_Flags ("gfx/hud/crosshair_health", CACHEPICFLAG_QUIET);
222 zymsb_crosshair_clip = Draw_CachePic_Flags ("gfx/hud/crosshair_clip", CACHEPICFLAG_QUIET);
223 zymsb_crosshair_ammo = Draw_CachePic_Flags ("gfx/hud/crosshair_ammo", CACHEPICFLAG_QUIET);
224 zymsb_crosshair_background = Draw_CachePic_Flags ("gfx/hud/crosshair_background", CACHEPICFLAG_QUIET);
225 zymsb_crosshair_left1 = Draw_CachePic_Flags ("gfx/hud/crosshair_left1", CACHEPICFLAG_QUIET);
226 zymsb_crosshair_left2 = Draw_CachePic_Flags ("gfx/hud/crosshair_left2", CACHEPICFLAG_QUIET);
227 zymsb_crosshair_right = Draw_CachePic_Flags ("gfx/hud/crosshair_right", CACHEPICFLAG_QUIET);
231 sb_disc = Draw_CachePic_Flags ("gfx/disc", CACHEPICFLAG_QUIET);
233 for (i = 0;i < 10;i++)
235 sb_nums[0][i] = Draw_CachePic_Flags (va("gfx/num_%i",i), CACHEPICFLAG_QUIET);
236 sb_nums[1][i] = Draw_CachePic_Flags (va("gfx/anum_%i",i), CACHEPICFLAG_QUIET);
239 sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET);
240 sb_nums[1][10] = Draw_CachePic_Flags ("gfx/anum_minus", CACHEPICFLAG_QUIET);
242 sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET);
243 sb_slash = Draw_CachePic_Flags ("gfx/num_slash", CACHEPICFLAG_QUIET);
245 sb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_shotgun", CACHEPICFLAG_QUIET);
246 sb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_sshotgun", CACHEPICFLAG_QUIET);
247 sb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_nailgun", CACHEPICFLAG_QUIET);
248 sb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_snailgun", CACHEPICFLAG_QUIET);
249 sb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_rlaunch", CACHEPICFLAG_QUIET);
250 sb_weapons[0][5] = Draw_CachePic_Flags ("gfx/inv_srlaunch", CACHEPICFLAG_QUIET);
251 sb_weapons[0][6] = Draw_CachePic_Flags ("gfx/inv_lightng", CACHEPICFLAG_QUIET);
253 sb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_shotgun", CACHEPICFLAG_QUIET);
254 sb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_sshotgun", CACHEPICFLAG_QUIET);
255 sb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_nailgun", CACHEPICFLAG_QUIET);
256 sb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_snailgun", CACHEPICFLAG_QUIET);
257 sb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_rlaunch", CACHEPICFLAG_QUIET);
258 sb_weapons[1][5] = Draw_CachePic_Flags ("gfx/inv2_srlaunch", CACHEPICFLAG_QUIET);
259 sb_weapons[1][6] = Draw_CachePic_Flags ("gfx/inv2_lightng", CACHEPICFLAG_QUIET);
261 for (i = 0;i < 5;i++)
263 sb_weapons[2+i][0] = Draw_CachePic_Flags (va("gfx/inva%i_shotgun",i+1), CACHEPICFLAG_QUIET);
264 sb_weapons[2+i][1] = Draw_CachePic_Flags (va("gfx/inva%i_sshotgun",i+1), CACHEPICFLAG_QUIET);
265 sb_weapons[2+i][2] = Draw_CachePic_Flags (va("gfx/inva%i_nailgun",i+1), CACHEPICFLAG_QUIET);
266 sb_weapons[2+i][3] = Draw_CachePic_Flags (va("gfx/inva%i_snailgun",i+1), CACHEPICFLAG_QUIET);
267 sb_weapons[2+i][4] = Draw_CachePic_Flags (va("gfx/inva%i_rlaunch",i+1), CACHEPICFLAG_QUIET);
268 sb_weapons[2+i][5] = Draw_CachePic_Flags (va("gfx/inva%i_srlaunch",i+1), CACHEPICFLAG_QUIET);
269 sb_weapons[2+i][6] = Draw_CachePic_Flags (va("gfx/inva%i_lightng",i+1), CACHEPICFLAG_QUIET);
272 sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
273 sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_nails", CACHEPICFLAG_QUIET);
274 sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
275 sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
277 sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor1", CACHEPICFLAG_QUIET);
278 sb_armor[1] = Draw_CachePic_Flags ("gfx/sb_armor2", CACHEPICFLAG_QUIET);
279 sb_armor[2] = Draw_CachePic_Flags ("gfx/sb_armor3", CACHEPICFLAG_QUIET);
281 sb_items[0] = Draw_CachePic_Flags ("gfx/sb_key1", CACHEPICFLAG_QUIET);
282 sb_items[1] = Draw_CachePic_Flags ("gfx/sb_key2", CACHEPICFLAG_QUIET);
283 sb_items[2] = Draw_CachePic_Flags ("gfx/sb_invis", CACHEPICFLAG_QUIET);
284 sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invuln", CACHEPICFLAG_QUIET);
285 sb_items[4] = Draw_CachePic_Flags ("gfx/sb_suit", CACHEPICFLAG_QUIET);
286 sb_items[5] = Draw_CachePic_Flags ("gfx/sb_quad", CACHEPICFLAG_QUIET);
288 sb_sigil[0] = Draw_CachePic_Flags ("gfx/sb_sigil1", CACHEPICFLAG_QUIET);
289 sb_sigil[1] = Draw_CachePic_Flags ("gfx/sb_sigil2", CACHEPICFLAG_QUIET);
290 sb_sigil[2] = Draw_CachePic_Flags ("gfx/sb_sigil3", CACHEPICFLAG_QUIET);
291 sb_sigil[3] = Draw_CachePic_Flags ("gfx/sb_sigil4", CACHEPICFLAG_QUIET);
293 sb_faces[4][0] = Draw_CachePic_Flags ("gfx/face1", CACHEPICFLAG_QUIET);
294 sb_faces[4][1] = Draw_CachePic_Flags ("gfx/face_p1", CACHEPICFLAG_QUIET);
295 sb_faces[3][0] = Draw_CachePic_Flags ("gfx/face2", CACHEPICFLAG_QUIET);
296 sb_faces[3][1] = Draw_CachePic_Flags ("gfx/face_p2", CACHEPICFLAG_QUIET);
297 sb_faces[2][0] = Draw_CachePic_Flags ("gfx/face3", CACHEPICFLAG_QUIET);
298 sb_faces[2][1] = Draw_CachePic_Flags ("gfx/face_p3", CACHEPICFLAG_QUIET);
299 sb_faces[1][0] = Draw_CachePic_Flags ("gfx/face4", CACHEPICFLAG_QUIET);
300 sb_faces[1][1] = Draw_CachePic_Flags ("gfx/face_p4", CACHEPICFLAG_QUIET);
301 sb_faces[0][0] = Draw_CachePic_Flags ("gfx/face5", CACHEPICFLAG_QUIET);
302 sb_faces[0][1] = Draw_CachePic_Flags ("gfx/face_p5", CACHEPICFLAG_QUIET);
304 sb_face_invis = Draw_CachePic_Flags ("gfx/face_invis", CACHEPICFLAG_QUIET);
305 sb_face_invuln = Draw_CachePic_Flags ("gfx/face_invul2", CACHEPICFLAG_QUIET);
306 sb_face_invis_invuln = Draw_CachePic_Flags ("gfx/face_inv2", CACHEPICFLAG_QUIET);
307 sb_face_quad = Draw_CachePic_Flags ("gfx/face_quad", CACHEPICFLAG_QUIET);
309 sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET);
310 sb_ibar = Draw_CachePic_Flags ("gfx/ibar", CACHEPICFLAG_QUIET);
311 sb_scorebar = Draw_CachePic_Flags ("gfx/scorebar", CACHEPICFLAG_QUIET);
313 //MED 01/04/97 added new hipnotic weapons
314 if (gamemode == GAME_HIPNOTIC)
316 hsb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_laser", CACHEPICFLAG_QUIET);
317 hsb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_mjolnir", CACHEPICFLAG_QUIET);
318 hsb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_gren_prox", CACHEPICFLAG_QUIET);
319 hsb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_prox_gren", CACHEPICFLAG_QUIET);
320 hsb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_prox", CACHEPICFLAG_QUIET);
322 hsb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_laser", CACHEPICFLAG_QUIET);
323 hsb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_mjolnir", CACHEPICFLAG_QUIET);
324 hsb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_gren_prox", CACHEPICFLAG_QUIET);
325 hsb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_prox_gren", CACHEPICFLAG_QUIET);
326 hsb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_prox", CACHEPICFLAG_QUIET);
328 for (i = 0;i < 5;i++)
330 hsb_weapons[2+i][0] = Draw_CachePic_Flags (va("gfx/inva%i_laser",i+1), CACHEPICFLAG_QUIET);
331 hsb_weapons[2+i][1] = Draw_CachePic_Flags (va("gfx/inva%i_mjolnir",i+1), CACHEPICFLAG_QUIET);
332 hsb_weapons[2+i][2] = Draw_CachePic_Flags (va("gfx/inva%i_gren_prox",i+1), CACHEPICFLAG_QUIET);
333 hsb_weapons[2+i][3] = Draw_CachePic_Flags (va("gfx/inva%i_prox_gren",i+1), CACHEPICFLAG_QUIET);
334 hsb_weapons[2+i][4] = Draw_CachePic_Flags (va("gfx/inva%i_prox",i+1), CACHEPICFLAG_QUIET);
337 hsb_items[0] = Draw_CachePic_Flags ("gfx/sb_wsuit", CACHEPICFLAG_QUIET);
338 hsb_items[1] = Draw_CachePic_Flags ("gfx/sb_eshld", CACHEPICFLAG_QUIET);
340 else if (gamemode == GAME_ROGUE)
342 rsb_invbar[0] = Draw_CachePic_Flags ("gfx/r_invbar1", CACHEPICFLAG_QUIET);
343 rsb_invbar[1] = Draw_CachePic_Flags ("gfx/r_invbar2", CACHEPICFLAG_QUIET);
345 rsb_weapons[0] = Draw_CachePic_Flags ("gfx/r_lava", CACHEPICFLAG_QUIET);
346 rsb_weapons[1] = Draw_CachePic_Flags ("gfx/r_superlava", CACHEPICFLAG_QUIET);
347 rsb_weapons[2] = Draw_CachePic_Flags ("gfx/r_gren", CACHEPICFLAG_QUIET);
348 rsb_weapons[3] = Draw_CachePic_Flags ("gfx/r_multirock", CACHEPICFLAG_QUIET);
349 rsb_weapons[4] = Draw_CachePic_Flags ("gfx/r_plasma", CACHEPICFLAG_QUIET);
351 rsb_items[0] = Draw_CachePic_Flags ("gfx/r_shield1", CACHEPICFLAG_QUIET);
352 rsb_items[1] = Draw_CachePic_Flags ("gfx/r_agrav1", CACHEPICFLAG_QUIET);
354 // PGM 01/19/97 - team color border
355 rsb_teambord = Draw_CachePic_Flags ("gfx/r_teambord", CACHEPICFLAG_QUIET);
356 // PGM 01/19/97 - team color border
358 rsb_ammo[0] = Draw_CachePic_Flags ("gfx/r_ammolava", CACHEPICFLAG_QUIET);
359 rsb_ammo[1] = Draw_CachePic_Flags ("gfx/r_ammomulti", CACHEPICFLAG_QUIET);
360 rsb_ammo[2] = Draw_CachePic_Flags ("gfx/r_ammoplasma", CACHEPICFLAG_QUIET);
364 sb_ranking = Draw_CachePic_Flags ("gfx/ranking", CACHEPICFLAG_QUIET);
365 sb_complete = Draw_CachePic_Flags ("gfx/complete", CACHEPICFLAG_QUIET);
366 sb_inter = Draw_CachePic_Flags ("gfx/inter", CACHEPICFLAG_QUIET);
367 sb_finale = Draw_CachePic_Flags ("gfx/finale", CACHEPICFLAG_QUIET);
370 void sbar_shutdown(void)
374 void sbar_newmap(void)
378 void Sbar_Init (void)
380 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
381 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
382 Cvar_RegisterVariable(&showfps);
383 Cvar_RegisterVariable(&showsound);
384 Cvar_RegisterVariable(&showblur);
385 Cvar_RegisterVariable(&showspeed);
386 Cvar_RegisterVariable(&showtopspeed);
387 Cvar_RegisterVariable(&showtime);
388 Cvar_RegisterVariable(&showtime_format);
389 Cvar_RegisterVariable(&showdate);
390 Cvar_RegisterVariable(&showdate_format);
391 Cvar_RegisterVariable(&showtex);
392 Cvar_RegisterVariable(&sbar_alpha_bg);
393 Cvar_RegisterVariable(&sbar_alpha_fg);
394 Cvar_RegisterVariable(&sbar_hudselector);
395 Cvar_RegisterVariable(&sbar_scorerank);
396 Cvar_RegisterVariable(&sbar_gametime);
397 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
398 Cvar_RegisterVariable(&sbar_info_pos);
399 Cvar_RegisterVariable(&cl_deathscoreboard);
401 Cvar_RegisterVariable(&crosshair_color_red);
402 Cvar_RegisterVariable(&crosshair_color_green);
403 Cvar_RegisterVariable(&crosshair_color_blue);
404 Cvar_RegisterVariable(&crosshair_color_alpha);
405 Cvar_RegisterVariable(&crosshair_size);
407 Cvar_RegisterVariable(&sbar_flagstatus_right); // (GAME_NEXUZI ONLY)
408 Cvar_RegisterVariable(&sbar_flagstatus_pos); // (GAME_NEXUIZ ONLY)
410 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap, NULL, NULL);
414 //=============================================================================
416 // drawing routines are relative to the status bar location
425 void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
427 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
430 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
432 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
435 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
437 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
444 Draws one solid graphics character
447 void Sbar_DrawCharacter (int x, int y, int num)
449 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);
457 void Sbar_DrawString (int x, int y, char *str)
459 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR);
467 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
472 l = dpsnprintf(str, sizeof(str), "%i", num);
486 Sbar_DrawPic (x, y, sb_nums[color][frame]);
499 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
507 l = dpsnprintf(str, sizeof(str), "%0*i", digits, num);
510 l = dpsnprintf(str, sizeof(str), "%i", num);
515 x += (digits-l) * lettersize;
524 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
531 //=============================================================================
534 int Sbar_IsTeammatch(void)
536 // currently only nexuiz uses the team score board
537 return ((gamemode == GAME_NEXUIZ)
538 && (teamplay.integer > 0));
546 static int fragsort[MAX_SCOREBOARD];
547 static int scoreboardlines;
549 int Sbar_GetSortedPlayerIndex (int index)
551 return index >= 0 && index < scoreboardlines ? fragsort[index] : -1;
554 static scoreboard_t teams[MAX_SCOREBOARD];
555 static int teamsort[MAX_SCOREBOARD];
556 static int teamlines;
557 void Sbar_SortFrags (void)
563 for (i=0 ; i<cl.maxclients ; i++)
565 if (cl.scores[i].name[0])
567 fragsort[scoreboardlines] = i;
572 for (i=0 ; i<scoreboardlines ; i++)
573 for (j=0 ; j<scoreboardlines-1-i ; j++)
574 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
577 fragsort[j] = fragsort[j+1];
582 if (Sbar_IsTeammatch ())
584 // now sort players by teams.
585 for (i=0 ; i<scoreboardlines ; i++)
587 for (j=0 ; j<scoreboardlines-1-i ; j++)
589 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
592 fragsort[j] = fragsort[j+1];
598 // calculate team scores
600 for (i=0 ; i<scoreboardlines ; i++)
602 if (color != (cl.scores[fragsort[i]].colors & 15))
604 const char* teamname;
606 color = cl.scores[fragsort[i]].colors & 15;
612 teamname = "^1Red Team";
615 teamname = "^4Blue Team";
618 teamname = "^6Pink Team";
621 teamname = "^3Yellow Team";
624 teamname = "Total Team Score";
627 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
629 teams[teamlines-1].frags = 0;
630 teams[teamlines-1].colors = color + 16 * color;
633 if (cl.scores[fragsort[i]].frags != -666)
635 // do not add spedcators
636 // (ugly hack for nexuiz)
637 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
641 // now sort teams by scores.
642 for (i=0 ; i<teamlines ; i++)
644 for (i=0 ; i<teamlines ; i++)
646 for (j=0 ; j<teamlines-1-i ; j++)
648 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
651 teamsort[j] = teamsort[j+1];
664 void Sbar_SoloScoreboard (void)
667 char str[80], timestr[40];
669 int minutes, seconds;
672 t = (cl.intermission ? cl.completed_time : cl.time);
673 minutes = (int)(t / 60);
674 seconds = (int)(t - 60*floor(t/60));
676 // monsters and secrets are now both on the top row
677 if (cl.stats[STAT_TOTALMONSTERS])
678 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
679 else if (cl.stats[STAT_MONSTERS]) // LA: Display something if monsters_killed is non-zero, but total_monsters is zero
680 Sbar_DrawString(8, 4, va("Monsters:%3i", cl.stats[STAT_MONSTERS]));
682 if (cl.stats[STAT_TOTALSECRETS])
683 Sbar_DrawString(8+22*8, 4, va("Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
684 else if (cl.stats[STAT_SECRETS]) // LA: And similarly for secrets
685 Sbar_DrawString(8+22*8, 4, va("Secrets:%3i", cl.stats[STAT_SECRETS]));
687 // format is like this: e1m1:The Sligpate Complex
688 dpsnprintf(str, sizeof(str), "%s:%s", cl.worldbasename, cl.worldmessage);
690 // if there's a newline character, terminate the string there
691 if (strchr(str, '\n'))
692 *(strchr(str, '\n')) = 0;
694 // make the time string
695 timelen = dpsnprintf(timestr, sizeof(timestr), " %i:%02i", minutes, seconds);
697 // truncate the level name if necessary to make room for time
699 if ((int)strlen(str) > max)
702 // print the filename and message
703 Sbar_DrawString(8, 12, str);
706 Sbar_DrawString(8 + max*8, 12, timestr);
710 int minutes, seconds, tens, units;
713 if (gamemode != GAME_NEXUIZ) {
714 dpsnprintf (str, sizeof(str), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
715 Sbar_DrawString (8, 4, str);
717 dpsnprintf (str, sizeof(str), "Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
718 Sbar_DrawString (8, 12, str);
722 minutes = (int)(cl.time / 60);
723 seconds = (int)(cl.time - 60*minutes);
725 units = seconds - 10*tens;
726 dpsnprintf (str, sizeof(str), "Time :%3i:%i%i", minutes, tens, units);
727 Sbar_DrawString (184, 4, str);
730 if (gamemode == GAME_NEXUIZ) {
731 l = (int) strlen (cl.worldname);
732 Sbar_DrawString (232 - l*4, 12, cl.worldname);
734 l = (int) strlen (cl.worldmessage);
735 Sbar_DrawString (232 - l*4, 12, cl.worldmessage);
745 void Sbar_DrawScoreboard (void)
747 Sbar_SoloScoreboard ();
748 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
749 //if (cl.gametype == GAME_DEATHMATCH)
751 Sbar_DeathmatchOverlay ();
754 //=============================================================================
756 // AK to make DrawInventory smaller
757 static void Sbar_DrawWeapon(int nr, float fade, int active)
759 if (sbar_hudselector.integer == 1)
761 // width = 300, height = 100
762 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
764 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);
766 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);
770 // width = 300, height = 100
771 const int w_width = 300, w_height = 100, w_space = 10;
772 const float w_scale = 0.4;
774 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);
775 //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);
784 void Sbar_DrawInventory (void)
791 if (gamemode == GAME_ROGUE)
793 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
794 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
796 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
799 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
802 for (i=0 ; i<7 ; i++)
804 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
806 time = cl.item_gettime[i];
807 flashon = (int)(max(0, cl.time - time)*10);
810 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
816 flashon = (flashon%5) + 2;
818 Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
824 if (gamemode == GAME_HIPNOTIC)
826 int grenadeflashing=0;
827 for (i=0 ; i<4 ; i++)
829 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
831 time = max(0, cl.item_gettime[hipweapons[i]]);
832 flashon = (int)((cl.time - time)*10);
835 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
841 flashon = (flashon%5) + 2;
843 // check grenade launcher
846 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
851 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
857 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
859 if (!grenadeflashing)
860 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
863 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
866 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
871 if (gamemode == GAME_ROGUE)
873 // check for powered up weapon.
874 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
876 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
877 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
881 for (i=0 ; i<4 ; i++)
883 dpsnprintf (num, sizeof(num), "%4i",cl.stats[STAT_SHELLS+i] );
885 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
887 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
889 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
891 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
895 for (i=0 ; i<6 ; i++)
896 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
898 //MED 01/04/97 changed keys
899 if (gamemode != GAME_HIPNOTIC || (i>1))
900 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
903 //MED 01/04/97 added hipnotic items
905 if (gamemode == GAME_HIPNOTIC)
907 for (i=0 ; i<2 ; i++)
908 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
909 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
912 if (gamemode == GAME_ROGUE)
915 for (i=0 ; i<2 ; i++)
916 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
917 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
922 for (i=0 ; i<4 ; i++)
923 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
924 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
928 //=============================================================================
935 void Sbar_DrawFrags (void)
945 l = min(scoreboardlines, 4);
949 for (i = 0;i < l;i++)
955 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
956 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);
957 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
958 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);
962 dpsnprintf (num, sizeof(num), "%3i",f);
964 if (k == cl.viewentity - 1)
966 Sbar_DrawCharacter ( x + 2, -24, 16);
967 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
969 Sbar_DrawCharacter (x + 8, -24, num[0]);
970 Sbar_DrawCharacter (x + 16, -24, num[1]);
971 Sbar_DrawCharacter (x + 24, -24, num[2]);
976 //=============================================================================
984 void Sbar_DrawFace (void)
988 // PGM 01/19/97 - team color drawing
989 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
990 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
996 s = &cl.scores[cl.viewentity - 1];
998 Sbar_DrawPic (112, 0, rsb_teambord);
999 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1000 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);
1001 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1002 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);
1006 dpsnprintf (num, sizeof(num), "%3i",f);
1008 if ((s->colors & 0xf0)==0)
1011 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1013 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1015 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1019 Sbar_DrawCharacter ( 109, 3, num[0]);
1020 Sbar_DrawCharacter ( 116, 3, num[1]);
1021 Sbar_DrawCharacter ( 123, 3, num[2]);
1026 // PGM 01/19/97 - team color drawing
1028 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1029 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1030 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1031 Sbar_DrawPic (112, 0, sb_face_quad );
1032 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1033 Sbar_DrawPic (112, 0, sb_face_invis );
1034 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1035 Sbar_DrawPic (112, 0, sb_face_invuln);
1038 f = cl.stats[STAT_HEALTH] / 20;
1040 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1043 double topspeed = 0;
1044 double topspeedxy = 0;
1045 time_t current_time = 3;
1046 time_t top_time = 0;
1047 time_t topxy_time = 0;
1049 static void get_showspeed_unit(int unitnumber, double *conversion_factor, const char **unit)
1052 unitnumber = showspeed.integer;
1057 if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC)
1061 *conversion_factor = 1.0;
1065 *conversion_factor = 0.0254;
1066 if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1067 // 1qu=1.5in is for non-Nexuiz/Xonotic only - Nexuiz/Xonotic players are overly large, but 1qu=1in fixes that
1071 *conversion_factor = 0.0254 * 3.6;
1072 if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1076 *conversion_factor = 0.0254 * 3.6 * 0.6213711922;
1077 if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1081 *conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
1082 if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1087 static double showfps_nexttime = 0, showfps_lasttime = -1;
1088 static double showfps_framerate = 0;
1089 static int showfps_framecount = 0;
1091 void Sbar_ShowFPS_Update(void)
1093 double interval = 1;
1096 if (newtime >= showfps_nexttime)
1098 showfps_framerate = showfps_framecount / (newtime - showfps_lasttime);
1099 if (showfps_nexttime < newtime - interval * 1.5)
1100 showfps_nexttime = newtime;
1101 showfps_lasttime = newtime;
1102 showfps_nexttime += interval;
1103 showfps_framecount = 0;
1105 showfps_framecount++;
1108 void Sbar_ShowFPS(void)
1110 float fps_x, fps_y, fps_scalex, fps_scaley, fps_strings = 0;
1111 char soundstring[32];
1113 char timestring[32];
1114 char datestring[32];
1115 char timedemostring1[32];
1116 char timedemostring2[32];
1117 char speedstring[32];
1118 char blurstring[32];
1119 char topspeedstring[48];
1120 char texstring[MAX_QPATH];
1121 qboolean red = false;
1124 timedemostring1[0] = 0;
1125 timedemostring2[0] = 0;
1131 topspeedstring[0] = 0;
1132 if (showfps.integer)
1134 red = (showfps_framerate < 1.0f);
1135 if(showfps.integer == 2)
1136 dpsnprintf(fpsstring, sizeof(fpsstring), "%7.3f mspf", (1000.0 / showfps_framerate));
1138 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0 / showfps_framerate + 0.5));
1140 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(showfps_framerate + 0.5));
1144 dpsnprintf(timedemostring1, sizeof(timedemostring1), "frame%4i %f", cls.td_frames, realtime - cls.td_starttime);
1145 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);
1150 if (showtime.integer)
1152 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1155 if (showdate.integer)
1157 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1160 if (showblur.integer)
1162 dpsnprintf(blurstring, sizeof(blurstring), "%3i%% blur", (int)(cl.motionbluralpha * 100));
1165 if (showsound.integer)
1167 dpsnprintf(soundstring, sizeof(soundstring), "%4i/4%i at %3ims", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds);
1170 if (showspeed.integer || showtopspeed.integer)
1172 double speed, speedxy, f;
1174 speed = VectorLength(cl.movement_velocity);
1175 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1176 if (showspeed.integer)
1178 get_showspeed_unit(showspeed.integer, &f, &unit);
1179 dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1182 if (showtopspeed.integer)
1184 qboolean topspeed_latched = false, topspeedxy_latched = false;
1185 get_showspeed_unit(showtopspeed.integer, &f, &unit);
1186 if (speed >= topspeed || current_time - top_time > 3)
1192 topspeed_latched = true;
1193 if (speedxy >= topspeedxy || current_time - topxy_time > 3)
1195 topspeedxy = speedxy;
1199 topspeedxy_latched = true;
1200 dpsnprintf(topspeedstring, sizeof(topspeedstring), "%s%.0f%s (%s%.0f%s) %s",
1201 topspeed_latched ? "^1" : "^xf88", f*topspeed, "^xf88",
1202 topspeedxy_latched ? "^1" : "^xf88", f*topspeedxy, "^xf88",
1204 time(¤t_time);
1208 if (showtex.integer)
1213 VectorMA(r_refdef.view.origin, 65536, r_refdef.view.forward, dest);
1214 trace.hittexture = NULL; // to make sure
1215 // TODO change this trace to be stopped by anything "visible" (i.e. with a drawsurface), but not stuff like weapclip
1216 // probably needs adding a new SUPERCONTENTS type
1217 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, true, false, NULL, true, true);
1218 if(trace.hittexture)
1219 strlcpy(texstring, trace.hittexture->name, sizeof(texstring));
1221 strlcpy(texstring, "(no texture hit)", sizeof(texstring));
1228 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1229 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_strings*fps_scaley);
1230 fps_y = vid_conheight.integer - sbar_info_pos.integer - fps_strings*fps_scaley;
1233 fps_x = vid_conwidth.integer - DrawQ_TextWidth(soundstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1234 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1235 DrawQ_String(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1236 fps_y += fps_scaley;
1240 r_draw2d_force = true;
1241 fps_x = vid_conwidth.integer - DrawQ_TextWidth(fpsstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1242 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1244 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1246 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1247 fps_y += fps_scaley;
1248 r_draw2d_force = false;
1250 if (timedemostring1[0])
1252 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring1, 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, timedemostring1, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1255 fps_y += fps_scaley;
1257 if (timedemostring2[0])
1259 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring2, 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, timedemostring2, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1262 fps_y += fps_scaley;
1266 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timestring, 0, fps_scalex, fps_scaley, true, 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, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1269 fps_y += fps_scaley;
1273 fps_x = vid_conwidth.integer - DrawQ_TextWidth(datestring, 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, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1276 fps_y += fps_scaley;
1280 fps_x = vid_conwidth.integer - DrawQ_TextWidth(speedstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1281 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1282 DrawQ_String(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1283 fps_y += fps_scaley;
1285 if (topspeedstring[0])
1287 fps_x = vid_conwidth.integer - DrawQ_TextWidth(topspeedstring, 0, fps_scalex, fps_scaley, false, FONT_INFOBAR);
1288 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1289 DrawQ_String(fps_x, fps_y, topspeedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR);
1290 fps_y += fps_scaley;
1294 fps_x = vid_conwidth.integer - DrawQ_TextWidth(blurstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1295 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1296 DrawQ_String(fps_x, fps_y, blurstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1297 fps_y += fps_scaley;
1301 fps_x = vid_conwidth.integer - DrawQ_TextWidth(texstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1302 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1303 DrawQ_String(fps_x, fps_y, texstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1304 fps_y += fps_scaley;
1309 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)
1312 c2 = bound(0, c2, 1);
1313 c1 = bound(0, c1, 1 - c2);
1315 r[1] = rangey + rangeheight * (c2 + c1);
1316 r[2] = rangey + rangeheight * (c2);
1320 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);
1322 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);
1324 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);
1326 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);
1334 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1335 extern cvar_t v_kicktime;
1336 void Sbar_Score (int margin);
1337 void Sbar_Draw (void)
1341 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1344 Sbar_DrawScoreboard ();
1345 else if (cl.intermission == 1)
1347 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1349 Sbar_DrawScoreboard();
1352 Sbar_IntermissionOverlay();
1354 else if (cl.intermission == 2)
1355 Sbar_FinaleOverlay();
1356 else if (gamemode == GAME_DELUXEQUAKE)
1359 else if (gamemode == GAME_SOM)
1361 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1362 Sbar_DrawScoreboard ();
1365 // this is the top left of the sbar area
1367 sbar_y = vid_conheight.integer - 24*3;
1370 if (cl.stats[STAT_ARMOR])
1372 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1373 Sbar_DrawPic(0, 0, somsb_armor[2]);
1374 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1375 Sbar_DrawPic(0, 0, somsb_armor[1]);
1376 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1377 Sbar_DrawPic(0, 0, somsb_armor[0]);
1378 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1382 Sbar_DrawPic(0, 24, somsb_health);
1383 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1386 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1387 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1388 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1389 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1390 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1391 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1392 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1393 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1394 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1395 if (cl.stats[STAT_SHELLS])
1396 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1399 else if (gamemode == GAME_NEXUIZ)
1401 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1403 sbar_x = (vid_conwidth.integer - 640)/2;
1404 sbar_y = vid_conheight.integer - 47;
1405 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1406 Sbar_DrawScoreboard ();
1408 else if (sb_lines && sbar_hudselector.integer == 1)
1412 int redflag, blueflag;
1415 sbar_x = (vid_conwidth.integer - 320)/2;
1416 sbar_y = vid_conheight.integer - 24 - 16;
1418 // calculate intensity to draw weapons bar at
1419 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1420 fade = bound(0.7, fade, 1);
1421 for (i = 0; i < 8;i++)
1422 if (cl.stats[STAT_ITEMS] & (1 << i))
1423 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1424 if((cl.stats[STAT_ITEMS] & (1<<12)))
1425 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1428 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1429 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1430 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1431 if (redflag == 3 && blueflag == 3)
1433 // The Impossible Combination[tm]
1434 // Can only happen in Key Hunt mode...
1435 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[14]);
1440 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64)), sb_items[redflag+10]);
1442 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[blueflag+14]);
1446 if (cl.stats[STAT_ARMOR] > 0)
1448 Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1449 if(cl.stats[STAT_ARMOR] > 200)
1450 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1451 else if(cl.stats[STAT_ARMOR] > 100)
1452 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1453 else if(cl.stats[STAT_ARMOR] > 50)
1454 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1455 else if(cl.stats[STAT_ARMOR] > 25)
1456 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1458 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1462 if (cl.stats[STAT_HEALTH] != 0)
1464 Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1465 if(cl.stats[STAT_HEALTH] > 200)
1466 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1467 else if(cl.stats[STAT_HEALTH] > 100)
1468 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1469 else if(cl.stats[STAT_HEALTH] > 50)
1470 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1471 else if(cl.stats[STAT_HEALTH] > 25)
1472 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1474 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1478 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1480 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1481 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1482 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1483 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1484 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1485 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1486 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1487 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1488 if(cl.stats[STAT_AMMO] > 10)
1489 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1491 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1494 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1495 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1498 // The margin can be at most 8 to support 640x480 console size:
1499 // 320 + 2 * (144 + 16) = 640
1505 int redflag, blueflag;
1508 sbar_x = (vid_conwidth.integer - 640)/2;
1509 sbar_y = vid_conheight.integer - 47;
1511 // calculate intensity to draw weapons bar at
1512 fade = 3 - 2 * (cl.time - cl.weapontime);
1515 fade = min(fade, 1);
1516 for (i = 0; i < 8;i++)
1517 if (cl.stats[STAT_ITEMS] & (1 << i))
1518 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1520 if((cl.stats[STAT_ITEMS] & (1<<12)))
1521 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1524 //if (!cl.islocalgame)
1525 // Sbar_DrawFrags ();
1528 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1530 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1533 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1534 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1535 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1536 if (redflag == 3 && blueflag == 3)
1538 // The Impossible Combination[tm]
1539 // Can only happen in Key Hunt mode...
1540 Sbar_DrawPic ((int) x, -179, sb_items[14]);
1545 Sbar_DrawPic ((int) x, -117, sb_items[redflag+10]);
1547 Sbar_DrawPic ((int) x, -177, sb_items[blueflag+14]);
1551 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1554 if(cl.stats[STAT_HEALTH] > 100)
1555 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1556 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1557 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1559 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1561 // AK dont draw ammo for the laser
1562 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1564 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1565 Sbar_DrawPic (519, 0, sb_ammo[0]);
1566 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1567 Sbar_DrawPic (519, 0, sb_ammo[1]);
1568 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1569 Sbar_DrawPic (519, 0, sb_ammo[2]);
1570 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1571 Sbar_DrawPic (519, 0, sb_ammo[3]);
1573 if(cl.stats[STAT_AMMO] <= 10)
1574 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1576 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1581 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1583 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1584 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1589 // Mini scoreboard uses 12*4 per other team, that is, 144
1590 // pixels when there are four teams...
1591 // Nexuiz by default sets vid_conwidth to 800... makes
1593 // so we need to shift it by 64 pixels to the right to fit
1594 // BUT: then it overlaps with the image that gets drawn
1595 // for viewsize 100! Therefore, just account for 3 teams,
1596 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1600 else if (gamemode == GAME_ZYMOTIC)
1603 float scale = 64.0f / 256.0f;
1604 float kickoffset[3];
1605 VectorClear(kickoffset);
1608 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1609 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1611 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1612 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1613 // left1 16, 48 : 126 -66
1614 // left2 16, 128 : 196 -66
1615 // right 176, 48 : 196 -136
1616 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);
1617 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);
1618 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);
1619 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1621 float scale = 128.0f / 256.0f;
1622 float healthstart, healthheight, healthstarttc, healthendtc;
1623 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1624 float ammostart, ammoheight, ammostarttc, ammoendtc;
1625 float clipstart, clipheight, clipstarttc, clipendtc;
1626 float kickoffset[3], offset;
1627 VectorClear(kickoffset);
1630 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1631 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1633 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1634 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1635 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1636 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);
1637 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);
1638 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);
1639 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);
1640 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1641 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1642 healthstart = 204 - healthheight;
1643 shieldstart = healthstart - shieldheight;
1644 healthstarttc = healthstart * (1.0f / 256.0f);
1645 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1646 shieldstarttc = shieldstart * (1.0f / 256.0f);
1647 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1648 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1649 ammostart = 114 - ammoheight;
1650 ammostarttc = ammostart * (1.0f / 256.0f);
1651 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1652 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1653 clipstart = 190 - clipheight;
1654 clipstarttc = clipstart * (1.0f / 256.0f);
1655 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1656 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);
1657 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);
1658 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);
1659 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);
1660 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1661 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1664 else // Quake and others
1666 sbar_x = (vid_conwidth.integer - 320)/2;
1667 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1668 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1669 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1673 if (gamemode != GAME_GOODVSBAD2)
1674 Sbar_DrawInventory ();
1675 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1679 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1681 if (gamemode != GAME_GOODVSBAD2)
1682 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1683 Sbar_DrawScoreboard ();
1687 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1689 // keys (hipnotic only)
1690 //MED 01/04/97 moved keys here so they would not be overwritten
1691 if (gamemode == GAME_HIPNOTIC)
1693 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1694 Sbar_DrawPic (209, 3, sb_items[0]);
1695 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1696 Sbar_DrawPic (209, 12, sb_items[1]);
1699 if (gamemode != GAME_GOODVSBAD2)
1701 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1703 Sbar_DrawNum (24, 0, 666, 3, 1);
1704 Sbar_DrawPic (0, 0, sb_disc);
1708 if (gamemode == GAME_ROGUE)
1710 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1711 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1712 Sbar_DrawPic (0, 0, sb_armor[2]);
1713 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1714 Sbar_DrawPic (0, 0, sb_armor[1]);
1715 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1716 Sbar_DrawPic (0, 0, sb_armor[0]);
1720 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1721 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1722 Sbar_DrawPic (0, 0, sb_armor[2]);
1723 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1724 Sbar_DrawPic (0, 0, sb_armor[1]);
1725 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1726 Sbar_DrawPic (0, 0, sb_armor[0]);
1735 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1738 if (gamemode == GAME_ROGUE)
1740 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1741 Sbar_DrawPic (224, 0, sb_ammo[0]);
1742 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1743 Sbar_DrawPic (224, 0, sb_ammo[1]);
1744 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1745 Sbar_DrawPic (224, 0, sb_ammo[2]);
1746 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1747 Sbar_DrawPic (224, 0, sb_ammo[3]);
1748 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1749 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1750 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1751 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1752 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1753 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1757 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1758 Sbar_DrawPic (224, 0, sb_ammo[0]);
1759 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1760 Sbar_DrawPic (224, 0, sb_ammo[1]);
1761 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1762 Sbar_DrawPic (224, 0, sb_ammo[2]);
1763 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1764 Sbar_DrawPic (224, 0, sb_ammo[3]);
1767 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1769 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1770 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1772 if (gamemode == GAME_TRANSFUSION)
1773 Sbar_MiniDeathmatchOverlay (0, 0);
1775 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1782 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1784 pic = Draw_CachePic (va("gfx/crosshair%i", crosshair.integer));
1785 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);
1788 if (cl_prydoncursor.integer > 0)
1789 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);
1792 //=============================================================================
1796 Sbar_DeathmatchOverlay
1800 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1803 qboolean myself = false;
1805 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1807 if((s - cl.scores) == cl.playerentity - 1)
1809 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1810 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1813 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1815 if (s->qw_spectator)
1817 if (s->qw_ping || s->qw_packetloss)
1818 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 );
1820 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 );
1824 // draw colors behind score
1830 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1831 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);
1832 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1833 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);
1835 //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);
1836 if (s->qw_ping || s->qw_packetloss)
1837 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 );
1839 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 );
1844 if (s->qw_spectator)
1846 if (s->qw_ping || s->qw_packetloss)
1847 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 );
1849 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 );
1853 // draw colors behind score
1854 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1855 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);
1856 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1857 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);
1859 //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);
1860 if (s->qw_ping || s->qw_packetloss)
1861 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 );
1863 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 );
1869 void Sbar_DeathmatchOverlay (void)
1871 int i, y, xmin, xmax, ymin, ymax;
1873 // request new ping times every two second
1874 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1876 cl.last_ping_request = realtime;
1877 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1879 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1880 MSG_WriteString(&cls.netcon->message, "pings");
1882 else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6/* || cls.protocol == PROTOCOL_DARKPLACES7*/)
1884 // these servers usually lack the pings command and so a less efficient "ping" command must be sent, which on modern DP servers will also reply with a pingplreport command after the ping listing
1885 static int ping_anyway_counter = 0;
1886 if(cl.parsingtextexpectingpingforscores == 1)
1888 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1889 if(++ping_anyway_counter >= 5)
1890 cl.parsingtextexpectingpingforscores = 0;
1892 if(cl.parsingtextexpectingpingforscores != 1)
1894 ping_anyway_counter = 0;
1895 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1896 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1897 MSG_WriteString(&cls.netcon->message, "ping");
1902 // newer server definitely has pings command, so use it for more efficiency, avoids ping reports spamming the console if they are misparsed, and saves a little bandwidth
1903 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1904 MSG_WriteString(&cls.netcon->message, "pings");
1912 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1914 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1915 xmin = (int) (vid_conwidth.integer - (26 + 15) * 8 * FONT_SBAR->maxwidth) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1917 xmin = (int) (vid_conwidth.integer - (16 + 25) * 8 * FONT_SBAR->maxwidth) / 2; // 16 characters until name, then we assume 25 character names (they can be longer but usually aren't)
1918 xmax = vid_conwidth.integer - xmin;
1920 if(gamemode == GAME_NEXUIZ)
1921 DrawQ_Pic (xmin - 8, ymin - 8, 0, xmax-xmin+1 + 2*8, ymax-ymin+1 + 2*8, 0, 0, 0, sbar_alpha_bg.value, 0);
1923 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1927 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1929 DrawQ_String(xmin, y, va("ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1933 DrawQ_String(xmin, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1937 if (Sbar_IsTeammatch ())
1939 // show team scores first
1940 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1941 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1945 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1946 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1951 Sbar_MiniDeathmatchOverlay
1955 void Sbar_MiniDeathmatchOverlay (int x, int y)
1957 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1959 // do not draw this if sbar_miniscoreboard_size is zero
1960 if(sbar_miniscoreboard_size.value == 0)
1962 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1963 if(sbar_miniscoreboard_size.value > 0)
1964 y = (int) (vid_conheight.integer - sbar_miniscoreboard_size.value * 8);
1969 // decide where to print
1970 if (gamemode == GAME_TRANSFUSION)
1971 numlines = (vid_conwidth.integer - x + 127) / 128;
1973 numlines = (vid_conheight.integer - y + 7) / 8;
1975 // give up if there isn't room
1976 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1980 for (i = 0; i < scoreboardlines; i++)
1981 if (fragsort[i] == cl.playerentity - 1)
1985 range_end = scoreboardlines;
1988 if (gamemode != GAME_TRANSFUSION)
1989 if (Sbar_IsTeammatch ())
1991 // reserve space for the team scores
1992 numlines -= teamlines;
1994 // find first and last player of my team (only draw the team totals and my own team)
1995 range_begin = range_end = i;
1996 myteam = cl.scores[fragsort[i]].colors & 15;
1997 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1999 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
2002 // looks better than two players
2012 i = min(i, range_end - numlines);
2013 i = max(i, range_begin);
2015 if (gamemode == GAME_TRANSFUSION)
2017 for (;i < range_end && x < vid_conwidth.integer;i++)
2018 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2022 if(range_end - i < numlines) // won't draw to bottom?
2023 y += 8 * (numlines - (range_end - i)); // bottom align
2024 // show team scores first
2025 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
2026 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
2028 for (;i < range_end && y < vid_conheight.integer;i++)
2029 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2033 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
2035 static int const sortorder[16] =
2054 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
2055 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
2056 int tc1 = sortorder[t1->colors & 15];
2057 int tc2 = sortorder[t2->colors & 15];
2061 void Sbar_Score (int margin)
2063 int i, me, score, otherleader, place, distribution, minutes, seconds;
2065 int sbar_x_save = sbar_x;
2066 int sbar_y_save = sbar_y;
2069 sbar_y = (int) (vid_conheight.value - (32+12));
2072 me = cl.playerentity - 1;
2073 if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients)
2075 if(Sbar_IsTeammatch())
2079 // team1 team3 team4
2083 scoreboard_t *teamcolorsort[16];
2086 for(i = 0; i < teamlines; ++i)
2087 teamcolorsort[i] = &(teams[i]);
2089 // Now sort them by color
2090 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
2093 // -12*4: four digits space
2094 place = (teamlines - 1) * (-12 * 4);
2096 for(i = 0; i < teamlines; ++i)
2098 int cindex = teamcolorsort[i]->colors & 15;
2099 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
2100 float cm = max(max(c[0], c[1]), c[2]);
2101 float cr = c[0] / cm;
2102 float cg = c[1] / cm;
2103 float cb = c[2] / cm;
2104 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
2106 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
2110 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
2123 // find leading score other than ourselves, to calculate distribution
2124 // find our place in the scoreboard
2125 score = cl.scores[me].frags;
2126 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
2128 if (cl.scores[i].name[0] && i != me)
2130 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
2132 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
2136 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
2138 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2139 else if (place == 2)
2140 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2142 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2143 if (otherleader < 0)
2144 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2145 if (distribution >= 0)
2147 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2148 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2150 else if (distribution >= -5)
2152 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2153 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2157 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2158 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2163 if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT])
2165 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2166 minutes = (int)floor(timeleft / 60);
2167 seconds = (int)(floor(timeleft) - minutes * 60);
2170 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2171 if(sb_colon && sb_colon->tex != r_texture_notexture)
2172 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2173 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2175 else if (minutes >= 1)
2177 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2178 if(sb_colon && sb_colon->tex != r_texture_notexture)
2179 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2180 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2182 else if ((int)(timeleft * 4) & 1)
2183 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2185 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2187 else if (sbar_gametime.integer)
2189 minutes = (int)floor(cl.time / 60);
2190 seconds = (int)(floor(cl.time) - minutes * 60);
2191 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2192 if(sb_colon && sb_colon->tex != r_texture_notexture)
2193 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2194 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2197 sbar_x = sbar_x_save;
2198 sbar_y = sbar_y_save;
2203 Sbar_IntermissionOverlay
2207 void Sbar_IntermissionOverlay (void)
2212 if (cl.gametype == GAME_DEATHMATCH)
2214 Sbar_DeathmatchOverlay ();
2218 sbar_x = (vid_conwidth.integer - 320) >> 1;
2219 sbar_y = (vid_conheight.integer - 200) >> 1;
2221 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2222 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2225 dig = (int)cl.completed_time / 60;
2226 Sbar_DrawNum (160, 64, dig, 3, 0);
2227 num = (int)cl.completed_time - dig*60;
2228 Sbar_DrawPic (234,64,sb_colon);
2229 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2230 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2232 // LA: Display as "a" instead of "a/b" if b is 0
2233 if(cl.stats[STAT_TOTALSECRETS])
2235 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2236 if (gamemode != GAME_NEXUIZ)
2237 Sbar_DrawPic (232, 104, sb_slash);
2238 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2242 Sbar_DrawNum (240, 104, cl.stats[STAT_SECRETS], 3, 0);
2245 if(cl.stats[STAT_TOTALMONSTERS])
2247 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2248 if (gamemode != GAME_NEXUIZ)
2249 Sbar_DrawPic (232, 144, sb_slash);
2250 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2254 Sbar_DrawNum (240, 144, cl.stats[STAT_MONSTERS], 3, 0);
2265 void Sbar_FinaleOverlay (void)
2267 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);