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)"};
99 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
101 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
102 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
103 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
104 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
105 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
107 void Sbar_MiniDeathmatchOverlay (int x, int y);
108 void Sbar_DeathmatchOverlay (void);
109 void Sbar_IntermissionOverlay (void);
110 void Sbar_FinaleOverlay (void);
120 void Sbar_ShowScores (void)
124 sb_showscores = true;
134 void Sbar_DontShowScores (void)
136 sb_showscores = false;
139 void sbar_start(void)
143 if (gamemode == GAME_NETHERWORLD)
146 else if (gamemode == GAME_SOM)
148 sb_disc = Draw_CachePic("gfx/disc", true);
150 for (i = 0;i < 10;i++)
151 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
153 somsb_health = Draw_CachePic("gfx/hud_health", true);
154 somsb_ammo[0] = Draw_CachePic("gfx/sb_shells", true);
155 somsb_ammo[1] = Draw_CachePic("gfx/sb_nails", true);
156 somsb_ammo[2] = Draw_CachePic("gfx/sb_rocket", true);
157 somsb_ammo[3] = Draw_CachePic("gfx/sb_cells", true);
158 somsb_armor[0] = Draw_CachePic("gfx/sb_armor1", true);
159 somsb_armor[1] = Draw_CachePic("gfx/sb_armor2", true);
160 somsb_armor[2] = Draw_CachePic("gfx/sb_armor3", true);
162 else if (gamemode == GAME_NEXUIZ)
164 for (i = 0;i < 10;i++)
165 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
166 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
167 sb_colon = Draw_CachePic ("gfx/num_colon", true);
169 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
170 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets", true);
171 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
172 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
174 sb_armor[0] = Draw_CachePic ("gfx/sb_armor", true);
178 sb_health = Draw_CachePic ("gfx/sb_health", true);
180 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo", true);
181 sb_items[3] = Draw_CachePic ("gfx/sb_invinc", true);
182 sb_items[4] = Draw_CachePic ("gfx/sb_energy", true);
183 sb_items[5] = Draw_CachePic ("gfx/sb_str", true);
185 sb_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken", true);
186 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost", true);
187 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying", true);
188 sb_items[14] = Draw_CachePic ("gfx/sb_key_carrying", true);
189 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken", true);
190 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost", true);
191 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying", true);
193 sb_sbar = Draw_CachePic("gfx/sbar", true);
194 sb_sbar_minimal = Draw_CachePic("gfx/sbar_minimal", true);
195 sb_sbar_overlay = Draw_CachePic("gfx/sbar_overlay", true);
197 for(i = 0; i < 9;i++)
198 sb_weapons[0][i] = Draw_CachePic(va("gfx/inv_weapon%i",i), true);
200 else if (gamemode == GAME_ZYMOTIC)
202 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center", true);
203 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line", true);
204 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health", true);
205 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip", true);
206 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo", true);
207 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background", true);
208 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1", true);
209 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2", true);
210 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right", true);
214 sb_disc = Draw_CachePic("gfx/disc", true);
216 for (i = 0;i < 10;i++)
218 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
219 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i), true);
222 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
223 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus", true);
225 sb_colon = Draw_CachePic ("gfx/num_colon", true);
226 sb_slash = Draw_CachePic ("gfx/num_slash", true);
228 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun", true);
229 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun", true);
230 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun", true);
231 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun", true);
232 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch", true);
233 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch", true);
234 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng", true);
236 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun", true);
237 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun", true);
238 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun", true);
239 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun", true);
240 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch", true);
241 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch", true);
242 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng", true);
244 for (i = 0;i < 5;i++)
246 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1), true);
247 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1), true);
248 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1), true);
249 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1), true);
250 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1), true);
251 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1), true);
252 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1), true);
255 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
256 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails", true);
257 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
258 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
260 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1", true);
261 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2", true);
262 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3", true);
264 sb_items[0] = Draw_CachePic ("gfx/sb_key1", true);
265 sb_items[1] = Draw_CachePic ("gfx/sb_key2", true);
266 sb_items[2] = Draw_CachePic ("gfx/sb_invis", true);
267 sb_items[3] = Draw_CachePic ("gfx/sb_invuln", true);
268 sb_items[4] = Draw_CachePic ("gfx/sb_suit", true);
269 sb_items[5] = Draw_CachePic ("gfx/sb_quad", true);
271 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1", true);
272 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2", true);
273 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3", true);
274 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4", true);
276 sb_faces[4][0] = Draw_CachePic ("gfx/face1", true);
277 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1", true);
278 sb_faces[3][0] = Draw_CachePic ("gfx/face2", true);
279 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2", true);
280 sb_faces[2][0] = Draw_CachePic ("gfx/face3", true);
281 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3", true);
282 sb_faces[1][0] = Draw_CachePic ("gfx/face4", true);
283 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4", true);
284 sb_faces[0][0] = Draw_CachePic ("gfx/face5", true);
285 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5", true);
287 sb_face_invis = Draw_CachePic ("gfx/face_invis", true);
288 sb_face_invuln = Draw_CachePic ("gfx/face_invul2", true);
289 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2", true);
290 sb_face_quad = Draw_CachePic ("gfx/face_quad", true);
292 sb_sbar = Draw_CachePic ("gfx/sbar", true);
293 sb_ibar = Draw_CachePic ("gfx/ibar", true);
294 sb_scorebar = Draw_CachePic ("gfx/scorebar", true);
296 //MED 01/04/97 added new hipnotic weapons
297 if (gamemode == GAME_HIPNOTIC)
299 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser", true);
300 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir", true);
301 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox", true);
302 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren", true);
303 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox", true);
305 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser", true);
306 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir", true);
307 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox", true);
308 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren", true);
309 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox", true);
311 for (i = 0;i < 5;i++)
313 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1), true);
314 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1), true);
315 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1), true);
316 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1), true);
317 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1), true);
320 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit", true);
321 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld", true);
323 else if (gamemode == GAME_ROGUE)
325 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1", true);
326 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2", true);
328 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava", true);
329 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava", true);
330 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren", true);
331 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock", true);
332 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma", true);
334 rsb_items[0] = Draw_CachePic ("gfx/r_shield1", true);
335 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1", true);
337 // PGM 01/19/97 - team color border
338 rsb_teambord = Draw_CachePic ("gfx/r_teambord", true);
339 // PGM 01/19/97 - team color border
341 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava", true);
342 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti", true);
343 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma", true);
347 sb_ranking = Draw_CachePic ("gfx/ranking", true);
348 sb_complete = Draw_CachePic ("gfx/complete", true);
349 sb_inter = Draw_CachePic ("gfx/inter", true);
350 sb_finale = Draw_CachePic ("gfx/finale", true);
353 void sbar_shutdown(void)
357 void sbar_newmap(void)
361 void Sbar_Init (void)
363 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
364 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
365 Cvar_RegisterVariable(&showfps);
366 Cvar_RegisterVariable(&showtime);
367 Cvar_RegisterVariable(&showtime_format);
368 Cvar_RegisterVariable(&showdate);
369 Cvar_RegisterVariable(&showdate_format);
370 Cvar_RegisterVariable(&sbar_alpha_bg);
371 Cvar_RegisterVariable(&sbar_alpha_fg);
372 Cvar_RegisterVariable(&sbar_hudselector);
373 Cvar_RegisterVariable(&cl_deathscoreboard);
375 Cvar_RegisterVariable(&crosshair_color_red);
376 Cvar_RegisterVariable(&crosshair_color_green);
377 Cvar_RegisterVariable(&crosshair_color_blue);
378 Cvar_RegisterVariable(&crosshair_color_alpha);
379 Cvar_RegisterVariable(&crosshair_size);
381 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
385 //=============================================================================
387 // drawing routines are relative to the status bar location
396 void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
398 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
401 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
403 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
406 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
408 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
415 Draws one solid graphics character
418 void Sbar_DrawCharacter (int x, int y, int num)
420 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);
428 void Sbar_DrawString (int x, int y, char *str)
430 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false);
438 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
443 l = sprintf(str, "%i", num);
457 Sbar_DrawPic (x, y, sb_nums[color][frame]);
470 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
478 l = sprintf(str, "%0*i", digits, num);
481 l = sprintf(str, "%i", num);
486 x += (digits-l) * lettersize;
495 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
502 //=============================================================================
505 int Sbar_IsTeammatch()
507 // currently only nexuiz uses the team score board
508 return ((gamemode == GAME_NEXUIZ)
509 && (teamplay.integer > 0));
517 static int fragsort[MAX_SCOREBOARD];
518 static int scoreboardlines;
520 //[515]: Sbar_GetPlayer for csqc "getplayerkey" func
521 int Sbar_GetPlayer (int index)
526 if(index >= scoreboardlines)
528 index = fragsort[index];
530 if(index >= scoreboardlines)
535 static scoreboard_t teams[MAX_SCOREBOARD];
536 static int teamsort[MAX_SCOREBOARD];
537 static int teamlines;
538 void Sbar_SortFrags (void)
544 for (i=0 ; i<cl.maxclients ; i++)
546 if (cl.scores[i].name[0])
548 fragsort[scoreboardlines] = i;
553 for (i=0 ; i<scoreboardlines ; i++)
554 for (j=0 ; j<scoreboardlines-1-i ; j++)
555 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
558 fragsort[j] = fragsort[j+1];
563 if (Sbar_IsTeammatch ())
565 // now sort players by teams.
566 for (i=0 ; i<scoreboardlines ; i++)
568 for (j=0 ; j<scoreboardlines-1-i ; j++)
570 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
573 fragsort[j] = fragsort[j+1];
579 // calculate team scores
581 for (i=0 ; i<scoreboardlines ; i++)
583 if (color != (cl.scores[fragsort[i]].colors & 15))
585 const char* teamname;
587 color = cl.scores[fragsort[i]].colors & 15;
593 teamname = "^1Red Team";
596 teamname = "^4Blue Team";
599 teamname = "^6Pink Team";
602 teamname = "^3Yellow Team";
605 teamname = "Total Team Score";
608 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
610 teams[teamlines-1].frags = 0;
611 teams[teamlines-1].colors = color + 16 * color;
614 if (cl.scores[fragsort[i]].frags != -666)
616 // do not add spedcators
617 // (ugly hack for nexuiz)
618 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
622 // now sort teams by scores.
623 for (i=0 ; i<teamlines ; i++)
625 for (i=0 ; i<teamlines ; i++)
627 for (j=0 ; j<teamlines-1-i ; j++)
629 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
632 teamsort[j] = teamsort[j+1];
645 void Sbar_SoloScoreboard (void)
648 char str[80], timestr[40];
650 int minutes, seconds;
653 t = (cl.intermission ? cl.completed_time : cl.time);
654 minutes = (int)(t / 60);
655 seconds = (int)(t - 60*floor(t/60));
657 // monsters and secrets are now both on the top row
658 if (cl.stats[STAT_TOTALMONSTERS])
659 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
660 if (cl.stats[STAT_TOTALSECRETS])
661 Sbar_DrawString(8+22*8, 4, va("Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
663 // figure out the map's filename without path or extension
664 strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
665 if (strrchr(str, '.'))
666 *(strrchr(str, '.')) = 0;
668 // append a : separator and then the full title
669 strlcat(str, ":", sizeof(str));
670 strlcat(str, cl.levelname, sizeof(str));
672 // if there's a newline character, terminate the string there
673 if (strchr(str, '\n'))
674 *(strchr(str, '\n')) = 0;
676 // make the time string
677 timelen = sprintf(timestr, " %i:%02i", minutes, seconds);
679 // truncate the level name if necessary to make room for time
681 if ((int)strlen(str) > max)
684 // print the filename and message
685 Sbar_DrawString(8, 12, str);
688 Sbar_DrawString(8 + max*8, 12, timestr);
692 int minutes, seconds, tens, units;
695 if (gamemode != GAME_NEXUIZ) {
696 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
697 Sbar_DrawString (8, 4, str);
699 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
700 Sbar_DrawString (8, 12, str);
704 minutes = (int)(cl.time / 60);
705 seconds = (int)(cl.time - 60*minutes);
707 units = seconds - 10*tens;
708 sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
709 Sbar_DrawString (184, 4, str);
712 if (gamemode == GAME_NEXUIZ) {
713 l = (int) strlen (cl.worldmodel->name);
714 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
716 l = (int) strlen (cl.levelname);
717 Sbar_DrawString (232 - l*4, 12, cl.levelname);
727 void Sbar_DrawScoreboard (void)
729 Sbar_SoloScoreboard ();
730 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
731 //if (cl.gametype == GAME_DEATHMATCH)
733 Sbar_DeathmatchOverlay ();
736 //=============================================================================
738 // AK to make DrawInventory smaller
739 static void Sbar_DrawWeapon(int nr, float fade, int active)
741 if (sbar_hudselector.integer == 1)
743 // width = 300, height = 100
744 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
746 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);
747 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);
751 // width = 300, height = 100
752 const int w_width = 300, w_height = 100, w_space = 10;
753 const float w_scale = 0.4;
755 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);
756 //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);
765 void Sbar_DrawInventory (void)
772 if (gamemode == GAME_ROGUE)
774 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
775 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
777 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
780 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
783 for (i=0 ; i<7 ; i++)
785 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
787 time = cl.item_gettime[i];
788 flashon = (int)(max(0, cl.time - time)*10);
791 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
797 flashon = (flashon%5) + 2;
799 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
805 if (gamemode == GAME_HIPNOTIC)
807 int grenadeflashing=0;
808 for (i=0 ; i<4 ; i++)
810 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
812 time = max(0, cl.item_gettime[hipweapons[i]]);
813 flashon = (int)((cl.time - time)*10);
816 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
822 flashon = (flashon%5) + 2;
824 // check grenade launcher
827 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
832 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
838 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
840 if (!grenadeflashing)
841 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
844 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
847 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
852 if (gamemode == GAME_ROGUE)
854 // check for powered up weapon.
855 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
857 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
858 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
862 for (i=0 ; i<4 ; i++)
864 sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] );
866 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
868 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
870 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
874 for (i=0 ; i<6 ; i++)
875 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
877 //MED 01/04/97 changed keys
878 if (gamemode != GAME_HIPNOTIC || (i>1))
879 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
882 //MED 01/04/97 added hipnotic items
884 if (gamemode == GAME_HIPNOTIC)
886 for (i=0 ; i<2 ; i++)
887 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
888 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
891 if (gamemode == GAME_ROGUE)
894 for (i=0 ; i<2 ; i++)
895 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
896 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
901 for (i=0 ; i<4 ; i++)
902 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
903 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
907 //=============================================================================
914 void Sbar_DrawFrags (void)
924 l = min(scoreboardlines, 4);
928 for (i = 0;i < l;i++)
934 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
935 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);
936 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
937 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);
941 sprintf (num, "%3i",f);
943 if (k == cl.viewentity - 1)
945 Sbar_DrawCharacter ( x + 2, -24, 16);
946 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
948 Sbar_DrawCharacter (x + 8, -24, num[0]);
949 Sbar_DrawCharacter (x + 16, -24, num[1]);
950 Sbar_DrawCharacter (x + 24, -24, num[2]);
955 //=============================================================================
963 void Sbar_DrawFace (void)
967 // PGM 01/19/97 - team color drawing
968 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
969 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
975 s = &cl.scores[cl.viewentity - 1];
977 Sbar_DrawPic (112, 0, rsb_teambord);
978 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
979 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);
980 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
981 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);
985 sprintf (num, "%3i",f);
987 if ((s->colors & 0xf0)==0)
990 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
992 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
994 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
998 Sbar_DrawCharacter ( 109, 3, num[0]);
999 Sbar_DrawCharacter ( 116, 3, num[1]);
1000 Sbar_DrawCharacter ( 123, 3, num[2]);
1005 // PGM 01/19/97 - team color drawing
1007 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1008 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1009 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1010 Sbar_DrawPic (112, 0, sb_face_quad );
1011 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1012 Sbar_DrawPic (112, 0, sb_face_invis );
1013 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1014 Sbar_DrawPic (112, 0, sb_face_invuln);
1017 f = cl.stats[STAT_HEALTH] / 20;
1019 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1023 void Sbar_ShowFPS(void)
1025 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1027 char timestring[32];
1028 char datestring[32];
1029 qboolean red = false;
1033 if (showfps.integer)
1036 static double nexttime = 0, lasttime = 0;
1037 static double framerate = 0;
1038 static int framecount = 0;
1041 if (newtime >= nexttime)
1043 framerate = framecount / (newtime - lasttime);
1045 nexttime = max(nexttime + 1, lasttime - 1);
1051 if ((red = (calc < 1.0f)))
1052 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1054 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1056 if (showtime.integer)
1057 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1058 if (showdate.integer)
1059 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1060 if (fpsstring[0] || timestring[0])
1064 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
1065 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1066 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1067 fps_y = vid_conheight.integer - fps_height;
1070 fps_x = vid_conwidth.integer - fps_scalex * strlen(fpsstring);
1071 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(fpsstring), fps_scaley, 0, 0, 0, 0.5, 0);
1073 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true);
1075 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1076 fps_y += fps_scaley;
1080 fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
1081 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(timestring), fps_scaley, 0, 0, 0, 0.5, 0);
1082 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1083 fps_y += fps_scaley;
1087 fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
1088 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(datestring), fps_scaley, 0, 0, 0, 0.5, 0);
1089 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1090 fps_y += fps_scaley;
1095 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)
1098 c2 = bound(0, c2, 1);
1099 c1 = bound(0, c1, 1 - c2);
1101 r[1] = rangey + rangeheight * (c2 + c1);
1102 r[2] = rangey + rangeheight * (c2);
1106 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);
1108 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);
1110 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);
1112 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);
1120 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1121 extern cvar_t v_kicktime;
1122 void Sbar_Score (void);
1123 void Sbar_Draw (void)
1127 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1130 Sbar_DrawScoreboard ();
1131 else if (cl.intermission == 1)
1133 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1135 Sbar_DrawScoreboard();
1138 Sbar_IntermissionOverlay();
1140 else if (cl.intermission == 2)
1141 Sbar_FinaleOverlay();
1142 else if (gamemode == GAME_NETHERWORLD)
1145 else if (gamemode == GAME_SOM)
1147 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1148 Sbar_DrawScoreboard ();
1151 // this is the top left of the sbar area
1153 sbar_y = vid_conheight.integer - 24*3;
1156 if (cl.stats[STAT_ARMOR])
1158 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1159 Sbar_DrawPic(0, 0, somsb_armor[2]);
1160 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1161 Sbar_DrawPic(0, 0, somsb_armor[1]);
1162 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1163 Sbar_DrawPic(0, 0, somsb_armor[0]);
1164 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1168 Sbar_DrawPic(0, 24, somsb_health);
1169 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1172 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1173 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1174 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1175 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1176 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1177 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1178 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1179 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1180 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1181 if (cl.stats[STAT_SHELLS])
1182 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1185 else if (gamemode == GAME_NEXUIZ)
1187 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1189 sbar_x = (vid_conwidth.integer - 640)/2;
1190 sbar_y = vid_conheight.integer - 47;
1191 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1192 Sbar_DrawScoreboard ();
1194 else if (sb_lines && sbar_hudselector.integer == 1)
1198 int redflag, blueflag;
1200 sbar_x = (vid_conwidth.integer - 320)/2;
1201 sbar_y = vid_conheight.integer - 24 - 16;
1203 // calculate intensity to draw weapons bar at
1204 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1205 fade = bound(0.7, fade, 1);
1206 for (i = 0; i < 8;i++)
1207 if (cl.stats[STAT_ITEMS] & (1 << i))
1208 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1209 if((cl.stats[STAT_ITEMS] & (1<<12)))
1210 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1213 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1214 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1215 if (redflag == 3 && blueflag == 3)
1217 // The Impossible Combination[tm]
1218 // Can only happen in Key Hunt mode...
1219 Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1224 Sbar_DrawPic (10 - sbar_x, -109, sb_items[redflag+10]);
1226 Sbar_DrawPic (10 - sbar_x, -169, sb_items[blueflag+14]);
1230 if (cl.stats[STAT_ARMOR] > 0)
1232 Sbar_DrawStretchPic (0, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1233 if(cl.stats[STAT_ARMOR] > 100)
1234 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0,1,0);
1235 else if(cl.stats[STAT_ARMOR] > 25)
1236 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1238 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1242 if (cl.stats[STAT_HEALTH] != 0)
1244 Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1245 if(cl.stats[STAT_HEALTH] > 100)
1246 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0,1,0);
1247 else if(cl.stats[STAT_HEALTH] > 25)
1248 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1250 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1254 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1256 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1257 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1258 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1259 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1260 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1261 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1262 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1263 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1264 if(cl.stats[STAT_AMMO] > 10)
1265 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1267 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1270 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1271 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1279 int redflag, blueflag;
1281 sbar_x = (vid_conwidth.integer - 640)/2;
1282 sbar_y = vid_conheight.integer - 47;
1284 // calculate intensity to draw weapons bar at
1285 fade = 3 - 2 * (cl.time - cl.weapontime);
1288 fade = min(fade, 1);
1289 for (i = 0; i < 8;i++)
1290 if (cl.stats[STAT_ITEMS] & (1 << i))
1291 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1293 if((cl.stats[STAT_ITEMS] & (1<<12)))
1294 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1297 //if (!cl.islocalgame)
1298 // Sbar_DrawFrags ();
1301 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1303 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1306 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1307 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1308 if (redflag == 3 && blueflag == 3)
1310 // The Impossible Combination[tm]
1311 // Can only happen in Key Hunt mode...
1312 Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1317 Sbar_DrawPic (10 - sbar_x, -109, sb_items[redflag+10]);
1319 Sbar_DrawPic (10 - sbar_x, -169, sb_items[blueflag+14]);
1323 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1326 if(cl.stats[STAT_HEALTH] > 100)
1327 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1328 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1329 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1331 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1333 // AK dont draw ammo for the laser
1334 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1336 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1337 Sbar_DrawPic (519, 0, sb_ammo[0]);
1338 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1339 Sbar_DrawPic (519, 0, sb_ammo[1]);
1340 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1341 Sbar_DrawPic (519, 0, sb_ammo[2]);
1342 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1343 Sbar_DrawPic (519, 0, sb_ammo[3]);
1345 if(cl.stats[STAT_AMMO] <= 10)
1346 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1348 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1353 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1355 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1356 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1362 else if (gamemode == GAME_ZYMOTIC)
1365 float scale = 64.0f / 256.0f;
1366 float kickoffset[3];
1367 VectorClear(kickoffset);
1370 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1371 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1373 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1374 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1375 // left1 16, 48 : 126 -66
1376 // left2 16, 128 : 196 -66
1377 // right 176, 48 : 196 -136
1378 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);
1379 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);
1380 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);
1381 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1383 float scale = 128.0f / 256.0f;
1384 float healthstart, healthheight, healthstarttc, healthendtc;
1385 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1386 float ammostart, ammoheight, ammostarttc, ammoendtc;
1387 float clipstart, clipheight, clipstarttc, clipendtc;
1388 float kickoffset[3], offset;
1389 VectorClear(kickoffset);
1392 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1393 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1395 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1396 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1397 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1398 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);
1399 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);
1400 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);
1401 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);
1402 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1403 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1404 healthstart = 204 - healthheight;
1405 shieldstart = healthstart - shieldheight;
1406 healthstarttc = healthstart * (1.0f / 256.0f);
1407 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1408 shieldstarttc = shieldstart * (1.0f / 256.0f);
1409 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1410 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1411 ammostart = 114 - ammoheight;
1412 ammostarttc = ammostart * (1.0f / 256.0f);
1413 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1414 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1415 clipstart = 190 - clipheight;
1416 clipstarttc = clipstart * (1.0f / 256.0f);
1417 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1418 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);
1419 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);
1420 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);
1421 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);
1422 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1423 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1426 else // Quake and others
1428 sbar_x = (vid_conwidth.integer - 320)/2;
1429 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1430 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1431 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1435 if (gamemode != GAME_GOODVSBAD2)
1436 Sbar_DrawInventory ();
1437 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1441 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1443 if (gamemode != GAME_GOODVSBAD2)
1444 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1445 Sbar_DrawScoreboard ();
1449 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1451 // keys (hipnotic only)
1452 //MED 01/04/97 moved keys here so they would not be overwritten
1453 if (gamemode == GAME_HIPNOTIC)
1455 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1456 Sbar_DrawPic (209, 3, sb_items[0]);
1457 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1458 Sbar_DrawPic (209, 12, sb_items[1]);
1461 if (gamemode != GAME_GOODVSBAD2)
1463 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1465 Sbar_DrawNum (24, 0, 666, 3, 1);
1466 Sbar_DrawPic (0, 0, sb_disc);
1470 if (gamemode == GAME_ROGUE)
1472 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1473 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1474 Sbar_DrawPic (0, 0, sb_armor[2]);
1475 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1476 Sbar_DrawPic (0, 0, sb_armor[1]);
1477 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1478 Sbar_DrawPic (0, 0, sb_armor[0]);
1482 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1483 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1484 Sbar_DrawPic (0, 0, sb_armor[2]);
1485 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1486 Sbar_DrawPic (0, 0, sb_armor[1]);
1487 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1488 Sbar_DrawPic (0, 0, sb_armor[0]);
1497 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1500 if (gamemode == GAME_ROGUE)
1502 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1503 Sbar_DrawPic (224, 0, sb_ammo[0]);
1504 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1505 Sbar_DrawPic (224, 0, sb_ammo[1]);
1506 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1507 Sbar_DrawPic (224, 0, sb_ammo[2]);
1508 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1509 Sbar_DrawPic (224, 0, sb_ammo[3]);
1510 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1511 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1512 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1513 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1514 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1515 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1519 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1520 Sbar_DrawPic (224, 0, sb_ammo[0]);
1521 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1522 Sbar_DrawPic (224, 0, sb_ammo[1]);
1523 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1524 Sbar_DrawPic (224, 0, sb_ammo[2]);
1525 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1526 Sbar_DrawPic (224, 0, sb_ammo[3]);
1529 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1533 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1534 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1536 if (gamemode == GAME_TRANSFUSION)
1537 Sbar_MiniDeathmatchOverlay (0, 0);
1539 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1547 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1548 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);
1550 if (cl_prydoncursor.integer)
1551 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);
1554 //=============================================================================
1558 Sbar_DeathmatchOverlay
1562 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1565 qboolean myself = false;
1567 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1569 if((s - cl.scores) == cl.playerentity - 1)
1571 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1572 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1575 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1577 if (s->qw_spectator)
1579 if (s->qw_ping || s->qw_packetloss)
1580 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 );
1582 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 );
1586 // draw colors behind score
1587 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1588 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);
1589 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1590 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);
1592 //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);
1593 if (s->qw_ping || s->qw_packetloss)
1594 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 );
1596 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 );
1601 if (s->qw_spectator)
1603 if (s->qw_ping || s->qw_packetloss)
1604 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 );
1606 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 );
1610 // draw colors behind score
1611 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1612 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);
1613 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1614 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);
1616 //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);
1617 if (s->qw_ping || s->qw_packetloss)
1618 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 );
1620 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 );
1626 void Sbar_DeathmatchOverlay (void)
1630 // request new ping times every two second
1631 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1633 cl.last_ping_request = realtime;
1634 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1636 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1637 MSG_WriteString(&cls.netcon->message, "pings");
1639 else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || 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*/)
1641 // 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
1642 static int ping_anyway_counter = 0;
1643 if(cl.parsingtextexpectingpingforscores == 1)
1645 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1646 if(++ping_anyway_counter >= 5)
1647 cl.parsingtextexpectingpingforscores = 0;
1649 if(cl.parsingtextexpectingpingforscores != 1)
1651 ping_anyway_counter = 0;
1652 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1653 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1654 MSG_WriteString(&cls.netcon->message, "ping");
1659 // 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
1660 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1661 MSG_WriteString(&cls.netcon->message, "pings");
1665 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1671 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1673 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)
1674 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 );
1678 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)
1679 DrawQ_String(x, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1683 if (Sbar_IsTeammatch ())
1685 // show team scores first
1686 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1687 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1691 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1692 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1697 Sbar_MiniDeathmatchOverlay
1701 void Sbar_MiniDeathmatchOverlay (int x, int y)
1703 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1708 // decide where to print
1709 if (gamemode == GAME_TRANSFUSION)
1710 numlines = (vid_conwidth.integer - x + 127) / 128;
1712 numlines = (vid_conheight.integer - y + 7) / 8;
1714 // give up if there isn't room
1715 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1719 for (i = 0; i < scoreboardlines; i++)
1720 if (fragsort[i] == cl.playerentity - 1)
1724 range_end = scoreboardlines;
1727 if (gamemode != GAME_TRANSFUSION)
1728 if (Sbar_IsTeammatch ())
1730 // reserve space for the team scores
1731 numlines -= teamlines;
1733 // find first and last player of my team (only draw the team totals and my own team)
1734 range_begin = range_end = i;
1735 myteam = cl.scores[fragsort[i]].colors & 15;
1736 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1738 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1741 // looks better than two players
1751 i = min(i, range_end - numlines);
1752 i = max(i, range_begin);
1754 if (gamemode == GAME_TRANSFUSION)
1756 for (;i < range_end && x < vid_conwidth.integer;i++)
1757 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1761 if(range_end - i < numlines) // won't draw to bottom?
1762 y += 8 * (numlines - (range_end - i)); // bottom align
1763 // show team scores first
1764 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1765 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1767 for (;i < range_end && y < vid_conheight.integer;i++)
1768 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1772 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1774 static int const sortorder[16] =
1793 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1794 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1795 int tc1 = sortorder[t1->colors & 15];
1796 int tc2 = sortorder[t2->colors & 15];
1800 void Sbar_Score (void)
1802 int i, me, score, otherleader, place, distribution, minutes, seconds;
1805 sbar_y = vid_conheight.value - (32+12);
1806 me = cl.playerentity - 1;
1807 if (me >= 0 && me < cl.maxclients)
1809 if(Sbar_IsTeammatch())
1813 // team1 team3 team4
1817 scoreboard_t *teamcolorsort[16];
1820 for(i = 0; i < teamlines; ++i)
1821 teamcolorsort[i] = &(teams[i]);
1823 // Now sort them by color
1824 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1827 // -12*4: four digits space
1828 place = -24 + (teamlines - 1) * (-12 * 4);
1830 for(i = 0; i < teamlines; ++i)
1832 int cindex = teamcolorsort[i]->colors & 15;
1833 unsigned char *c = (unsigned char *)&palette_complete[(cindex << 4) + 8];
1834 float cm = max(max(c[0], c[1]), c[2]);
1835 float cr = c[0] / cm;
1836 float cg = c[1] / cm;
1837 float cb = c[2] / cm;
1838 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1840 Sbar_DrawXNum(-32*4-24, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1844 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1857 // find leading score other than ourselves, to calculate distribution
1858 // find our place in the scoreboard
1859 score = cl.scores[me].frags;
1860 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1862 if (cl.scores[i].name[0] && i != me)
1864 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1866 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1870 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1872 Sbar_DrawXNum(-3*12-24, -12, place, 3, 12, 1, 1, 1, 1, 0);
1873 else if (place == 2)
1874 Sbar_DrawXNum(-3*12-24, -12, place, 3, 12, 1, 1, 0, 1, 0);
1876 Sbar_DrawXNum(-3*12-24, -12, place, 3, 12, 1, 0, 0, 1, 0);
1877 if (otherleader < 0)
1878 Sbar_DrawXNum(-32*4-24, 0, score, 4, 32, 1, 1, 1, 1, 0);
1879 if (distribution >= 0)
1881 Sbar_DrawXNum(-7*12-24, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
1882 Sbar_DrawXNum(-32*4-24, 0, score, 4, 32, 1, 1, 1, 1, 0);
1884 else if (distribution >= -5)
1886 Sbar_DrawXNum(-7*12-24, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
1887 Sbar_DrawXNum(-32*4-24, 0, score, 4, 32, 1, 1, 0, 1, 0);
1891 Sbar_DrawXNum(-7*12-24, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
1892 Sbar_DrawXNum(-32*4-24, 0, score, 4, 32, 1, 0, 0, 1, 0);
1897 if (cl.statsf[STAT_TIMELIMIT])
1899 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
1900 minutes = (int)floor(timeleft / 60);
1901 seconds = (int)(floor(timeleft) - minutes * 60);
1904 Sbar_DrawXNum(-12*6-24, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1905 if(sb_colon && sb_colon->tex != r_texture_notexture)
1906 DrawQ_Pic(sbar_x-24 + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1907 Sbar_DrawXNum(-12*2-24, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1909 else if (minutes >= 1)
1911 Sbar_DrawXNum(-12*6-24, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
1912 if(sb_colon && sb_colon->tex != r_texture_notexture)
1913 DrawQ_Pic(sbar_x-24 + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
1914 Sbar_DrawXNum(-12*2-24, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
1916 else if ((int)(timeleft * 4) & 1)
1917 Sbar_DrawXNum(-12*2-24, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1919 Sbar_DrawXNum(-12*2-24, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
1923 minutes = (int)floor(cl.time / 60);
1924 seconds = (int)(floor(cl.time) - minutes * 60);
1925 Sbar_DrawXNum(-12*6-24, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1926 if(sb_colon && sb_colon->tex != r_texture_notexture)
1927 DrawQ_Pic(sbar_x-24 + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1928 Sbar_DrawXNum(-12*2-24, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1934 Sbar_IntermissionOverlay
1938 void Sbar_IntermissionOverlay (void)
1943 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1944 //if (cl.gametype == GAME_DEATHMATCH)
1945 if (!cl.islocalgame)
1947 Sbar_DeathmatchOverlay ();
1951 sbar_x = (vid_conwidth.integer - 320) >> 1;
1952 sbar_y = (vid_conheight.integer - 200) >> 1;
1954 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1955 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1958 dig = (int)cl.completed_time / 60;
1959 Sbar_DrawNum (160, 64, dig, 3, 0);
1960 num = (int)cl.completed_time - dig*60;
1961 Sbar_DrawPic (234,64,sb_colon);
1962 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1963 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
1965 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1966 if (gamemode != GAME_NEXUIZ)
1967 Sbar_DrawPic (232, 104, sb_slash);
1968 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1970 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1971 if (gamemode != GAME_NEXUIZ)
1972 Sbar_DrawPic (232, 144, sb_slash);
1973 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1984 void Sbar_FinaleOverlay (void)
1986 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);