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);
1545 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1546 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1548 if (gamemode == GAME_TRANSFUSION)
1549 Sbar_MiniDeathmatchOverlay (0, 0);
1551 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1560 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1561 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);
1563 if (cl_prydoncursor.integer)
1564 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);
1567 //=============================================================================
1571 Sbar_DeathmatchOverlay
1575 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1578 qboolean myself = false;
1580 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1582 if((s - cl.scores) == cl.playerentity - 1)
1584 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1585 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1588 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1590 if (s->qw_spectator)
1592 if (s->qw_ping || s->qw_packetloss)
1593 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 );
1595 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 );
1599 // draw colors behind score
1600 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1601 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);
1602 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1603 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);
1605 //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);
1606 if (s->qw_ping || s->qw_packetloss)
1607 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 );
1609 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 );
1614 if (s->qw_spectator)
1616 if (s->qw_ping || s->qw_packetloss)
1617 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 );
1619 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 );
1623 // draw colors behind score
1624 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1625 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);
1626 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1627 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);
1629 //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);
1630 if (s->qw_ping || s->qw_packetloss)
1631 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 );
1633 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 );
1639 void Sbar_DeathmatchOverlay (void)
1643 // request new ping times every two second
1644 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1646 cl.last_ping_request = realtime;
1647 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1649 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1650 MSG_WriteString(&cls.netcon->message, "pings");
1652 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*/)
1654 // 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
1655 static int ping_anyway_counter = 0;
1656 if(cl.parsingtextexpectingpingforscores == 1)
1658 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1659 if(++ping_anyway_counter >= 5)
1660 cl.parsingtextexpectingpingforscores = 0;
1662 if(cl.parsingtextexpectingpingforscores != 1)
1664 ping_anyway_counter = 0;
1665 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1666 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1667 MSG_WriteString(&cls.netcon->message, "ping");
1672 // 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
1673 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1674 MSG_WriteString(&cls.netcon->message, "pings");
1678 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1684 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1686 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)
1687 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 );
1691 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)
1692 DrawQ_String(x, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1696 if (Sbar_IsTeammatch ())
1698 // show team scores first
1699 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1700 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1704 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1705 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1710 Sbar_MiniDeathmatchOverlay
1714 void Sbar_MiniDeathmatchOverlay (int x, int y)
1716 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1718 // do not draw this if sbar_miniscoreboard_size is zero
1719 if(sbar_miniscoreboard_size.value == 0)
1721 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1722 if(sbar_miniscoreboard_size.value > 0)
1723 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1728 // decide where to print
1729 if (gamemode == GAME_TRANSFUSION)
1730 numlines = (vid_conwidth.integer - x + 127) / 128;
1732 numlines = (vid_conheight.integer - y + 7) / 8;
1734 // give up if there isn't room
1735 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1739 for (i = 0; i < scoreboardlines; i++)
1740 if (fragsort[i] == cl.playerentity - 1)
1744 range_end = scoreboardlines;
1747 if (gamemode != GAME_TRANSFUSION)
1748 if (Sbar_IsTeammatch ())
1750 // reserve space for the team scores
1751 numlines -= teamlines;
1753 // find first and last player of my team (only draw the team totals and my own team)
1754 range_begin = range_end = i;
1755 myteam = cl.scores[fragsort[i]].colors & 15;
1756 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1758 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1761 // looks better than two players
1771 i = min(i, range_end - numlines);
1772 i = max(i, range_begin);
1774 if (gamemode == GAME_TRANSFUSION)
1776 for (;i < range_end && x < vid_conwidth.integer;i++)
1777 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1781 if(range_end - i < numlines) // won't draw to bottom?
1782 y += 8 * (numlines - (range_end - i)); // bottom align
1783 // show team scores first
1784 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1785 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1787 for (;i < range_end && y < vid_conheight.integer;i++)
1788 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1792 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1794 static int const sortorder[16] =
1813 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1814 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1815 int tc1 = sortorder[t1->colors & 15];
1816 int tc2 = sortorder[t2->colors & 15];
1820 void Sbar_Score (int margin)
1822 int i, me, score, otherleader, place, distribution, minutes, seconds;
1824 int sbar_x_save = sbar_x;
1825 int sbar_y_save = sbar_y;
1827 sbar_y = vid_conheight.value - (32+12);
1830 me = cl.playerentity - 1;
1831 if (me >= 0 && me < cl.maxclients)
1833 if(Sbar_IsTeammatch())
1837 // team1 team3 team4
1841 scoreboard_t *teamcolorsort[16];
1844 for(i = 0; i < teamlines; ++i)
1845 teamcolorsort[i] = &(teams[i]);
1847 // Now sort them by color
1848 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1851 // -12*4: four digits space
1852 place = (teamlines - 1) * (-12 * 4);
1854 for(i = 0; i < teamlines; ++i)
1856 int cindex = teamcolorsort[i]->colors & 15;
1857 unsigned char *c = (unsigned char *)&palette_complete[(cindex << 4) + 8];
1858 float cm = max(max(c[0], c[1]), c[2]);
1859 float cr = c[0] / cm;
1860 float cg = c[1] / cm;
1861 float cb = c[2] / cm;
1862 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1864 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1868 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1881 // find leading score other than ourselves, to calculate distribution
1882 // find our place in the scoreboard
1883 score = cl.scores[me].frags;
1884 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1886 if (cl.scores[i].name[0] && i != me)
1888 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1890 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1894 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1896 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1897 else if (place == 2)
1898 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
1900 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
1901 if (otherleader < 0)
1902 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1903 if (distribution >= 0)
1905 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
1906 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
1908 else if (distribution >= -5)
1910 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
1911 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
1915 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
1916 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
1921 if (cl.statsf[STAT_TIMELIMIT])
1923 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
1924 minutes = (int)floor(timeleft / 60);
1925 seconds = (int)(floor(timeleft) - minutes * 60);
1928 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1929 if(sb_colon && sb_colon->tex != r_texture_notexture)
1930 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1931 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1933 else if (minutes >= 1)
1935 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 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, 0, sbar_alpha_fg.value, 0);
1938 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
1940 else if ((int)(timeleft * 4) & 1)
1941 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1943 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
1947 minutes = (int)floor(cl.time / 60);
1948 seconds = (int)(floor(cl.time) - minutes * 60);
1949 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
1950 if(sb_colon && sb_colon->tex != r_texture_notexture)
1951 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1952 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1955 sbar_x = sbar_x_save;
1956 sbar_y = sbar_y_save;
1961 Sbar_IntermissionOverlay
1965 void Sbar_IntermissionOverlay (void)
1970 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1971 //if (cl.gametype == GAME_DEATHMATCH)
1972 if (!cl.islocalgame)
1974 Sbar_DeathmatchOverlay ();
1978 sbar_x = (vid_conwidth.integer - 320) >> 1;
1979 sbar_y = (vid_conheight.integer - 200) >> 1;
1981 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1982 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1985 dig = (int)cl.completed_time / 60;
1986 Sbar_DrawNum (160, 64, dig, 3, 0);
1987 num = (int)cl.completed_time - dig*60;
1988 Sbar_DrawPic (234,64,sb_colon);
1989 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1990 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
1992 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1993 if (gamemode != GAME_NEXUIZ)
1994 Sbar_DrawPic (232, 104, sb_slash);
1995 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1997 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1998 if (gamemode != GAME_NEXUIZ)
1999 Sbar_DrawPic (232, 144, sb_slash);
2000 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2011 void Sbar_FinaleOverlay (void)
2013 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);