2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // sbar.c -- status bar code
26 #define STAT_MINUS 10 // num frame for '-' stats digit
27 cachepic_t *sb_nums[2][11];
28 cachepic_t *sb_colon, *sb_slash;
31 cachepic_t *sb_scorebar;
32 // AK only used by NEX
33 cachepic_t *sb_sbar_minimal;
34 cachepic_t *sb_sbar_overlay;
36 // AK changed the bound to 9
37 cachepic_t *sb_weapons[7][9]; // 0 is active, 1 is owned, 2-5 are flashes
38 cachepic_t *sb_ammo[4];
39 cachepic_t *sb_sigil[4];
40 cachepic_t *sb_armor[3];
41 cachepic_t *sb_items[32];
43 // 0-4 are based on health (in 20 increments)
44 // 0 is static, 1 is temporary animation
45 cachepic_t *sb_faces[5][2];
46 cachepic_t *sb_health; // GAME_NEXUIZ
48 cachepic_t *sb_face_invis;
49 cachepic_t *sb_face_quad;
50 cachepic_t *sb_face_invuln;
51 cachepic_t *sb_face_invis_invuln;
53 qboolean sb_showscores;
55 int sb_lines; // scan lines to draw
57 cachepic_t *rsb_invbar[2];
58 cachepic_t *rsb_weapons[5];
59 cachepic_t *rsb_items[2];
60 cachepic_t *rsb_ammo[3];
61 cachepic_t *rsb_teambord; // PGM 01/19/97 - team color border
63 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
64 cachepic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
65 //MED 01/04/97 added array to simplify weapon parsing
66 int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
67 //MED 01/04/97 added hipnotic items array
68 cachepic_t *hsb_items[2];
71 cachepic_t *somsb_health;
72 cachepic_t *somsb_ammo[4];
73 cachepic_t *somsb_armor[3];
75 cachepic_t *zymsb_crosshair_center;
76 cachepic_t *zymsb_crosshair_line;
77 cachepic_t *zymsb_crosshair_health;
78 cachepic_t *zymsb_crosshair_ammo;
79 cachepic_t *zymsb_crosshair_clip;
80 cachepic_t *zymsb_crosshair_background;
81 cachepic_t *zymsb_crosshair_left1;
82 cachepic_t *zymsb_crosshair_left2;
83 cachepic_t *zymsb_crosshair_right;
85 cachepic_t *sb_ranking;
86 cachepic_t *sb_complete;
88 cachepic_t *sb_finale;
90 cvar_t showfps = {CVAR_SAVE, "showfps", "0", "shows your rendered fps (frames per second)"};
91 cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"};
92 cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"};
93 cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"};
94 cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"};
95 cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
96 cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
97 cvar_t sbar_hudselector = {CVAR_SAVE, "sbar_hudselector", "0", "selects which of the builtin hud layouts to use (meaning is somewhat dependent on gamemode, so nexuiz has a very different set of hud layouts than quake for example)"};
98 cvar_t sbar_miniscoreboard_size = {CVAR_SAVE, "sbar_miniscoreboard_size", "-1", "sets the size of the mini deathmatch overlay in items, or disables it when set to 0, or sets it to a sane default when set to -1"};
100 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
102 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
103 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
104 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
105 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
106 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
108 void Sbar_MiniDeathmatchOverlay (int x, int y);
109 void Sbar_DeathmatchOverlay (void);
110 void Sbar_IntermissionOverlay (void);
111 void Sbar_FinaleOverlay (void);
121 void Sbar_ShowScores (void)
125 sb_showscores = true;
135 void Sbar_DontShowScores (void)
137 sb_showscores = false;
140 void sbar_start(void)
144 if (gamemode == GAME_NETHERWORLD)
147 else if (gamemode == GAME_SOM)
149 sb_disc = Draw_CachePic("gfx/disc", true);
151 for (i = 0;i < 10;i++)
152 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
154 somsb_health = Draw_CachePic("gfx/hud_health", true);
155 somsb_ammo[0] = Draw_CachePic("gfx/sb_shells", true);
156 somsb_ammo[1] = Draw_CachePic("gfx/sb_nails", true);
157 somsb_ammo[2] = Draw_CachePic("gfx/sb_rocket", true);
158 somsb_ammo[3] = Draw_CachePic("gfx/sb_cells", true);
159 somsb_armor[0] = Draw_CachePic("gfx/sb_armor1", true);
160 somsb_armor[1] = Draw_CachePic("gfx/sb_armor2", true);
161 somsb_armor[2] = Draw_CachePic("gfx/sb_armor3", true);
163 else if (gamemode == GAME_NEXUIZ)
165 for (i = 0;i < 10;i++)
166 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
167 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
168 sb_colon = Draw_CachePic ("gfx/num_colon", true);
170 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
171 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets", true);
172 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
173 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
175 sb_armor[0] = Draw_CachePic ("gfx/sb_armor", true);
179 sb_health = Draw_CachePic ("gfx/sb_health", true);
181 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo", true);
182 sb_items[3] = Draw_CachePic ("gfx/sb_invinc", true);
183 sb_items[4] = Draw_CachePic ("gfx/sb_energy", true);
184 sb_items[5] = Draw_CachePic ("gfx/sb_str", true);
186 sb_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken", true);
187 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost", true);
188 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying", true);
189 sb_items[14] = Draw_CachePic ("gfx/sb_key_carrying", true);
190 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken", true);
191 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost", true);
192 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying", true);
194 sb_sbar = Draw_CachePic("gfx/sbar", true);
195 sb_sbar_minimal = Draw_CachePic("gfx/sbar_minimal", true);
196 sb_sbar_overlay = Draw_CachePic("gfx/sbar_overlay", true);
198 for(i = 0; i < 9;i++)
199 sb_weapons[0][i] = Draw_CachePic(va("gfx/inv_weapon%i",i), true);
201 else if (gamemode == GAME_ZYMOTIC)
203 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center", true);
204 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line", true);
205 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health", true);
206 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip", true);
207 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo", true);
208 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background", true);
209 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1", true);
210 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2", true);
211 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right", true);
215 sb_disc = Draw_CachePic("gfx/disc", true);
217 for (i = 0;i < 10;i++)
219 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
220 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i), true);
223 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
224 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus", true);
226 sb_colon = Draw_CachePic ("gfx/num_colon", true);
227 sb_slash = Draw_CachePic ("gfx/num_slash", true);
229 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun", true);
230 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun", true);
231 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun", true);
232 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun", true);
233 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch", true);
234 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch", true);
235 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng", true);
237 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun", true);
238 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun", true);
239 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun", true);
240 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun", true);
241 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch", true);
242 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch", true);
243 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng", true);
245 for (i = 0;i < 5;i++)
247 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1), true);
248 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1), true);
249 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1), true);
250 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1), true);
251 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1), true);
252 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1), true);
253 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1), true);
256 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
257 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails", true);
258 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
259 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
261 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1", true);
262 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2", true);
263 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3", true);
265 sb_items[0] = Draw_CachePic ("gfx/sb_key1", true);
266 sb_items[1] = Draw_CachePic ("gfx/sb_key2", true);
267 sb_items[2] = Draw_CachePic ("gfx/sb_invis", true);
268 sb_items[3] = Draw_CachePic ("gfx/sb_invuln", true);
269 sb_items[4] = Draw_CachePic ("gfx/sb_suit", true);
270 sb_items[5] = Draw_CachePic ("gfx/sb_quad", true);
272 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1", true);
273 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2", true);
274 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3", true);
275 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4", true);
277 sb_faces[4][0] = Draw_CachePic ("gfx/face1", true);
278 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1", true);
279 sb_faces[3][0] = Draw_CachePic ("gfx/face2", true);
280 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2", true);
281 sb_faces[2][0] = Draw_CachePic ("gfx/face3", true);
282 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3", true);
283 sb_faces[1][0] = Draw_CachePic ("gfx/face4", true);
284 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4", true);
285 sb_faces[0][0] = Draw_CachePic ("gfx/face5", true);
286 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5", true);
288 sb_face_invis = Draw_CachePic ("gfx/face_invis", true);
289 sb_face_invuln = Draw_CachePic ("gfx/face_invul2", true);
290 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2", true);
291 sb_face_quad = Draw_CachePic ("gfx/face_quad", true);
293 sb_sbar = Draw_CachePic ("gfx/sbar", true);
294 sb_ibar = Draw_CachePic ("gfx/ibar", true);
295 sb_scorebar = Draw_CachePic ("gfx/scorebar", true);
297 //MED 01/04/97 added new hipnotic weapons
298 if (gamemode == GAME_HIPNOTIC)
300 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser", true);
301 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir", true);
302 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox", true);
303 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren", true);
304 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox", true);
306 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser", true);
307 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir", true);
308 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox", true);
309 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren", true);
310 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox", true);
312 for (i = 0;i < 5;i++)
314 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1), true);
315 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1), true);
316 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1), true);
317 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1), true);
318 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1), true);
321 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit", true);
322 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld", true);
324 else if (gamemode == GAME_ROGUE)
326 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1", true);
327 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2", true);
329 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava", true);
330 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava", true);
331 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren", true);
332 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock", true);
333 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma", true);
335 rsb_items[0] = Draw_CachePic ("gfx/r_shield1", true);
336 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1", true);
338 // PGM 01/19/97 - team color border
339 rsb_teambord = Draw_CachePic ("gfx/r_teambord", true);
340 // PGM 01/19/97 - team color border
342 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava", true);
343 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti", true);
344 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma", true);
348 sb_ranking = Draw_CachePic ("gfx/ranking", true);
349 sb_complete = Draw_CachePic ("gfx/complete", true);
350 sb_inter = Draw_CachePic ("gfx/inter", true);
351 sb_finale = Draw_CachePic ("gfx/finale", true);
354 void sbar_shutdown(void)
358 void sbar_newmap(void)
362 void Sbar_Init (void)
364 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
365 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
366 Cvar_RegisterVariable(&showfps);
367 Cvar_RegisterVariable(&showtime);
368 Cvar_RegisterVariable(&showtime_format);
369 Cvar_RegisterVariable(&showdate);
370 Cvar_RegisterVariable(&showdate_format);
371 Cvar_RegisterVariable(&sbar_alpha_bg);
372 Cvar_RegisterVariable(&sbar_alpha_fg);
373 Cvar_RegisterVariable(&sbar_hudselector);
374 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
375 Cvar_RegisterVariable(&cl_deathscoreboard);
377 Cvar_RegisterVariable(&crosshair_color_red);
378 Cvar_RegisterVariable(&crosshair_color_green);
379 Cvar_RegisterVariable(&crosshair_color_blue);
380 Cvar_RegisterVariable(&crosshair_color_alpha);
381 Cvar_RegisterVariable(&crosshair_size);
383 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
387 //=============================================================================
389 // drawing routines are relative to the status bar location
398 void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
400 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
403 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
405 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
408 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
410 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
417 Draws one solid graphics character
420 void Sbar_DrawCharacter (int x, int y, int num)
422 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);
430 void Sbar_DrawString (int x, int y, char *str)
432 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false);
440 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
445 l = sprintf(str, "%i", num);
459 Sbar_DrawPic (x, y, sb_nums[color][frame]);
472 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
480 l = sprintf(str, "%0*i", digits, num);
483 l = sprintf(str, "%i", num);
488 x += (digits-l) * lettersize;
497 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
504 //=============================================================================
507 int Sbar_IsTeammatch()
509 // currently only nexuiz uses the team score board
510 return ((gamemode == GAME_NEXUIZ)
511 && (teamplay.integer > 0));
519 static int fragsort[MAX_SCOREBOARD];
520 static int scoreboardlines;
522 //[515]: Sbar_GetPlayer for csqc "getplayerkey" func
523 int Sbar_GetPlayer (int index)
528 if(index >= scoreboardlines)
530 index = fragsort[index];
532 if(index >= scoreboardlines)
537 static scoreboard_t teams[MAX_SCOREBOARD];
538 static int teamsort[MAX_SCOREBOARD];
539 static int teamlines;
540 void Sbar_SortFrags (void)
546 for (i=0 ; i<cl.maxclients ; i++)
548 if (cl.scores[i].name[0])
550 fragsort[scoreboardlines] = i;
555 for (i=0 ; i<scoreboardlines ; i++)
556 for (j=0 ; j<scoreboardlines-1-i ; j++)
557 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
560 fragsort[j] = fragsort[j+1];
565 if (Sbar_IsTeammatch ())
567 // now sort players by teams.
568 for (i=0 ; i<scoreboardlines ; i++)
570 for (j=0 ; j<scoreboardlines-1-i ; j++)
572 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
575 fragsort[j] = fragsort[j+1];
581 // calculate team scores
583 for (i=0 ; i<scoreboardlines ; i++)
585 if (color != (cl.scores[fragsort[i]].colors & 15))
587 const char* teamname;
589 color = cl.scores[fragsort[i]].colors & 15;
595 teamname = "^1Red Team";
598 teamname = "^4Blue Team";
601 teamname = "^6Pink Team";
604 teamname = "^3Yellow Team";
607 teamname = "Total Team Score";
610 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
612 teams[teamlines-1].frags = 0;
613 teams[teamlines-1].colors = color + 16 * color;
616 if (cl.scores[fragsort[i]].frags != -666)
618 // do not add spedcators
619 // (ugly hack for nexuiz)
620 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
624 // now sort teams by scores.
625 for (i=0 ; i<teamlines ; i++)
627 for (i=0 ; i<teamlines ; i++)
629 for (j=0 ; j<teamlines-1-i ; j++)
631 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
634 teamsort[j] = teamsort[j+1];
647 void Sbar_SoloScoreboard (void)
650 char str[80], timestr[40];
652 int minutes, seconds;
655 t = (cl.intermission ? cl.completed_time : cl.time);
656 minutes = (int)(t / 60);
657 seconds = (int)(t - 60*floor(t/60));
659 // monsters and secrets are now both on the top row
660 if (cl.stats[STAT_TOTALMONSTERS])
661 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
662 if (cl.stats[STAT_TOTALSECRETS])
663 Sbar_DrawString(8+22*8, 4, va("Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
665 // figure out the map's filename without path or extension
666 strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
667 if (strrchr(str, '.'))
668 *(strrchr(str, '.')) = 0;
670 // append a : separator and then the full title
671 strlcat(str, ":", sizeof(str));
672 strlcat(str, cl.levelname, sizeof(str));
674 // if there's a newline character, terminate the string there
675 if (strchr(str, '\n'))
676 *(strchr(str, '\n')) = 0;
678 // make the time string
679 timelen = sprintf(timestr, " %i:%02i", minutes, seconds);
681 // truncate the level name if necessary to make room for time
683 if ((int)strlen(str) > max)
686 // print the filename and message
687 Sbar_DrawString(8, 12, str);
690 Sbar_DrawString(8 + max*8, 12, timestr);
694 int minutes, seconds, tens, units;
697 if (gamemode != GAME_NEXUIZ) {
698 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
699 Sbar_DrawString (8, 4, str);
701 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
702 Sbar_DrawString (8, 12, str);
706 minutes = (int)(cl.time / 60);
707 seconds = (int)(cl.time - 60*minutes);
709 units = seconds - 10*tens;
710 sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
711 Sbar_DrawString (184, 4, str);
714 if (gamemode == GAME_NEXUIZ) {
715 l = (int) strlen (cl.worldmodel->name);
716 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
718 l = (int) strlen (cl.levelname);
719 Sbar_DrawString (232 - l*4, 12, cl.levelname);
729 void Sbar_DrawScoreboard (void)
731 Sbar_SoloScoreboard ();
732 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
733 //if (cl.gametype == GAME_DEATHMATCH)
735 Sbar_DeathmatchOverlay ();
738 //=============================================================================
740 // AK to make DrawInventory smaller
741 static void Sbar_DrawWeapon(int nr, float fade, int active)
743 if (sbar_hudselector.integer == 1)
745 // width = 300, height = 100
746 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
748 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);
749 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);
753 // width = 300, height = 100
754 const int w_width = 300, w_height = 100, w_space = 10;
755 const float w_scale = 0.4;
757 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);
758 //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);
767 void Sbar_DrawInventory (void)
774 if (gamemode == GAME_ROGUE)
776 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
777 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
779 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
782 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
785 for (i=0 ; i<7 ; i++)
787 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
789 time = cl.item_gettime[i];
790 flashon = (int)(max(0, cl.time - time)*10);
793 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
799 flashon = (flashon%5) + 2;
801 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
807 if (gamemode == GAME_HIPNOTIC)
809 int grenadeflashing=0;
810 for (i=0 ; i<4 ; i++)
812 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
814 time = max(0, cl.item_gettime[hipweapons[i]]);
815 flashon = (int)((cl.time - time)*10);
818 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
824 flashon = (flashon%5) + 2;
826 // check grenade launcher
829 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
834 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
840 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
842 if (!grenadeflashing)
843 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
846 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
849 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
854 if (gamemode == GAME_ROGUE)
856 // check for powered up weapon.
857 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
859 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
860 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
864 for (i=0 ; i<4 ; i++)
866 sprintf (num, "%4i",cl.stats[STAT_SHELLS+i] );
868 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
870 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
872 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
874 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
878 for (i=0 ; i<6 ; i++)
879 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
881 //MED 01/04/97 changed keys
882 if (gamemode != GAME_HIPNOTIC || (i>1))
883 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
886 //MED 01/04/97 added hipnotic items
888 if (gamemode == GAME_HIPNOTIC)
890 for (i=0 ; i<2 ; i++)
891 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
892 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
895 if (gamemode == GAME_ROGUE)
898 for (i=0 ; i<2 ; i++)
899 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
900 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
905 for (i=0 ; i<4 ; i++)
906 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
907 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
911 //=============================================================================
918 void Sbar_DrawFrags (void)
928 l = min(scoreboardlines, 4);
932 for (i = 0;i < l;i++)
938 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
939 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);
940 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
941 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);
945 sprintf (num, "%3i",f);
947 if (k == cl.viewentity - 1)
949 Sbar_DrawCharacter ( x + 2, -24, 16);
950 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
952 Sbar_DrawCharacter (x + 8, -24, num[0]);
953 Sbar_DrawCharacter (x + 16, -24, num[1]);
954 Sbar_DrawCharacter (x + 24, -24, num[2]);
959 //=============================================================================
967 void Sbar_DrawFace (void)
971 // PGM 01/19/97 - team color drawing
972 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
973 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
979 s = &cl.scores[cl.viewentity - 1];
981 Sbar_DrawPic (112, 0, rsb_teambord);
982 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
983 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);
984 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
985 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);
989 sprintf (num, "%3i",f);
991 if ((s->colors & 0xf0)==0)
994 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
996 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
998 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1002 Sbar_DrawCharacter ( 109, 3, num[0]);
1003 Sbar_DrawCharacter ( 116, 3, num[1]);
1004 Sbar_DrawCharacter ( 123, 3, num[2]);
1009 // PGM 01/19/97 - team color drawing
1011 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1012 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1013 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1014 Sbar_DrawPic (112, 0, sb_face_quad );
1015 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1016 Sbar_DrawPic (112, 0, sb_face_invis );
1017 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1018 Sbar_DrawPic (112, 0, sb_face_invuln);
1021 f = cl.stats[STAT_HEALTH] / 20;
1023 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1027 void Sbar_ShowFPS(void)
1029 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1031 char timestring[32];
1032 char datestring[32];
1033 qboolean red = false;
1037 if (showfps.integer)
1040 static double nexttime = 0, lasttime = 0;
1041 static double framerate = 0;
1042 static int framecount = 0;
1045 if (newtime >= nexttime)
1047 framerate = framecount / (newtime - lasttime);
1049 nexttime = max(nexttime + 1, lasttime - 1);
1055 if ((red = (calc < 1.0f)))
1056 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1058 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1060 if (showtime.integer)
1061 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1062 if (showdate.integer)
1063 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1064 if (fpsstring[0] || timestring[0])
1068 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
1069 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1070 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1071 fps_y = vid_conheight.integer - fps_height;
1074 fps_x = vid_conwidth.integer - fps_scalex * strlen(fpsstring);
1075 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(fpsstring), fps_scaley, 0, 0, 0, 0.5, 0);
1077 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true);
1079 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1080 fps_y += fps_scaley;
1084 fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
1085 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(timestring), fps_scaley, 0, 0, 0, 0.5, 0);
1086 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1087 fps_y += fps_scaley;
1091 fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
1092 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(datestring), fps_scaley, 0, 0, 0, 0.5, 0);
1093 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1094 fps_y += fps_scaley;
1099 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)
1102 c2 = bound(0, c2, 1);
1103 c1 = bound(0, c1, 1 - c2);
1105 r[1] = rangey + rangeheight * (c2 + c1);
1106 r[2] = rangey + rangeheight * (c2);
1110 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);
1112 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);
1114 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);
1116 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);
1124 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1125 extern cvar_t v_kicktime;
1126 void Sbar_Score (int margin);
1127 void Sbar_Draw (void)
1131 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1134 Sbar_DrawScoreboard ();
1135 else if (cl.intermission == 1)
1137 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1139 Sbar_DrawScoreboard();
1142 Sbar_IntermissionOverlay();
1144 else if (cl.intermission == 2)
1145 Sbar_FinaleOverlay();
1146 else if (gamemode == GAME_NETHERWORLD)
1149 else if (gamemode == GAME_SOM)
1151 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1152 Sbar_DrawScoreboard ();
1155 // this is the top left of the sbar area
1157 sbar_y = vid_conheight.integer - 24*3;
1160 if (cl.stats[STAT_ARMOR])
1162 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1163 Sbar_DrawPic(0, 0, somsb_armor[2]);
1164 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1165 Sbar_DrawPic(0, 0, somsb_armor[1]);
1166 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1167 Sbar_DrawPic(0, 0, somsb_armor[0]);
1168 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1172 Sbar_DrawPic(0, 24, somsb_health);
1173 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1176 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1177 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1178 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1179 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1180 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1181 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1182 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1183 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1184 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1185 if (cl.stats[STAT_SHELLS])
1186 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1189 else if (gamemode == GAME_NEXUIZ)
1191 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1193 sbar_x = (vid_conwidth.integer - 640)/2;
1194 sbar_y = vid_conheight.integer - 47;
1195 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1196 Sbar_DrawScoreboard ();
1198 else if (sb_lines && sbar_hudselector.integer == 1)
1202 int redflag, blueflag;
1204 sbar_x = (vid_conwidth.integer - 320)/2;
1205 sbar_y = vid_conheight.integer - 24 - 16;
1207 // calculate intensity to draw weapons bar at
1208 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1209 fade = bound(0.7, fade, 1);
1210 for (i = 0; i < 8;i++)
1211 if (cl.stats[STAT_ITEMS] & (1 << i))
1212 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1213 if((cl.stats[STAT_ITEMS] & (1<<12)))
1214 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1217 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1218 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1219 if (redflag == 3 && blueflag == 3)
1221 // The Impossible Combination[tm]
1222 // Can only happen in Key Hunt mode...
1223 Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1228 Sbar_DrawPic (10 - sbar_x, -117, sb_items[redflag+10]);
1230 Sbar_DrawPic (10 - sbar_x, -177, sb_items[blueflag+14]);
1234 if (cl.stats[STAT_ARMOR] > 0)
1236 Sbar_DrawStretchPic (0, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1237 if(cl.stats[STAT_ARMOR] > 100)
1238 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0,1,0);
1239 else if(cl.stats[STAT_ARMOR] > 25)
1240 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1242 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1246 if (cl.stats[STAT_HEALTH] != 0)
1248 Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1249 if(cl.stats[STAT_HEALTH] > 100)
1250 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0,1,0);
1251 else if(cl.stats[STAT_HEALTH] > 25)
1252 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1254 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1258 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1260 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1261 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1262 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1263 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1264 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1265 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1266 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1267 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1268 if(cl.stats[STAT_AMMO] > 10)
1269 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1271 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1274 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1275 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1278 // The margin can be at most 8 to support 640x480 console size:
1279 // 320 + 2 * (144 + 16) = 640
1285 int redflag, blueflag;
1287 sbar_x = (vid_conwidth.integer - 640)/2;
1288 sbar_y = vid_conheight.integer - 47;
1290 // calculate intensity to draw weapons bar at
1291 fade = 3 - 2 * (cl.time - cl.weapontime);
1294 fade = min(fade, 1);
1295 for (i = 0; i < 8;i++)
1296 if (cl.stats[STAT_ITEMS] & (1 << i))
1297 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1299 if((cl.stats[STAT_ITEMS] & (1<<12)))
1300 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1303 //if (!cl.islocalgame)
1304 // Sbar_DrawFrags ();
1307 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1309 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1312 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1313 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1314 if (redflag == 3 && blueflag == 3)
1316 // The Impossible Combination[tm]
1317 // Can only happen in Key Hunt mode...
1318 Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1323 Sbar_DrawPic (10 - sbar_x, -117, sb_items[redflag+10]);
1325 Sbar_DrawPic (10 - sbar_x, -177, sb_items[blueflag+14]);
1329 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1332 if(cl.stats[STAT_HEALTH] > 100)
1333 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1334 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1335 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1337 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1339 // AK dont draw ammo for the laser
1340 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1342 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1343 Sbar_DrawPic (519, 0, sb_ammo[0]);
1344 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1345 Sbar_DrawPic (519, 0, sb_ammo[1]);
1346 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1347 Sbar_DrawPic (519, 0, sb_ammo[2]);
1348 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1349 Sbar_DrawPic (519, 0, sb_ammo[3]);
1351 if(cl.stats[STAT_AMMO] <= 10)
1352 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1354 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1359 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1361 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1362 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1367 // Mini scoreboard uses 12*4 per other team, that is, 144
1368 // pixels when there are four teams...
1369 // Nexuiz by default sets vid_conwidth to 800... makes
1371 // so we need to shift it by 64 pixels to the right to fit
1372 // BUT: then it overlaps with the image that gets drawn
1373 // for viewsize 100! Therefore, just account for 3 teams,
1374 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1378 else if (gamemode == GAME_ZYMOTIC)
1381 float scale = 64.0f / 256.0f;
1382 float kickoffset[3];
1383 VectorClear(kickoffset);
1386 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1387 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1389 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1390 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1391 // left1 16, 48 : 126 -66
1392 // left2 16, 128 : 196 -66
1393 // right 176, 48 : 196 -136
1394 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);
1395 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);
1396 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);
1397 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1399 float scale = 128.0f / 256.0f;
1400 float healthstart, healthheight, healthstarttc, healthendtc;
1401 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1402 float ammostart, ammoheight, ammostarttc, ammoendtc;
1403 float clipstart, clipheight, clipstarttc, clipendtc;
1404 float kickoffset[3], offset;
1405 VectorClear(kickoffset);
1408 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1409 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1411 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1412 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1413 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1414 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);
1415 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);
1416 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);
1417 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);
1418 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1419 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1420 healthstart = 204 - healthheight;
1421 shieldstart = healthstart - shieldheight;
1422 healthstarttc = healthstart * (1.0f / 256.0f);
1423 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1424 shieldstarttc = shieldstart * (1.0f / 256.0f);
1425 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1426 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1427 ammostart = 114 - ammoheight;
1428 ammostarttc = ammostart * (1.0f / 256.0f);
1429 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1430 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1431 clipstart = 190 - clipheight;
1432 clipstarttc = clipstart * (1.0f / 256.0f);
1433 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1434 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);
1435 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);
1436 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);
1437 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);
1438 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1439 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1442 else // Quake and others
1444 sbar_x = (vid_conwidth.integer - 320)/2;
1445 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1446 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1447 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1451 if (gamemode != GAME_GOODVSBAD2)
1452 Sbar_DrawInventory ();
1453 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1457 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1459 if (gamemode != GAME_GOODVSBAD2)
1460 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1461 Sbar_DrawScoreboard ();
1465 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1467 // keys (hipnotic only)
1468 //MED 01/04/97 moved keys here so they would not be overwritten
1469 if (gamemode == GAME_HIPNOTIC)
1471 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1472 Sbar_DrawPic (209, 3, sb_items[0]);
1473 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1474 Sbar_DrawPic (209, 12, sb_items[1]);
1477 if (gamemode != GAME_GOODVSBAD2)
1479 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1481 Sbar_DrawNum (24, 0, 666, 3, 1);
1482 Sbar_DrawPic (0, 0, sb_disc);
1486 if (gamemode == GAME_ROGUE)
1488 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1489 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1490 Sbar_DrawPic (0, 0, sb_armor[2]);
1491 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1492 Sbar_DrawPic (0, 0, sb_armor[1]);
1493 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1494 Sbar_DrawPic (0, 0, sb_armor[0]);
1498 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1499 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1500 Sbar_DrawPic (0, 0, sb_armor[2]);
1501 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1502 Sbar_DrawPic (0, 0, sb_armor[1]);
1503 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1504 Sbar_DrawPic (0, 0, sb_armor[0]);
1513 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1516 if (gamemode == GAME_ROGUE)
1518 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1519 Sbar_DrawPic (224, 0, sb_ammo[0]);
1520 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1521 Sbar_DrawPic (224, 0, sb_ammo[1]);
1522 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1523 Sbar_DrawPic (224, 0, sb_ammo[2]);
1524 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1525 Sbar_DrawPic (224, 0, sb_ammo[3]);
1526 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1527 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1528 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1529 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1530 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1531 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1535 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1536 Sbar_DrawPic (224, 0, sb_ammo[0]);
1537 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1538 Sbar_DrawPic (224, 0, sb_ammo[1]);
1539 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1540 Sbar_DrawPic (224, 0, sb_ammo[2]);
1541 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1542 Sbar_DrawPic (224, 0, sb_ammo[3]);
1545 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1547 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1548 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1550 if (gamemode == GAME_TRANSFUSION)
1551 Sbar_MiniDeathmatchOverlay (0, 0);
1553 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1562 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1563 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);
1565 if (cl_prydoncursor.integer)
1566 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);
1569 //=============================================================================
1573 Sbar_DeathmatchOverlay
1577 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1580 qboolean myself = false;
1582 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1584 if((s - cl.scores) == cl.playerentity - 1)
1586 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1587 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1590 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1592 if (s->qw_spectator)
1594 if (s->qw_ping || s->qw_packetloss)
1595 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 );
1597 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 );
1601 // draw colors behind score
1607 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
1608 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);
1609 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
1610 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);
1612 //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);
1613 if (s->qw_ping || s->qw_packetloss)
1614 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 );
1616 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 );
1621 if (s->qw_spectator)
1623 if (s->qw_ping || s->qw_packetloss)
1624 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 );
1626 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 );
1630 // draw colors behind score
1631 c = (unsigned char *)&palette_pantsscoreboard[(s->colors & 0xf0) >> 4];
1632 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);
1633 c = (unsigned char *)&palette_shirtscoreboard[s->colors & 0xf];
1634 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);
1636 //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);
1637 if (s->qw_ping || s->qw_packetloss)
1638 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 );
1640 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 );
1646 void Sbar_DeathmatchOverlay (void)
1650 // request new ping times every two second
1651 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1653 cl.last_ping_request = realtime;
1654 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1656 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1657 MSG_WriteString(&cls.netcon->message, "pings");
1659 else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6/* || cls.protocol == PROTOCOL_DARKPLACES7*/)
1661 // 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
1662 static int ping_anyway_counter = 0;
1663 if(cl.parsingtextexpectingpingforscores == 1)
1665 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1666 if(++ping_anyway_counter >= 5)
1667 cl.parsingtextexpectingpingforscores = 0;
1669 if(cl.parsingtextexpectingpingforscores != 1)
1671 ping_anyway_counter = 0;
1672 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1673 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1674 MSG_WriteString(&cls.netcon->message, "ping");
1679 // 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
1680 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1681 MSG_WriteString(&cls.netcon->message, "pings");
1685 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1691 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1693 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)
1694 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 );
1698 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)
1699 DrawQ_String(x, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1703 if (Sbar_IsTeammatch ())
1705 // show team scores first
1706 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1707 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1711 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1712 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1717 Sbar_MiniDeathmatchOverlay
1721 void Sbar_MiniDeathmatchOverlay (int x, int y)
1723 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1725 // do not draw this if sbar_miniscoreboard_size is zero
1726 if(sbar_miniscoreboard_size.value == 0)
1728 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1729 if(sbar_miniscoreboard_size.value > 0)
1730 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1735 // decide where to print
1736 if (gamemode == GAME_TRANSFUSION)
1737 numlines = (vid_conwidth.integer - x + 127) / 128;
1739 numlines = (vid_conheight.integer - y + 7) / 8;
1741 // give up if there isn't room
1742 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1746 for (i = 0; i < scoreboardlines; i++)
1747 if (fragsort[i] == cl.playerentity - 1)
1751 range_end = scoreboardlines;
1754 if (gamemode != GAME_TRANSFUSION)
1755 if (Sbar_IsTeammatch ())
1757 // reserve space for the team scores
1758 numlines -= teamlines;
1760 // find first and last player of my team (only draw the team totals and my own team)
1761 range_begin = range_end = i;
1762 myteam = cl.scores[fragsort[i]].colors & 15;
1763 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1765 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1768 // looks better than two players
1778 i = min(i, range_end - numlines);
1779 i = max(i, range_begin);
1781 if (gamemode == GAME_TRANSFUSION)
1783 for (;i < range_end && x < vid_conwidth.integer;i++)
1784 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1788 if(range_end - i < numlines) // won't draw to bottom?
1789 y += 8 * (numlines - (range_end - i)); // bottom align
1790 // show team scores first
1791 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1792 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1794 for (;i < range_end && y < vid_conheight.integer;i++)
1795 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1799 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1801 static int const sortorder[16] =
1820 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1821 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1822 int tc1 = sortorder[t1->colors & 15];
1823 int tc2 = sortorder[t2->colors & 15];
1827 void Sbar_Score (int margin)
1829 int i, me, score, otherleader, place, distribution, minutes, seconds;
1831 int sbar_x_save = sbar_x;
1832 int sbar_y_save = sbar_y;
1834 sbar_y = vid_conheight.value - (32+12);
1837 me = cl.playerentity - 1;
1838 if (me >= 0 && me < cl.maxclients)
1840 if(Sbar_IsTeammatch())
1844 // team1 team3 team4
1848 scoreboard_t *teamcolorsort[16];
1851 for(i = 0; i < teamlines; ++i)
1852 teamcolorsort[i] = &(teams[i]);
1854 // Now sort them by color
1855 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1858 // -12*4: four digits space
1859 place = (teamlines - 1) * (-12 * 4);
1861 for(i = 0; i < teamlines; ++i)
1863 int cindex = teamcolorsort[i]->colors & 15;
1864 unsigned char *c = (unsigned char *)&palette_shirtscoreboard[cindex];
1865 float cm = max(max(c[0], c[1]), c[2]);
1866 float cr = c[0] / cm;
1867 float cg = c[1] / cm;
1868 float cb = c[2] / cm;
1869 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1871 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1875 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1888 // find leading score other than ourselves, to calculate distribution
1889 // find our place in the scoreboard
1890 score = cl.scores[me].frags;
1891 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1893 if (cl.scores[i].name[0] && i != me)
1895 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1897 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1901 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1903 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1904 else if (place == 2)
1905 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
1907 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
1908 if (otherleader < 0)
1909 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1910 if (distribution >= 0)
1912 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
1913 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1915 else if (distribution >= -5)
1917 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
1918 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
1922 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
1923 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
1928 if (cl.statsf[STAT_TIMELIMIT])
1930 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
1931 minutes = (int)floor(timeleft / 60);
1932 seconds = (int)(floor(timeleft) - minutes * 60);
1935 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1936 if(sb_colon && sb_colon->tex != r_texture_notexture)
1937 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1938 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1940 else if (minutes >= 1)
1942 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
1943 if(sb_colon && sb_colon->tex != r_texture_notexture)
1944 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
1945 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
1947 else if ((int)(timeleft * 4) & 1)
1948 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1950 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
1954 minutes = (int)floor(cl.time / 60);
1955 seconds = (int)(floor(cl.time) - minutes * 60);
1956 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1957 if(sb_colon && sb_colon->tex != r_texture_notexture)
1958 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1959 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1962 sbar_x = sbar_x_save;
1963 sbar_y = sbar_y_save;
1968 Sbar_IntermissionOverlay
1972 void Sbar_IntermissionOverlay (void)
1977 if (cl.gametype == GAME_DEATHMATCH)
1979 Sbar_DeathmatchOverlay ();
1983 sbar_x = (vid_conwidth.integer - 320) >> 1;
1984 sbar_y = (vid_conheight.integer - 200) >> 1;
1986 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1987 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1990 dig = (int)cl.completed_time / 60;
1991 Sbar_DrawNum (160, 64, dig, 3, 0);
1992 num = (int)cl.completed_time - dig*60;
1993 Sbar_DrawPic (234,64,sb_colon);
1994 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1995 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
1997 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1998 if (gamemode != GAME_NEXUIZ)
1999 Sbar_DrawPic (232, 104, sb_slash);
2000 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2002 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2003 if (gamemode != GAME_NEXUIZ)
2004 Sbar_DrawPic (232, 144, sb_slash);
2005 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2016 void Sbar_FinaleOverlay (void)
2018 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);