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_NETHERWORLD)
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 (sbar_x + x + 4 , sbar_y + y, va("%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, true);
438 void Sbar_DrawString (int x, int y, char *str)
440 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false);
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);
757 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);
761 // width = 300, height = 100
762 const int w_width = 300, w_height = 100, w_space = 10;
763 const float w_scale = 0.4;
765 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);
766 //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);
775 void Sbar_DrawInventory (void)
782 if (gamemode == GAME_ROGUE)
784 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
785 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
787 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
790 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
793 for (i=0 ; i<7 ; i++)
795 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
797 time = cl.item_gettime[i];
798 flashon = (int)(max(0, cl.time - time)*10);
801 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
807 flashon = (flashon%5) + 2;
809 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
815 if (gamemode == GAME_HIPNOTIC)
817 int grenadeflashing=0;
818 for (i=0 ; i<4 ; i++)
820 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
822 time = max(0, cl.item_gettime[hipweapons[i]]);
823 flashon = (int)((cl.time - time)*10);
826 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
832 flashon = (flashon%5) + 2;
834 // check grenade launcher
837 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
842 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
848 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
850 if (!grenadeflashing)
851 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
854 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
857 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
862 if (gamemode == GAME_ROGUE)
864 // check for powered up weapon.
865 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
867 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
868 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
872 for (i=0 ; i<4 ; i++)
874 sprintf (num, "%4i",cl.stats[STAT_SHELLS+i] );
876 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
878 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
880 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
882 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
886 for (i=0 ; i<6 ; i++)
887 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
889 //MED 01/04/97 changed keys
890 if (gamemode != GAME_HIPNOTIC || (i>1))
891 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
894 //MED 01/04/97 added hipnotic items
896 if (gamemode == GAME_HIPNOTIC)
898 for (i=0 ; i<2 ; i++)
899 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
900 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
903 if (gamemode == GAME_ROGUE)
906 for (i=0 ; i<2 ; i++)
907 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
908 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
913 for (i=0 ; i<4 ; i++)
914 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
915 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
919 //=============================================================================
926 void Sbar_DrawFrags (void)
936 l = min(scoreboardlines, 4);
940 for (i = 0;i < l;i++)
946 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
947 DrawQ_Fill (sbar_x + x + 10, sbar_y - 23, 28, 4, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
948 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
949 DrawQ_Fill (sbar_x + x + 10, sbar_y + 4 - 23, 28, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
953 sprintf (num, "%3i",f);
955 if (k == cl.viewentity - 1)
957 Sbar_DrawCharacter ( x + 2, -24, 16);
958 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
960 Sbar_DrawCharacter (x + 8, -24, num[0]);
961 Sbar_DrawCharacter (x + 16, -24, num[1]);
962 Sbar_DrawCharacter (x + 24, -24, num[2]);
967 //=============================================================================
975 void Sbar_DrawFace (void)
979 // PGM 01/19/97 - team color drawing
980 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
981 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
987 s = &cl.scores[cl.viewentity - 1];
989 Sbar_DrawPic (112, 0, rsb_teambord);
990 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
991 DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+3, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
992 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
993 DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+12, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
997 sprintf (num, "%3i",f);
999 if ((s->colors & 0xf0)==0)
1002 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1004 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1006 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1010 Sbar_DrawCharacter ( 109, 3, num[0]);
1011 Sbar_DrawCharacter ( 116, 3, num[1]);
1012 Sbar_DrawCharacter ( 123, 3, num[2]);
1017 // PGM 01/19/97 - team color drawing
1019 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1020 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1021 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1022 Sbar_DrawPic (112, 0, sb_face_quad );
1023 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1024 Sbar_DrawPic (112, 0, sb_face_invis );
1025 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1026 Sbar_DrawPic (112, 0, sb_face_invuln);
1029 f = cl.stats[STAT_HEALTH] / 20;
1031 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1035 void Sbar_ShowFPS(void)
1037 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1039 char timestring[32];
1040 char datestring[32];
1041 qboolean red = false;
1045 if (showfps.integer)
1048 static double nexttime = 0, lasttime = 0;
1049 static double framerate = 0;
1050 static int framecount = 0;
1053 if (newtime >= nexttime)
1055 framerate = framecount / (newtime - lasttime);
1057 nexttime = max(nexttime + 1, lasttime - 1);
1063 if ((red = (calc < 1.0f)))
1064 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1066 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1068 if (showtime.integer)
1069 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1070 if (showdate.integer)
1071 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1072 if (fpsstring[0] || timestring[0])
1076 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
1077 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1078 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1079 fps_y = vid_conheight.integer - fps_height;
1082 fps_x = vid_conwidth.integer - fps_scalex * strlen(fpsstring);
1083 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(fpsstring), fps_scaley, 0, 0, 0, 0.5, 0);
1085 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true);
1087 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1088 fps_y += fps_scaley;
1092 fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
1093 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(timestring), fps_scaley, 0, 0, 0, 0.5, 0);
1094 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1095 fps_y += fps_scaley;
1099 fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
1100 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(datestring), fps_scaley, 0, 0, 0, 0.5, 0);
1101 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1102 fps_y += fps_scaley;
1107 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)
1110 c2 = bound(0, c2, 1);
1111 c1 = bound(0, c1, 1 - c2);
1113 r[1] = rangey + rangeheight * (c2 + c1);
1114 r[2] = rangey + rangeheight * (c2);
1118 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);
1120 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);
1122 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);
1124 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);
1132 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1133 extern cvar_t v_kicktime;
1134 void Sbar_Score (int margin);
1135 void Sbar_Draw (void)
1139 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1142 Sbar_DrawScoreboard ();
1143 else if (cl.intermission == 1)
1145 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1147 Sbar_DrawScoreboard();
1150 Sbar_IntermissionOverlay();
1152 else if (cl.intermission == 2)
1153 Sbar_FinaleOverlay();
1154 else if (gamemode == GAME_NETHERWORLD)
1157 else if (gamemode == GAME_SOM)
1159 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1160 Sbar_DrawScoreboard ();
1163 // this is the top left of the sbar area
1165 sbar_y = vid_conheight.integer - 24*3;
1168 if (cl.stats[STAT_ARMOR])
1170 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1171 Sbar_DrawPic(0, 0, somsb_armor[2]);
1172 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1173 Sbar_DrawPic(0, 0, somsb_armor[1]);
1174 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1175 Sbar_DrawPic(0, 0, somsb_armor[0]);
1176 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1180 Sbar_DrawPic(0, 24, somsb_health);
1181 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1184 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1185 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1186 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1187 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1188 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1189 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1190 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1191 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1192 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1193 if (cl.stats[STAT_SHELLS])
1194 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1197 else if (gamemode == GAME_NEXUIZ)
1199 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1201 sbar_x = (vid_conwidth.integer - 640)/2;
1202 sbar_y = vid_conheight.integer - 47;
1203 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1204 Sbar_DrawScoreboard ();
1206 else if (sb_lines && sbar_hudselector.integer == 1)
1210 int redflag, blueflag;
1213 sbar_x = (vid_conwidth.integer - 320)/2;
1214 sbar_y = vid_conheight.integer - 24 - 16;
1216 // calculate intensity to draw weapons bar at
1217 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1218 fade = bound(0.7, fade, 1);
1219 for (i = 0; i < 8;i++)
1220 if (cl.stats[STAT_ITEMS] & (1 << i))
1221 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1222 if((cl.stats[STAT_ITEMS] & (1<<12)))
1223 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1226 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1227 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1228 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1229 if (redflag == 3 && blueflag == 3)
1231 // The Impossible Combination[tm]
1232 // Can only happen in Key Hunt mode...
1233 Sbar_DrawPic (x, -179, sb_items[14]);
1238 Sbar_DrawPic (x, -117, sb_items[redflag+10]);
1240 Sbar_DrawPic (x, -177, sb_items[blueflag+14]);
1244 if (cl.stats[STAT_ARMOR] > 0)
1246 Sbar_DrawStretchPic (0, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1247 if(cl.stats[STAT_ARMOR] > 200)
1248 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1249 else if(cl.stats[STAT_ARMOR] > 100)
1250 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1251 else if(cl.stats[STAT_ARMOR] > 50)
1252 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1253 else if(cl.stats[STAT_ARMOR] > 25)
1254 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1256 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1260 if (cl.stats[STAT_HEALTH] != 0)
1262 Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1263 if(cl.stats[STAT_HEALTH] > 200)
1264 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1265 else if(cl.stats[STAT_HEALTH] > 100)
1266 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1267 else if(cl.stats[STAT_HEALTH] > 50)
1268 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1269 else if(cl.stats[STAT_HEALTH] > 25)
1270 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1272 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1276 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1278 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1279 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1280 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1281 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1282 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1283 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1284 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1285 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1286 if(cl.stats[STAT_AMMO] > 10)
1287 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1289 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1292 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1293 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1296 // The margin can be at most 8 to support 640x480 console size:
1297 // 320 + 2 * (144 + 16) = 640
1303 int redflag, blueflag;
1306 sbar_x = (vid_conwidth.integer - 640)/2;
1307 sbar_y = vid_conheight.integer - 47;
1309 // calculate intensity to draw weapons bar at
1310 fade = 3 - 2 * (cl.time - cl.weapontime);
1313 fade = min(fade, 1);
1314 for (i = 0; i < 8;i++)
1315 if (cl.stats[STAT_ITEMS] & (1 << i))
1316 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1318 if((cl.stats[STAT_ITEMS] & (1<<12)))
1319 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1322 //if (!cl.islocalgame)
1323 // Sbar_DrawFrags ();
1326 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1328 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1331 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1332 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1333 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1334 if (redflag == 3 && blueflag == 3)
1336 // The Impossible Combination[tm]
1337 // Can only happen in Key Hunt mode...
1338 Sbar_DrawPic (x, -179, sb_items[14]);
1343 Sbar_DrawPic (x, -117, sb_items[redflag+10]);
1345 Sbar_DrawPic (x, -177, sb_items[blueflag+14]);
1349 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1352 if(cl.stats[STAT_HEALTH] > 100)
1353 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1354 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1355 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1357 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1359 // AK dont draw ammo for the laser
1360 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1362 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1363 Sbar_DrawPic (519, 0, sb_ammo[0]);
1364 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1365 Sbar_DrawPic (519, 0, sb_ammo[1]);
1366 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1367 Sbar_DrawPic (519, 0, sb_ammo[2]);
1368 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1369 Sbar_DrawPic (519, 0, sb_ammo[3]);
1371 if(cl.stats[STAT_AMMO] <= 10)
1372 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1374 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1379 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1381 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1382 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1387 // Mini scoreboard uses 12*4 per other team, that is, 144
1388 // pixels when there are four teams...
1389 // Nexuiz by default sets vid_conwidth to 800... makes
1391 // so we need to shift it by 64 pixels to the right to fit
1392 // BUT: then it overlaps with the image that gets drawn
1393 // for viewsize 100! Therefore, just account for 3 teams,
1394 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1398 else if (gamemode == GAME_ZYMOTIC)
1401 float scale = 64.0f / 256.0f;
1402 float kickoffset[3];
1403 VectorClear(kickoffset);
1406 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1407 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1409 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1410 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1411 // left1 16, 48 : 126 -66
1412 // left2 16, 128 : 196 -66
1413 // right 176, 48 : 196 -136
1414 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);
1415 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);
1416 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);
1417 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1419 float scale = 128.0f / 256.0f;
1420 float healthstart, healthheight, healthstarttc, healthendtc;
1421 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1422 float ammostart, ammoheight, ammostarttc, ammoendtc;
1423 float clipstart, clipheight, clipstarttc, clipendtc;
1424 float kickoffset[3], offset;
1425 VectorClear(kickoffset);
1428 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1429 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1431 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1432 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1433 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1434 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);
1435 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);
1436 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);
1437 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);
1438 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1439 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1440 healthstart = 204 - healthheight;
1441 shieldstart = healthstart - shieldheight;
1442 healthstarttc = healthstart * (1.0f / 256.0f);
1443 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1444 shieldstarttc = shieldstart * (1.0f / 256.0f);
1445 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1446 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1447 ammostart = 114 - ammoheight;
1448 ammostarttc = ammostart * (1.0f / 256.0f);
1449 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1450 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1451 clipstart = 190 - clipheight;
1452 clipstarttc = clipstart * (1.0f / 256.0f);
1453 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1454 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);
1455 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);
1456 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);
1457 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);
1458 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1459 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1462 else // Quake and others
1464 sbar_x = (vid_conwidth.integer - 320)/2;
1465 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1466 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1467 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1471 if (gamemode != GAME_GOODVSBAD2)
1472 Sbar_DrawInventory ();
1473 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1477 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1479 if (gamemode != GAME_GOODVSBAD2)
1480 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1481 Sbar_DrawScoreboard ();
1485 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1487 // keys (hipnotic only)
1488 //MED 01/04/97 moved keys here so they would not be overwritten
1489 if (gamemode == GAME_HIPNOTIC)
1491 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1492 Sbar_DrawPic (209, 3, sb_items[0]);
1493 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1494 Sbar_DrawPic (209, 12, sb_items[1]);
1497 if (gamemode != GAME_GOODVSBAD2)
1499 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1501 Sbar_DrawNum (24, 0, 666, 3, 1);
1502 Sbar_DrawPic (0, 0, sb_disc);
1506 if (gamemode == GAME_ROGUE)
1508 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1509 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1510 Sbar_DrawPic (0, 0, sb_armor[2]);
1511 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1512 Sbar_DrawPic (0, 0, sb_armor[1]);
1513 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1514 Sbar_DrawPic (0, 0, sb_armor[0]);
1518 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1519 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1520 Sbar_DrawPic (0, 0, sb_armor[2]);
1521 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1522 Sbar_DrawPic (0, 0, sb_armor[1]);
1523 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1524 Sbar_DrawPic (0, 0, sb_armor[0]);
1533 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1536 if (gamemode == GAME_ROGUE)
1538 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1539 Sbar_DrawPic (224, 0, sb_ammo[0]);
1540 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1541 Sbar_DrawPic (224, 0, sb_ammo[1]);
1542 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1543 Sbar_DrawPic (224, 0, sb_ammo[2]);
1544 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1545 Sbar_DrawPic (224, 0, sb_ammo[3]);
1546 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1547 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1548 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1549 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1550 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1551 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1555 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1556 Sbar_DrawPic (224, 0, sb_ammo[0]);
1557 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1558 Sbar_DrawPic (224, 0, sb_ammo[1]);
1559 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1560 Sbar_DrawPic (224, 0, sb_ammo[2]);
1561 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1562 Sbar_DrawPic (224, 0, sb_ammo[3]);
1565 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1567 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1568 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1570 if (gamemode == GAME_TRANSFUSION)
1571 Sbar_MiniDeathmatchOverlay (0, 0);
1573 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1582 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1583 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);
1585 if (cl_prydoncursor.integer)
1586 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);
1589 //=============================================================================
1593 Sbar_DeathmatchOverlay
1597 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1600 qboolean myself = false;
1602 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1604 if((s - cl.scores) == cl.playerentity - 1)
1606 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1607 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1610 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1612 if (s->qw_spectator)
1614 if (s->qw_ping || s->qw_packetloss)
1615 DrawQ_String(x, y, va("%4i %3i %4i spectator %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1617 DrawQ_String(x, y, va(" %4i spectator %c%s", minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1621 // draw colors behind score
1627 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
1628 DrawQ_Fill(x + 14*8, y+1, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1629 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
1630 DrawQ_Fill(x + 14*8, y+4, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1632 //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);
1633 if (s->qw_ping || s->qw_packetloss)
1634 DrawQ_String(x, y, va("%4i %3i %4i %5i %-4s %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1636 DrawQ_String(x, y, va(" %4i %5i %-4s %c%s", minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1641 if (s->qw_spectator)
1643 if (s->qw_ping || s->qw_packetloss)
1644 DrawQ_String(x, y, va("%4i %3i spect %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1646 DrawQ_String(x, y, va(" spect %c%s", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1650 // draw colors behind score
1651 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
1652 DrawQ_Fill(x + 9*8, y+1, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1653 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
1654 DrawQ_Fill(x + 9*8, y+4, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1656 //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);
1657 if (s->qw_ping || s->qw_packetloss)
1658 DrawQ_String(x, y, va("%4i %3i %5i %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1660 DrawQ_String(x, y, va(" %5i %c%s", (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1666 void Sbar_DeathmatchOverlay (void)
1670 // request new ping times every two second
1671 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1673 cl.last_ping_request = realtime;
1674 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1676 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1677 MSG_WriteString(&cls.netcon->message, "pings");
1679 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*/)
1681 // 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
1682 static int ping_anyway_counter = 0;
1683 if(cl.parsingtextexpectingpingforscores == 1)
1685 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1686 if(++ping_anyway_counter >= 5)
1687 cl.parsingtextexpectingpingforscores = 0;
1689 if(cl.parsingtextexpectingpingforscores != 1)
1691 ping_anyway_counter = 0;
1692 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1693 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1694 MSG_WriteString(&cls.netcon->message, "ping");
1699 // 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
1700 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1701 MSG_WriteString(&cls.netcon->message, "pings");
1705 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1711 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1713 x = (vid_conwidth.integer - (26 + 15) * 8) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1714 DrawQ_String(x, y, va("ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1718 x = (vid_conwidth.integer - (16 + 15) * 8) / 2; // 16 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1719 DrawQ_String(x, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1723 if (Sbar_IsTeammatch ())
1725 // show team scores first
1726 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1727 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1731 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1732 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1737 Sbar_MiniDeathmatchOverlay
1741 void Sbar_MiniDeathmatchOverlay (int x, int y)
1743 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1745 // do not draw this if sbar_miniscoreboard_size is zero
1746 if(sbar_miniscoreboard_size.value == 0)
1748 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1749 if(sbar_miniscoreboard_size.value > 0)
1750 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1755 // decide where to print
1756 if (gamemode == GAME_TRANSFUSION)
1757 numlines = (vid_conwidth.integer - x + 127) / 128;
1759 numlines = (vid_conheight.integer - y + 7) / 8;
1761 // give up if there isn't room
1762 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1766 for (i = 0; i < scoreboardlines; i++)
1767 if (fragsort[i] == cl.playerentity - 1)
1771 range_end = scoreboardlines;
1774 if (gamemode != GAME_TRANSFUSION)
1775 if (Sbar_IsTeammatch ())
1777 // reserve space for the team scores
1778 numlines -= teamlines;
1780 // find first and last player of my team (only draw the team totals and my own team)
1781 range_begin = range_end = i;
1782 myteam = cl.scores[fragsort[i]].colors & 15;
1783 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1785 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1788 // looks better than two players
1798 i = min(i, range_end - numlines);
1799 i = max(i, range_begin);
1801 if (gamemode == GAME_TRANSFUSION)
1803 for (;i < range_end && x < vid_conwidth.integer;i++)
1804 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1808 if(range_end - i < numlines) // won't draw to bottom?
1809 y += 8 * (numlines - (range_end - i)); // bottom align
1810 // show team scores first
1811 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1812 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1814 for (;i < range_end && y < vid_conheight.integer;i++)
1815 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1819 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1821 static int const sortorder[16] =
1840 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1841 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1842 int tc1 = sortorder[t1->colors & 15];
1843 int tc2 = sortorder[t2->colors & 15];
1847 void Sbar_Score (int margin)
1849 int i, me, score, otherleader, place, distribution, minutes, seconds;
1851 int sbar_x_save = sbar_x;
1852 int sbar_y_save = sbar_y;
1854 sbar_y = vid_conheight.value - (32+12);
1857 me = cl.playerentity - 1;
1858 if (me >= 0 && me < cl.maxclients)
1860 if(Sbar_IsTeammatch())
1864 // team1 team3 team4
1868 scoreboard_t *teamcolorsort[16];
1871 for(i = 0; i < teamlines; ++i)
1872 teamcolorsort[i] = &(teams[i]);
1874 // Now sort them by color
1875 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1878 // -12*4: four digits space
1879 place = (teamlines - 1) * (-12 * 4);
1881 for(i = 0; i < teamlines; ++i)
1883 int cindex = teamcolorsort[i]->colors & 15;
1884 unsigned char *c = (unsigned char *)&palette_shirtscoreboard[cindex];
1885 float cm = max(max(c[0], c[1]), c[2]);
1886 float cr = c[0] / cm;
1887 float cg = c[1] / cm;
1888 float cb = c[2] / cm;
1889 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1891 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1895 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1908 // find leading score other than ourselves, to calculate distribution
1909 // find our place in the scoreboard
1910 score = cl.scores[me].frags;
1911 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1913 if (cl.scores[i].name[0] && i != me)
1915 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1917 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1921 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1923 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1924 else if (place == 2)
1925 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
1927 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
1928 if (otherleader < 0)
1929 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1930 if (distribution >= 0)
1932 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
1933 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1935 else if (distribution >= -5)
1937 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
1938 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
1942 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
1943 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
1948 if (cl.statsf[STAT_TIMELIMIT])
1950 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
1951 minutes = (int)floor(timeleft / 60);
1952 seconds = (int)(floor(timeleft) - minutes * 60);
1955 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1956 if(sb_colon && sb_colon->tex != r_texture_notexture)
1957 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1958 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1960 else if (minutes >= 1)
1962 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
1963 if(sb_colon && sb_colon->tex != r_texture_notexture)
1964 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
1965 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
1967 else if ((int)(timeleft * 4) & 1)
1968 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1970 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
1974 minutes = (int)floor(cl.time / 60);
1975 seconds = (int)(floor(cl.time) - minutes * 60);
1976 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1977 if(sb_colon && sb_colon->tex != r_texture_notexture)
1978 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1979 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1982 sbar_x = sbar_x_save;
1983 sbar_y = sbar_y_save;
1988 Sbar_IntermissionOverlay
1992 void Sbar_IntermissionOverlay (void)
1997 if (cl.gametype == GAME_DEATHMATCH)
1999 Sbar_DeathmatchOverlay ();
2003 sbar_x = (vid_conwidth.integer - 320) >> 1;
2004 sbar_y = (vid_conheight.integer - 200) >> 1;
2006 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2007 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2010 dig = (int)cl.completed_time / 60;
2011 Sbar_DrawNum (160, 64, dig, 3, 0);
2012 num = (int)cl.completed_time - dig*60;
2013 Sbar_DrawPic (234,64,sb_colon);
2014 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2015 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2017 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2018 if (gamemode != GAME_NEXUIZ)
2019 Sbar_DrawPic (232, 104, sb_slash);
2020 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2022 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2023 if (gamemode != GAME_NEXUIZ)
2024 Sbar_DrawPic (232, 144, sb_slash);
2025 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2036 void Sbar_FinaleOverlay (void)
2038 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);