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 showspeed = {CVAR_SAVE, "showspeed", "0", "shows your current speed (qu per second); number selects unit: 1 = qu/s, 2 = m/s, 3 = km/h, 4 = mph, 5 = knots"};
92 cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"};
93 cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"};
94 cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"};
95 cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"};
96 cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
97 cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
98 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 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 sbar_flagstatus_right = {CVAR_SAVE, "sbar_flagstatus_right", "0", "moves Nexuiz flag status icons to the right"};
102 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
104 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
105 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
106 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
107 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
108 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
110 void Sbar_MiniDeathmatchOverlay (int x, int y);
111 void Sbar_DeathmatchOverlay (void);
112 void Sbar_IntermissionOverlay (void);
113 void Sbar_FinaleOverlay (void);
115 void CL_VM_UpdateShowingScoresState (int showingscores);
125 void Sbar_ShowScores (void)
129 sb_showscores = true;
130 CL_VM_UpdateShowingScoresState(sb_showscores);
140 void Sbar_DontShowScores (void)
142 sb_showscores = false;
143 CL_VM_UpdateShowingScoresState(sb_showscores);
146 void sbar_start(void)
150 if (gamemode == GAME_DELUXEQUAKE)
153 else if (gamemode == GAME_SOM)
155 sb_disc = Draw_CachePic("gfx/disc", true);
157 for (i = 0;i < 10;i++)
158 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
160 somsb_health = Draw_CachePic("gfx/hud_health", true);
161 somsb_ammo[0] = Draw_CachePic("gfx/sb_shells", true);
162 somsb_ammo[1] = Draw_CachePic("gfx/sb_nails", true);
163 somsb_ammo[2] = Draw_CachePic("gfx/sb_rocket", true);
164 somsb_ammo[3] = Draw_CachePic("gfx/sb_cells", true);
165 somsb_armor[0] = Draw_CachePic("gfx/sb_armor1", true);
166 somsb_armor[1] = Draw_CachePic("gfx/sb_armor2", true);
167 somsb_armor[2] = Draw_CachePic("gfx/sb_armor3", true);
169 else if (gamemode == GAME_NEXUIZ)
171 for (i = 0;i < 10;i++)
172 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
173 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
174 sb_colon = Draw_CachePic ("gfx/num_colon", true);
176 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
177 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets", true);
178 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
179 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
181 sb_armor[0] = Draw_CachePic ("gfx/sb_armor", true);
185 sb_health = Draw_CachePic ("gfx/sb_health", true);
187 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo", true);
188 sb_items[3] = Draw_CachePic ("gfx/sb_invinc", true);
189 sb_items[4] = Draw_CachePic ("gfx/sb_energy", true);
190 sb_items[5] = Draw_CachePic ("gfx/sb_str", true);
192 sb_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken", true);
193 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost", true);
194 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying", true);
195 sb_items[14] = Draw_CachePic ("gfx/sb_key_carrying", true);
196 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken", true);
197 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost", true);
198 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying", true);
200 sb_sbar = Draw_CachePic("gfx/sbar", true);
201 sb_sbar_minimal = Draw_CachePic("gfx/sbar_minimal", true);
202 sb_sbar_overlay = Draw_CachePic("gfx/sbar_overlay", true);
204 for(i = 0; i < 9;i++)
205 sb_weapons[0][i] = Draw_CachePic(va("gfx/inv_weapon%i",i), true);
207 else if (gamemode == GAME_ZYMOTIC)
209 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center", true);
210 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line", true);
211 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health", true);
212 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip", true);
213 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo", true);
214 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background", true);
215 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1", true);
216 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2", true);
217 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right", true);
221 sb_disc = Draw_CachePic("gfx/disc", true);
223 for (i = 0;i < 10;i++)
225 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
226 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i), true);
229 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
230 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus", true);
232 sb_colon = Draw_CachePic ("gfx/num_colon", true);
233 sb_slash = Draw_CachePic ("gfx/num_slash", true);
235 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun", true);
236 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun", true);
237 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun", true);
238 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun", true);
239 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch", true);
240 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch", true);
241 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng", true);
243 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun", true);
244 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun", true);
245 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun", true);
246 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun", true);
247 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch", true);
248 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch", true);
249 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng", true);
251 for (i = 0;i < 5;i++)
253 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1), true);
254 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1), true);
255 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1), true);
256 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1), true);
257 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1), true);
258 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1), true);
259 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1), true);
262 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
263 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails", true);
264 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
265 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
267 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1", true);
268 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2", true);
269 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3", true);
271 sb_items[0] = Draw_CachePic ("gfx/sb_key1", true);
272 sb_items[1] = Draw_CachePic ("gfx/sb_key2", true);
273 sb_items[2] = Draw_CachePic ("gfx/sb_invis", true);
274 sb_items[3] = Draw_CachePic ("gfx/sb_invuln", true);
275 sb_items[4] = Draw_CachePic ("gfx/sb_suit", true);
276 sb_items[5] = Draw_CachePic ("gfx/sb_quad", true);
278 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1", true);
279 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2", true);
280 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3", true);
281 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4", true);
283 sb_faces[4][0] = Draw_CachePic ("gfx/face1", true);
284 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1", true);
285 sb_faces[3][0] = Draw_CachePic ("gfx/face2", true);
286 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2", true);
287 sb_faces[2][0] = Draw_CachePic ("gfx/face3", true);
288 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3", true);
289 sb_faces[1][0] = Draw_CachePic ("gfx/face4", true);
290 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4", true);
291 sb_faces[0][0] = Draw_CachePic ("gfx/face5", true);
292 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5", true);
294 sb_face_invis = Draw_CachePic ("gfx/face_invis", true);
295 sb_face_invuln = Draw_CachePic ("gfx/face_invul2", true);
296 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2", true);
297 sb_face_quad = Draw_CachePic ("gfx/face_quad", true);
299 sb_sbar = Draw_CachePic ("gfx/sbar", true);
300 sb_ibar = Draw_CachePic ("gfx/ibar", true);
301 sb_scorebar = Draw_CachePic ("gfx/scorebar", true);
303 //MED 01/04/97 added new hipnotic weapons
304 if (gamemode == GAME_HIPNOTIC)
306 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser", true);
307 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir", true);
308 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox", true);
309 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren", true);
310 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox", true);
312 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser", true);
313 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir", true);
314 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox", true);
315 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren", true);
316 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox", true);
318 for (i = 0;i < 5;i++)
320 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1), true);
321 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1), true);
322 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1), true);
323 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1), true);
324 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1), true);
327 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit", true);
328 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld", true);
330 else if (gamemode == GAME_ROGUE)
332 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1", true);
333 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2", true);
335 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava", true);
336 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava", true);
337 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren", true);
338 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock", true);
339 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma", true);
341 rsb_items[0] = Draw_CachePic ("gfx/r_shield1", true);
342 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1", true);
344 // PGM 01/19/97 - team color border
345 rsb_teambord = Draw_CachePic ("gfx/r_teambord", true);
346 // PGM 01/19/97 - team color border
348 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava", true);
349 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti", true);
350 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma", true);
354 sb_ranking = Draw_CachePic ("gfx/ranking", true);
355 sb_complete = Draw_CachePic ("gfx/complete", true);
356 sb_inter = Draw_CachePic ("gfx/inter", true);
357 sb_finale = Draw_CachePic ("gfx/finale", true);
360 void sbar_shutdown(void)
364 void sbar_newmap(void)
368 void Sbar_Init (void)
370 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
371 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
372 Cvar_RegisterVariable(&showfps);
373 Cvar_RegisterVariable(&showspeed);
374 Cvar_RegisterVariable(&showtime);
375 Cvar_RegisterVariable(&showtime_format);
376 Cvar_RegisterVariable(&showdate);
377 Cvar_RegisterVariable(&showdate_format);
378 Cvar_RegisterVariable(&sbar_alpha_bg);
379 Cvar_RegisterVariable(&sbar_alpha_fg);
380 Cvar_RegisterVariable(&sbar_hudselector);
381 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
382 Cvar_RegisterVariable(&cl_deathscoreboard);
384 Cvar_RegisterVariable(&crosshair_color_red);
385 Cvar_RegisterVariable(&crosshair_color_green);
386 Cvar_RegisterVariable(&crosshair_color_blue);
387 Cvar_RegisterVariable(&crosshair_color_alpha);
388 Cvar_RegisterVariable(&crosshair_size);
390 if(gamemode == GAME_NEXUIZ)
391 Cvar_RegisterVariable(&sbar_flagstatus_right); // this cvar makes no sense in other games
393 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
397 //=============================================================================
399 // drawing routines are relative to the status bar location
408 void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
410 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
413 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
415 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
418 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
420 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
427 Draws one solid graphics character
430 void Sbar_DrawCharacter (int x, int y, int num)
432 DrawQ_String_Font (sbar_x + x + 4 , sbar_y + y, va("%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, true, FONT_SBAR);
440 void Sbar_DrawString (int x, int y, char *str)
442 DrawQ_String_Font (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR);
450 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
455 l = sprintf(str, "%i", num);
469 Sbar_DrawPic (x, y, sb_nums[color][frame]);
482 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
490 l = sprintf(str, "%0*i", digits, num);
493 l = sprintf(str, "%i", num);
498 x += (digits-l) * lettersize;
507 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
514 //=============================================================================
517 int Sbar_IsTeammatch()
519 // currently only nexuiz uses the team score board
520 return ((gamemode == GAME_NEXUIZ)
521 && (teamplay.integer > 0));
529 static int fragsort[MAX_SCOREBOARD];
530 static int scoreboardlines;
532 //[515]: Sbar_GetPlayer for csqc "getplayerkey" func
533 int Sbar_GetPlayer (int index)
538 if(index >= scoreboardlines)
540 index = fragsort[index];
542 if(index >= scoreboardlines)
547 static scoreboard_t teams[MAX_SCOREBOARD];
548 static int teamsort[MAX_SCOREBOARD];
549 static int teamlines;
550 void Sbar_SortFrags (void)
556 for (i=0 ; i<cl.maxclients ; i++)
558 if (cl.scores[i].name[0])
560 fragsort[scoreboardlines] = i;
565 for (i=0 ; i<scoreboardlines ; i++)
566 for (j=0 ; j<scoreboardlines-1-i ; j++)
567 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
570 fragsort[j] = fragsort[j+1];
575 if (Sbar_IsTeammatch ())
577 // now sort players by teams.
578 for (i=0 ; i<scoreboardlines ; i++)
580 for (j=0 ; j<scoreboardlines-1-i ; j++)
582 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
585 fragsort[j] = fragsort[j+1];
591 // calculate team scores
593 for (i=0 ; i<scoreboardlines ; i++)
595 if (color != (cl.scores[fragsort[i]].colors & 15))
597 const char* teamname;
599 color = cl.scores[fragsort[i]].colors & 15;
605 teamname = "^1Red Team";
608 teamname = "^4Blue Team";
611 teamname = "^6Pink Team";
614 teamname = "^3Yellow Team";
617 teamname = "Total Team Score";
620 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
622 teams[teamlines-1].frags = 0;
623 teams[teamlines-1].colors = color + 16 * color;
626 if (cl.scores[fragsort[i]].frags != -666)
628 // do not add spedcators
629 // (ugly hack for nexuiz)
630 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
634 // now sort teams by scores.
635 for (i=0 ; i<teamlines ; i++)
637 for (i=0 ; i<teamlines ; i++)
639 for (j=0 ; j<teamlines-1-i ; j++)
641 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
644 teamsort[j] = teamsort[j+1];
657 void Sbar_SoloScoreboard (void)
660 char str[80], timestr[40];
662 int minutes, seconds;
665 t = (cl.intermission ? cl.completed_time : cl.time);
666 minutes = (int)(t / 60);
667 seconds = (int)(t - 60*floor(t/60));
669 // monsters and secrets are now both on the top row
670 if (cl.stats[STAT_TOTALMONSTERS])
671 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
672 if (cl.stats[STAT_TOTALSECRETS])
673 Sbar_DrawString(8+22*8, 4, va("Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
675 // figure out the map's filename without path or extension
676 strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
677 if (strrchr(str, '.'))
678 *(strrchr(str, '.')) = 0;
680 // append a : separator and then the full title
681 strlcat(str, ":", sizeof(str));
682 strlcat(str, cl.levelname, sizeof(str));
684 // if there's a newline character, terminate the string there
685 if (strchr(str, '\n'))
686 *(strchr(str, '\n')) = 0;
688 // make the time string
689 timelen = sprintf(timestr, " %i:%02i", minutes, seconds);
691 // truncate the level name if necessary to make room for time
693 if ((int)strlen(str) > max)
696 // print the filename and message
697 Sbar_DrawString(8, 12, str);
700 Sbar_DrawString(8 + max*8, 12, timestr);
704 int minutes, seconds, tens, units;
707 if (gamemode != GAME_NEXUIZ) {
708 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
709 Sbar_DrawString (8, 4, str);
711 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
712 Sbar_DrawString (8, 12, str);
716 minutes = (int)(cl.time / 60);
717 seconds = (int)(cl.time - 60*minutes);
719 units = seconds - 10*tens;
720 sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
721 Sbar_DrawString (184, 4, str);
724 if (gamemode == GAME_NEXUIZ) {
725 l = (int) strlen (cl.worldmodel->name);
726 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
728 l = (int) strlen (cl.levelname);
729 Sbar_DrawString (232 - l*4, 12, cl.levelname);
739 void Sbar_DrawScoreboard (void)
741 Sbar_SoloScoreboard ();
742 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
743 //if (cl.gametype == GAME_DEATHMATCH)
745 Sbar_DeathmatchOverlay ();
748 //=============================================================================
750 // AK to make DrawInventory smaller
751 static void Sbar_DrawWeapon(int nr, float fade, int active)
753 if (sbar_hudselector.integer == 1)
755 // width = 300, height = 100
756 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
758 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);
760 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);
764 // width = 300, height = 100
765 const int w_width = 300, w_height = 100, w_space = 10;
766 const float w_scale = 0.4;
768 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);
769 //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);
778 void Sbar_DrawInventory (void)
785 if (gamemode == GAME_ROGUE)
787 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
788 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
790 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
793 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
796 for (i=0 ; i<7 ; i++)
798 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
800 time = cl.item_gettime[i];
801 flashon = (int)(max(0, cl.time - time)*10);
804 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
810 flashon = (flashon%5) + 2;
812 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
818 if (gamemode == GAME_HIPNOTIC)
820 int grenadeflashing=0;
821 for (i=0 ; i<4 ; i++)
823 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
825 time = max(0, cl.item_gettime[hipweapons[i]]);
826 flashon = (int)((cl.time - time)*10);
829 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
835 flashon = (flashon%5) + 2;
837 // check grenade launcher
840 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
845 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
851 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
853 if (!grenadeflashing)
854 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
857 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
860 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
865 if (gamemode == GAME_ROGUE)
867 // check for powered up weapon.
868 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
870 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
871 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
875 for (i=0 ; i<4 ; i++)
877 sprintf (num, "%4i",cl.stats[STAT_SHELLS+i] );
879 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
881 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
883 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
885 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
889 for (i=0 ; i<6 ; i++)
890 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
892 //MED 01/04/97 changed keys
893 if (gamemode != GAME_HIPNOTIC || (i>1))
894 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
897 //MED 01/04/97 added hipnotic items
899 if (gamemode == GAME_HIPNOTIC)
901 for (i=0 ; i<2 ; i++)
902 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
903 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
906 if (gamemode == GAME_ROGUE)
909 for (i=0 ; i<2 ; i++)
910 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
911 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
916 for (i=0 ; i<4 ; i++)
917 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
918 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
922 //=============================================================================
929 void Sbar_DrawFrags (void)
939 l = min(scoreboardlines, 4);
943 for (i = 0;i < l;i++)
949 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
950 DrawQ_Fill (sbar_x + x + 10, sbar_y - 23, 28, 4, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
951 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
952 DrawQ_Fill (sbar_x + x + 10, sbar_y + 4 - 23, 28, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
956 sprintf (num, "%3i",f);
958 if (k == cl.viewentity - 1)
960 Sbar_DrawCharacter ( x + 2, -24, 16);
961 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
963 Sbar_DrawCharacter (x + 8, -24, num[0]);
964 Sbar_DrawCharacter (x + 16, -24, num[1]);
965 Sbar_DrawCharacter (x + 24, -24, num[2]);
970 //=============================================================================
978 void Sbar_DrawFace (void)
982 // PGM 01/19/97 - team color drawing
983 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
984 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
990 s = &cl.scores[cl.viewentity - 1];
992 Sbar_DrawPic (112, 0, rsb_teambord);
993 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
994 DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+3, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
995 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
996 DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+12, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1000 sprintf (num, "%3i",f);
1002 if ((s->colors & 0xf0)==0)
1005 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1007 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1009 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1013 Sbar_DrawCharacter ( 109, 3, num[0]);
1014 Sbar_DrawCharacter ( 116, 3, num[1]);
1015 Sbar_DrawCharacter ( 123, 3, num[2]);
1020 // PGM 01/19/97 - team color drawing
1022 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1023 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1024 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1025 Sbar_DrawPic (112, 0, sb_face_quad );
1026 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1027 Sbar_DrawPic (112, 0, sb_face_invis );
1028 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1029 Sbar_DrawPic (112, 0, sb_face_invuln);
1032 f = cl.stats[STAT_HEALTH] / 20;
1034 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1038 void Sbar_ShowFPS(void)
1040 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1042 char timestring[32];
1043 char datestring[32];
1044 char speedstring[32];
1045 qboolean red = false;
1050 if (showfps.integer)
1053 static double nexttime = 0, lasttime = 0;
1054 static double framerate = 0;
1055 static int framecount = 0;
1058 if (newtime >= nexttime)
1060 framerate = framecount / (newtime - lasttime);
1062 nexttime = max(nexttime + 1, lasttime - 1);
1068 if ((red = (calc < 1.0f)))
1069 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1071 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1073 if (showtime.integer)
1074 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1075 if (showdate.integer)
1076 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1077 if (showspeed.integer)
1079 double speed, speedxy, f;
1081 speed = VectorLength(cl.movement_velocity);
1082 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1083 switch(showspeed.integer)
1087 if(gamemode == GAME_NEXUIZ)
1096 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1097 // 1qu=1.5in is for non-Nexuiz only - Nexuiz players are overly large, but 1qu=1in fixes that
1102 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1106 f = 0.0254 * 3.6 * 0.6213711922;
1107 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1111 f = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
1112 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1115 dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1117 if (fpsstring[0] || timestring[0] || datestring[0] || speedstring[0])
1121 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0) + (speedstring[0] != 0));
1122 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1123 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1124 fps_y = vid_conheight.integer - fps_height;
1127 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(fpsstring, 0, true, FONT_INFOBAR) * fps_scalex;
1128 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1130 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1132 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1133 fps_y += fps_scaley;
1137 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(timestring, 0, true, FONT_INFOBAR) * fps_scalex;
1138 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1139 DrawQ_String_Font(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1140 fps_y += fps_scaley;
1144 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(datestring, 0, true, FONT_INFOBAR) * fps_scalex;
1145 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1146 DrawQ_String_Font(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1147 fps_y += fps_scaley;
1151 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(speedstring, 0, true, FONT_INFOBAR) * fps_scalex;
1152 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1153 DrawQ_String_Font(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1154 fps_y += fps_scaley;
1159 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)
1162 c2 = bound(0, c2, 1);
1163 c1 = bound(0, c1, 1 - c2);
1165 r[1] = rangey + rangeheight * (c2 + c1);
1166 r[2] = rangey + rangeheight * (c2);
1170 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);
1172 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);
1174 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);
1176 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);
1184 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1185 extern cvar_t v_kicktime;
1186 void Sbar_Score (int margin);
1187 void Sbar_Draw (void)
1191 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1194 Sbar_DrawScoreboard ();
1195 else if (cl.intermission == 1)
1197 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1199 Sbar_DrawScoreboard();
1202 Sbar_IntermissionOverlay();
1204 else if (cl.intermission == 2)
1205 Sbar_FinaleOverlay();
1206 else if (gamemode == GAME_DELUXEQUAKE)
1209 else if (gamemode == GAME_SOM)
1211 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1212 Sbar_DrawScoreboard ();
1215 // this is the top left of the sbar area
1217 sbar_y = vid_conheight.integer - 24*3;
1220 if (cl.stats[STAT_ARMOR])
1222 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1223 Sbar_DrawPic(0, 0, somsb_armor[2]);
1224 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1225 Sbar_DrawPic(0, 0, somsb_armor[1]);
1226 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1227 Sbar_DrawPic(0, 0, somsb_armor[0]);
1228 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1232 Sbar_DrawPic(0, 24, somsb_health);
1233 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1236 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1237 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1238 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1239 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1240 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1241 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1242 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1243 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1244 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1245 if (cl.stats[STAT_SHELLS])
1246 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1249 else if (gamemode == GAME_NEXUIZ)
1251 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1253 sbar_x = (vid_conwidth.integer - 640)/2;
1254 sbar_y = vid_conheight.integer - 47;
1255 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1256 Sbar_DrawScoreboard ();
1258 else if (sb_lines && sbar_hudselector.integer == 1)
1262 int redflag, blueflag;
1265 sbar_x = (vid_conwidth.integer - 320)/2;
1266 sbar_y = vid_conheight.integer - 24 - 16;
1268 // calculate intensity to draw weapons bar at
1269 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1270 fade = bound(0.7, fade, 1);
1271 for (i = 0; i < 8;i++)
1272 if (cl.stats[STAT_ITEMS] & (1 << i))
1273 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1274 if((cl.stats[STAT_ITEMS] & (1<<12)))
1275 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1278 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1279 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1280 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1281 if (redflag == 3 && blueflag == 3)
1283 // The Impossible Combination[tm]
1284 // Can only happen in Key Hunt mode...
1285 Sbar_DrawPic (x, -179, sb_items[14]);
1290 Sbar_DrawPic (x, -117, sb_items[redflag+10]);
1292 Sbar_DrawPic (x, -177, sb_items[blueflag+14]);
1296 if (cl.stats[STAT_ARMOR] > 0)
1298 Sbar_DrawStretchPic (0, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1299 if(cl.stats[STAT_ARMOR] > 200)
1300 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1301 else if(cl.stats[STAT_ARMOR] > 100)
1302 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1303 else if(cl.stats[STAT_ARMOR] > 50)
1304 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1305 else if(cl.stats[STAT_ARMOR] > 25)
1306 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1308 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1312 if (cl.stats[STAT_HEALTH] != 0)
1314 Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1315 if(cl.stats[STAT_HEALTH] > 200)
1316 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1317 else if(cl.stats[STAT_HEALTH] > 100)
1318 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1319 else if(cl.stats[STAT_HEALTH] > 50)
1320 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1321 else if(cl.stats[STAT_HEALTH] > 25)
1322 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1324 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1328 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1330 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1331 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1332 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1333 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1334 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1335 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1336 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1337 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1338 if(cl.stats[STAT_AMMO] > 10)
1339 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1341 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1344 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1345 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1348 // The margin can be at most 8 to support 640x480 console size:
1349 // 320 + 2 * (144 + 16) = 640
1355 int redflag, blueflag;
1358 sbar_x = (vid_conwidth.integer - 640)/2;
1359 sbar_y = vid_conheight.integer - 47;
1361 // calculate intensity to draw weapons bar at
1362 fade = 3 - 2 * (cl.time - cl.weapontime);
1365 fade = min(fade, 1);
1366 for (i = 0; i < 8;i++)
1367 if (cl.stats[STAT_ITEMS] & (1 << i))
1368 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1370 if((cl.stats[STAT_ITEMS] & (1<<12)))
1371 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1374 //if (!cl.islocalgame)
1375 // Sbar_DrawFrags ();
1378 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1380 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1383 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1384 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1385 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1386 if (redflag == 3 && blueflag == 3)
1388 // The Impossible Combination[tm]
1389 // Can only happen in Key Hunt mode...
1390 Sbar_DrawPic (x, -179, sb_items[14]);
1395 Sbar_DrawPic (x, -117, sb_items[redflag+10]);
1397 Sbar_DrawPic (x, -177, sb_items[blueflag+14]);
1401 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1404 if(cl.stats[STAT_HEALTH] > 100)
1405 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1406 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1407 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1409 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1411 // AK dont draw ammo for the laser
1412 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1414 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1415 Sbar_DrawPic (519, 0, sb_ammo[0]);
1416 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1417 Sbar_DrawPic (519, 0, sb_ammo[1]);
1418 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1419 Sbar_DrawPic (519, 0, sb_ammo[2]);
1420 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1421 Sbar_DrawPic (519, 0, sb_ammo[3]);
1423 if(cl.stats[STAT_AMMO] <= 10)
1424 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1426 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1431 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1433 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1434 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1439 // Mini scoreboard uses 12*4 per other team, that is, 144
1440 // pixels when there are four teams...
1441 // Nexuiz by default sets vid_conwidth to 800... makes
1443 // so we need to shift it by 64 pixels to the right to fit
1444 // BUT: then it overlaps with the image that gets drawn
1445 // for viewsize 100! Therefore, just account for 3 teams,
1446 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1450 else if (gamemode == GAME_ZYMOTIC)
1453 float scale = 64.0f / 256.0f;
1454 float kickoffset[3];
1455 VectorClear(kickoffset);
1458 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1459 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1461 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1462 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1463 // left1 16, 48 : 126 -66
1464 // left2 16, 128 : 196 -66
1465 // right 176, 48 : 196 -136
1466 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);
1467 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);
1468 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);
1469 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1471 float scale = 128.0f / 256.0f;
1472 float healthstart, healthheight, healthstarttc, healthendtc;
1473 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1474 float ammostart, ammoheight, ammostarttc, ammoendtc;
1475 float clipstart, clipheight, clipstarttc, clipendtc;
1476 float kickoffset[3], offset;
1477 VectorClear(kickoffset);
1480 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1481 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1483 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1484 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1485 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1486 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);
1487 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);
1488 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);
1489 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);
1490 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1491 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1492 healthstart = 204 - healthheight;
1493 shieldstart = healthstart - shieldheight;
1494 healthstarttc = healthstart * (1.0f / 256.0f);
1495 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1496 shieldstarttc = shieldstart * (1.0f / 256.0f);
1497 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1498 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1499 ammostart = 114 - ammoheight;
1500 ammostarttc = ammostart * (1.0f / 256.0f);
1501 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1502 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1503 clipstart = 190 - clipheight;
1504 clipstarttc = clipstart * (1.0f / 256.0f);
1505 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1506 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);
1507 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);
1508 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);
1509 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);
1510 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1511 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1514 else // Quake and others
1516 sbar_x = (vid_conwidth.integer - 320)/2;
1517 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1518 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1519 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1523 if (gamemode != GAME_GOODVSBAD2)
1524 Sbar_DrawInventory ();
1525 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1529 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1531 if (gamemode != GAME_GOODVSBAD2)
1532 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1533 Sbar_DrawScoreboard ();
1537 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1539 // keys (hipnotic only)
1540 //MED 01/04/97 moved keys here so they would not be overwritten
1541 if (gamemode == GAME_HIPNOTIC)
1543 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1544 Sbar_DrawPic (209, 3, sb_items[0]);
1545 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1546 Sbar_DrawPic (209, 12, sb_items[1]);
1549 if (gamemode != GAME_GOODVSBAD2)
1551 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1553 Sbar_DrawNum (24, 0, 666, 3, 1);
1554 Sbar_DrawPic (0, 0, sb_disc);
1558 if (gamemode == GAME_ROGUE)
1560 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1561 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1562 Sbar_DrawPic (0, 0, sb_armor[2]);
1563 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1564 Sbar_DrawPic (0, 0, sb_armor[1]);
1565 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1566 Sbar_DrawPic (0, 0, sb_armor[0]);
1570 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1571 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1572 Sbar_DrawPic (0, 0, sb_armor[2]);
1573 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1574 Sbar_DrawPic (0, 0, sb_armor[1]);
1575 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1576 Sbar_DrawPic (0, 0, sb_armor[0]);
1585 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1588 if (gamemode == GAME_ROGUE)
1590 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1591 Sbar_DrawPic (224, 0, sb_ammo[0]);
1592 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1593 Sbar_DrawPic (224, 0, sb_ammo[1]);
1594 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1595 Sbar_DrawPic (224, 0, sb_ammo[2]);
1596 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1597 Sbar_DrawPic (224, 0, sb_ammo[3]);
1598 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1599 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1600 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1601 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1602 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1603 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1607 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1608 Sbar_DrawPic (224, 0, sb_ammo[0]);
1609 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1610 Sbar_DrawPic (224, 0, sb_ammo[1]);
1611 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1612 Sbar_DrawPic (224, 0, sb_ammo[2]);
1613 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1614 Sbar_DrawPic (224, 0, sb_ammo[3]);
1617 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1619 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1620 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1622 if (gamemode == GAME_TRANSFUSION)
1623 Sbar_MiniDeathmatchOverlay (0, 0);
1625 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1634 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1636 pic = Draw_CachePic(va("gfx/crosshair%i", crosshair.integer), true);
1637 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);
1640 if (cl_prydoncursor.integer)
1641 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);
1644 //=============================================================================
1648 Sbar_DeathmatchOverlay
1652 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1655 qboolean myself = false;
1657 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1659 if((s - cl.scores) == cl.playerentity - 1)
1661 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1662 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1665 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1667 if (s->qw_spectator)
1669 if (s->qw_ping || s->qw_packetloss)
1670 DrawQ_String_Font(x, y, va("%4i %3i %4i spectator %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1672 DrawQ_String_Font(x, y, va(" %4i spectator %c%s", minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1676 // draw colors behind score
1682 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1683 DrawQ_Fill(x + 14*8*FONT_SBAR->width_of[0], y+1, 40*FONT_SBAR->width_of[0], 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1684 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1685 DrawQ_Fill(x + 14*8*FONT_SBAR->width_of[0], y+4, 40*FONT_SBAR->width_of[0], 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1687 //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);
1688 if (s->qw_ping || s->qw_packetloss)
1689 DrawQ_String_Font(x, y, va("%4i %3i %4i %5i %-4s %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1691 DrawQ_String_Font(x, y, va(" %4i %5i %-4s %c%s", minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1696 if (s->qw_spectator)
1698 if (s->qw_ping || s->qw_packetloss)
1699 DrawQ_String_Font(x, y, va("%4i %3i spect %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1701 DrawQ_String_Font(x, y, va(" spect %c%s", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1705 // draw colors behind score
1706 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1707 DrawQ_Fill(x + 9*8*FONT_SBAR->width_of[0], y+1, 40*FONT_SBAR->width_of[0], 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1708 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1709 DrawQ_Fill(x + 9*8*FONT_SBAR->width_of[0], y+4, 40*FONT_SBAR->width_of[0], 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1711 //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);
1712 if (s->qw_ping || s->qw_packetloss)
1713 DrawQ_String_Font(x, y, va("%4i %3i %5i %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1715 DrawQ_String_Font(x, y, va(" %5i %c%s", (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1721 void Sbar_DeathmatchOverlay (void)
1723 int i, y, xmin, xmax, ymin, ymax;
1725 // request new ping times every two second
1726 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1728 cl.last_ping_request = realtime;
1729 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1731 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1732 MSG_WriteString(&cls.netcon->message, "pings");
1734 else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6/* || cls.protocol == PROTOCOL_DARKPLACES7*/)
1736 // 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
1737 static int ping_anyway_counter = 0;
1738 if(cl.parsingtextexpectingpingforscores == 1)
1740 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1741 if(++ping_anyway_counter >= 5)
1742 cl.parsingtextexpectingpingforscores = 0;
1744 if(cl.parsingtextexpectingpingforscores != 1)
1746 ping_anyway_counter = 0;
1747 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1748 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1749 MSG_WriteString(&cls.netcon->message, "ping");
1754 // 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
1755 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1756 MSG_WriteString(&cls.netcon->message, "pings");
1764 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1766 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1767 xmin = (vid_conwidth.integer - (26 + 15) * 8 * FONT_SBAR->width_of[0]) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1769 xmin = (vid_conwidth.integer - (16 + 25) * 8 * FONT_SBAR->width_of[0]) / 2; // 16 characters until name, then we assume 25 character names (they can be longer but usually aren't)
1770 xmax = vid_conwidth.integer - xmin;
1772 if(gamemode == GAME_NEXUIZ)
1773 DrawQ_Pic (xmin - 8, ymin - 8, 0, xmax-xmin+1 + 2*8, ymax-ymin+1 + 2*8, 0, 0, 0, sbar_alpha_bg.value, 0);
1775 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1779 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1781 DrawQ_String_Font(xmin, y, va("ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1785 DrawQ_String_Font(xmin, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1789 if (Sbar_IsTeammatch ())
1791 // show team scores first
1792 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1793 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1797 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1798 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1803 Sbar_MiniDeathmatchOverlay
1807 void Sbar_MiniDeathmatchOverlay (int x, int y)
1809 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1811 // do not draw this if sbar_miniscoreboard_size is zero
1812 if(sbar_miniscoreboard_size.value == 0)
1814 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1815 if(sbar_miniscoreboard_size.value > 0)
1816 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1821 // decide where to print
1822 if (gamemode == GAME_TRANSFUSION)
1823 numlines = (vid_conwidth.integer - x + 127) / 128;
1825 numlines = (vid_conheight.integer - y + 7) / 8;
1827 // give up if there isn't room
1828 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1832 for (i = 0; i < scoreboardlines; i++)
1833 if (fragsort[i] == cl.playerentity - 1)
1837 range_end = scoreboardlines;
1840 if (gamemode != GAME_TRANSFUSION)
1841 if (Sbar_IsTeammatch ())
1843 // reserve space for the team scores
1844 numlines -= teamlines;
1846 // find first and last player of my team (only draw the team totals and my own team)
1847 range_begin = range_end = i;
1848 myteam = cl.scores[fragsort[i]].colors & 15;
1849 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1851 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1854 // looks better than two players
1864 i = min(i, range_end - numlines);
1865 i = max(i, range_begin);
1867 if (gamemode == GAME_TRANSFUSION)
1869 for (;i < range_end && x < vid_conwidth.integer;i++)
1870 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1874 if(range_end - i < numlines) // won't draw to bottom?
1875 y += 8 * (numlines - (range_end - i)); // bottom align
1876 // show team scores first
1877 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1878 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1880 for (;i < range_end && y < vid_conheight.integer;i++)
1881 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1885 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1887 static int const sortorder[16] =
1906 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1907 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1908 int tc1 = sortorder[t1->colors & 15];
1909 int tc2 = sortorder[t2->colors & 15];
1913 void Sbar_Score (int margin)
1915 int i, me, score, otherleader, place, distribution, minutes, seconds;
1917 int sbar_x_save = sbar_x;
1918 int sbar_y_save = sbar_y;
1920 sbar_y = vid_conheight.value - (32+12);
1923 me = cl.playerentity - 1;
1924 if (me >= 0 && me < cl.maxclients)
1926 if(Sbar_IsTeammatch())
1930 // team1 team3 team4
1934 scoreboard_t *teamcolorsort[16];
1937 for(i = 0; i < teamlines; ++i)
1938 teamcolorsort[i] = &(teams[i]);
1940 // Now sort them by color
1941 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1944 // -12*4: four digits space
1945 place = (teamlines - 1) * (-12 * 4);
1947 for(i = 0; i < teamlines; ++i)
1949 int cindex = teamcolorsort[i]->colors & 15;
1950 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
1951 float cm = max(max(c[0], c[1]), c[2]);
1952 float cr = c[0] / cm;
1953 float cg = c[1] / cm;
1954 float cb = c[2] / cm;
1955 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1957 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1961 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1974 // find leading score other than ourselves, to calculate distribution
1975 // find our place in the scoreboard
1976 score = cl.scores[me].frags;
1977 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1979 if (cl.scores[i].name[0] && i != me)
1981 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1983 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1987 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1989 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1990 else if (place == 2)
1991 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
1993 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
1994 if (otherleader < 0)
1995 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1996 if (distribution >= 0)
1998 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
1999 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2001 else if (distribution >= -5)
2003 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2004 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2008 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2009 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2014 if (cl.statsf[STAT_TIMELIMIT])
2016 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2017 minutes = (int)floor(timeleft / 60);
2018 seconds = (int)(floor(timeleft) - minutes * 60);
2021 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2022 if(sb_colon && sb_colon->tex != r_texture_notexture)
2023 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2024 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2026 else if (minutes >= 1)
2028 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2029 if(sb_colon && sb_colon->tex != r_texture_notexture)
2030 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2031 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2033 else if ((int)(timeleft * 4) & 1)
2034 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2036 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2040 minutes = (int)floor(cl.time / 60);
2041 seconds = (int)(floor(cl.time) - minutes * 60);
2042 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2043 if(sb_colon && sb_colon->tex != r_texture_notexture)
2044 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2045 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2048 sbar_x = sbar_x_save;
2049 sbar_y = sbar_y_save;
2054 Sbar_IntermissionOverlay
2058 void Sbar_IntermissionOverlay (void)
2063 if (cl.gametype == GAME_DEATHMATCH)
2065 Sbar_DeathmatchOverlay ();
2069 sbar_x = (vid_conwidth.integer - 320) >> 1;
2070 sbar_y = (vid_conheight.integer - 200) >> 1;
2072 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2073 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2076 dig = (int)cl.completed_time / 60;
2077 Sbar_DrawNum (160, 64, dig, 3, 0);
2078 num = (int)cl.completed_time - dig*60;
2079 Sbar_DrawPic (234,64,sb_colon);
2080 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2081 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2083 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2084 if (gamemode != GAME_NEXUIZ)
2085 Sbar_DrawPic (232, 104, sb_slash);
2086 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2088 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2089 if (gamemode != GAME_NEXUIZ)
2090 Sbar_DrawPic (232, 144, sb_slash);
2091 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2102 void Sbar_FinaleOverlay (void)
2104 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);