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, "%3i",cl.stats[STAT_SHELLS+i] );
868 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
870 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
872 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
876 for (i=0 ; i<6 ; i++)
877 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
879 //MED 01/04/97 changed keys
880 if (gamemode != GAME_HIPNOTIC || (i>1))
881 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
884 //MED 01/04/97 added hipnotic items
886 if (gamemode == GAME_HIPNOTIC)
888 for (i=0 ; i<2 ; i++)
889 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
890 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
893 if (gamemode == GAME_ROGUE)
896 for (i=0 ; i<2 ; i++)
897 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
898 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
903 for (i=0 ; i<4 ; i++)
904 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
905 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
909 //=============================================================================
916 void Sbar_DrawFrags (void)
926 l = min(scoreboardlines, 4);
930 for (i = 0;i < l;i++)
936 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
937 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);
938 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
939 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);
943 sprintf (num, "%3i",f);
945 if (k == cl.viewentity - 1)
947 Sbar_DrawCharacter ( x + 2, -24, 16);
948 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
950 Sbar_DrawCharacter (x + 8, -24, num[0]);
951 Sbar_DrawCharacter (x + 16, -24, num[1]);
952 Sbar_DrawCharacter (x + 24, -24, num[2]);
957 //=============================================================================
965 void Sbar_DrawFace (void)
969 // PGM 01/19/97 - team color drawing
970 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
971 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
977 s = &cl.scores[cl.viewentity - 1];
979 Sbar_DrawPic (112, 0, rsb_teambord);
980 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
981 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);
982 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
983 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);
987 sprintf (num, "%3i",f);
989 if ((s->colors & 0xf0)==0)
992 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
994 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
996 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1000 Sbar_DrawCharacter ( 109, 3, num[0]);
1001 Sbar_DrawCharacter ( 116, 3, num[1]);
1002 Sbar_DrawCharacter ( 123, 3, num[2]);
1007 // PGM 01/19/97 - team color drawing
1009 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1010 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1011 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1012 Sbar_DrawPic (112, 0, sb_face_quad );
1013 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1014 Sbar_DrawPic (112, 0, sb_face_invis );
1015 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1016 Sbar_DrawPic (112, 0, sb_face_invuln);
1019 f = cl.stats[STAT_HEALTH] / 20;
1021 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1025 void Sbar_ShowFPS(void)
1027 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1029 char timestring[32];
1030 char datestring[32];
1031 qboolean red = false;
1035 if (showfps.integer)
1038 static double nexttime = 0, lasttime = 0;
1039 static double framerate = 0;
1040 static int framecount = 0;
1043 if (newtime >= nexttime)
1045 framerate = framecount / (newtime - lasttime);
1047 nexttime = max(nexttime + 1, lasttime - 1);
1053 if ((red = (calc < 1.0f)))
1054 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1056 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1058 if (showtime.integer)
1059 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1060 if (showdate.integer)
1061 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1062 if (fpsstring[0] || timestring[0])
1066 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
1067 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1068 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1069 fps_y = vid_conheight.integer - fps_height;
1072 fps_x = vid_conwidth.integer - fps_scalex * strlen(fpsstring);
1073 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(fpsstring), fps_scaley, 0, 0, 0, 0.5, 0);
1075 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true);
1077 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1078 fps_y += fps_scaley;
1082 fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
1083 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(timestring), fps_scaley, 0, 0, 0, 0.5, 0);
1084 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1085 fps_y += fps_scaley;
1089 fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
1090 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(datestring), fps_scaley, 0, 0, 0, 0.5, 0);
1091 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1092 fps_y += fps_scaley;
1097 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)
1100 c2 = bound(0, c2, 1);
1101 c1 = bound(0, c1, 1 - c2);
1103 r[1] = rangey + rangeheight * (c2 + c1);
1104 r[2] = rangey + rangeheight * (c2);
1108 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);
1110 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);
1112 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);
1114 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);
1122 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1123 extern cvar_t v_kicktime;
1124 void Sbar_Score (int margin);
1125 void Sbar_Draw (void)
1129 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1132 Sbar_DrawScoreboard ();
1133 else if (cl.intermission == 1)
1135 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1137 Sbar_DrawScoreboard();
1140 Sbar_IntermissionOverlay();
1142 else if (cl.intermission == 2)
1143 Sbar_FinaleOverlay();
1144 else if (gamemode == GAME_NETHERWORLD)
1147 else if (gamemode == GAME_SOM)
1149 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1150 Sbar_DrawScoreboard ();
1153 // this is the top left of the sbar area
1155 sbar_y = vid_conheight.integer - 24*3;
1158 if (cl.stats[STAT_ARMOR])
1160 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1161 Sbar_DrawPic(0, 0, somsb_armor[2]);
1162 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1163 Sbar_DrawPic(0, 0, somsb_armor[1]);
1164 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1165 Sbar_DrawPic(0, 0, somsb_armor[0]);
1166 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1170 Sbar_DrawPic(0, 24, somsb_health);
1171 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1174 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1175 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1176 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1177 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1178 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1179 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1180 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1181 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1182 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1183 if (cl.stats[STAT_SHELLS])
1184 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1187 else if (gamemode == GAME_NEXUIZ)
1189 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1191 sbar_x = (vid_conwidth.integer - 640)/2;
1192 sbar_y = vid_conheight.integer - 47;
1193 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1194 Sbar_DrawScoreboard ();
1196 else if (sb_lines && sbar_hudselector.integer == 1)
1200 int redflag, blueflag;
1202 sbar_x = (vid_conwidth.integer - 320)/2;
1203 sbar_y = vid_conheight.integer - 24 - 16;
1205 // calculate intensity to draw weapons bar at
1206 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1207 fade = bound(0.7, fade, 1);
1208 for (i = 0; i < 8;i++)
1209 if (cl.stats[STAT_ITEMS] & (1 << i))
1210 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1211 if((cl.stats[STAT_ITEMS] & (1<<12)))
1212 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1215 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1216 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1217 if (redflag == 3 && blueflag == 3)
1219 // The Impossible Combination[tm]
1220 // Can only happen in Key Hunt mode...
1221 Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1226 Sbar_DrawPic (10 - sbar_x, -117, sb_items[redflag+10]);
1228 Sbar_DrawPic (10 - sbar_x, -177, sb_items[blueflag+14]);
1232 if (cl.stats[STAT_ARMOR] > 0)
1234 Sbar_DrawStretchPic (0, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1235 if(cl.stats[STAT_ARMOR] > 100)
1236 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0,1,0);
1237 else if(cl.stats[STAT_ARMOR] > 25)
1238 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1240 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1244 if (cl.stats[STAT_HEALTH] != 0)
1246 Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1247 if(cl.stats[STAT_HEALTH] > 100)
1248 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0,1,0);
1249 else if(cl.stats[STAT_HEALTH] > 25)
1250 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1252 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1256 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1258 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1259 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1260 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1261 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1262 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1263 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1264 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1265 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1266 if(cl.stats[STAT_AMMO] > 10)
1267 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1269 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1272 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1273 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1276 // The margin can be at most 8 to support 640x480 console size:
1277 // 320 + 2 * (144 + 16) = 640
1283 int redflag, blueflag;
1285 sbar_x = (vid_conwidth.integer - 640)/2;
1286 sbar_y = vid_conheight.integer - 47;
1288 // calculate intensity to draw weapons bar at
1289 fade = 3 - 2 * (cl.time - cl.weapontime);
1292 fade = min(fade, 1);
1293 for (i = 0; i < 8;i++)
1294 if (cl.stats[STAT_ITEMS] & (1 << i))
1295 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1297 if((cl.stats[STAT_ITEMS] & (1<<12)))
1298 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1301 //if (!cl.islocalgame)
1302 // Sbar_DrawFrags ();
1305 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1307 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1310 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1311 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1312 if (redflag == 3 && blueflag == 3)
1314 // The Impossible Combination[tm]
1315 // Can only happen in Key Hunt mode...
1316 Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1321 Sbar_DrawPic (10 - sbar_x, -117, sb_items[redflag+10]);
1323 Sbar_DrawPic (10 - sbar_x, -177, sb_items[blueflag+14]);
1327 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1330 if(cl.stats[STAT_HEALTH] > 100)
1331 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1332 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1333 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1335 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1337 // AK dont draw ammo for the laser
1338 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1340 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1341 Sbar_DrawPic (519, 0, sb_ammo[0]);
1342 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1343 Sbar_DrawPic (519, 0, sb_ammo[1]);
1344 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1345 Sbar_DrawPic (519, 0, sb_ammo[2]);
1346 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1347 Sbar_DrawPic (519, 0, sb_ammo[3]);
1349 if(cl.stats[STAT_AMMO] <= 10)
1350 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1352 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1357 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1359 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1360 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1365 // Mini scoreboard uses 12*4 per other team, that is, 144
1366 // pixels when there are four teams...
1367 // Nexuiz by default sets vid_conwidth to 800... makes
1369 // so we need to shift it by 64 pixels to the right to fit
1370 // BUT: then it overlaps with the image that gets drawn
1371 // for viewsize 100! Therefore, just account for 3 teams,
1372 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1376 else if (gamemode == GAME_ZYMOTIC)
1379 float scale = 64.0f / 256.0f;
1380 float kickoffset[3];
1381 VectorClear(kickoffset);
1384 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1385 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1387 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1388 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1389 // left1 16, 48 : 126 -66
1390 // left2 16, 128 : 196 -66
1391 // right 176, 48 : 196 -136
1392 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);
1393 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);
1394 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);
1395 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1397 float scale = 128.0f / 256.0f;
1398 float healthstart, healthheight, healthstarttc, healthendtc;
1399 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1400 float ammostart, ammoheight, ammostarttc, ammoendtc;
1401 float clipstart, clipheight, clipstarttc, clipendtc;
1402 float kickoffset[3], offset;
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 = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1410 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1411 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1412 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);
1413 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);
1414 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);
1415 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);
1416 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1417 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1418 healthstart = 204 - healthheight;
1419 shieldstart = healthstart - shieldheight;
1420 healthstarttc = healthstart * (1.0f / 256.0f);
1421 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1422 shieldstarttc = shieldstart * (1.0f / 256.0f);
1423 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1424 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1425 ammostart = 114 - ammoheight;
1426 ammostarttc = ammostart * (1.0f / 256.0f);
1427 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1428 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1429 clipstart = 190 - clipheight;
1430 clipstarttc = clipstart * (1.0f / 256.0f);
1431 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1432 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);
1433 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);
1434 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);
1435 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);
1436 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1437 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1440 else // Quake and others
1442 sbar_x = (vid_conwidth.integer - 320)/2;
1443 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1444 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1445 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1449 if (gamemode != GAME_GOODVSBAD2)
1450 Sbar_DrawInventory ();
1451 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1455 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1457 if (gamemode != GAME_GOODVSBAD2)
1458 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1459 Sbar_DrawScoreboard ();
1463 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1465 // keys (hipnotic only)
1466 //MED 01/04/97 moved keys here so they would not be overwritten
1467 if (gamemode == GAME_HIPNOTIC)
1469 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1470 Sbar_DrawPic (209, 3, sb_items[0]);
1471 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1472 Sbar_DrawPic (209, 12, sb_items[1]);
1475 if (gamemode != GAME_GOODVSBAD2)
1477 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1479 Sbar_DrawNum (24, 0, 666, 3, 1);
1480 Sbar_DrawPic (0, 0, sb_disc);
1484 if (gamemode == GAME_ROGUE)
1486 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1487 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1488 Sbar_DrawPic (0, 0, sb_armor[2]);
1489 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1490 Sbar_DrawPic (0, 0, sb_armor[1]);
1491 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1492 Sbar_DrawPic (0, 0, sb_armor[0]);
1496 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1497 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1498 Sbar_DrawPic (0, 0, sb_armor[2]);
1499 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1500 Sbar_DrawPic (0, 0, sb_armor[1]);
1501 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1502 Sbar_DrawPic (0, 0, sb_armor[0]);
1511 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1514 if (gamemode == GAME_ROGUE)
1516 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1517 Sbar_DrawPic (224, 0, sb_ammo[0]);
1518 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1519 Sbar_DrawPic (224, 0, sb_ammo[1]);
1520 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1521 Sbar_DrawPic (224, 0, sb_ammo[2]);
1522 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1523 Sbar_DrawPic (224, 0, sb_ammo[3]);
1524 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1525 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1526 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1527 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1528 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1529 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1533 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1534 Sbar_DrawPic (224, 0, sb_ammo[0]);
1535 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1536 Sbar_DrawPic (224, 0, sb_ammo[1]);
1537 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1538 Sbar_DrawPic (224, 0, sb_ammo[2]);
1539 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1540 Sbar_DrawPic (224, 0, sb_ammo[3]);
1543 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);
1561 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1562 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);
1564 if (cl_prydoncursor.integer)
1565 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);
1568 //=============================================================================
1572 Sbar_DeathmatchOverlay
1576 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1579 qboolean myself = false;
1581 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1583 if((s - cl.scores) == cl.playerentity - 1)
1585 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1586 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1589 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1591 if (s->qw_spectator)
1593 if (s->qw_ping || s->qw_packetloss)
1594 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 );
1596 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 );
1600 // draw colors behind score
1601 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1602 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);
1603 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1604 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);
1606 //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);
1607 if (s->qw_ping || s->qw_packetloss)
1608 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 );
1610 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 );
1615 if (s->qw_spectator)
1617 if (s->qw_ping || s->qw_packetloss)
1618 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 );
1620 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 );
1624 // draw colors behind score
1625 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1626 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);
1627 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1628 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);
1630 //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);
1631 if (s->qw_ping || s->qw_packetloss)
1632 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 );
1634 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 );
1640 void Sbar_DeathmatchOverlay (void)
1644 // request new ping times every two second
1645 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1647 cl.last_ping_request = realtime;
1648 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1650 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1651 MSG_WriteString(&cls.netcon->message, "pings");
1653 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*/)
1655 // 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
1656 static int ping_anyway_counter = 0;
1657 if(cl.parsingtextexpectingpingforscores == 1)
1659 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1660 if(++ping_anyway_counter >= 5)
1661 cl.parsingtextexpectingpingforscores = 0;
1663 if(cl.parsingtextexpectingpingforscores != 1)
1665 ping_anyway_counter = 0;
1666 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1667 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1668 MSG_WriteString(&cls.netcon->message, "ping");
1673 // 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
1674 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1675 MSG_WriteString(&cls.netcon->message, "pings");
1679 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1685 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1687 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)
1688 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 );
1692 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)
1693 DrawQ_String(x, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1697 if (Sbar_IsTeammatch ())
1699 // show team scores first
1700 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1701 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1705 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1706 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1711 Sbar_MiniDeathmatchOverlay
1715 void Sbar_MiniDeathmatchOverlay (int x, int y)
1717 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1719 // do not draw this if sbar_miniscoreboard_size is zero
1720 if(sbar_miniscoreboard_size.value == 0)
1722 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1723 if(sbar_miniscoreboard_size.value > 0)
1724 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1729 // decide where to print
1730 if (gamemode == GAME_TRANSFUSION)
1731 numlines = (vid_conwidth.integer - x + 127) / 128;
1733 numlines = (vid_conheight.integer - y + 7) / 8;
1735 // give up if there isn't room
1736 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1740 for (i = 0; i < scoreboardlines; i++)
1741 if (fragsort[i] == cl.playerentity - 1)
1745 range_end = scoreboardlines;
1748 if (gamemode != GAME_TRANSFUSION)
1749 if (Sbar_IsTeammatch ())
1751 // reserve space for the team scores
1752 numlines -= teamlines;
1754 // find first and last player of my team (only draw the team totals and my own team)
1755 range_begin = range_end = i;
1756 myteam = cl.scores[fragsort[i]].colors & 15;
1757 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1759 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1762 // looks better than two players
1772 i = min(i, range_end - numlines);
1773 i = max(i, range_begin);
1775 if (gamemode == GAME_TRANSFUSION)
1777 for (;i < range_end && x < vid_conwidth.integer;i++)
1778 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1782 if(range_end - i < numlines) // won't draw to bottom?
1783 y += 8 * (numlines - (range_end - i)); // bottom align
1784 // show team scores first
1785 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1786 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1788 for (;i < range_end && y < vid_conheight.integer;i++)
1789 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1793 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1795 static int const sortorder[16] =
1814 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1815 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1816 int tc1 = sortorder[t1->colors & 15];
1817 int tc2 = sortorder[t2->colors & 15];
1821 void Sbar_Score (int margin)
1823 int i, me, score, otherleader, place, distribution, minutes, seconds;
1825 int sbar_x_save = sbar_x;
1826 int sbar_y_save = sbar_y;
1828 sbar_y = vid_conheight.value - (32+12);
1831 me = cl.playerentity - 1;
1832 if (me >= 0 && me < cl.maxclients)
1834 if(Sbar_IsTeammatch())
1838 // team1 team3 team4
1842 scoreboard_t *teamcolorsort[16];
1845 for(i = 0; i < teamlines; ++i)
1846 teamcolorsort[i] = &(teams[i]);
1848 // Now sort them by color
1849 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1852 // -12*4: four digits space
1853 place = (teamlines - 1) * (-12 * 4);
1855 for(i = 0; i < teamlines; ++i)
1857 int cindex = teamcolorsort[i]->colors & 15;
1858 unsigned char *c = (unsigned char *)&palette_complete[(cindex << 4) + 8];
1859 float cm = max(max(c[0], c[1]), c[2]);
1860 float cr = c[0] / cm;
1861 float cg = c[1] / cm;
1862 float cb = c[2] / cm;
1863 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1865 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1869 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1882 // find leading score other than ourselves, to calculate distribution
1883 // find our place in the scoreboard
1884 score = cl.scores[me].frags;
1885 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1887 if (cl.scores[i].name[0] && i != me)
1889 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1891 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1895 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1897 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1898 else if (place == 2)
1899 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
1901 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
1902 if (otherleader < 0)
1903 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1904 if (distribution >= 0)
1906 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
1907 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1909 else if (distribution >= -5)
1911 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
1912 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
1916 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
1917 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
1922 if (cl.statsf[STAT_TIMELIMIT])
1924 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
1925 minutes = (int)floor(timeleft / 60);
1926 seconds = (int)(floor(timeleft) - minutes * 60);
1929 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1930 if(sb_colon && sb_colon->tex != r_texture_notexture)
1931 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1932 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1934 else if (minutes >= 1)
1936 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
1937 if(sb_colon && sb_colon->tex != r_texture_notexture)
1938 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
1939 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
1941 else if ((int)(timeleft * 4) & 1)
1942 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1944 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
1948 minutes = (int)floor(cl.time / 60);
1949 seconds = (int)(floor(cl.time) - minutes * 60);
1950 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1951 if(sb_colon && sb_colon->tex != r_texture_notexture)
1952 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1953 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1956 sbar_x = sbar_x_save;
1957 sbar_y = sbar_y_save;
1962 Sbar_IntermissionOverlay
1966 void Sbar_IntermissionOverlay (void)
1971 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1972 //if (cl.gametype == GAME_DEATHMATCH)
1973 if (!cl.islocalgame)
1975 Sbar_DeathmatchOverlay ();
1979 sbar_x = (vid_conwidth.integer - 320) >> 1;
1980 sbar_y = (vid_conheight.integer - 200) >> 1;
1982 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1983 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1986 dig = (int)cl.completed_time / 60;
1987 Sbar_DrawNum (160, 64, dig, 3, 0);
1988 num = (int)cl.completed_time - dig*60;
1989 Sbar_DrawPic (234,64,sb_colon);
1990 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1991 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
1993 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1994 if (gamemode != GAME_NEXUIZ)
1995 Sbar_DrawPic (232, 104, sb_slash);
1996 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1998 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1999 if (gamemode != GAME_NEXUIZ)
2000 Sbar_DrawPic (232, 144, sb_slash);
2001 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2012 void Sbar_FinaleOverlay (void)
2014 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);