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] > 100)
1242 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0,1,0);
1243 else if(cl.stats[STAT_ARMOR] > 25)
1244 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1246 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1250 if (cl.stats[STAT_HEALTH] != 0)
1252 Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1253 if(cl.stats[STAT_HEALTH] > 100)
1254 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0,1,0);
1255 else if(cl.stats[STAT_HEALTH] > 25)
1256 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1258 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1262 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1264 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1265 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1266 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1267 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1268 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1269 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1270 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1271 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1272 if(cl.stats[STAT_AMMO] > 10)
1273 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1275 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1278 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1279 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1282 // The margin can be at most 8 to support 640x480 console size:
1283 // 320 + 2 * (144 + 16) = 640
1289 int redflag, blueflag;
1291 sbar_x = (vid_conwidth.integer - 640)/2;
1292 sbar_y = vid_conheight.integer - 47;
1294 // calculate intensity to draw weapons bar at
1295 fade = 3 - 2 * (cl.time - cl.weapontime);
1298 fade = min(fade, 1);
1299 for (i = 0; i < 8;i++)
1300 if (cl.stats[STAT_ITEMS] & (1 << i))
1301 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1303 if((cl.stats[STAT_ITEMS] & (1<<12)))
1304 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1307 //if (!cl.islocalgame)
1308 // Sbar_DrawFrags ();
1311 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1313 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1316 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1317 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1318 if (redflag == 3 && blueflag == 3)
1320 // The Impossible Combination[tm]
1321 // Can only happen in Key Hunt mode...
1322 Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1327 Sbar_DrawPic (10 - sbar_x, -117, sb_items[redflag+10]);
1329 Sbar_DrawPic (10 - sbar_x, -177, sb_items[blueflag+14]);
1333 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1336 if(cl.stats[STAT_HEALTH] > 100)
1337 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1338 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1339 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1341 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1343 // AK dont draw ammo for the laser
1344 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1346 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1347 Sbar_DrawPic (519, 0, sb_ammo[0]);
1348 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1349 Sbar_DrawPic (519, 0, sb_ammo[1]);
1350 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1351 Sbar_DrawPic (519, 0, sb_ammo[2]);
1352 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1353 Sbar_DrawPic (519, 0, sb_ammo[3]);
1355 if(cl.stats[STAT_AMMO] <= 10)
1356 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1358 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1363 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1365 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1366 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1371 // Mini scoreboard uses 12*4 per other team, that is, 144
1372 // pixels when there are four teams...
1373 // Nexuiz by default sets vid_conwidth to 800... makes
1375 // so we need to shift it by 64 pixels to the right to fit
1376 // BUT: then it overlaps with the image that gets drawn
1377 // for viewsize 100! Therefore, just account for 3 teams,
1378 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1382 else if (gamemode == GAME_ZYMOTIC)
1385 float scale = 64.0f / 256.0f;
1386 float kickoffset[3];
1387 VectorClear(kickoffset);
1390 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1391 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1393 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1394 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1395 // left1 16, 48 : 126 -66
1396 // left2 16, 128 : 196 -66
1397 // right 176, 48 : 196 -136
1398 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);
1399 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);
1400 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);
1401 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1403 float scale = 128.0f / 256.0f;
1404 float healthstart, healthheight, healthstarttc, healthendtc;
1405 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1406 float ammostart, ammoheight, ammostarttc, ammoendtc;
1407 float clipstart, clipheight, clipstarttc, clipendtc;
1408 float kickoffset[3], offset;
1409 VectorClear(kickoffset);
1412 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1413 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1415 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1416 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1417 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1418 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);
1419 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);
1420 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);
1421 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);
1422 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1423 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1424 healthstart = 204 - healthheight;
1425 shieldstart = healthstart - shieldheight;
1426 healthstarttc = healthstart * (1.0f / 256.0f);
1427 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1428 shieldstarttc = shieldstart * (1.0f / 256.0f);
1429 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1430 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1431 ammostart = 114 - ammoheight;
1432 ammostarttc = ammostart * (1.0f / 256.0f);
1433 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1434 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1435 clipstart = 190 - clipheight;
1436 clipstarttc = clipstart * (1.0f / 256.0f);
1437 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1438 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);
1439 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);
1440 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);
1441 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);
1442 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1443 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1446 else // Quake and others
1448 sbar_x = (vid_conwidth.integer - 320)/2;
1449 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1450 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1451 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1455 if (gamemode != GAME_GOODVSBAD2)
1456 Sbar_DrawInventory ();
1457 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1461 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1463 if (gamemode != GAME_GOODVSBAD2)
1464 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1465 Sbar_DrawScoreboard ();
1469 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1471 // keys (hipnotic only)
1472 //MED 01/04/97 moved keys here so they would not be overwritten
1473 if (gamemode == GAME_HIPNOTIC)
1475 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1476 Sbar_DrawPic (209, 3, sb_items[0]);
1477 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1478 Sbar_DrawPic (209, 12, sb_items[1]);
1481 if (gamemode != GAME_GOODVSBAD2)
1483 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1485 Sbar_DrawNum (24, 0, 666, 3, 1);
1486 Sbar_DrawPic (0, 0, sb_disc);
1490 if (gamemode == GAME_ROGUE)
1492 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1493 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1494 Sbar_DrawPic (0, 0, sb_armor[2]);
1495 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1496 Sbar_DrawPic (0, 0, sb_armor[1]);
1497 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1498 Sbar_DrawPic (0, 0, sb_armor[0]);
1502 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1503 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1504 Sbar_DrawPic (0, 0, sb_armor[2]);
1505 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1506 Sbar_DrawPic (0, 0, sb_armor[1]);
1507 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1508 Sbar_DrawPic (0, 0, sb_armor[0]);
1517 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1520 if (gamemode == GAME_ROGUE)
1522 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1523 Sbar_DrawPic (224, 0, sb_ammo[0]);
1524 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1525 Sbar_DrawPic (224, 0, sb_ammo[1]);
1526 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1527 Sbar_DrawPic (224, 0, sb_ammo[2]);
1528 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1529 Sbar_DrawPic (224, 0, sb_ammo[3]);
1530 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1531 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1532 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1533 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1534 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1535 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1539 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1540 Sbar_DrawPic (224, 0, sb_ammo[0]);
1541 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1542 Sbar_DrawPic (224, 0, sb_ammo[1]);
1543 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1544 Sbar_DrawPic (224, 0, sb_ammo[2]);
1545 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1546 Sbar_DrawPic (224, 0, sb_ammo[3]);
1549 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1551 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1552 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1554 if (gamemode == GAME_TRANSFUSION)
1555 Sbar_MiniDeathmatchOverlay (0, 0);
1557 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1566 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1567 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);
1569 if (cl_prydoncursor.integer)
1570 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);
1573 //=============================================================================
1577 Sbar_DeathmatchOverlay
1581 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1584 qboolean myself = false;
1586 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1588 if((s - cl.scores) == cl.playerentity - 1)
1590 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1591 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1594 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1596 if (s->qw_spectator)
1598 if (s->qw_ping || s->qw_packetloss)
1599 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 );
1601 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 );
1605 // draw colors behind score
1611 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
1612 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);
1613 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
1614 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);
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 %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 );
1620 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 );
1625 if (s->qw_spectator)
1627 if (s->qw_ping || s->qw_packetloss)
1628 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 );
1630 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 );
1634 // draw colors behind score
1635 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
1636 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);
1637 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
1638 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);
1640 //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);
1641 if (s->qw_ping || s->qw_packetloss)
1642 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 );
1644 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 );
1650 void Sbar_DeathmatchOverlay (void)
1654 // request new ping times every two second
1655 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1657 cl.last_ping_request = realtime;
1658 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1660 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1661 MSG_WriteString(&cls.netcon->message, "pings");
1663 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*/)
1665 // 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
1666 static int ping_anyway_counter = 0;
1667 if(cl.parsingtextexpectingpingforscores == 1)
1669 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1670 if(++ping_anyway_counter >= 5)
1671 cl.parsingtextexpectingpingforscores = 0;
1673 if(cl.parsingtextexpectingpingforscores != 1)
1675 ping_anyway_counter = 0;
1676 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1677 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1678 MSG_WriteString(&cls.netcon->message, "ping");
1683 // 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
1684 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1685 MSG_WriteString(&cls.netcon->message, "pings");
1689 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1695 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1697 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)
1698 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 );
1702 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)
1703 DrawQ_String(x, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1707 if (Sbar_IsTeammatch ())
1709 // show team scores first
1710 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1711 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1715 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1716 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1721 Sbar_MiniDeathmatchOverlay
1725 void Sbar_MiniDeathmatchOverlay (int x, int y)
1727 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1729 // do not draw this if sbar_miniscoreboard_size is zero
1730 if(sbar_miniscoreboard_size.value == 0)
1732 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1733 if(sbar_miniscoreboard_size.value > 0)
1734 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1739 // decide where to print
1740 if (gamemode == GAME_TRANSFUSION)
1741 numlines = (vid_conwidth.integer - x + 127) / 128;
1743 numlines = (vid_conheight.integer - y + 7) / 8;
1745 // give up if there isn't room
1746 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1750 for (i = 0; i < scoreboardlines; i++)
1751 if (fragsort[i] == cl.playerentity - 1)
1755 range_end = scoreboardlines;
1758 if (gamemode != GAME_TRANSFUSION)
1759 if (Sbar_IsTeammatch ())
1761 // reserve space for the team scores
1762 numlines -= teamlines;
1764 // find first and last player of my team (only draw the team totals and my own team)
1765 range_begin = range_end = i;
1766 myteam = cl.scores[fragsort[i]].colors & 15;
1767 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1769 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1772 // looks better than two players
1782 i = min(i, range_end - numlines);
1783 i = max(i, range_begin);
1785 if (gamemode == GAME_TRANSFUSION)
1787 for (;i < range_end && x < vid_conwidth.integer;i++)
1788 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1792 if(range_end - i < numlines) // won't draw to bottom?
1793 y += 8 * (numlines - (range_end - i)); // bottom align
1794 // show team scores first
1795 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1796 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1798 for (;i < range_end && y < vid_conheight.integer;i++)
1799 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1803 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1805 static int const sortorder[16] =
1824 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1825 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1826 int tc1 = sortorder[t1->colors & 15];
1827 int tc2 = sortorder[t2->colors & 15];
1831 void Sbar_Score (int margin)
1833 int i, me, score, otherleader, place, distribution, minutes, seconds;
1835 int sbar_x_save = sbar_x;
1836 int sbar_y_save = sbar_y;
1838 sbar_y = vid_conheight.value - (32+12);
1841 me = cl.playerentity - 1;
1842 if (me >= 0 && me < cl.maxclients)
1844 if(Sbar_IsTeammatch())
1848 // team1 team3 team4
1852 scoreboard_t *teamcolorsort[16];
1855 for(i = 0; i < teamlines; ++i)
1856 teamcolorsort[i] = &(teams[i]);
1858 // Now sort them by color
1859 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1862 // -12*4: four digits space
1863 place = (teamlines - 1) * (-12 * 4);
1865 for(i = 0; i < teamlines; ++i)
1867 int cindex = teamcolorsort[i]->colors & 15;
1868 unsigned char *c = (unsigned char *)&palette_shirtscoreboard[cindex];
1869 float cm = max(max(c[0], c[1]), c[2]);
1870 float cr = c[0] / cm;
1871 float cg = c[1] / cm;
1872 float cb = c[2] / cm;
1873 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1875 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1879 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1892 // find leading score other than ourselves, to calculate distribution
1893 // find our place in the scoreboard
1894 score = cl.scores[me].frags;
1895 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1897 if (cl.scores[i].name[0] && i != me)
1899 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1901 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1905 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1907 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1908 else if (place == 2)
1909 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
1911 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
1912 if (otherleader < 0)
1913 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1914 if (distribution >= 0)
1916 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
1917 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1919 else if (distribution >= -5)
1921 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
1922 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
1926 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
1927 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
1932 if (cl.statsf[STAT_TIMELIMIT])
1934 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
1935 minutes = (int)floor(timeleft / 60);
1936 seconds = (int)(floor(timeleft) - minutes * 60);
1939 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1940 if(sb_colon && sb_colon->tex != r_texture_notexture)
1941 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1942 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1944 else if (minutes >= 1)
1946 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
1947 if(sb_colon && sb_colon->tex != r_texture_notexture)
1948 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
1949 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
1951 else if ((int)(timeleft * 4) & 1)
1952 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1954 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
1958 minutes = (int)floor(cl.time / 60);
1959 seconds = (int)(floor(cl.time) - minutes * 60);
1960 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1961 if(sb_colon && sb_colon->tex != r_texture_notexture)
1962 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1963 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1966 sbar_x = sbar_x_save;
1967 sbar_y = sbar_y_save;
1972 Sbar_IntermissionOverlay
1976 void Sbar_IntermissionOverlay (void)
1981 if (cl.gametype == GAME_DEATHMATCH)
1983 Sbar_DeathmatchOverlay ();
1987 sbar_x = (vid_conwidth.integer - 320) >> 1;
1988 sbar_y = (vid_conheight.integer - 200) >> 1;
1990 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1991 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1994 dig = (int)cl.completed_time / 60;
1995 Sbar_DrawNum (160, 64, dig, 3, 0);
1996 num = (int)cl.completed_time - dig*60;
1997 Sbar_DrawPic (234,64,sb_colon);
1998 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1999 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2001 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2002 if (gamemode != GAME_NEXUIZ)
2003 Sbar_DrawPic (232, 104, sb_slash);
2004 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2006 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2007 if (gamemode != GAME_NEXUIZ)
2008 Sbar_DrawPic (232, 144, sb_slash);
2009 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2020 void Sbar_FinaleOverlay (void)
2022 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);