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)
1215 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, org);
1216 VectorSet(temp, 65536, 0, 0);
1217 Matrix4x4_Transform(&r_refdef.view.matrix, temp, dest);
1218 trace.hittexture = NULL; // to make sure
1219 // TODO change this trace to be stopped by anything "visible" (i.e. with a drawsurface), but not stuff like weapclip
1220 // probably needs adding a new SUPERCONTENTS type
1221 trace = CL_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, true, false, NULL, true, true);
1222 if(trace.hittexture)
1223 strlcpy(texstring, trace.hittexture->name, sizeof(texstring));
1225 strlcpy(texstring, "(no texture hit)", sizeof(texstring));
1232 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1233 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_strings*fps_scaley);
1234 fps_y = vid_conheight.integer - sbar_info_pos.integer - fps_strings*fps_scaley;
1237 fps_x = vid_conwidth.integer - DrawQ_TextWidth(soundstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1238 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1239 DrawQ_String(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1240 fps_y += fps_scaley;
1244 r_draw2d_force = true;
1245 fps_x = vid_conwidth.integer - DrawQ_TextWidth(fpsstring, 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);
1248 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1250 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1251 fps_y += fps_scaley;
1252 r_draw2d_force = false;
1254 if (timedemostring1[0])
1256 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring1, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1257 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1258 DrawQ_String(fps_x, fps_y, timedemostring1, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1259 fps_y += fps_scaley;
1261 if (timedemostring2[0])
1263 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring2, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1264 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1265 DrawQ_String(fps_x, fps_y, timedemostring2, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1266 fps_y += fps_scaley;
1270 fps_x = vid_conwidth.integer - DrawQ_TextWidth(timestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1271 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1272 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1273 fps_y += fps_scaley;
1277 fps_x = vid_conwidth.integer - DrawQ_TextWidth(datestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1278 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1279 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1280 fps_y += fps_scaley;
1284 fps_x = vid_conwidth.integer - DrawQ_TextWidth(speedstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1285 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1286 DrawQ_String(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1287 fps_y += fps_scaley;
1289 if (topspeedstring[0])
1291 fps_x = vid_conwidth.integer - DrawQ_TextWidth(topspeedstring, 0, fps_scalex, fps_scaley, false, FONT_INFOBAR);
1292 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1293 DrawQ_String(fps_x, fps_y, topspeedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR);
1294 fps_y += fps_scaley;
1298 fps_x = vid_conwidth.integer - DrawQ_TextWidth(blurstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1299 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1300 DrawQ_String(fps_x, fps_y, blurstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1301 fps_y += fps_scaley;
1305 fps_x = vid_conwidth.integer - DrawQ_TextWidth(texstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1306 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1307 DrawQ_String(fps_x, fps_y, texstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1308 fps_y += fps_scaley;
1313 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)
1316 c2 = bound(0, c2, 1);
1317 c1 = bound(0, c1, 1 - c2);
1319 r[1] = rangey + rangeheight * (c2 + c1);
1320 r[2] = rangey + rangeheight * (c2);
1324 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);
1326 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);
1328 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);
1330 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);
1338 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1339 extern cvar_t v_kicktime;
1340 void Sbar_Score (int margin);
1341 void Sbar_Draw (void)
1345 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1348 Sbar_DrawScoreboard ();
1349 else if (cl.intermission == 1)
1351 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1353 Sbar_DrawScoreboard();
1356 Sbar_IntermissionOverlay();
1358 else if (cl.intermission == 2)
1359 Sbar_FinaleOverlay();
1360 else if (gamemode == GAME_DELUXEQUAKE)
1363 else if (gamemode == GAME_SOM)
1365 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1366 Sbar_DrawScoreboard ();
1369 // this is the top left of the sbar area
1371 sbar_y = vid_conheight.integer - 24*3;
1374 if (cl.stats[STAT_ARMOR])
1376 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1377 Sbar_DrawPic(0, 0, somsb_armor[2]);
1378 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1379 Sbar_DrawPic(0, 0, somsb_armor[1]);
1380 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1381 Sbar_DrawPic(0, 0, somsb_armor[0]);
1382 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1386 Sbar_DrawPic(0, 24, somsb_health);
1387 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1390 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1391 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1392 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1393 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1394 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1395 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1396 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1397 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1398 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1399 if (cl.stats[STAT_SHELLS])
1400 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1403 else if (gamemode == GAME_NEXUIZ)
1405 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1407 sbar_x = (vid_conwidth.integer - 640)/2;
1408 sbar_y = vid_conheight.integer - 47;
1409 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1410 Sbar_DrawScoreboard ();
1412 else if (sb_lines && sbar_hudselector.integer == 1)
1416 int redflag, blueflag;
1419 sbar_x = (vid_conwidth.integer - 320)/2;
1420 sbar_y = vid_conheight.integer - 24 - 16;
1422 // calculate intensity to draw weapons bar at
1423 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1424 fade = bound(0.7, fade, 1);
1425 for (i = 0; i < 8;i++)
1426 if (cl.stats[STAT_ITEMS] & (1 << i))
1427 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1428 if((cl.stats[STAT_ITEMS] & (1<<12)))
1429 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1432 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1433 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1434 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1435 if (redflag == 3 && blueflag == 3)
1437 // The Impossible Combination[tm]
1438 // Can only happen in Key Hunt mode...
1439 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[14]);
1444 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64)), sb_items[redflag+10]);
1446 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[blueflag+14]);
1450 if (cl.stats[STAT_ARMOR] > 0)
1452 Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1453 if(cl.stats[STAT_ARMOR] > 200)
1454 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1455 else if(cl.stats[STAT_ARMOR] > 100)
1456 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1457 else if(cl.stats[STAT_ARMOR] > 50)
1458 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1459 else if(cl.stats[STAT_ARMOR] > 25)
1460 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1462 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1466 if (cl.stats[STAT_HEALTH] != 0)
1468 Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1469 if(cl.stats[STAT_HEALTH] > 200)
1470 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1471 else if(cl.stats[STAT_HEALTH] > 100)
1472 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1473 else if(cl.stats[STAT_HEALTH] > 50)
1474 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1475 else if(cl.stats[STAT_HEALTH] > 25)
1476 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1478 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1482 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1484 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1485 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1486 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1487 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1488 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1489 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1490 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1491 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1492 if(cl.stats[STAT_AMMO] > 10)
1493 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1495 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1498 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1499 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1502 // The margin can be at most 8 to support 640x480 console size:
1503 // 320 + 2 * (144 + 16) = 640
1509 int redflag, blueflag;
1512 sbar_x = (vid_conwidth.integer - 640)/2;
1513 sbar_y = vid_conheight.integer - 47;
1515 // calculate intensity to draw weapons bar at
1516 fade = 3 - 2 * (cl.time - cl.weapontime);
1519 fade = min(fade, 1);
1520 for (i = 0; i < 8;i++)
1521 if (cl.stats[STAT_ITEMS] & (1 << i))
1522 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1524 if((cl.stats[STAT_ITEMS] & (1<<12)))
1525 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1528 //if (!cl.islocalgame)
1529 // Sbar_DrawFrags ();
1532 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1534 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1537 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1538 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1539 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1540 if (redflag == 3 && blueflag == 3)
1542 // The Impossible Combination[tm]
1543 // Can only happen in Key Hunt mode...
1544 Sbar_DrawPic ((int) x, -179, sb_items[14]);
1549 Sbar_DrawPic ((int) x, -117, sb_items[redflag+10]);
1551 Sbar_DrawPic ((int) x, -177, sb_items[blueflag+14]);
1555 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1558 if(cl.stats[STAT_HEALTH] > 100)
1559 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1560 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1561 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1563 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1565 // AK dont draw ammo for the laser
1566 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1568 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1569 Sbar_DrawPic (519, 0, sb_ammo[0]);
1570 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1571 Sbar_DrawPic (519, 0, sb_ammo[1]);
1572 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1573 Sbar_DrawPic (519, 0, sb_ammo[2]);
1574 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1575 Sbar_DrawPic (519, 0, sb_ammo[3]);
1577 if(cl.stats[STAT_AMMO] <= 10)
1578 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1580 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1585 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1587 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1588 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1593 // Mini scoreboard uses 12*4 per other team, that is, 144
1594 // pixels when there are four teams...
1595 // Nexuiz by default sets vid_conwidth to 800... makes
1597 // so we need to shift it by 64 pixels to the right to fit
1598 // BUT: then it overlaps with the image that gets drawn
1599 // for viewsize 100! Therefore, just account for 3 teams,
1600 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1604 else if (gamemode == GAME_ZYMOTIC)
1607 float scale = 64.0f / 256.0f;
1608 float kickoffset[3];
1609 VectorClear(kickoffset);
1612 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1613 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1615 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1616 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1617 // left1 16, 48 : 126 -66
1618 // left2 16, 128 : 196 -66
1619 // right 176, 48 : 196 -136
1620 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);
1621 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);
1622 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);
1623 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1625 float scale = 128.0f / 256.0f;
1626 float healthstart, healthheight, healthstarttc, healthendtc;
1627 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1628 float ammostart, ammoheight, ammostarttc, ammoendtc;
1629 float clipstart, clipheight, clipstarttc, clipendtc;
1630 float kickoffset[3], offset;
1631 VectorClear(kickoffset);
1634 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1635 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1637 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1638 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1639 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1640 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);
1641 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);
1642 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);
1643 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);
1644 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1645 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1646 healthstart = 204 - healthheight;
1647 shieldstart = healthstart - shieldheight;
1648 healthstarttc = healthstart * (1.0f / 256.0f);
1649 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1650 shieldstarttc = shieldstart * (1.0f / 256.0f);
1651 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1652 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1653 ammostart = 114 - ammoheight;
1654 ammostarttc = ammostart * (1.0f / 256.0f);
1655 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1656 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1657 clipstart = 190 - clipheight;
1658 clipstarttc = clipstart * (1.0f / 256.0f);
1659 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1660 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);
1661 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);
1662 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);
1663 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);
1664 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1665 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1668 else // Quake and others
1670 sbar_x = (vid_conwidth.integer - 320)/2;
1671 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1672 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1673 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1677 if (gamemode != GAME_GOODVSBAD2)
1678 Sbar_DrawInventory ();
1679 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1683 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1685 if (gamemode != GAME_GOODVSBAD2)
1686 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1687 Sbar_DrawScoreboard ();
1691 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1693 // keys (hipnotic only)
1694 //MED 01/04/97 moved keys here so they would not be overwritten
1695 if (gamemode == GAME_HIPNOTIC)
1697 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1698 Sbar_DrawPic (209, 3, sb_items[0]);
1699 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1700 Sbar_DrawPic (209, 12, sb_items[1]);
1703 if (gamemode != GAME_GOODVSBAD2)
1705 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1707 Sbar_DrawNum (24, 0, 666, 3, 1);
1708 Sbar_DrawPic (0, 0, sb_disc);
1712 if (gamemode == GAME_ROGUE)
1714 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1715 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1716 Sbar_DrawPic (0, 0, sb_armor[2]);
1717 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1718 Sbar_DrawPic (0, 0, sb_armor[1]);
1719 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1720 Sbar_DrawPic (0, 0, sb_armor[0]);
1724 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1725 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1726 Sbar_DrawPic (0, 0, sb_armor[2]);
1727 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1728 Sbar_DrawPic (0, 0, sb_armor[1]);
1729 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1730 Sbar_DrawPic (0, 0, sb_armor[0]);
1739 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1742 if (gamemode == GAME_ROGUE)
1744 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1745 Sbar_DrawPic (224, 0, sb_ammo[0]);
1746 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1747 Sbar_DrawPic (224, 0, sb_ammo[1]);
1748 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1749 Sbar_DrawPic (224, 0, sb_ammo[2]);
1750 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1751 Sbar_DrawPic (224, 0, sb_ammo[3]);
1752 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1753 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1754 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1755 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1756 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1757 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1761 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1762 Sbar_DrawPic (224, 0, sb_ammo[0]);
1763 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1764 Sbar_DrawPic (224, 0, sb_ammo[1]);
1765 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1766 Sbar_DrawPic (224, 0, sb_ammo[2]);
1767 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1768 Sbar_DrawPic (224, 0, sb_ammo[3]);
1771 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1773 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1774 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1776 if (gamemode == GAME_TRANSFUSION)
1777 Sbar_MiniDeathmatchOverlay (0, 0);
1779 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1786 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1788 pic = Draw_CachePic (va("gfx/crosshair%i", crosshair.integer));
1789 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);
1792 if (cl_prydoncursor.integer > 0)
1793 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);
1796 //=============================================================================
1800 Sbar_DeathmatchOverlay
1804 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1807 qboolean myself = false;
1809 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1811 if((s - cl.scores) == cl.playerentity - 1)
1813 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1814 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1817 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1819 if (s->qw_spectator)
1821 if (s->qw_ping || s->qw_packetloss)
1822 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 );
1824 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 );
1828 // draw colors behind score
1834 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1835 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);
1836 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1837 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);
1839 //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);
1840 if (s->qw_ping || s->qw_packetloss)
1841 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 );
1843 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 );
1848 if (s->qw_spectator)
1850 if (s->qw_ping || s->qw_packetloss)
1851 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 );
1853 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 );
1857 // draw colors behind score
1858 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1859 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);
1860 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1861 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);
1863 //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);
1864 if (s->qw_ping || s->qw_packetloss)
1865 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 );
1867 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 );
1873 void Sbar_DeathmatchOverlay (void)
1875 int i, y, xmin, xmax, ymin, ymax;
1877 // request new ping times every two second
1878 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1880 cl.last_ping_request = realtime;
1881 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1883 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1884 MSG_WriteString(&cls.netcon->message, "pings");
1886 else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6/* || cls.protocol == PROTOCOL_DARKPLACES7*/)
1888 // these servers usually lack the pings command and so a less efficient "ping" command must be sent, which on modern DP servers will also reply with a pingplreport command after the ping listing
1889 static int ping_anyway_counter = 0;
1890 if(cl.parsingtextexpectingpingforscores == 1)
1892 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1893 if(++ping_anyway_counter >= 5)
1894 cl.parsingtextexpectingpingforscores = 0;
1896 if(cl.parsingtextexpectingpingforscores != 1)
1898 ping_anyway_counter = 0;
1899 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1900 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1901 MSG_WriteString(&cls.netcon->message, "ping");
1906 // newer server definitely has pings command, so use it for more efficiency, avoids ping reports spamming the console if they are misparsed, and saves a little bandwidth
1907 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1908 MSG_WriteString(&cls.netcon->message, "pings");
1916 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1918 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1919 xmin = (int) (vid_conwidth.integer - (26 + 15) * 8 * FONT_SBAR->maxwidth) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1921 xmin = (int) (vid_conwidth.integer - (16 + 25) * 8 * FONT_SBAR->maxwidth) / 2; // 16 characters until name, then we assume 25 character names (they can be longer but usually aren't)
1922 xmax = vid_conwidth.integer - xmin;
1924 if(gamemode == GAME_NEXUIZ)
1925 DrawQ_Pic (xmin - 8, ymin - 8, 0, xmax-xmin+1 + 2*8, ymax-ymin+1 + 2*8, 0, 0, 0, sbar_alpha_bg.value, 0);
1927 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1931 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1933 DrawQ_String(xmin, y, va("ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1937 DrawQ_String(xmin, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1941 if (Sbar_IsTeammatch ())
1943 // show team scores first
1944 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1945 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1949 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1950 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1955 Sbar_MiniDeathmatchOverlay
1959 void Sbar_MiniDeathmatchOverlay (int x, int y)
1961 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1963 // do not draw this if sbar_miniscoreboard_size is zero
1964 if(sbar_miniscoreboard_size.value == 0)
1966 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1967 if(sbar_miniscoreboard_size.value > 0)
1968 y = (int) (vid_conheight.integer - sbar_miniscoreboard_size.value * 8);
1973 // decide where to print
1974 if (gamemode == GAME_TRANSFUSION)
1975 numlines = (vid_conwidth.integer - x + 127) / 128;
1977 numlines = (vid_conheight.integer - y + 7) / 8;
1979 // give up if there isn't room
1980 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1984 for (i = 0; i < scoreboardlines; i++)
1985 if (fragsort[i] == cl.playerentity - 1)
1989 range_end = scoreboardlines;
1992 if (gamemode != GAME_TRANSFUSION)
1993 if (Sbar_IsTeammatch ())
1995 // reserve space for the team scores
1996 numlines -= teamlines;
1998 // find first and last player of my team (only draw the team totals and my own team)
1999 range_begin = range_end = i;
2000 myteam = cl.scores[fragsort[i]].colors & 15;
2001 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
2003 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
2006 // looks better than two players
2016 i = min(i, range_end - numlines);
2017 i = max(i, range_begin);
2019 if (gamemode == GAME_TRANSFUSION)
2021 for (;i < range_end && x < vid_conwidth.integer;i++)
2022 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2026 if(range_end - i < numlines) // won't draw to bottom?
2027 y += 8 * (numlines - (range_end - i)); // bottom align
2028 // show team scores first
2029 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
2030 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
2032 for (;i < range_end && y < vid_conheight.integer;i++)
2033 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
2037 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
2039 static int const sortorder[16] =
2058 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
2059 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
2060 int tc1 = sortorder[t1->colors & 15];
2061 int tc2 = sortorder[t2->colors & 15];
2065 void Sbar_Score (int margin)
2067 int i, me, score, otherleader, place, distribution, minutes, seconds;
2069 int sbar_x_save = sbar_x;
2070 int sbar_y_save = sbar_y;
2073 sbar_y = (int) (vid_conheight.value - (32+12));
2076 me = cl.playerentity - 1;
2077 if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients)
2079 if(Sbar_IsTeammatch())
2083 // team1 team3 team4
2087 scoreboard_t *teamcolorsort[16];
2090 for(i = 0; i < teamlines; ++i)
2091 teamcolorsort[i] = &(teams[i]);
2093 // Now sort them by color
2094 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
2097 // -12*4: four digits space
2098 place = (teamlines - 1) * (-12 * 4);
2100 for(i = 0; i < teamlines; ++i)
2102 int cindex = teamcolorsort[i]->colors & 15;
2103 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
2104 float cm = max(max(c[0], c[1]), c[2]);
2105 float cr = c[0] / cm;
2106 float cg = c[1] / cm;
2107 float cb = c[2] / cm;
2108 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
2110 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
2114 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
2127 // find leading score other than ourselves, to calculate distribution
2128 // find our place in the scoreboard
2129 score = cl.scores[me].frags;
2130 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
2132 if (cl.scores[i].name[0] && i != me)
2134 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
2136 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
2140 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
2142 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2143 else if (place == 2)
2144 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2146 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2147 if (otherleader < 0)
2148 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2149 if (distribution >= 0)
2151 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2152 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2154 else if (distribution >= -5)
2156 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2157 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2161 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2162 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2167 if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT])
2169 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2170 minutes = (int)floor(timeleft / 60);
2171 seconds = (int)(floor(timeleft) - minutes * 60);
2174 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2175 if(sb_colon && sb_colon->tex != r_texture_notexture)
2176 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2177 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2179 else if (minutes >= 1)
2181 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2182 if(sb_colon && sb_colon->tex != r_texture_notexture)
2183 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2184 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2186 else if ((int)(timeleft * 4) & 1)
2187 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2189 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2191 else if (sbar_gametime.integer)
2193 minutes = (int)floor(cl.time / 60);
2194 seconds = (int)(floor(cl.time) - minutes * 60);
2195 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2196 if(sb_colon && sb_colon->tex != r_texture_notexture)
2197 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2198 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2201 sbar_x = sbar_x_save;
2202 sbar_y = sbar_y_save;
2207 Sbar_IntermissionOverlay
2211 void Sbar_IntermissionOverlay (void)
2216 if (cl.gametype == GAME_DEATHMATCH)
2218 Sbar_DeathmatchOverlay ();
2222 sbar_x = (vid_conwidth.integer - 320) >> 1;
2223 sbar_y = (vid_conheight.integer - 200) >> 1;
2225 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2226 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2229 dig = (int)cl.completed_time / 60;
2230 Sbar_DrawNum (160, 64, dig, 3, 0);
2231 num = (int)cl.completed_time - dig*60;
2232 Sbar_DrawPic (234,64,sb_colon);
2233 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2234 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2236 // LA: Display as "a" instead of "a/b" if b is 0
2237 if(cl.stats[STAT_TOTALSECRETS])
2239 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2240 if (gamemode != GAME_NEXUIZ)
2241 Sbar_DrawPic (232, 104, sb_slash);
2242 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2246 Sbar_DrawNum (240, 104, cl.stats[STAT_SECRETS], 3, 0);
2249 if(cl.stats[STAT_TOTALMONSTERS])
2251 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2252 if (gamemode != GAME_NEXUIZ)
2253 Sbar_DrawPic (232, 144, sb_slash);
2254 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2258 Sbar_DrawNum (240, 144, cl.stats[STAT_MONSTERS], 3, 0);
2269 void Sbar_FinaleOverlay (void)
2271 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);