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 showsound = {CVAR_SAVE, "showsound", "0", "shows number of active sound sources, sound latency, and other statistics"};
92 cvar_t showspeed = {CVAR_SAVE, "showspeed", "0", "shows your current speed (qu per second); number selects unit: 1 = qu/s, 2 = m/s, 3 = km/h, 4 = mph, 5 = knots"};
93 cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"};
94 cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"};
95 cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"};
96 cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"};
97 cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
98 cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
99 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)"};
100 cvar_t sbar_scorerank = {CVAR_SAVE, "sbar_scorerank", "1", "shows an overlay for your score (or team score) and rank in the scoreboard"};
101 cvar_t sbar_gametime = {CVAR_SAVE, "sbar_gametime", "1", "shows an overlay for the time left in the current match/level (or current game time if there is no timelimit set)"};
102 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"};
103 cvar_t sbar_flagstatus_right = {CVAR_SAVE, "sbar_flagstatus_right", "0", "moves Nexuiz flag status icons to the right"};
104 cvar_t sbar_flagstatus_pos = {CVAR_SAVE, "sbar_flagstatus_pos", "115", "pixel position of the Nexuiz flag status icons, from the bottom"};
106 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
108 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
109 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
110 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
111 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
112 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
114 void Sbar_MiniDeathmatchOverlay (int x, int y);
115 void Sbar_DeathmatchOverlay (void);
116 void Sbar_IntermissionOverlay (void);
117 void Sbar_FinaleOverlay (void);
119 void CL_VM_UpdateShowingScoresState (int showingscores);
129 void Sbar_ShowScores (void)
133 sb_showscores = true;
134 CL_VM_UpdateShowingScoresState(sb_showscores);
144 void Sbar_DontShowScores (void)
146 sb_showscores = false;
147 CL_VM_UpdateShowingScoresState(sb_showscores);
150 void sbar_start(void)
154 if (gamemode == GAME_DELUXEQUAKE)
157 else if (gamemode == GAME_SOM)
159 sb_disc = Draw_CachePic ("gfx/disc");
161 for (i = 0;i < 10;i++)
162 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i));
164 somsb_health = Draw_CachePic ("gfx/hud_health");
165 somsb_ammo[0] = Draw_CachePic ("gfx/sb_shells");
166 somsb_ammo[1] = Draw_CachePic ("gfx/sb_nails");
167 somsb_ammo[2] = Draw_CachePic ("gfx/sb_rocket");
168 somsb_ammo[3] = Draw_CachePic ("gfx/sb_cells");
169 somsb_armor[0] = Draw_CachePic ("gfx/sb_armor1");
170 somsb_armor[1] = Draw_CachePic ("gfx/sb_armor2");
171 somsb_armor[2] = Draw_CachePic ("gfx/sb_armor3");
173 else if (gamemode == GAME_NEXUIZ)
175 for (i = 0;i < 10;i++)
176 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i));
177 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus");
178 sb_colon = Draw_CachePic ("gfx/num_colon");
180 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells");
181 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets");
182 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket");
183 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells");
185 sb_armor[0] = Draw_CachePic ("gfx/sb_armor");
189 sb_health = Draw_CachePic ("gfx/sb_health");
191 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo");
192 sb_items[3] = Draw_CachePic ("gfx/sb_invinc");
193 sb_items[4] = Draw_CachePic ("gfx/sb_energy");
194 sb_items[5] = Draw_CachePic ("gfx/sb_str");
196 sb_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken");
197 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost");
198 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying");
199 sb_items[14] = Draw_CachePic ("gfx/sb_key_carrying");
200 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken");
201 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost");
202 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying");
204 sb_sbar = Draw_CachePic ("gfx/sbar");
205 sb_sbar_minimal = Draw_CachePic ("gfx/sbar_minimal");
206 sb_sbar_overlay = Draw_CachePic ("gfx/sbar_overlay");
208 for(i = 0; i < 9;i++)
209 sb_weapons[0][i] = Draw_CachePic (va("gfx/inv_weapon%i",i));
211 else if (gamemode == GAME_ZYMOTIC)
213 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center");
214 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line");
215 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health");
216 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip");
217 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo");
218 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background");
219 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1");
220 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2");
221 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right");
225 sb_disc = Draw_CachePic ("gfx/disc");
227 for (i = 0;i < 10;i++)
229 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i));
230 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i));
233 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus");
234 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus");
236 sb_colon = Draw_CachePic ("gfx/num_colon");
237 sb_slash = Draw_CachePic ("gfx/num_slash");
239 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun");
240 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun");
241 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun");
242 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun");
243 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch");
244 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch");
245 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng");
247 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun");
248 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun");
249 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun");
250 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun");
251 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch");
252 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch");
253 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng");
255 for (i = 0;i < 5;i++)
257 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1));
258 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1));
259 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1));
260 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1));
261 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1));
262 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1));
263 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1));
266 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells");
267 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails");
268 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket");
269 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells");
271 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1");
272 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2");
273 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3");
275 sb_items[0] = Draw_CachePic ("gfx/sb_key1");
276 sb_items[1] = Draw_CachePic ("gfx/sb_key2");
277 sb_items[2] = Draw_CachePic ("gfx/sb_invis");
278 sb_items[3] = Draw_CachePic ("gfx/sb_invuln");
279 sb_items[4] = Draw_CachePic ("gfx/sb_suit");
280 sb_items[5] = Draw_CachePic ("gfx/sb_quad");
282 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1");
283 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2");
284 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3");
285 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4");
287 sb_faces[4][0] = Draw_CachePic ("gfx/face1");
288 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1");
289 sb_faces[3][0] = Draw_CachePic ("gfx/face2");
290 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2");
291 sb_faces[2][0] = Draw_CachePic ("gfx/face3");
292 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3");
293 sb_faces[1][0] = Draw_CachePic ("gfx/face4");
294 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4");
295 sb_faces[0][0] = Draw_CachePic ("gfx/face5");
296 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5");
298 sb_face_invis = Draw_CachePic ("gfx/face_invis");
299 sb_face_invuln = Draw_CachePic ("gfx/face_invul2");
300 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2");
301 sb_face_quad = Draw_CachePic ("gfx/face_quad");
303 sb_sbar = Draw_CachePic ("gfx/sbar");
304 sb_ibar = Draw_CachePic ("gfx/ibar");
305 sb_scorebar = Draw_CachePic ("gfx/scorebar");
307 //MED 01/04/97 added new hipnotic weapons
308 if (gamemode == GAME_HIPNOTIC)
310 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser");
311 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir");
312 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox");
313 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren");
314 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox");
316 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser");
317 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir");
318 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox");
319 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren");
320 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox");
322 for (i = 0;i < 5;i++)
324 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1));
325 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1));
326 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1));
327 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1));
328 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1));
331 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit");
332 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld");
334 else if (gamemode == GAME_ROGUE)
336 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1");
337 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2");
339 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava");
340 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava");
341 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren");
342 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock");
343 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma");
345 rsb_items[0] = Draw_CachePic ("gfx/r_shield1");
346 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1");
348 // PGM 01/19/97 - team color border
349 rsb_teambord = Draw_CachePic ("gfx/r_teambord");
350 // PGM 01/19/97 - team color border
352 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava");
353 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti");
354 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma");
358 sb_ranking = Draw_CachePic ("gfx/ranking");
359 sb_complete = Draw_CachePic ("gfx/complete");
360 sb_inter = Draw_CachePic ("gfx/inter");
361 sb_finale = Draw_CachePic ("gfx/finale");
364 void sbar_shutdown(void)
368 void sbar_newmap(void)
372 void Sbar_Init (void)
374 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
375 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
376 Cvar_RegisterVariable(&showfps);
377 Cvar_RegisterVariable(&showsound);
378 Cvar_RegisterVariable(&showspeed);
379 Cvar_RegisterVariable(&showtime);
380 Cvar_RegisterVariable(&showtime_format);
381 Cvar_RegisterVariable(&showdate);
382 Cvar_RegisterVariable(&showdate_format);
383 Cvar_RegisterVariable(&sbar_alpha_bg);
384 Cvar_RegisterVariable(&sbar_alpha_fg);
385 Cvar_RegisterVariable(&sbar_hudselector);
386 Cvar_RegisterVariable(&sbar_scorerank);
387 Cvar_RegisterVariable(&sbar_gametime);
388 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
389 Cvar_RegisterVariable(&cl_deathscoreboard);
391 Cvar_RegisterVariable(&crosshair_color_red);
392 Cvar_RegisterVariable(&crosshair_color_green);
393 Cvar_RegisterVariable(&crosshair_color_blue);
394 Cvar_RegisterVariable(&crosshair_color_alpha);
395 Cvar_RegisterVariable(&crosshair_size);
397 if(gamemode == GAME_NEXUIZ)
399 Cvar_RegisterVariable(&sbar_flagstatus_right); // this cvar makes no sense in other games
400 Cvar_RegisterVariable(&sbar_flagstatus_pos); // this cvar makes no sense in other games
403 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
407 //=============================================================================
409 // drawing routines are relative to the status bar location
418 void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
420 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
423 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
425 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
428 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
430 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
437 Draws one solid graphics character
440 void Sbar_DrawCharacter (int x, int y, int num)
442 DrawQ_String_Font (sbar_x + x + 4 , sbar_y + y, va("%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, true, FONT_SBAR);
450 void Sbar_DrawString (int x, int y, char *str)
452 DrawQ_String_Font (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR);
460 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
465 l = dpsnprintf(str, sizeof(str), "%i", num);
479 Sbar_DrawPic (x, y, sb_nums[color][frame]);
492 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
500 l = dpsnprintf(str, sizeof(str), "%0*i", digits, num);
503 l = dpsnprintf(str, sizeof(str), "%i", num);
508 x += (digits-l) * lettersize;
517 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
524 //=============================================================================
527 int Sbar_IsTeammatch()
529 // currently only nexuiz uses the team score board
530 return ((gamemode == GAME_NEXUIZ)
531 && (teamplay.integer > 0));
539 static int fragsort[MAX_SCOREBOARD];
540 static int scoreboardlines;
542 int Sbar_GetSortedPlayerIndex (int index)
544 return index >= 0 && index < scoreboardlines ? fragsort[index] : -1;
547 static scoreboard_t teams[MAX_SCOREBOARD];
548 static int teamsort[MAX_SCOREBOARD];
549 static int teamlines;
550 void Sbar_SortFrags (void)
556 for (i=0 ; i<cl.maxclients ; i++)
558 if (cl.scores[i].name[0])
560 fragsort[scoreboardlines] = i;
565 for (i=0 ; i<scoreboardlines ; i++)
566 for (j=0 ; j<scoreboardlines-1-i ; j++)
567 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
570 fragsort[j] = fragsort[j+1];
575 if (Sbar_IsTeammatch ())
577 // now sort players by teams.
578 for (i=0 ; i<scoreboardlines ; i++)
580 for (j=0 ; j<scoreboardlines-1-i ; j++)
582 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
585 fragsort[j] = fragsort[j+1];
591 // calculate team scores
593 for (i=0 ; i<scoreboardlines ; i++)
595 if (color != (cl.scores[fragsort[i]].colors & 15))
597 const char* teamname;
599 color = cl.scores[fragsort[i]].colors & 15;
605 teamname = "^1Red Team";
608 teamname = "^4Blue Team";
611 teamname = "^6Pink Team";
614 teamname = "^3Yellow Team";
617 teamname = "Total Team Score";
620 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
622 teams[teamlines-1].frags = 0;
623 teams[teamlines-1].colors = color + 16 * color;
626 if (cl.scores[fragsort[i]].frags != -666)
628 // do not add spedcators
629 // (ugly hack for nexuiz)
630 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
634 // now sort teams by scores.
635 for (i=0 ; i<teamlines ; i++)
637 for (i=0 ; i<teamlines ; i++)
639 for (j=0 ; j<teamlines-1-i ; j++)
641 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
644 teamsort[j] = teamsort[j+1];
657 void Sbar_SoloScoreboard (void)
660 char str[80], timestr[40];
662 int minutes, seconds;
665 t = (cl.intermission ? cl.completed_time : cl.time);
666 minutes = (int)(t / 60);
667 seconds = (int)(t - 60*floor(t/60));
669 // monsters and secrets are now both on the top row
670 if (cl.stats[STAT_TOTALMONSTERS])
671 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
672 if (cl.stats[STAT_TOTALSECRETS])
673 Sbar_DrawString(8+22*8, 4, va("Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
675 // figure out the map's filename without path or extension
676 strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
677 if (strrchr(str, '.'))
678 *(strrchr(str, '.')) = 0;
680 // append a : separator and then the full title
681 strlcat(str, ":", sizeof(str));
682 strlcat(str, cl.levelname, sizeof(str));
684 // if there's a newline character, terminate the string there
685 if (strchr(str, '\n'))
686 *(strchr(str, '\n')) = 0;
688 // make the time string
689 timelen = dpsnprintf(timestr, sizeof(timestr), " %i:%02i", minutes, seconds);
691 // truncate the level name if necessary to make room for time
693 if ((int)strlen(str) > max)
696 // print the filename and message
697 Sbar_DrawString(8, 12, str);
700 Sbar_DrawString(8 + max*8, 12, timestr);
704 int minutes, seconds, tens, units;
707 if (gamemode != GAME_NEXUIZ) {
708 dpsnprintf (str, sizeof(str), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
709 Sbar_DrawString (8, 4, str);
711 dpsnprintf (str, sizeof(str), "Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
712 Sbar_DrawString (8, 12, str);
716 minutes = (int)(cl.time / 60);
717 seconds = (int)(cl.time - 60*minutes);
719 units = seconds - 10*tens;
720 dpsnprintf (str, sizeof(str), "Time :%3i:%i%i", minutes, tens, units);
721 Sbar_DrawString (184, 4, str);
724 if (gamemode == GAME_NEXUIZ) {
725 l = (int) strlen (cl.worldmodel->name);
726 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
728 l = (int) strlen (cl.levelname);
729 Sbar_DrawString (232 - l*4, 12, cl.levelname);
739 void Sbar_DrawScoreboard (void)
741 Sbar_SoloScoreboard ();
742 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
743 //if (cl.gametype == GAME_DEATHMATCH)
745 Sbar_DeathmatchOverlay ();
748 //=============================================================================
750 // AK to make DrawInventory smaller
751 static void Sbar_DrawWeapon(int nr, float fade, int active)
753 if (sbar_hudselector.integer == 1)
755 // width = 300, height = 100
756 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
758 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);
760 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);
764 // width = 300, height = 100
765 const int w_width = 300, w_height = 100, w_space = 10;
766 const float w_scale = 0.4;
768 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);
769 //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);
778 void Sbar_DrawInventory (void)
785 if (gamemode == GAME_ROGUE)
787 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
788 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
790 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
793 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
796 for (i=0 ; i<7 ; i++)
798 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
800 time = cl.item_gettime[i];
801 flashon = (int)(max(0, cl.time - time)*10);
804 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
810 flashon = (flashon%5) + 2;
812 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
818 if (gamemode == GAME_HIPNOTIC)
820 int grenadeflashing=0;
821 for (i=0 ; i<4 ; i++)
823 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
825 time = max(0, cl.item_gettime[hipweapons[i]]);
826 flashon = (int)((cl.time - time)*10);
829 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
835 flashon = (flashon%5) + 2;
837 // check grenade launcher
840 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
845 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
851 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
853 if (!grenadeflashing)
854 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
857 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
860 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
865 if (gamemode == GAME_ROGUE)
867 // check for powered up weapon.
868 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
870 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
871 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
875 for (i=0 ; i<4 ; i++)
877 dpsnprintf (num, sizeof(num), "%4i",cl.stats[STAT_SHELLS+i] );
879 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
881 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
883 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
885 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
889 for (i=0 ; i<6 ; i++)
890 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
892 //MED 01/04/97 changed keys
893 if (gamemode != GAME_HIPNOTIC || (i>1))
894 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
897 //MED 01/04/97 added hipnotic items
899 if (gamemode == GAME_HIPNOTIC)
901 for (i=0 ; i<2 ; i++)
902 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
903 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
906 if (gamemode == GAME_ROGUE)
909 for (i=0 ; i<2 ; i++)
910 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
911 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
916 for (i=0 ; i<4 ; i++)
917 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
918 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
922 //=============================================================================
929 void Sbar_DrawFrags (void)
939 l = min(scoreboardlines, 4);
943 for (i = 0;i < l;i++)
949 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
950 DrawQ_Fill (sbar_x + x + 10, sbar_y - 23, 28, 4, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
951 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
952 DrawQ_Fill (sbar_x + x + 10, sbar_y + 4 - 23, 28, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
956 dpsnprintf (num, sizeof(num), "%3i",f);
958 if (k == cl.viewentity - 1)
960 Sbar_DrawCharacter ( x + 2, -24, 16);
961 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
963 Sbar_DrawCharacter (x + 8, -24, num[0]);
964 Sbar_DrawCharacter (x + 16, -24, num[1]);
965 Sbar_DrawCharacter (x + 24, -24, num[2]);
970 //=============================================================================
978 void Sbar_DrawFace (void)
982 // PGM 01/19/97 - team color drawing
983 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
984 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
990 s = &cl.scores[cl.viewentity - 1];
992 Sbar_DrawPic (112, 0, rsb_teambord);
993 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
994 DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+3, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
995 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
996 DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+12, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1000 dpsnprintf (num, sizeof(num), "%3i",f);
1002 if ((s->colors & 0xf0)==0)
1005 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1007 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1009 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1013 Sbar_DrawCharacter ( 109, 3, num[0]);
1014 Sbar_DrawCharacter ( 116, 3, num[1]);
1015 Sbar_DrawCharacter ( 123, 3, num[2]);
1020 // PGM 01/19/97 - team color drawing
1022 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1023 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1024 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1025 Sbar_DrawPic (112, 0, sb_face_quad );
1026 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1027 Sbar_DrawPic (112, 0, sb_face_invis );
1028 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1029 Sbar_DrawPic (112, 0, sb_face_invuln);
1032 f = cl.stats[STAT_HEALTH] / 20;
1034 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1038 void Sbar_ShowFPS(void)
1040 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1041 char soundstring[32];
1043 char timestring[32];
1044 char datestring[32];
1045 char speedstring[32];
1046 qboolean red = false;
1052 if (showfps.integer)
1055 static double nexttime = 0, lasttime = 0;
1056 static double framerate = 0;
1057 static int framecount = 0;
1058 double interval = 0.25;
1061 if (newtime >= nexttime)
1063 framerate = framecount / (newtime - lasttime);
1064 if (nexttime < newtime - interval * 1.5)
1067 nexttime += interval;
1073 if ((red = (calc < 1.0f)))
1074 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1076 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1078 if (showtime.integer)
1079 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1080 if (showdate.integer)
1081 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1082 if (showsound.integer)
1083 dpsnprintf(soundstring, sizeof(soundstring), "%4i/%4i at %3ims\n", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds);
1084 if (showspeed.integer)
1086 double speed, speedxy, f;
1088 speed = VectorLength(cl.movement_velocity);
1089 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1090 switch(showspeed.integer)
1094 if(gamemode == GAME_NEXUIZ)
1103 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1104 // 1qu=1.5in is for non-Nexuiz only - Nexuiz players are overly large, but 1qu=1in fixes that
1109 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1113 f = 0.0254 * 3.6 * 0.6213711922;
1114 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1118 f = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
1119 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1122 dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1124 if (fpsstring[0] || timestring[0] || datestring[0] || speedstring[0])
1128 fps_height = fps_scaley * ((soundstring[0] != 0) + (fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0) + (speedstring[0] != 0));
1129 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1130 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1131 fps_y = vid_conheight.integer - fps_height;
1134 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(soundstring, 0, true, FONT_INFOBAR) * fps_scalex;
1135 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1136 DrawQ_String_Font(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1137 fps_y += fps_scaley;
1141 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(fpsstring, 0, true, FONT_INFOBAR) * fps_scalex;
1142 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1144 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1146 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1147 fps_y += fps_scaley;
1151 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(timestring, 0, true, FONT_INFOBAR) * fps_scalex;
1152 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1153 DrawQ_String_Font(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1154 fps_y += fps_scaley;
1158 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(datestring, 0, true, FONT_INFOBAR) * fps_scalex;
1159 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1160 DrawQ_String_Font(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1161 fps_y += fps_scaley;
1165 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(speedstring, 0, true, FONT_INFOBAR) * fps_scalex;
1166 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1167 DrawQ_String_Font(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1168 fps_y += fps_scaley;
1173 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)
1176 c2 = bound(0, c2, 1);
1177 c1 = bound(0, c1, 1 - c2);
1179 r[1] = rangey + rangeheight * (c2 + c1);
1180 r[2] = rangey + rangeheight * (c2);
1184 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);
1186 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);
1188 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);
1190 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);
1198 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1199 extern cvar_t v_kicktime;
1200 void Sbar_Score (int margin);
1201 void Sbar_Draw (void)
1205 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1208 Sbar_DrawScoreboard ();
1209 else if (cl.intermission == 1)
1211 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1213 Sbar_DrawScoreboard();
1216 Sbar_IntermissionOverlay();
1218 else if (cl.intermission == 2)
1219 Sbar_FinaleOverlay();
1220 else if (gamemode == GAME_DELUXEQUAKE)
1223 else if (gamemode == GAME_SOM)
1225 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1226 Sbar_DrawScoreboard ();
1229 // this is the top left of the sbar area
1231 sbar_y = vid_conheight.integer - 24*3;
1234 if (cl.stats[STAT_ARMOR])
1236 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1237 Sbar_DrawPic(0, 0, somsb_armor[2]);
1238 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1239 Sbar_DrawPic(0, 0, somsb_armor[1]);
1240 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1241 Sbar_DrawPic(0, 0, somsb_armor[0]);
1242 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1246 Sbar_DrawPic(0, 24, somsb_health);
1247 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1250 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1251 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1252 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1253 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1254 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1255 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1256 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1257 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1258 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1259 if (cl.stats[STAT_SHELLS])
1260 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1263 else if (gamemode == GAME_NEXUIZ)
1265 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1267 sbar_x = (vid_conwidth.integer - 640)/2;
1268 sbar_y = vid_conheight.integer - 47;
1269 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1270 Sbar_DrawScoreboard ();
1272 else if (sb_lines && sbar_hudselector.integer == 1)
1276 int redflag, blueflag;
1279 sbar_x = (vid_conwidth.integer - 320)/2;
1280 sbar_y = vid_conheight.integer - 24 - 16;
1282 // calculate intensity to draw weapons bar at
1283 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1284 fade = bound(0.7, fade, 1);
1285 for (i = 0; i < 8;i++)
1286 if (cl.stats[STAT_ITEMS] & (1 << i))
1287 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1288 if((cl.stats[STAT_ITEMS] & (1<<12)))
1289 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1292 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1293 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1294 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1295 if (redflag == 3 && blueflag == 3)
1297 // The Impossible Combination[tm]
1298 // Can only happen in Key Hunt mode...
1299 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128), sb_items[14]);
1304 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64), sb_items[redflag+10]);
1306 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128), sb_items[blueflag+14]);
1310 if (cl.stats[STAT_ARMOR] > 0)
1312 Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1313 if(cl.stats[STAT_ARMOR] > 200)
1314 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1315 else if(cl.stats[STAT_ARMOR] > 100)
1316 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1317 else if(cl.stats[STAT_ARMOR] > 50)
1318 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1319 else if(cl.stats[STAT_ARMOR] > 25)
1320 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1322 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1326 if (cl.stats[STAT_HEALTH] != 0)
1328 Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1329 if(cl.stats[STAT_HEALTH] > 200)
1330 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1331 else if(cl.stats[STAT_HEALTH] > 100)
1332 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1333 else if(cl.stats[STAT_HEALTH] > 50)
1334 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1335 else if(cl.stats[STAT_HEALTH] > 25)
1336 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1338 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1342 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1344 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1345 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1346 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1347 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1348 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1349 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1350 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1351 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1352 if(cl.stats[STAT_AMMO] > 10)
1353 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1355 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1358 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1359 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1362 // The margin can be at most 8 to support 640x480 console size:
1363 // 320 + 2 * (144 + 16) = 640
1369 int redflag, blueflag;
1372 sbar_x = (vid_conwidth.integer - 640)/2;
1373 sbar_y = vid_conheight.integer - 47;
1375 // calculate intensity to draw weapons bar at
1376 fade = 3 - 2 * (cl.time - cl.weapontime);
1379 fade = min(fade, 1);
1380 for (i = 0; i < 8;i++)
1381 if (cl.stats[STAT_ITEMS] & (1 << i))
1382 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1384 if((cl.stats[STAT_ITEMS] & (1<<12)))
1385 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1388 //if (!cl.islocalgame)
1389 // Sbar_DrawFrags ();
1392 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1394 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1397 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1398 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1399 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1400 if (redflag == 3 && blueflag == 3)
1402 // The Impossible Combination[tm]
1403 // Can only happen in Key Hunt mode...
1404 Sbar_DrawPic (x, -179, sb_items[14]);
1409 Sbar_DrawPic (x, -117, sb_items[redflag+10]);
1411 Sbar_DrawPic (x, -177, sb_items[blueflag+14]);
1415 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1418 if(cl.stats[STAT_HEALTH] > 100)
1419 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1420 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1421 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1423 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1425 // AK dont draw ammo for the laser
1426 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1428 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1429 Sbar_DrawPic (519, 0, sb_ammo[0]);
1430 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1431 Sbar_DrawPic (519, 0, sb_ammo[1]);
1432 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1433 Sbar_DrawPic (519, 0, sb_ammo[2]);
1434 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1435 Sbar_DrawPic (519, 0, sb_ammo[3]);
1437 if(cl.stats[STAT_AMMO] <= 10)
1438 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1440 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1445 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1447 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1448 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1453 // Mini scoreboard uses 12*4 per other team, that is, 144
1454 // pixels when there are four teams...
1455 // Nexuiz by default sets vid_conwidth to 800... makes
1457 // so we need to shift it by 64 pixels to the right to fit
1458 // BUT: then it overlaps with the image that gets drawn
1459 // for viewsize 100! Therefore, just account for 3 teams,
1460 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1464 else if (gamemode == GAME_ZYMOTIC)
1467 float scale = 64.0f / 256.0f;
1468 float kickoffset[3];
1469 VectorClear(kickoffset);
1472 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1473 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1475 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1476 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1477 // left1 16, 48 : 126 -66
1478 // left2 16, 128 : 196 -66
1479 // right 176, 48 : 196 -136
1480 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);
1481 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);
1482 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);
1483 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1485 float scale = 128.0f / 256.0f;
1486 float healthstart, healthheight, healthstarttc, healthendtc;
1487 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1488 float ammostart, ammoheight, ammostarttc, ammoendtc;
1489 float clipstart, clipheight, clipstarttc, clipendtc;
1490 float kickoffset[3], offset;
1491 VectorClear(kickoffset);
1494 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1495 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1497 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1498 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1499 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1500 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);
1501 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);
1502 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);
1503 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);
1504 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1505 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1506 healthstart = 204 - healthheight;
1507 shieldstart = healthstart - shieldheight;
1508 healthstarttc = healthstart * (1.0f / 256.0f);
1509 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1510 shieldstarttc = shieldstart * (1.0f / 256.0f);
1511 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1512 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1513 ammostart = 114 - ammoheight;
1514 ammostarttc = ammostart * (1.0f / 256.0f);
1515 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1516 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1517 clipstart = 190 - clipheight;
1518 clipstarttc = clipstart * (1.0f / 256.0f);
1519 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1520 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);
1521 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);
1522 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);
1523 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);
1524 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1525 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1528 else // Quake and others
1530 sbar_x = (vid_conwidth.integer - 320)/2;
1531 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1532 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1533 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1537 if (gamemode != GAME_GOODVSBAD2)
1538 Sbar_DrawInventory ();
1539 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1543 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1545 if (gamemode != GAME_GOODVSBAD2)
1546 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1547 Sbar_DrawScoreboard ();
1551 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1553 // keys (hipnotic only)
1554 //MED 01/04/97 moved keys here so they would not be overwritten
1555 if (gamemode == GAME_HIPNOTIC)
1557 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1558 Sbar_DrawPic (209, 3, sb_items[0]);
1559 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1560 Sbar_DrawPic (209, 12, sb_items[1]);
1563 if (gamemode != GAME_GOODVSBAD2)
1565 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1567 Sbar_DrawNum (24, 0, 666, 3, 1);
1568 Sbar_DrawPic (0, 0, sb_disc);
1572 if (gamemode == GAME_ROGUE)
1574 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1575 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1576 Sbar_DrawPic (0, 0, sb_armor[2]);
1577 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1578 Sbar_DrawPic (0, 0, sb_armor[1]);
1579 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1580 Sbar_DrawPic (0, 0, sb_armor[0]);
1584 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1585 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1586 Sbar_DrawPic (0, 0, sb_armor[2]);
1587 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1588 Sbar_DrawPic (0, 0, sb_armor[1]);
1589 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1590 Sbar_DrawPic (0, 0, sb_armor[0]);
1599 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1602 if (gamemode == GAME_ROGUE)
1604 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1605 Sbar_DrawPic (224, 0, sb_ammo[0]);
1606 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1607 Sbar_DrawPic (224, 0, sb_ammo[1]);
1608 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1609 Sbar_DrawPic (224, 0, sb_ammo[2]);
1610 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1611 Sbar_DrawPic (224, 0, sb_ammo[3]);
1612 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1613 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1614 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1615 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1616 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1617 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1621 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1622 Sbar_DrawPic (224, 0, sb_ammo[0]);
1623 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1624 Sbar_DrawPic (224, 0, sb_ammo[1]);
1625 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1626 Sbar_DrawPic (224, 0, sb_ammo[2]);
1627 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1628 Sbar_DrawPic (224, 0, sb_ammo[3]);
1631 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1633 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1634 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1636 if (gamemode == GAME_TRANSFUSION)
1637 Sbar_MiniDeathmatchOverlay (0, 0);
1639 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1648 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1650 pic = Draw_CachePic (va("gfx/crosshair%i", crosshair.integer));
1651 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);
1654 if (cl_prydoncursor.integer)
1655 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)), 0, 0, 1, 1, 1, 1, 0);
1658 //=============================================================================
1662 Sbar_DeathmatchOverlay
1666 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1669 qboolean myself = false;
1671 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1673 if((s - cl.scores) == cl.playerentity - 1)
1675 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1676 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1679 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1681 if (s->qw_spectator)
1683 if (s->qw_ping || s->qw_packetloss)
1684 DrawQ_String_Font(x, y, va("%4i %3i %4i spectator %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1686 DrawQ_String_Font(x, y, va(" %4i spectator %c%s", minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1690 // draw colors behind score
1696 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1697 DrawQ_Fill(x + 14*8*FONT_SBAR->maxwidth, y+1, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1698 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1699 DrawQ_Fill(x + 14*8*FONT_SBAR->maxwidth, y+4, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1701 //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);
1702 if (s->qw_ping || s->qw_packetloss)
1703 DrawQ_String_Font(x, y, va("%4i %3i %4i %5i %-4s %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1705 DrawQ_String_Font(x, y, va(" %4i %5i %-4s %c%s", minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1710 if (s->qw_spectator)
1712 if (s->qw_ping || s->qw_packetloss)
1713 DrawQ_String_Font(x, y, va("%4i %3i spect %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1715 DrawQ_String_Font(x, y, va(" spect %c%s", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1719 // draw colors behind score
1720 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1721 DrawQ_Fill(x + 9*8*FONT_SBAR->maxwidth, y+1, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1722 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1723 DrawQ_Fill(x + 9*8*FONT_SBAR->maxwidth, y+4, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1725 //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);
1726 if (s->qw_ping || s->qw_packetloss)
1727 DrawQ_String_Font(x, y, va("%4i %3i %5i %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1729 DrawQ_String_Font(x, y, va(" %5i %c%s", (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1735 void Sbar_DeathmatchOverlay (void)
1737 int i, y, xmin, xmax, ymin, ymax;
1739 // request new ping times every two second
1740 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1742 cl.last_ping_request = realtime;
1743 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1745 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1746 MSG_WriteString(&cls.netcon->message, "pings");
1748 else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6/* || cls.protocol == PROTOCOL_DARKPLACES7*/)
1750 // 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
1751 static int ping_anyway_counter = 0;
1752 if(cl.parsingtextexpectingpingforscores == 1)
1754 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1755 if(++ping_anyway_counter >= 5)
1756 cl.parsingtextexpectingpingforscores = 0;
1758 if(cl.parsingtextexpectingpingforscores != 1)
1760 ping_anyway_counter = 0;
1761 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1762 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1763 MSG_WriteString(&cls.netcon->message, "ping");
1768 // 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
1769 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1770 MSG_WriteString(&cls.netcon->message, "pings");
1778 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1780 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1781 xmin = (vid_conwidth.integer - (26 + 15) * 8 * FONT_SBAR->maxwidth) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1783 xmin = (vid_conwidth.integer - (16 + 25) * 8 * FONT_SBAR->maxwidth) / 2; // 16 characters until name, then we assume 25 character names (they can be longer but usually aren't)
1784 xmax = vid_conwidth.integer - xmin;
1786 if(gamemode == GAME_NEXUIZ)
1787 DrawQ_Pic (xmin - 8, ymin - 8, 0, xmax-xmin+1 + 2*8, ymax-ymin+1 + 2*8, 0, 0, 0, sbar_alpha_bg.value, 0);
1789 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1793 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1795 DrawQ_String_Font(xmin, y, va("ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1799 DrawQ_String_Font(xmin, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1803 if (Sbar_IsTeammatch ())
1805 // show team scores first
1806 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1807 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1811 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1812 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1817 Sbar_MiniDeathmatchOverlay
1821 void Sbar_MiniDeathmatchOverlay (int x, int y)
1823 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1825 // do not draw this if sbar_miniscoreboard_size is zero
1826 if(sbar_miniscoreboard_size.value == 0)
1828 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1829 if(sbar_miniscoreboard_size.value > 0)
1830 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1835 // decide where to print
1836 if (gamemode == GAME_TRANSFUSION)
1837 numlines = (vid_conwidth.integer - x + 127) / 128;
1839 numlines = (vid_conheight.integer - y + 7) / 8;
1841 // give up if there isn't room
1842 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1846 for (i = 0; i < scoreboardlines; i++)
1847 if (fragsort[i] == cl.playerentity - 1)
1851 range_end = scoreboardlines;
1854 if (gamemode != GAME_TRANSFUSION)
1855 if (Sbar_IsTeammatch ())
1857 // reserve space for the team scores
1858 numlines -= teamlines;
1860 // find first and last player of my team (only draw the team totals and my own team)
1861 range_begin = range_end = i;
1862 myteam = cl.scores[fragsort[i]].colors & 15;
1863 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1865 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1868 // looks better than two players
1878 i = min(i, range_end - numlines);
1879 i = max(i, range_begin);
1881 if (gamemode == GAME_TRANSFUSION)
1883 for (;i < range_end && x < vid_conwidth.integer;i++)
1884 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1888 if(range_end - i < numlines) // won't draw to bottom?
1889 y += 8 * (numlines - (range_end - i)); // bottom align
1890 // show team scores first
1891 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1892 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1894 for (;i < range_end && y < vid_conheight.integer;i++)
1895 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1899 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1901 static int const sortorder[16] =
1920 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1921 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1922 int tc1 = sortorder[t1->colors & 15];
1923 int tc2 = sortorder[t2->colors & 15];
1927 void Sbar_Score (int margin)
1929 int i, me, score, otherleader, place, distribution, minutes, seconds;
1931 int sbar_x_save = sbar_x;
1932 int sbar_y_save = sbar_y;
1935 sbar_y = vid_conheight.value - (32+12);
1938 me = cl.playerentity - 1;
1939 if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients)
1941 if(Sbar_IsTeammatch())
1945 // team1 team3 team4
1949 scoreboard_t *teamcolorsort[16];
1952 for(i = 0; i < teamlines; ++i)
1953 teamcolorsort[i] = &(teams[i]);
1955 // Now sort them by color
1956 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1959 // -12*4: four digits space
1960 place = (teamlines - 1) * (-12 * 4);
1962 for(i = 0; i < teamlines; ++i)
1964 int cindex = teamcolorsort[i]->colors & 15;
1965 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
1966 float cm = max(max(c[0], c[1]), c[2]);
1967 float cr = c[0] / cm;
1968 float cg = c[1] / cm;
1969 float cb = c[2] / cm;
1970 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1972 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1976 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1989 // find leading score other than ourselves, to calculate distribution
1990 // find our place in the scoreboard
1991 score = cl.scores[me].frags;
1992 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1994 if (cl.scores[i].name[0] && i != me)
1996 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1998 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
2002 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
2004 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2005 else if (place == 2)
2006 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2008 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2009 if (otherleader < 0)
2010 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2011 if (distribution >= 0)
2013 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2014 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2016 else if (distribution >= -5)
2018 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2019 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2023 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2024 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2029 if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT])
2031 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2032 minutes = (int)floor(timeleft / 60);
2033 seconds = (int)(floor(timeleft) - minutes * 60);
2036 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2037 if(sb_colon && sb_colon->tex != r_texture_notexture)
2038 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2039 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2041 else if (minutes >= 1)
2043 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2044 if(sb_colon && sb_colon->tex != r_texture_notexture)
2045 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2046 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2048 else if ((int)(timeleft * 4) & 1)
2049 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2051 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2053 else if (sbar_gametime.integer)
2055 minutes = (int)floor(cl.time / 60);
2056 seconds = (int)(floor(cl.time) - minutes * 60);
2057 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2058 if(sb_colon && sb_colon->tex != r_texture_notexture)
2059 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2060 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2063 sbar_x = sbar_x_save;
2064 sbar_y = sbar_y_save;
2069 Sbar_IntermissionOverlay
2073 void Sbar_IntermissionOverlay (void)
2078 if (cl.gametype == GAME_DEATHMATCH)
2080 Sbar_DeathmatchOverlay ();
2084 sbar_x = (vid_conwidth.integer - 320) >> 1;
2085 sbar_y = (vid_conheight.integer - 200) >> 1;
2087 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2088 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2091 dig = (int)cl.completed_time / 60;
2092 Sbar_DrawNum (160, 64, dig, 3, 0);
2093 num = (int)cl.completed_time - dig*60;
2094 Sbar_DrawPic (234,64,sb_colon);
2095 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2096 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2098 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2099 if (gamemode != GAME_NEXUIZ)
2100 Sbar_DrawPic (232, 104, sb_slash);
2101 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2103 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2104 if (gamemode != GAME_NEXUIZ)
2105 Sbar_DrawPic (232, 144, sb_slash);
2106 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2117 void Sbar_FinaleOverlay (void)
2119 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);