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
26 #define STAT_MINUS 10 // num frame for '-' stats digit
27 cachepic_t *sb_nums[2][11];
28 cachepic_t *sb_colon, *sb_slash;
31 cachepic_t *sb_scorebar;
32 // AK only used by NEX
33 cachepic_t *sb_sbar_minimal;
34 cachepic_t *sb_sbar_overlay;
36 // AK changed the bound to 9
37 cachepic_t *sb_weapons[7][9]; // 0 is active, 1 is owned, 2-5 are flashes
38 cachepic_t *sb_ammo[4];
39 cachepic_t *sb_sigil[4];
40 cachepic_t *sb_armor[3];
41 cachepic_t *sb_items[32];
43 // 0-4 are based on health (in 20 increments)
44 // 0 is static, 1 is temporary animation
45 cachepic_t *sb_faces[5][2];
46 cachepic_t *sb_health; // GAME_NEXUIZ
48 cachepic_t *sb_face_invis;
49 cachepic_t *sb_face_quad;
50 cachepic_t *sb_face_invuln;
51 cachepic_t *sb_face_invis_invuln;
53 qboolean sb_showscores;
55 int sb_lines; // scan lines to draw
57 cachepic_t *rsb_invbar[2];
58 cachepic_t *rsb_weapons[5];
59 cachepic_t *rsb_items[2];
60 cachepic_t *rsb_ammo[3];
61 cachepic_t *rsb_teambord; // PGM 01/19/97 - team color border
63 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
64 cachepic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
65 //MED 01/04/97 added array to simplify weapon parsing
66 int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
67 //MED 01/04/97 added hipnotic items array
68 cachepic_t *hsb_items[2];
71 cachepic_t *somsb_health;
72 cachepic_t *somsb_ammo[4];
73 cachepic_t *somsb_armor[3];
75 cachepic_t *zymsb_crosshair_center;
76 cachepic_t *zymsb_crosshair_line;
77 cachepic_t *zymsb_crosshair_health;
78 cachepic_t *zymsb_crosshair_ammo;
79 cachepic_t *zymsb_crosshair_clip;
80 cachepic_t *zymsb_crosshair_background;
81 cachepic_t *zymsb_crosshair_left1;
82 cachepic_t *zymsb_crosshair_left2;
83 cachepic_t *zymsb_crosshair_right;
85 cachepic_t *sb_ranking;
86 cachepic_t *sb_complete;
88 cachepic_t *sb_finale;
90 cvar_t showfps = {CVAR_SAVE, "showfps", "0", "shows your rendered fps (frames per second)"};
91 cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"};
92 cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"};
93 cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"};
94 cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"};
95 cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
96 cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
97 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)"};
98 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"};
100 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
102 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
103 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
104 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
105 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
106 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
108 void Sbar_MiniDeathmatchOverlay (int x, int y);
109 void Sbar_DeathmatchOverlay (void);
110 void Sbar_IntermissionOverlay (void);
111 void Sbar_FinaleOverlay (void);
113 void CL_VM_UpdateShowingScoresState (int showingscores);
123 void Sbar_ShowScores (void)
127 sb_showscores = true;
128 CL_VM_UpdateShowingScoresState(sb_showscores);
138 void Sbar_DontShowScores (void)
140 sb_showscores = false;
141 CL_VM_UpdateShowingScoresState(sb_showscores);
144 void sbar_start(void)
148 if (gamemode == GAME_NETHERWORLD)
151 else if (gamemode == GAME_SOM)
153 sb_disc = Draw_CachePic("gfx/disc", true);
155 for (i = 0;i < 10;i++)
156 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
158 somsb_health = Draw_CachePic("gfx/hud_health", true);
159 somsb_ammo[0] = Draw_CachePic("gfx/sb_shells", true);
160 somsb_ammo[1] = Draw_CachePic("gfx/sb_nails", true);
161 somsb_ammo[2] = Draw_CachePic("gfx/sb_rocket", true);
162 somsb_ammo[3] = Draw_CachePic("gfx/sb_cells", true);
163 somsb_armor[0] = Draw_CachePic("gfx/sb_armor1", true);
164 somsb_armor[1] = Draw_CachePic("gfx/sb_armor2", true);
165 somsb_armor[2] = Draw_CachePic("gfx/sb_armor3", true);
167 else if (gamemode == GAME_NEXUIZ)
169 for (i = 0;i < 10;i++)
170 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
171 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
172 sb_colon = Draw_CachePic ("gfx/num_colon", true);
174 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
175 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets", true);
176 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
177 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
179 sb_armor[0] = Draw_CachePic ("gfx/sb_armor", true);
183 sb_health = Draw_CachePic ("gfx/sb_health", true);
185 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo", true);
186 sb_items[3] = Draw_CachePic ("gfx/sb_invinc", true);
187 sb_items[4] = Draw_CachePic ("gfx/sb_energy", true);
188 sb_items[5] = Draw_CachePic ("gfx/sb_str", true);
190 sb_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken", true);
191 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost", true);
192 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying", true);
193 sb_items[14] = Draw_CachePic ("gfx/sb_key_carrying", true);
194 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken", true);
195 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost", true);
196 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying", true);
198 sb_sbar = Draw_CachePic("gfx/sbar", true);
199 sb_sbar_minimal = Draw_CachePic("gfx/sbar_minimal", true);
200 sb_sbar_overlay = Draw_CachePic("gfx/sbar_overlay", true);
202 for(i = 0; i < 9;i++)
203 sb_weapons[0][i] = Draw_CachePic(va("gfx/inv_weapon%i",i), true);
205 else if (gamemode == GAME_ZYMOTIC)
207 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center", true);
208 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line", true);
209 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health", true);
210 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip", true);
211 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo", true);
212 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background", true);
213 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1", true);
214 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2", true);
215 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right", true);
219 sb_disc = Draw_CachePic("gfx/disc", true);
221 for (i = 0;i < 10;i++)
223 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
224 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i), true);
227 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
228 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus", true);
230 sb_colon = Draw_CachePic ("gfx/num_colon", true);
231 sb_slash = Draw_CachePic ("gfx/num_slash", true);
233 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun", true);
234 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun", true);
235 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun", true);
236 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun", true);
237 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch", true);
238 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch", true);
239 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng", true);
241 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun", true);
242 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun", true);
243 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun", true);
244 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun", true);
245 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch", true);
246 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch", true);
247 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng", true);
249 for (i = 0;i < 5;i++)
251 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1), true);
252 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1), true);
253 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1), true);
254 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1), true);
255 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1), true);
256 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1), true);
257 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1), true);
260 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
261 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails", true);
262 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
263 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
265 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1", true);
266 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2", true);
267 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3", true);
269 sb_items[0] = Draw_CachePic ("gfx/sb_key1", true);
270 sb_items[1] = Draw_CachePic ("gfx/sb_key2", true);
271 sb_items[2] = Draw_CachePic ("gfx/sb_invis", true);
272 sb_items[3] = Draw_CachePic ("gfx/sb_invuln", true);
273 sb_items[4] = Draw_CachePic ("gfx/sb_suit", true);
274 sb_items[5] = Draw_CachePic ("gfx/sb_quad", true);
276 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1", true);
277 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2", true);
278 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3", true);
279 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4", true);
281 sb_faces[4][0] = Draw_CachePic ("gfx/face1", true);
282 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1", true);
283 sb_faces[3][0] = Draw_CachePic ("gfx/face2", true);
284 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2", true);
285 sb_faces[2][0] = Draw_CachePic ("gfx/face3", true);
286 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3", true);
287 sb_faces[1][0] = Draw_CachePic ("gfx/face4", true);
288 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4", true);
289 sb_faces[0][0] = Draw_CachePic ("gfx/face5", true);
290 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5", true);
292 sb_face_invis = Draw_CachePic ("gfx/face_invis", true);
293 sb_face_invuln = Draw_CachePic ("gfx/face_invul2", true);
294 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2", true);
295 sb_face_quad = Draw_CachePic ("gfx/face_quad", true);
297 sb_sbar = Draw_CachePic ("gfx/sbar", true);
298 sb_ibar = Draw_CachePic ("gfx/ibar", true);
299 sb_scorebar = Draw_CachePic ("gfx/scorebar", true);
301 //MED 01/04/97 added new hipnotic weapons
302 if (gamemode == GAME_HIPNOTIC)
304 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser", true);
305 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir", true);
306 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox", true);
307 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren", true);
308 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox", true);
310 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser", true);
311 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir", true);
312 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox", true);
313 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren", true);
314 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox", true);
316 for (i = 0;i < 5;i++)
318 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1), true);
319 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1), true);
320 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1), true);
321 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1), true);
322 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1), true);
325 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit", true);
326 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld", true);
328 else if (gamemode == GAME_ROGUE)
330 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1", true);
331 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2", true);
333 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava", true);
334 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava", true);
335 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren", true);
336 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock", true);
337 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma", true);
339 rsb_items[0] = Draw_CachePic ("gfx/r_shield1", true);
340 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1", true);
342 // PGM 01/19/97 - team color border
343 rsb_teambord = Draw_CachePic ("gfx/r_teambord", true);
344 // PGM 01/19/97 - team color border
346 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava", true);
347 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti", true);
348 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma", true);
352 sb_ranking = Draw_CachePic ("gfx/ranking", true);
353 sb_complete = Draw_CachePic ("gfx/complete", true);
354 sb_inter = Draw_CachePic ("gfx/inter", true);
355 sb_finale = Draw_CachePic ("gfx/finale", true);
358 void sbar_shutdown(void)
362 void sbar_newmap(void)
366 void Sbar_Init (void)
368 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
369 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
370 Cvar_RegisterVariable(&showfps);
371 Cvar_RegisterVariable(&showtime);
372 Cvar_RegisterVariable(&showtime_format);
373 Cvar_RegisterVariable(&showdate);
374 Cvar_RegisterVariable(&showdate_format);
375 Cvar_RegisterVariable(&sbar_alpha_bg);
376 Cvar_RegisterVariable(&sbar_alpha_fg);
377 Cvar_RegisterVariable(&sbar_hudselector);
378 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
379 Cvar_RegisterVariable(&cl_deathscoreboard);
381 Cvar_RegisterVariable(&crosshair_color_red);
382 Cvar_RegisterVariable(&crosshair_color_green);
383 Cvar_RegisterVariable(&crosshair_color_blue);
384 Cvar_RegisterVariable(&crosshair_color_alpha);
385 Cvar_RegisterVariable(&crosshair_size);
387 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
391 //=============================================================================
393 // drawing routines are relative to the status bar location
402 void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
404 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
407 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
409 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
412 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
414 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
421 Draws one solid graphics character
424 void Sbar_DrawCharacter (int x, int y, int num)
426 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);
434 void Sbar_DrawString (int x, int y, char *str)
436 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false);
444 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
449 l = sprintf(str, "%i", num);
463 Sbar_DrawPic (x, y, sb_nums[color][frame]);
476 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
484 l = sprintf(str, "%0*i", digits, num);
487 l = sprintf(str, "%i", num);
492 x += (digits-l) * lettersize;
501 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
508 //=============================================================================
511 int Sbar_IsTeammatch()
513 // currently only nexuiz uses the team score board
514 return ((gamemode == GAME_NEXUIZ)
515 && (teamplay.integer > 0));
523 static int fragsort[MAX_SCOREBOARD];
524 static int scoreboardlines;
526 //[515]: Sbar_GetPlayer for csqc "getplayerkey" func
527 int Sbar_GetPlayer (int index)
532 if(index >= scoreboardlines)
534 index = fragsort[index];
536 if(index >= scoreboardlines)
541 static scoreboard_t teams[MAX_SCOREBOARD];
542 static int teamsort[MAX_SCOREBOARD];
543 static int teamlines;
544 void Sbar_SortFrags (void)
550 for (i=0 ; i<cl.maxclients ; i++)
552 if (cl.scores[i].name[0])
554 fragsort[scoreboardlines] = i;
559 for (i=0 ; i<scoreboardlines ; i++)
560 for (j=0 ; j<scoreboardlines-1-i ; j++)
561 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
564 fragsort[j] = fragsort[j+1];
569 if (Sbar_IsTeammatch ())
571 // now sort players by teams.
572 for (i=0 ; i<scoreboardlines ; i++)
574 for (j=0 ; j<scoreboardlines-1-i ; j++)
576 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
579 fragsort[j] = fragsort[j+1];
585 // calculate team scores
587 for (i=0 ; i<scoreboardlines ; i++)
589 if (color != (cl.scores[fragsort[i]].colors & 15))
591 const char* teamname;
593 color = cl.scores[fragsort[i]].colors & 15;
599 teamname = "^1Red Team";
602 teamname = "^4Blue Team";
605 teamname = "^6Pink Team";
608 teamname = "^3Yellow Team";
611 teamname = "Total Team Score";
614 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
616 teams[teamlines-1].frags = 0;
617 teams[teamlines-1].colors = color + 16 * color;
620 if (cl.scores[fragsort[i]].frags != -666)
622 // do not add spedcators
623 // (ugly hack for nexuiz)
624 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
628 // now sort teams by scores.
629 for (i=0 ; i<teamlines ; i++)
631 for (i=0 ; i<teamlines ; i++)
633 for (j=0 ; j<teamlines-1-i ; j++)
635 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
638 teamsort[j] = teamsort[j+1];
651 void Sbar_SoloScoreboard (void)
654 char str[80], timestr[40];
656 int minutes, seconds;
659 t = (cl.intermission ? cl.completed_time : cl.time);
660 minutes = (int)(t / 60);
661 seconds = (int)(t - 60*floor(t/60));
663 // monsters and secrets are now both on the top row
664 if (cl.stats[STAT_TOTALMONSTERS])
665 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
666 if (cl.stats[STAT_TOTALSECRETS])
667 Sbar_DrawString(8+22*8, 4, va("Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
669 // figure out the map's filename without path or extension
670 strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
671 if (strrchr(str, '.'))
672 *(strrchr(str, '.')) = 0;
674 // append a : separator and then the full title
675 strlcat(str, ":", sizeof(str));
676 strlcat(str, cl.levelname, sizeof(str));
678 // if there's a newline character, terminate the string there
679 if (strchr(str, '\n'))
680 *(strchr(str, '\n')) = 0;
682 // make the time string
683 timelen = sprintf(timestr, " %i:%02i", minutes, seconds);
685 // truncate the level name if necessary to make room for time
687 if ((int)strlen(str) > max)
690 // print the filename and message
691 Sbar_DrawString(8, 12, str);
694 Sbar_DrawString(8 + max*8, 12, timestr);
698 int minutes, seconds, tens, units;
701 if (gamemode != GAME_NEXUIZ) {
702 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
703 Sbar_DrawString (8, 4, str);
705 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
706 Sbar_DrawString (8, 12, str);
710 minutes = (int)(cl.time / 60);
711 seconds = (int)(cl.time - 60*minutes);
713 units = seconds - 10*tens;
714 sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
715 Sbar_DrawString (184, 4, str);
718 if (gamemode == GAME_NEXUIZ) {
719 l = (int) strlen (cl.worldmodel->name);
720 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
722 l = (int) strlen (cl.levelname);
723 Sbar_DrawString (232 - l*4, 12, cl.levelname);
733 void Sbar_DrawScoreboard (void)
735 Sbar_SoloScoreboard ();
736 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
737 //if (cl.gametype == GAME_DEATHMATCH)
739 Sbar_DeathmatchOverlay ();
742 //=============================================================================
744 // AK to make DrawInventory smaller
745 static void Sbar_DrawWeapon(int nr, float fade, int active)
747 if (sbar_hudselector.integer == 1)
749 // width = 300, height = 100
750 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
752 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);
753 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);
757 // width = 300, height = 100
758 const int w_width = 300, w_height = 100, w_space = 10;
759 const float w_scale = 0.4;
761 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);
762 //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);
771 void Sbar_DrawInventory (void)
778 if (gamemode == GAME_ROGUE)
780 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
781 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
783 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
786 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
789 for (i=0 ; i<7 ; i++)
791 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
793 time = cl.item_gettime[i];
794 flashon = (int)(max(0, cl.time - time)*10);
797 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
803 flashon = (flashon%5) + 2;
805 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
811 if (gamemode == GAME_HIPNOTIC)
813 int grenadeflashing=0;
814 for (i=0 ; i<4 ; i++)
816 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
818 time = max(0, cl.item_gettime[hipweapons[i]]);
819 flashon = (int)((cl.time - time)*10);
822 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
828 flashon = (flashon%5) + 2;
830 // check grenade launcher
833 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
838 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
844 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
846 if (!grenadeflashing)
847 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
850 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
853 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
858 if (gamemode == GAME_ROGUE)
860 // check for powered up weapon.
861 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
863 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
864 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
868 for (i=0 ; i<4 ; i++)
870 sprintf (num, "%4i",cl.stats[STAT_SHELLS+i] );
872 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
874 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
876 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
878 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
882 for (i=0 ; i<6 ; i++)
883 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
885 //MED 01/04/97 changed keys
886 if (gamemode != GAME_HIPNOTIC || (i>1))
887 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
890 //MED 01/04/97 added hipnotic items
892 if (gamemode == GAME_HIPNOTIC)
894 for (i=0 ; i<2 ; i++)
895 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
896 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
899 if (gamemode == GAME_ROGUE)
902 for (i=0 ; i<2 ; i++)
903 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
904 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
909 for (i=0 ; i<4 ; i++)
910 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
911 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
915 //=============================================================================
922 void Sbar_DrawFrags (void)
932 l = min(scoreboardlines, 4);
936 for (i = 0;i < l;i++)
942 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
943 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
944 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
945 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
949 sprintf (num, "%3i",f);
951 if (k == cl.viewentity - 1)
953 Sbar_DrawCharacter ( x + 2, -24, 16);
954 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
956 Sbar_DrawCharacter (x + 8, -24, num[0]);
957 Sbar_DrawCharacter (x + 16, -24, num[1]);
958 Sbar_DrawCharacter (x + 24, -24, num[2]);
963 //=============================================================================
971 void Sbar_DrawFace (void)
975 // PGM 01/19/97 - team color drawing
976 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
977 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
983 s = &cl.scores[cl.viewentity - 1];
985 Sbar_DrawPic (112, 0, rsb_teambord);
986 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
987 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
988 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
989 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
993 sprintf (num, "%3i",f);
995 if ((s->colors & 0xf0)==0)
998 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1000 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1002 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1006 Sbar_DrawCharacter ( 109, 3, num[0]);
1007 Sbar_DrawCharacter ( 116, 3, num[1]);
1008 Sbar_DrawCharacter ( 123, 3, num[2]);
1013 // PGM 01/19/97 - team color drawing
1015 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1016 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1017 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1018 Sbar_DrawPic (112, 0, sb_face_quad );
1019 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1020 Sbar_DrawPic (112, 0, sb_face_invis );
1021 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1022 Sbar_DrawPic (112, 0, sb_face_invuln);
1025 f = cl.stats[STAT_HEALTH] / 20;
1027 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1031 void Sbar_ShowFPS(void)
1033 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1035 char timestring[32];
1036 char datestring[32];
1037 qboolean red = false;
1041 if (showfps.integer)
1044 static double nexttime = 0, lasttime = 0;
1045 static double framerate = 0;
1046 static int framecount = 0;
1049 if (newtime >= nexttime)
1051 framerate = framecount / (newtime - lasttime);
1053 nexttime = max(nexttime + 1, lasttime - 1);
1059 if ((red = (calc < 1.0f)))
1060 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1062 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1064 if (showtime.integer)
1065 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1066 if (showdate.integer)
1067 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1068 if (fpsstring[0] || timestring[0])
1072 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
1073 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1074 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1075 fps_y = vid_conheight.integer - fps_height;
1078 fps_x = vid_conwidth.integer - fps_scalex * strlen(fpsstring);
1079 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(fpsstring), fps_scaley, 0, 0, 0, 0.5, 0);
1081 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true);
1083 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1084 fps_y += fps_scaley;
1088 fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
1089 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(timestring), fps_scaley, 0, 0, 0, 0.5, 0);
1090 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1091 fps_y += fps_scaley;
1095 fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
1096 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(datestring), fps_scaley, 0, 0, 0, 0.5, 0);
1097 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1098 fps_y += fps_scaley;
1103 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)
1106 c2 = bound(0, c2, 1);
1107 c1 = bound(0, c1, 1 - c2);
1109 r[1] = rangey + rangeheight * (c2 + c1);
1110 r[2] = rangey + rangeheight * (c2);
1114 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);
1116 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);
1118 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);
1120 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);
1128 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1129 extern cvar_t v_kicktime;
1130 void Sbar_Score (int margin);
1131 void Sbar_Draw (void)
1135 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1138 Sbar_DrawScoreboard ();
1139 else if (cl.intermission == 1)
1141 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1143 Sbar_DrawScoreboard();
1146 Sbar_IntermissionOverlay();
1148 else if (cl.intermission == 2)
1149 Sbar_FinaleOverlay();
1150 else if (gamemode == GAME_NETHERWORLD)
1153 else if (gamemode == GAME_SOM)
1155 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1156 Sbar_DrawScoreboard ();
1159 // this is the top left of the sbar area
1161 sbar_y = vid_conheight.integer - 24*3;
1164 if (cl.stats[STAT_ARMOR])
1166 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1167 Sbar_DrawPic(0, 0, somsb_armor[2]);
1168 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1169 Sbar_DrawPic(0, 0, somsb_armor[1]);
1170 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1171 Sbar_DrawPic(0, 0, somsb_armor[0]);
1172 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1176 Sbar_DrawPic(0, 24, somsb_health);
1177 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1180 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1181 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1182 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1183 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1184 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1185 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1186 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1187 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1188 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1189 if (cl.stats[STAT_SHELLS])
1190 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1193 else if (gamemode == GAME_NEXUIZ)
1195 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1197 sbar_x = (vid_conwidth.integer - 640)/2;
1198 sbar_y = vid_conheight.integer - 47;
1199 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1200 Sbar_DrawScoreboard ();
1202 else if (sb_lines && sbar_hudselector.integer == 1)
1206 int redflag, blueflag;
1208 sbar_x = (vid_conwidth.integer - 320)/2;
1209 sbar_y = vid_conheight.integer - 24 - 16;
1211 // calculate intensity to draw weapons bar at
1212 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1213 fade = bound(0.7, fade, 1);
1214 for (i = 0; i < 8;i++)
1215 if (cl.stats[STAT_ITEMS] & (1 << i))
1216 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1217 if((cl.stats[STAT_ITEMS] & (1<<12)))
1218 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1221 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1222 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1223 if (redflag == 3 && blueflag == 3)
1225 // The Impossible Combination[tm]
1226 // Can only happen in Key Hunt mode...
1227 Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1232 Sbar_DrawPic (10 - sbar_x, -117, sb_items[redflag+10]);
1234 Sbar_DrawPic (10 - sbar_x, -177, sb_items[blueflag+14]);
1238 if (cl.stats[STAT_ARMOR] > 0)
1240 Sbar_DrawStretchPic (0, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1241 if(cl.stats[STAT_ARMOR] > 200)
1242 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1243 else if(cl.stats[STAT_ARMOR] > 100)
1244 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1245 else if(cl.stats[STAT_ARMOR] > 50)
1246 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1247 else if(cl.stats[STAT_ARMOR] > 25)
1248 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1250 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1254 if (cl.stats[STAT_HEALTH] != 0)
1256 Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1257 if(cl.stats[STAT_HEALTH] > 200)
1258 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1259 else if(cl.stats[STAT_HEALTH] > 100)
1260 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1261 else if(cl.stats[STAT_HEALTH] > 50)
1262 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1263 else if(cl.stats[STAT_HEALTH] > 25)
1264 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1266 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1270 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1272 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1273 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1274 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1275 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1276 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1277 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1278 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1279 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1280 if(cl.stats[STAT_AMMO] > 10)
1281 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1283 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1286 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1287 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1290 // The margin can be at most 8 to support 640x480 console size:
1291 // 320 + 2 * (144 + 16) = 640
1297 int redflag, blueflag;
1299 sbar_x = (vid_conwidth.integer - 640)/2;
1300 sbar_y = vid_conheight.integer - 47;
1302 // calculate intensity to draw weapons bar at
1303 fade = 3 - 2 * (cl.time - cl.weapontime);
1306 fade = min(fade, 1);
1307 for (i = 0; i < 8;i++)
1308 if (cl.stats[STAT_ITEMS] & (1 << i))
1309 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1311 if((cl.stats[STAT_ITEMS] & (1<<12)))
1312 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1315 //if (!cl.islocalgame)
1316 // Sbar_DrawFrags ();
1319 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1321 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1324 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1325 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1326 if (redflag == 3 && blueflag == 3)
1328 // The Impossible Combination[tm]
1329 // Can only happen in Key Hunt mode...
1330 Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1335 Sbar_DrawPic (10 - sbar_x, -117, sb_items[redflag+10]);
1337 Sbar_DrawPic (10 - sbar_x, -177, sb_items[blueflag+14]);
1341 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1344 if(cl.stats[STAT_HEALTH] > 100)
1345 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1346 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1347 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1349 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1351 // AK dont draw ammo for the laser
1352 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1354 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1355 Sbar_DrawPic (519, 0, sb_ammo[0]);
1356 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1357 Sbar_DrawPic (519, 0, sb_ammo[1]);
1358 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1359 Sbar_DrawPic (519, 0, sb_ammo[2]);
1360 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1361 Sbar_DrawPic (519, 0, sb_ammo[3]);
1363 if(cl.stats[STAT_AMMO] <= 10)
1364 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1366 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1371 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1373 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1374 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1379 // Mini scoreboard uses 12*4 per other team, that is, 144
1380 // pixels when there are four teams...
1381 // Nexuiz by default sets vid_conwidth to 800... makes
1383 // so we need to shift it by 64 pixels to the right to fit
1384 // BUT: then it overlaps with the image that gets drawn
1385 // for viewsize 100! Therefore, just account for 3 teams,
1386 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1390 else if (gamemode == GAME_ZYMOTIC)
1393 float scale = 64.0f / 256.0f;
1394 float kickoffset[3];
1395 VectorClear(kickoffset);
1398 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1399 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1401 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1402 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1403 // left1 16, 48 : 126 -66
1404 // left2 16, 128 : 196 -66
1405 // right 176, 48 : 196 -136
1406 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);
1407 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);
1408 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);
1409 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1411 float scale = 128.0f / 256.0f;
1412 float healthstart, healthheight, healthstarttc, healthendtc;
1413 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1414 float ammostart, ammoheight, ammostarttc, ammoendtc;
1415 float clipstart, clipheight, clipstarttc, clipendtc;
1416 float kickoffset[3], offset;
1417 VectorClear(kickoffset);
1420 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1421 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1423 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1424 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1425 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1426 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);
1427 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);
1428 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);
1429 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);
1430 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1431 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1432 healthstart = 204 - healthheight;
1433 shieldstart = healthstart - shieldheight;
1434 healthstarttc = healthstart * (1.0f / 256.0f);
1435 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1436 shieldstarttc = shieldstart * (1.0f / 256.0f);
1437 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1438 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1439 ammostart = 114 - ammoheight;
1440 ammostarttc = ammostart * (1.0f / 256.0f);
1441 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1442 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1443 clipstart = 190 - clipheight;
1444 clipstarttc = clipstart * (1.0f / 256.0f);
1445 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1446 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);
1447 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);
1448 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);
1449 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);
1450 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1451 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1454 else // Quake and others
1456 sbar_x = (vid_conwidth.integer - 320)/2;
1457 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1458 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1459 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1463 if (gamemode != GAME_GOODVSBAD2)
1464 Sbar_DrawInventory ();
1465 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1469 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1471 if (gamemode != GAME_GOODVSBAD2)
1472 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1473 Sbar_DrawScoreboard ();
1477 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1479 // keys (hipnotic only)
1480 //MED 01/04/97 moved keys here so they would not be overwritten
1481 if (gamemode == GAME_HIPNOTIC)
1483 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1484 Sbar_DrawPic (209, 3, sb_items[0]);
1485 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1486 Sbar_DrawPic (209, 12, sb_items[1]);
1489 if (gamemode != GAME_GOODVSBAD2)
1491 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1493 Sbar_DrawNum (24, 0, 666, 3, 1);
1494 Sbar_DrawPic (0, 0, sb_disc);
1498 if (gamemode == GAME_ROGUE)
1500 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1501 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1502 Sbar_DrawPic (0, 0, sb_armor[2]);
1503 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1504 Sbar_DrawPic (0, 0, sb_armor[1]);
1505 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1506 Sbar_DrawPic (0, 0, sb_armor[0]);
1510 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1511 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1512 Sbar_DrawPic (0, 0, sb_armor[2]);
1513 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1514 Sbar_DrawPic (0, 0, sb_armor[1]);
1515 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1516 Sbar_DrawPic (0, 0, sb_armor[0]);
1525 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1528 if (gamemode == GAME_ROGUE)
1530 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1531 Sbar_DrawPic (224, 0, sb_ammo[0]);
1532 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1533 Sbar_DrawPic (224, 0, sb_ammo[1]);
1534 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1535 Sbar_DrawPic (224, 0, sb_ammo[2]);
1536 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1537 Sbar_DrawPic (224, 0, sb_ammo[3]);
1538 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1539 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1540 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1541 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1542 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1543 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1547 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1548 Sbar_DrawPic (224, 0, sb_ammo[0]);
1549 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1550 Sbar_DrawPic (224, 0, sb_ammo[1]);
1551 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1552 Sbar_DrawPic (224, 0, sb_ammo[2]);
1553 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1554 Sbar_DrawPic (224, 0, sb_ammo[3]);
1557 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1559 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1560 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1562 if (gamemode == GAME_TRANSFUSION)
1563 Sbar_MiniDeathmatchOverlay (0, 0);
1565 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1574 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1575 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);
1577 if (cl_prydoncursor.integer)
1578 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), true), 0, 0, 1, 1, 1, 1, 0);
1581 //=============================================================================
1585 Sbar_DeathmatchOverlay
1589 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1592 qboolean myself = false;
1594 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1596 if((s - cl.scores) == cl.playerentity - 1)
1598 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1599 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1602 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1604 if (s->qw_spectator)
1606 if (s->qw_ping || s->qw_packetloss)
1607 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 );
1609 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 );
1613 // draw colors behind score
1619 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
1620 DrawQ_Fill(x + 14*8, y+1, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1621 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
1622 DrawQ_Fill(x + 14*8, y+4, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1624 //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);
1625 if (s->qw_ping || s->qw_packetloss)
1626 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 );
1628 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 );
1633 if (s->qw_spectator)
1635 if (s->qw_ping || s->qw_packetloss)
1636 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 );
1638 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 );
1642 // draw colors behind score
1643 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
1644 DrawQ_Fill(x + 9*8, y+1, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1645 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
1646 DrawQ_Fill(x + 9*8, y+4, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1648 //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);
1649 if (s->qw_ping || s->qw_packetloss)
1650 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 );
1652 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 );
1658 void Sbar_DeathmatchOverlay (void)
1662 // request new ping times every two second
1663 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1665 cl.last_ping_request = realtime;
1666 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1668 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1669 MSG_WriteString(&cls.netcon->message, "pings");
1671 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*/)
1673 // 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
1674 static int ping_anyway_counter = 0;
1675 if(cl.parsingtextexpectingpingforscores == 1)
1677 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1678 if(++ping_anyway_counter >= 5)
1679 cl.parsingtextexpectingpingforscores = 0;
1681 if(cl.parsingtextexpectingpingforscores != 1)
1683 ping_anyway_counter = 0;
1684 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1685 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1686 MSG_WriteString(&cls.netcon->message, "ping");
1691 // 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
1692 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1693 MSG_WriteString(&cls.netcon->message, "pings");
1697 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1703 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1705 x = (vid_conwidth.integer - (26 + 15) * 8) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1706 DrawQ_String(x, y, va("ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1710 x = (vid_conwidth.integer - (16 + 15) * 8) / 2; // 16 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1711 DrawQ_String(x, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1715 if (Sbar_IsTeammatch ())
1717 // show team scores first
1718 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1719 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1723 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1724 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1729 Sbar_MiniDeathmatchOverlay
1733 void Sbar_MiniDeathmatchOverlay (int x, int y)
1735 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1737 // do not draw this if sbar_miniscoreboard_size is zero
1738 if(sbar_miniscoreboard_size.value == 0)
1740 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1741 if(sbar_miniscoreboard_size.value > 0)
1742 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1747 // decide where to print
1748 if (gamemode == GAME_TRANSFUSION)
1749 numlines = (vid_conwidth.integer - x + 127) / 128;
1751 numlines = (vid_conheight.integer - y + 7) / 8;
1753 // give up if there isn't room
1754 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1758 for (i = 0; i < scoreboardlines; i++)
1759 if (fragsort[i] == cl.playerentity - 1)
1763 range_end = scoreboardlines;
1766 if (gamemode != GAME_TRANSFUSION)
1767 if (Sbar_IsTeammatch ())
1769 // reserve space for the team scores
1770 numlines -= teamlines;
1772 // find first and last player of my team (only draw the team totals and my own team)
1773 range_begin = range_end = i;
1774 myteam = cl.scores[fragsort[i]].colors & 15;
1775 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1777 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1780 // looks better than two players
1790 i = min(i, range_end - numlines);
1791 i = max(i, range_begin);
1793 if (gamemode == GAME_TRANSFUSION)
1795 for (;i < range_end && x < vid_conwidth.integer;i++)
1796 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1800 if(range_end - i < numlines) // won't draw to bottom?
1801 y += 8 * (numlines - (range_end - i)); // bottom align
1802 // show team scores first
1803 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1804 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1806 for (;i < range_end && y < vid_conheight.integer;i++)
1807 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1811 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1813 static int const sortorder[16] =
1832 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1833 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1834 int tc1 = sortorder[t1->colors & 15];
1835 int tc2 = sortorder[t2->colors & 15];
1839 void Sbar_Score (int margin)
1841 int i, me, score, otherleader, place, distribution, minutes, seconds;
1843 int sbar_x_save = sbar_x;
1844 int sbar_y_save = sbar_y;
1846 sbar_y = vid_conheight.value - (32+12);
1849 me = cl.playerentity - 1;
1850 if (me >= 0 && me < cl.maxclients)
1852 if(Sbar_IsTeammatch())
1856 // team1 team3 team4
1860 scoreboard_t *teamcolorsort[16];
1863 for(i = 0; i < teamlines; ++i)
1864 teamcolorsort[i] = &(teams[i]);
1866 // Now sort them by color
1867 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1870 // -12*4: four digits space
1871 place = (teamlines - 1) * (-12 * 4);
1873 for(i = 0; i < teamlines; ++i)
1875 int cindex = teamcolorsort[i]->colors & 15;
1876 unsigned char *c = (unsigned char *)&palette_shirtscoreboard[cindex];
1877 float cm = max(max(c[0], c[1]), c[2]);
1878 float cr = c[0] / cm;
1879 float cg = c[1] / cm;
1880 float cb = c[2] / cm;
1881 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1883 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1887 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1900 // find leading score other than ourselves, to calculate distribution
1901 // find our place in the scoreboard
1902 score = cl.scores[me].frags;
1903 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1905 if (cl.scores[i].name[0] && i != me)
1907 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1909 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1913 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1915 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1916 else if (place == 2)
1917 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
1919 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
1920 if (otherleader < 0)
1921 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1922 if (distribution >= 0)
1924 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
1925 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1927 else if (distribution >= -5)
1929 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
1930 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
1934 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
1935 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
1940 if (cl.statsf[STAT_TIMELIMIT])
1942 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
1943 minutes = (int)floor(timeleft / 60);
1944 seconds = (int)(floor(timeleft) - minutes * 60);
1947 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1948 if(sb_colon && sb_colon->tex != r_texture_notexture)
1949 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1950 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1952 else if (minutes >= 1)
1954 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
1955 if(sb_colon && sb_colon->tex != r_texture_notexture)
1956 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
1957 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
1959 else if ((int)(timeleft * 4) & 1)
1960 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1962 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
1966 minutes = (int)floor(cl.time / 60);
1967 seconds = (int)(floor(cl.time) - minutes * 60);
1968 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1969 if(sb_colon && sb_colon->tex != r_texture_notexture)
1970 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1971 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1974 sbar_x = sbar_x_save;
1975 sbar_y = sbar_y_save;
1980 Sbar_IntermissionOverlay
1984 void Sbar_IntermissionOverlay (void)
1989 if (cl.gametype == GAME_DEATHMATCH)
1991 Sbar_DeathmatchOverlay ();
1995 sbar_x = (vid_conwidth.integer - 320) >> 1;
1996 sbar_y = (vid_conheight.integer - 200) >> 1;
1998 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1999 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2002 dig = (int)cl.completed_time / 60;
2003 Sbar_DrawNum (160, 64, dig, 3, 0);
2004 num = (int)cl.completed_time - dig*60;
2005 Sbar_DrawPic (234,64,sb_colon);
2006 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2007 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2009 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2010 if (gamemode != GAME_NEXUIZ)
2011 Sbar_DrawPic (232, 104, sb_slash);
2012 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2014 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2015 if (gamemode != GAME_NEXUIZ)
2016 Sbar_DrawPic (232, 144, sb_slash);
2017 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2028 void Sbar_FinaleOverlay (void)
2030 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);