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"};
99 cvar_t sbar_flagstatus_right = {CVAR_SAVE, "sbar_flagstatus_right", "0", "moves Nexuiz flag status icons to the right"};
101 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
103 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
104 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
105 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
106 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
107 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
109 void Sbar_MiniDeathmatchOverlay (int x, int y);
110 void Sbar_DeathmatchOverlay (void);
111 void Sbar_IntermissionOverlay (void);
112 void Sbar_FinaleOverlay (void);
114 void CL_VM_UpdateShowingScoresState (int showingscores);
124 void Sbar_ShowScores (void)
128 sb_showscores = true;
129 CL_VM_UpdateShowingScoresState(sb_showscores);
139 void Sbar_DontShowScores (void)
141 sb_showscores = false;
142 CL_VM_UpdateShowingScoresState(sb_showscores);
145 void sbar_start(void)
149 if (gamemode == GAME_DELUXEQUAKE)
152 else if (gamemode == GAME_SOM)
154 sb_disc = Draw_CachePic("gfx/disc", true);
156 for (i = 0;i < 10;i++)
157 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
159 somsb_health = Draw_CachePic("gfx/hud_health", true);
160 somsb_ammo[0] = Draw_CachePic("gfx/sb_shells", true);
161 somsb_ammo[1] = Draw_CachePic("gfx/sb_nails", true);
162 somsb_ammo[2] = Draw_CachePic("gfx/sb_rocket", true);
163 somsb_ammo[3] = Draw_CachePic("gfx/sb_cells", true);
164 somsb_armor[0] = Draw_CachePic("gfx/sb_armor1", true);
165 somsb_armor[1] = Draw_CachePic("gfx/sb_armor2", true);
166 somsb_armor[2] = Draw_CachePic("gfx/sb_armor3", true);
168 else if (gamemode == GAME_NEXUIZ)
170 for (i = 0;i < 10;i++)
171 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
172 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
173 sb_colon = Draw_CachePic ("gfx/num_colon", true);
175 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
176 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets", true);
177 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
178 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
180 sb_armor[0] = Draw_CachePic ("gfx/sb_armor", true);
184 sb_health = Draw_CachePic ("gfx/sb_health", true);
186 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo", true);
187 sb_items[3] = Draw_CachePic ("gfx/sb_invinc", true);
188 sb_items[4] = Draw_CachePic ("gfx/sb_energy", true);
189 sb_items[5] = Draw_CachePic ("gfx/sb_str", true);
191 sb_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken", true);
192 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost", true);
193 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying", true);
194 sb_items[14] = Draw_CachePic ("gfx/sb_key_carrying", true);
195 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken", true);
196 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost", true);
197 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying", true);
199 sb_sbar = Draw_CachePic("gfx/sbar", true);
200 sb_sbar_minimal = Draw_CachePic("gfx/sbar_minimal", true);
201 sb_sbar_overlay = Draw_CachePic("gfx/sbar_overlay", true);
203 for(i = 0; i < 9;i++)
204 sb_weapons[0][i] = Draw_CachePic(va("gfx/inv_weapon%i",i), true);
206 else if (gamemode == GAME_ZYMOTIC)
208 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center", true);
209 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line", true);
210 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health", true);
211 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip", true);
212 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo", true);
213 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background", true);
214 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1", true);
215 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2", true);
216 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right", true);
220 sb_disc = Draw_CachePic("gfx/disc", true);
222 for (i = 0;i < 10;i++)
224 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
225 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i), true);
228 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
229 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus", true);
231 sb_colon = Draw_CachePic ("gfx/num_colon", true);
232 sb_slash = Draw_CachePic ("gfx/num_slash", true);
234 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun", true);
235 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun", true);
236 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun", true);
237 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun", true);
238 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch", true);
239 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch", true);
240 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng", true);
242 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun", true);
243 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun", true);
244 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun", true);
245 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun", true);
246 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch", true);
247 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch", true);
248 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng", true);
250 for (i = 0;i < 5;i++)
252 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1), true);
253 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1), true);
254 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1), true);
255 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1), true);
256 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1), true);
257 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1), true);
258 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1), true);
261 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
262 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails", true);
263 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
264 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
266 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1", true);
267 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2", true);
268 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3", true);
270 sb_items[0] = Draw_CachePic ("gfx/sb_key1", true);
271 sb_items[1] = Draw_CachePic ("gfx/sb_key2", true);
272 sb_items[2] = Draw_CachePic ("gfx/sb_invis", true);
273 sb_items[3] = Draw_CachePic ("gfx/sb_invuln", true);
274 sb_items[4] = Draw_CachePic ("gfx/sb_suit", true);
275 sb_items[5] = Draw_CachePic ("gfx/sb_quad", true);
277 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1", true);
278 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2", true);
279 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3", true);
280 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4", true);
282 sb_faces[4][0] = Draw_CachePic ("gfx/face1", true);
283 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1", true);
284 sb_faces[3][0] = Draw_CachePic ("gfx/face2", true);
285 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2", true);
286 sb_faces[2][0] = Draw_CachePic ("gfx/face3", true);
287 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3", true);
288 sb_faces[1][0] = Draw_CachePic ("gfx/face4", true);
289 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4", true);
290 sb_faces[0][0] = Draw_CachePic ("gfx/face5", true);
291 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5", true);
293 sb_face_invis = Draw_CachePic ("gfx/face_invis", true);
294 sb_face_invuln = Draw_CachePic ("gfx/face_invul2", true);
295 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2", true);
296 sb_face_quad = Draw_CachePic ("gfx/face_quad", true);
298 sb_sbar = Draw_CachePic ("gfx/sbar", true);
299 sb_ibar = Draw_CachePic ("gfx/ibar", true);
300 sb_scorebar = Draw_CachePic ("gfx/scorebar", true);
302 //MED 01/04/97 added new hipnotic weapons
303 if (gamemode == GAME_HIPNOTIC)
305 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser", true);
306 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir", true);
307 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox", true);
308 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren", true);
309 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox", true);
311 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser", true);
312 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir", true);
313 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox", true);
314 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren", true);
315 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox", true);
317 for (i = 0;i < 5;i++)
319 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1), true);
320 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1), true);
321 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1), true);
322 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1), true);
323 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1), true);
326 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit", true);
327 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld", true);
329 else if (gamemode == GAME_ROGUE)
331 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1", true);
332 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2", true);
334 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava", true);
335 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava", true);
336 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren", true);
337 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock", true);
338 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma", true);
340 rsb_items[0] = Draw_CachePic ("gfx/r_shield1", true);
341 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1", true);
343 // PGM 01/19/97 - team color border
344 rsb_teambord = Draw_CachePic ("gfx/r_teambord", true);
345 // PGM 01/19/97 - team color border
347 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava", true);
348 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti", true);
349 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma", true);
353 sb_ranking = Draw_CachePic ("gfx/ranking", true);
354 sb_complete = Draw_CachePic ("gfx/complete", true);
355 sb_inter = Draw_CachePic ("gfx/inter", true);
356 sb_finale = Draw_CachePic ("gfx/finale", true);
359 void sbar_shutdown(void)
363 void sbar_newmap(void)
367 void Sbar_Init (void)
369 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
370 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
371 Cvar_RegisterVariable(&showfps);
372 Cvar_RegisterVariable(&showtime);
373 Cvar_RegisterVariable(&showtime_format);
374 Cvar_RegisterVariable(&showdate);
375 Cvar_RegisterVariable(&showdate_format);
376 Cvar_RegisterVariable(&sbar_alpha_bg);
377 Cvar_RegisterVariable(&sbar_alpha_fg);
378 Cvar_RegisterVariable(&sbar_hudselector);
379 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
380 Cvar_RegisterVariable(&cl_deathscoreboard);
382 Cvar_RegisterVariable(&crosshair_color_red);
383 Cvar_RegisterVariable(&crosshair_color_green);
384 Cvar_RegisterVariable(&crosshair_color_blue);
385 Cvar_RegisterVariable(&crosshair_color_alpha);
386 Cvar_RegisterVariable(&crosshair_size);
388 if(gamemode == GAME_NEXUIZ)
389 Cvar_RegisterVariable(&sbar_flagstatus_right); // this cvar makes no sense in other games
391 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
395 //=============================================================================
397 // drawing routines are relative to the status bar location
406 void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
408 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
411 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
413 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
416 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
418 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
425 Draws one solid graphics character
428 void Sbar_DrawCharacter (int x, int y, int num)
430 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);
438 void Sbar_DrawString (int x, int y, char *str)
440 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);
448 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
453 l = sprintf(str, "%i", num);
467 Sbar_DrawPic (x, y, sb_nums[color][frame]);
480 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
488 l = sprintf(str, "%0*i", digits, num);
491 l = sprintf(str, "%i", num);
496 x += (digits-l) * lettersize;
505 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
512 //=============================================================================
515 int Sbar_IsTeammatch()
517 // currently only nexuiz uses the team score board
518 return ((gamemode == GAME_NEXUIZ)
519 && (teamplay.integer > 0));
527 static int fragsort[MAX_SCOREBOARD];
528 static int scoreboardlines;
530 //[515]: Sbar_GetPlayer for csqc "getplayerkey" func
531 int Sbar_GetPlayer (int index)
536 if(index >= scoreboardlines)
538 index = fragsort[index];
540 if(index >= scoreboardlines)
545 static scoreboard_t teams[MAX_SCOREBOARD];
546 static int teamsort[MAX_SCOREBOARD];
547 static int teamlines;
548 void Sbar_SortFrags (void)
554 for (i=0 ; i<cl.maxclients ; i++)
556 if (cl.scores[i].name[0])
558 fragsort[scoreboardlines] = i;
563 for (i=0 ; i<scoreboardlines ; i++)
564 for (j=0 ; j<scoreboardlines-1-i ; j++)
565 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
568 fragsort[j] = fragsort[j+1];
573 if (Sbar_IsTeammatch ())
575 // now sort players by teams.
576 for (i=0 ; i<scoreboardlines ; i++)
578 for (j=0 ; j<scoreboardlines-1-i ; j++)
580 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
583 fragsort[j] = fragsort[j+1];
589 // calculate team scores
591 for (i=0 ; i<scoreboardlines ; i++)
593 if (color != (cl.scores[fragsort[i]].colors & 15))
595 const char* teamname;
597 color = cl.scores[fragsort[i]].colors & 15;
603 teamname = "^1Red Team";
606 teamname = "^4Blue Team";
609 teamname = "^6Pink Team";
612 teamname = "^3Yellow Team";
615 teamname = "Total Team Score";
618 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
620 teams[teamlines-1].frags = 0;
621 teams[teamlines-1].colors = color + 16 * color;
624 if (cl.scores[fragsort[i]].frags != -666)
626 // do not add spedcators
627 // (ugly hack for nexuiz)
628 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
632 // now sort teams by scores.
633 for (i=0 ; i<teamlines ; i++)
635 for (i=0 ; i<teamlines ; i++)
637 for (j=0 ; j<teamlines-1-i ; j++)
639 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
642 teamsort[j] = teamsort[j+1];
655 void Sbar_SoloScoreboard (void)
658 char str[80], timestr[40];
660 int minutes, seconds;
663 t = (cl.intermission ? cl.completed_time : cl.time);
664 minutes = (int)(t / 60);
665 seconds = (int)(t - 60*floor(t/60));
667 // monsters and secrets are now both on the top row
668 if (cl.stats[STAT_TOTALMONSTERS])
669 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
670 if (cl.stats[STAT_TOTALSECRETS])
671 Sbar_DrawString(8+22*8, 4, va("Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
673 // figure out the map's filename without path or extension
674 strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
675 if (strrchr(str, '.'))
676 *(strrchr(str, '.')) = 0;
678 // append a : separator and then the full title
679 strlcat(str, ":", sizeof(str));
680 strlcat(str, cl.levelname, sizeof(str));
682 // if there's a newline character, terminate the string there
683 if (strchr(str, '\n'))
684 *(strchr(str, '\n')) = 0;
686 // make the time string
687 timelen = sprintf(timestr, " %i:%02i", minutes, seconds);
689 // truncate the level name if necessary to make room for time
691 if ((int)strlen(str) > max)
694 // print the filename and message
695 Sbar_DrawString(8, 12, str);
698 Sbar_DrawString(8 + max*8, 12, timestr);
702 int minutes, seconds, tens, units;
705 if (gamemode != GAME_NEXUIZ) {
706 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
707 Sbar_DrawString (8, 4, str);
709 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
710 Sbar_DrawString (8, 12, str);
714 minutes = (int)(cl.time / 60);
715 seconds = (int)(cl.time - 60*minutes);
717 units = seconds - 10*tens;
718 sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
719 Sbar_DrawString (184, 4, str);
722 if (gamemode == GAME_NEXUIZ) {
723 l = (int) strlen (cl.worldmodel->name);
724 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
726 l = (int) strlen (cl.levelname);
727 Sbar_DrawString (232 - l*4, 12, cl.levelname);
737 void Sbar_DrawScoreboard (void)
739 Sbar_SoloScoreboard ();
740 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
741 //if (cl.gametype == GAME_DEATHMATCH)
743 Sbar_DeathmatchOverlay ();
746 //=============================================================================
748 // AK to make DrawInventory smaller
749 static void Sbar_DrawWeapon(int nr, float fade, int active)
751 if (sbar_hudselector.integer == 1)
753 // width = 300, height = 100
754 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
756 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);
758 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);
762 // width = 300, height = 100
763 const int w_width = 300, w_height = 100, w_space = 10;
764 const float w_scale = 0.4;
766 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);
767 //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);
776 void Sbar_DrawInventory (void)
783 if (gamemode == GAME_ROGUE)
785 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
786 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
788 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
791 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
794 for (i=0 ; i<7 ; i++)
796 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
798 time = cl.item_gettime[i];
799 flashon = (int)(max(0, cl.time - time)*10);
802 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
808 flashon = (flashon%5) + 2;
810 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
816 if (gamemode == GAME_HIPNOTIC)
818 int grenadeflashing=0;
819 for (i=0 ; i<4 ; i++)
821 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
823 time = max(0, cl.item_gettime[hipweapons[i]]);
824 flashon = (int)((cl.time - time)*10);
827 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
833 flashon = (flashon%5) + 2;
835 // check grenade launcher
838 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
843 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
849 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
851 if (!grenadeflashing)
852 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
855 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
858 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
863 if (gamemode == GAME_ROGUE)
865 // check for powered up weapon.
866 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
868 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
869 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
873 for (i=0 ; i<4 ; i++)
875 sprintf (num, "%4i",cl.stats[STAT_SHELLS+i] );
877 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
879 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
881 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
883 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
887 for (i=0 ; i<6 ; i++)
888 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
890 //MED 01/04/97 changed keys
891 if (gamemode != GAME_HIPNOTIC || (i>1))
892 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
895 //MED 01/04/97 added hipnotic items
897 if (gamemode == GAME_HIPNOTIC)
899 for (i=0 ; i<2 ; i++)
900 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
901 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
904 if (gamemode == GAME_ROGUE)
907 for (i=0 ; i<2 ; i++)
908 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
909 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
914 for (i=0 ; i<4 ; i++)
915 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
916 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
920 //=============================================================================
927 void Sbar_DrawFrags (void)
937 l = min(scoreboardlines, 4);
941 for (i = 0;i < l;i++)
947 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
948 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);
949 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
950 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);
954 sprintf (num, "%3i",f);
956 if (k == cl.viewentity - 1)
958 Sbar_DrawCharacter ( x + 2, -24, 16);
959 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
961 Sbar_DrawCharacter (x + 8, -24, num[0]);
962 Sbar_DrawCharacter (x + 16, -24, num[1]);
963 Sbar_DrawCharacter (x + 24, -24, num[2]);
968 //=============================================================================
976 void Sbar_DrawFace (void)
980 // PGM 01/19/97 - team color drawing
981 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
982 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
988 s = &cl.scores[cl.viewentity - 1];
990 Sbar_DrawPic (112, 0, rsb_teambord);
991 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
992 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);
993 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
994 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);
998 sprintf (num, "%3i",f);
1000 if ((s->colors & 0xf0)==0)
1003 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1005 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1007 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1011 Sbar_DrawCharacter ( 109, 3, num[0]);
1012 Sbar_DrawCharacter ( 116, 3, num[1]);
1013 Sbar_DrawCharacter ( 123, 3, num[2]);
1018 // PGM 01/19/97 - team color drawing
1020 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1021 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1022 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1023 Sbar_DrawPic (112, 0, sb_face_quad );
1024 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1025 Sbar_DrawPic (112, 0, sb_face_invis );
1026 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1027 Sbar_DrawPic (112, 0, sb_face_invuln);
1030 f = cl.stats[STAT_HEALTH] / 20;
1032 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1036 void Sbar_ShowFPS(void)
1038 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1040 char timestring[32];
1041 char datestring[32];
1042 qboolean red = false;
1046 if (showfps.integer)
1049 static double nexttime = 0, lasttime = 0;
1050 static double framerate = 0;
1051 static int framecount = 0;
1054 if (newtime >= nexttime)
1056 framerate = framecount / (newtime - lasttime);
1058 nexttime = max(nexttime + 1, lasttime - 1);
1064 if ((red = (calc < 1.0f)))
1065 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1067 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1069 if (showtime.integer)
1070 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1071 if (showdate.integer)
1072 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1073 if (fpsstring[0] || timestring[0])
1077 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
1078 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1079 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1080 fps_y = vid_conheight.integer - fps_height;
1083 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(fpsstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1084 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1086 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1088 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1089 fps_y += fps_scaley;
1093 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(timestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1094 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1095 DrawQ_String_Font(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1096 fps_y += fps_scaley;
1100 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(datestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1101 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1102 DrawQ_String_Font(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1103 fps_y += fps_scaley;
1108 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)
1111 c2 = bound(0, c2, 1);
1112 c1 = bound(0, c1, 1 - c2);
1114 r[1] = rangey + rangeheight * (c2 + c1);
1115 r[2] = rangey + rangeheight * (c2);
1119 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);
1121 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);
1123 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);
1125 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);
1133 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1134 extern cvar_t v_kicktime;
1135 void Sbar_Score (int margin);
1136 void Sbar_Draw (void)
1140 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1143 Sbar_DrawScoreboard ();
1144 else if (cl.intermission == 1)
1146 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1148 Sbar_DrawScoreboard();
1151 Sbar_IntermissionOverlay();
1153 else if (cl.intermission == 2)
1154 Sbar_FinaleOverlay();
1155 else if (gamemode == GAME_DELUXEQUAKE)
1158 else if (gamemode == GAME_SOM)
1160 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1161 Sbar_DrawScoreboard ();
1164 // this is the top left of the sbar area
1166 sbar_y = vid_conheight.integer - 24*3;
1169 if (cl.stats[STAT_ARMOR])
1171 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1172 Sbar_DrawPic(0, 0, somsb_armor[2]);
1173 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1174 Sbar_DrawPic(0, 0, somsb_armor[1]);
1175 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1176 Sbar_DrawPic(0, 0, somsb_armor[0]);
1177 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1181 Sbar_DrawPic(0, 24, somsb_health);
1182 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1185 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1186 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1187 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1188 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1189 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1190 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1191 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1192 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1193 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1194 if (cl.stats[STAT_SHELLS])
1195 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1198 else if (gamemode == GAME_NEXUIZ)
1200 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1202 sbar_x = (vid_conwidth.integer - 640)/2;
1203 sbar_y = vid_conheight.integer - 47;
1204 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1205 Sbar_DrawScoreboard ();
1207 else if (sb_lines && sbar_hudselector.integer == 1)
1211 int redflag, blueflag;
1214 sbar_x = (vid_conwidth.integer - 320)/2;
1215 sbar_y = vid_conheight.integer - 24 - 16;
1217 // calculate intensity to draw weapons bar at
1218 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1219 fade = bound(0.7, fade, 1);
1220 for (i = 0; i < 8;i++)
1221 if (cl.stats[STAT_ITEMS] & (1 << i))
1222 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1223 if((cl.stats[STAT_ITEMS] & (1<<12)))
1224 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1227 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1228 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1229 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1230 if (redflag == 3 && blueflag == 3)
1232 // The Impossible Combination[tm]
1233 // Can only happen in Key Hunt mode...
1234 Sbar_DrawPic (x, -179, sb_items[14]);
1239 Sbar_DrawPic (x, -117, sb_items[redflag+10]);
1241 Sbar_DrawPic (x, -177, sb_items[blueflag+14]);
1245 if (cl.stats[STAT_ARMOR] > 0)
1247 Sbar_DrawStretchPic (0, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1248 if(cl.stats[STAT_ARMOR] > 200)
1249 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1250 else if(cl.stats[STAT_ARMOR] > 100)
1251 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1252 else if(cl.stats[STAT_ARMOR] > 50)
1253 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1254 else if(cl.stats[STAT_ARMOR] > 25)
1255 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1257 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1261 if (cl.stats[STAT_HEALTH] != 0)
1263 Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1264 if(cl.stats[STAT_HEALTH] > 200)
1265 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1266 else if(cl.stats[STAT_HEALTH] > 100)
1267 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1268 else if(cl.stats[STAT_HEALTH] > 50)
1269 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1270 else if(cl.stats[STAT_HEALTH] > 25)
1271 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1273 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1277 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1279 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1280 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1281 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1282 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1283 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1284 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1285 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1286 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1287 if(cl.stats[STAT_AMMO] > 10)
1288 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1290 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1293 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1294 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1297 // The margin can be at most 8 to support 640x480 console size:
1298 // 320 + 2 * (144 + 16) = 640
1304 int redflag, blueflag;
1307 sbar_x = (vid_conwidth.integer - 640)/2;
1308 sbar_y = vid_conheight.integer - 47;
1310 // calculate intensity to draw weapons bar at
1311 fade = 3 - 2 * (cl.time - cl.weapontime);
1314 fade = min(fade, 1);
1315 for (i = 0; i < 8;i++)
1316 if (cl.stats[STAT_ITEMS] & (1 << i))
1317 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1319 if((cl.stats[STAT_ITEMS] & (1<<12)))
1320 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1323 //if (!cl.islocalgame)
1324 // Sbar_DrawFrags ();
1327 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1329 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1332 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1333 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1334 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1335 if (redflag == 3 && blueflag == 3)
1337 // The Impossible Combination[tm]
1338 // Can only happen in Key Hunt mode...
1339 Sbar_DrawPic (x, -179, sb_items[14]);
1344 Sbar_DrawPic (x, -117, sb_items[redflag+10]);
1346 Sbar_DrawPic (x, -177, sb_items[blueflag+14]);
1350 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1353 if(cl.stats[STAT_HEALTH] > 100)
1354 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1355 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1356 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1358 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1360 // AK dont draw ammo for the laser
1361 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1363 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1364 Sbar_DrawPic (519, 0, sb_ammo[0]);
1365 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1366 Sbar_DrawPic (519, 0, sb_ammo[1]);
1367 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1368 Sbar_DrawPic (519, 0, sb_ammo[2]);
1369 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1370 Sbar_DrawPic (519, 0, sb_ammo[3]);
1372 if(cl.stats[STAT_AMMO] <= 10)
1373 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1375 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1380 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1382 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1383 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1388 // Mini scoreboard uses 12*4 per other team, that is, 144
1389 // pixels when there are four teams...
1390 // Nexuiz by default sets vid_conwidth to 800... makes
1392 // so we need to shift it by 64 pixels to the right to fit
1393 // BUT: then it overlaps with the image that gets drawn
1394 // for viewsize 100! Therefore, just account for 3 teams,
1395 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1399 else if (gamemode == GAME_ZYMOTIC)
1402 float scale = 64.0f / 256.0f;
1403 float kickoffset[3];
1404 VectorClear(kickoffset);
1407 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1408 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1410 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1411 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1412 // left1 16, 48 : 126 -66
1413 // left2 16, 128 : 196 -66
1414 // right 176, 48 : 196 -136
1415 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);
1416 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);
1417 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);
1418 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1420 float scale = 128.0f / 256.0f;
1421 float healthstart, healthheight, healthstarttc, healthendtc;
1422 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1423 float ammostart, ammoheight, ammostarttc, ammoendtc;
1424 float clipstart, clipheight, clipstarttc, clipendtc;
1425 float kickoffset[3], offset;
1426 VectorClear(kickoffset);
1429 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1430 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1432 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1433 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1434 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1435 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);
1436 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);
1437 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);
1438 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);
1439 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1440 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1441 healthstart = 204 - healthheight;
1442 shieldstart = healthstart - shieldheight;
1443 healthstarttc = healthstart * (1.0f / 256.0f);
1444 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1445 shieldstarttc = shieldstart * (1.0f / 256.0f);
1446 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1447 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1448 ammostart = 114 - ammoheight;
1449 ammostarttc = ammostart * (1.0f / 256.0f);
1450 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1451 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1452 clipstart = 190 - clipheight;
1453 clipstarttc = clipstart * (1.0f / 256.0f);
1454 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1455 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);
1456 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);
1457 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);
1458 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);
1459 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1460 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1463 else // Quake and others
1465 sbar_x = (vid_conwidth.integer - 320)/2;
1466 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1467 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1468 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1472 if (gamemode != GAME_GOODVSBAD2)
1473 Sbar_DrawInventory ();
1474 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1478 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1480 if (gamemode != GAME_GOODVSBAD2)
1481 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1482 Sbar_DrawScoreboard ();
1486 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1488 // keys (hipnotic only)
1489 //MED 01/04/97 moved keys here so they would not be overwritten
1490 if (gamemode == GAME_HIPNOTIC)
1492 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1493 Sbar_DrawPic (209, 3, sb_items[0]);
1494 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1495 Sbar_DrawPic (209, 12, sb_items[1]);
1498 if (gamemode != GAME_GOODVSBAD2)
1500 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1502 Sbar_DrawNum (24, 0, 666, 3, 1);
1503 Sbar_DrawPic (0, 0, sb_disc);
1507 if (gamemode == GAME_ROGUE)
1509 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1510 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1511 Sbar_DrawPic (0, 0, sb_armor[2]);
1512 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1513 Sbar_DrawPic (0, 0, sb_armor[1]);
1514 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1515 Sbar_DrawPic (0, 0, sb_armor[0]);
1519 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1520 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1521 Sbar_DrawPic (0, 0, sb_armor[2]);
1522 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1523 Sbar_DrawPic (0, 0, sb_armor[1]);
1524 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1525 Sbar_DrawPic (0, 0, sb_armor[0]);
1534 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1537 if (gamemode == GAME_ROGUE)
1539 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1540 Sbar_DrawPic (224, 0, sb_ammo[0]);
1541 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1542 Sbar_DrawPic (224, 0, sb_ammo[1]);
1543 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1544 Sbar_DrawPic (224, 0, sb_ammo[2]);
1545 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1546 Sbar_DrawPic (224, 0, sb_ammo[3]);
1547 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1548 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1549 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1550 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1551 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1552 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1556 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1557 Sbar_DrawPic (224, 0, sb_ammo[0]);
1558 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1559 Sbar_DrawPic (224, 0, sb_ammo[1]);
1560 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1561 Sbar_DrawPic (224, 0, sb_ammo[2]);
1562 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1563 Sbar_DrawPic (224, 0, sb_ammo[3]);
1566 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1568 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1569 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1571 if (gamemode == GAME_TRANSFUSION)
1572 Sbar_MiniDeathmatchOverlay (0, 0);
1574 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1583 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1584 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);
1586 if (cl_prydoncursor.integer)
1587 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);
1590 //=============================================================================
1594 Sbar_DeathmatchOverlay
1598 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1601 qboolean myself = false;
1603 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1605 if((s - cl.scores) == cl.playerentity - 1)
1607 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1608 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1611 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1613 if (s->qw_spectator)
1615 if (s->qw_ping || s->qw_packetloss)
1616 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 );
1618 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 );
1622 // draw colors behind score
1628 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1629 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);
1630 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1631 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);
1633 //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);
1634 if (s->qw_ping || s->qw_packetloss)
1635 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 );
1637 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 );
1642 if (s->qw_spectator)
1644 if (s->qw_ping || s->qw_packetloss)
1645 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 );
1647 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 );
1651 // draw colors behind score
1652 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1653 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);
1654 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1655 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);
1657 //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);
1658 if (s->qw_ping || s->qw_packetloss)
1659 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 );
1661 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 );
1667 void Sbar_DeathmatchOverlay (void)
1669 int i, y, xmin, xmax, ymin, ymax;
1671 // request new ping times every two second
1672 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1674 cl.last_ping_request = realtime;
1675 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1677 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1678 MSG_WriteString(&cls.netcon->message, "pings");
1680 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*/)
1682 // 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
1683 static int ping_anyway_counter = 0;
1684 if(cl.parsingtextexpectingpingforscores == 1)
1686 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1687 if(++ping_anyway_counter >= 5)
1688 cl.parsingtextexpectingpingforscores = 0;
1690 if(cl.parsingtextexpectingpingforscores != 1)
1692 ping_anyway_counter = 0;
1693 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1694 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1695 MSG_WriteString(&cls.netcon->message, "ping");
1700 // 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
1701 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1702 MSG_WriteString(&cls.netcon->message, "pings");
1710 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1712 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1713 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)
1715 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)
1716 xmax = vid_conwidth.integer - xmin;
1718 if(gamemode == GAME_NEXUIZ)
1719 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);
1721 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1725 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1727 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 );
1731 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 );
1735 if (Sbar_IsTeammatch ())
1737 // show team scores first
1738 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1739 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1743 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1744 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1749 Sbar_MiniDeathmatchOverlay
1753 void Sbar_MiniDeathmatchOverlay (int x, int y)
1755 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1757 // do not draw this if sbar_miniscoreboard_size is zero
1758 if(sbar_miniscoreboard_size.value == 0)
1760 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1761 if(sbar_miniscoreboard_size.value > 0)
1762 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1767 // decide where to print
1768 if (gamemode == GAME_TRANSFUSION)
1769 numlines = (vid_conwidth.integer - x + 127) / 128;
1771 numlines = (vid_conheight.integer - y + 7) / 8;
1773 // give up if there isn't room
1774 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1778 for (i = 0; i < scoreboardlines; i++)
1779 if (fragsort[i] == cl.playerentity - 1)
1783 range_end = scoreboardlines;
1786 if (gamemode != GAME_TRANSFUSION)
1787 if (Sbar_IsTeammatch ())
1789 // reserve space for the team scores
1790 numlines -= teamlines;
1792 // find first and last player of my team (only draw the team totals and my own team)
1793 range_begin = range_end = i;
1794 myteam = cl.scores[fragsort[i]].colors & 15;
1795 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1797 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1800 // looks better than two players
1810 i = min(i, range_end - numlines);
1811 i = max(i, range_begin);
1813 if (gamemode == GAME_TRANSFUSION)
1815 for (;i < range_end && x < vid_conwidth.integer;i++)
1816 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1820 if(range_end - i < numlines) // won't draw to bottom?
1821 y += 8 * (numlines - (range_end - i)); // bottom align
1822 // show team scores first
1823 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1824 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1826 for (;i < range_end && y < vid_conheight.integer;i++)
1827 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1831 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1833 static int const sortorder[16] =
1852 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1853 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1854 int tc1 = sortorder[t1->colors & 15];
1855 int tc2 = sortorder[t2->colors & 15];
1859 void Sbar_Score (int margin)
1861 int i, me, score, otherleader, place, distribution, minutes, seconds;
1863 int sbar_x_save = sbar_x;
1864 int sbar_y_save = sbar_y;
1866 sbar_y = vid_conheight.value - (32+12);
1869 me = cl.playerentity - 1;
1870 if (me >= 0 && me < cl.maxclients)
1872 if(Sbar_IsTeammatch())
1876 // team1 team3 team4
1880 scoreboard_t *teamcolorsort[16];
1883 for(i = 0; i < teamlines; ++i)
1884 teamcolorsort[i] = &(teams[i]);
1886 // Now sort them by color
1887 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1890 // -12*4: four digits space
1891 place = (teamlines - 1) * (-12 * 4);
1893 for(i = 0; i < teamlines; ++i)
1895 int cindex = teamcolorsort[i]->colors & 15;
1896 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
1897 float cm = max(max(c[0], c[1]), c[2]);
1898 float cr = c[0] / cm;
1899 float cg = c[1] / cm;
1900 float cb = c[2] / cm;
1901 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1903 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1907 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1920 // find leading score other than ourselves, to calculate distribution
1921 // find our place in the scoreboard
1922 score = cl.scores[me].frags;
1923 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1925 if (cl.scores[i].name[0] && i != me)
1927 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1929 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1933 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1935 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1936 else if (place == 2)
1937 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
1939 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
1940 if (otherleader < 0)
1941 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1942 if (distribution >= 0)
1944 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
1945 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1947 else if (distribution >= -5)
1949 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
1950 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
1954 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
1955 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
1960 if (cl.statsf[STAT_TIMELIMIT])
1962 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
1963 minutes = (int)floor(timeleft / 60);
1964 seconds = (int)(floor(timeleft) - minutes * 60);
1967 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1968 if(sb_colon && sb_colon->tex != r_texture_notexture)
1969 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1970 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1972 else if (minutes >= 1)
1974 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
1975 if(sb_colon && sb_colon->tex != r_texture_notexture)
1976 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
1977 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
1979 else if ((int)(timeleft * 4) & 1)
1980 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1982 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
1986 minutes = (int)floor(cl.time / 60);
1987 seconds = (int)(floor(cl.time) - minutes * 60);
1988 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1989 if(sb_colon && sb_colon->tex != r_texture_notexture)
1990 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1991 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1994 sbar_x = sbar_x_save;
1995 sbar_y = sbar_y_save;
2000 Sbar_IntermissionOverlay
2004 void Sbar_IntermissionOverlay (void)
2009 if (cl.gametype == GAME_DEATHMATCH)
2011 Sbar_DeathmatchOverlay ();
2015 sbar_x = (vid_conwidth.integer - 320) >> 1;
2016 sbar_y = (vid_conheight.integer - 200) >> 1;
2018 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2019 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2022 dig = (int)cl.completed_time / 60;
2023 Sbar_DrawNum (160, 64, dig, 3, 0);
2024 num = (int)cl.completed_time - dig*60;
2025 Sbar_DrawPic (234,64,sb_colon);
2026 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2027 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2029 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2030 if (gamemode != GAME_NEXUIZ)
2031 Sbar_DrawPic (232, 104, sb_slash);
2032 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2034 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2035 if (gamemode != GAME_NEXUIZ)
2036 Sbar_DrawPic (232, 144, sb_slash);
2037 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2048 void Sbar_FinaleOverlay (void)
2050 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);