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_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"};
101 cvar_t sbar_flagstatus_right = {CVAR_SAVE, "sbar_flagstatus_right", "0", "moves Nexuiz flag status icons to the right"};
102 cvar_t sbar_flagstatus_pos = {CVAR_SAVE, "sbar_flagstatus_pos", "115", "pixel position of the Nexuiz flag status icons, from the bottom"};
104 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
106 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
107 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
108 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
109 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
110 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
112 void Sbar_MiniDeathmatchOverlay (int x, int y);
113 void Sbar_DeathmatchOverlay (void);
114 void Sbar_IntermissionOverlay (void);
115 void Sbar_FinaleOverlay (void);
117 void CL_VM_UpdateShowingScoresState (int showingscores);
127 void Sbar_ShowScores (void)
131 sb_showscores = true;
132 CL_VM_UpdateShowingScoresState(sb_showscores);
142 void Sbar_DontShowScores (void)
144 sb_showscores = false;
145 CL_VM_UpdateShowingScoresState(sb_showscores);
148 void sbar_start(void)
152 if (gamemode == GAME_DELUXEQUAKE)
155 else if (gamemode == GAME_SOM)
157 sb_disc = Draw_CachePic ("gfx/disc");
159 for (i = 0;i < 10;i++)
160 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i));
162 somsb_health = Draw_CachePic ("gfx/hud_health");
163 somsb_ammo[0] = Draw_CachePic ("gfx/sb_shells");
164 somsb_ammo[1] = Draw_CachePic ("gfx/sb_nails");
165 somsb_ammo[2] = Draw_CachePic ("gfx/sb_rocket");
166 somsb_ammo[3] = Draw_CachePic ("gfx/sb_cells");
167 somsb_armor[0] = Draw_CachePic ("gfx/sb_armor1");
168 somsb_armor[1] = Draw_CachePic ("gfx/sb_armor2");
169 somsb_armor[2] = Draw_CachePic ("gfx/sb_armor3");
171 else if (gamemode == GAME_NEXUIZ)
173 for (i = 0;i < 10;i++)
174 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i));
175 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus");
176 sb_colon = Draw_CachePic ("gfx/num_colon");
178 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells");
179 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets");
180 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket");
181 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells");
183 sb_armor[0] = Draw_CachePic ("gfx/sb_armor");
187 sb_health = Draw_CachePic ("gfx/sb_health");
189 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo");
190 sb_items[3] = Draw_CachePic ("gfx/sb_invinc");
191 sb_items[4] = Draw_CachePic ("gfx/sb_energy");
192 sb_items[5] = Draw_CachePic ("gfx/sb_str");
194 sb_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken");
195 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost");
196 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying");
197 sb_items[14] = Draw_CachePic ("gfx/sb_key_carrying");
198 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken");
199 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost");
200 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying");
202 sb_sbar = Draw_CachePic ("gfx/sbar");
203 sb_sbar_minimal = Draw_CachePic ("gfx/sbar_minimal");
204 sb_sbar_overlay = Draw_CachePic ("gfx/sbar_overlay");
206 for(i = 0; i < 9;i++)
207 sb_weapons[0][i] = Draw_CachePic (va("gfx/inv_weapon%i",i));
209 else if (gamemode == GAME_ZYMOTIC)
211 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center");
212 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line");
213 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health");
214 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip");
215 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo");
216 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background");
217 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1");
218 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2");
219 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right");
223 sb_disc = Draw_CachePic ("gfx/disc");
225 for (i = 0;i < 10;i++)
227 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i));
228 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i));
231 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus");
232 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus");
234 sb_colon = Draw_CachePic ("gfx/num_colon");
235 sb_slash = Draw_CachePic ("gfx/num_slash");
237 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun");
238 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun");
239 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun");
240 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun");
241 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch");
242 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch");
243 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng");
245 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun");
246 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun");
247 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun");
248 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun");
249 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch");
250 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch");
251 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng");
253 for (i = 0;i < 5;i++)
255 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1));
256 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1));
257 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1));
258 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1));
259 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1));
260 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1));
261 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1));
264 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells");
265 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails");
266 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket");
267 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells");
269 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1");
270 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2");
271 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3");
273 sb_items[0] = Draw_CachePic ("gfx/sb_key1");
274 sb_items[1] = Draw_CachePic ("gfx/sb_key2");
275 sb_items[2] = Draw_CachePic ("gfx/sb_invis");
276 sb_items[3] = Draw_CachePic ("gfx/sb_invuln");
277 sb_items[4] = Draw_CachePic ("gfx/sb_suit");
278 sb_items[5] = Draw_CachePic ("gfx/sb_quad");
280 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1");
281 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2");
282 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3");
283 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4");
285 sb_faces[4][0] = Draw_CachePic ("gfx/face1");
286 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1");
287 sb_faces[3][0] = Draw_CachePic ("gfx/face2");
288 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2");
289 sb_faces[2][0] = Draw_CachePic ("gfx/face3");
290 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3");
291 sb_faces[1][0] = Draw_CachePic ("gfx/face4");
292 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4");
293 sb_faces[0][0] = Draw_CachePic ("gfx/face5");
294 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5");
296 sb_face_invis = Draw_CachePic ("gfx/face_invis");
297 sb_face_invuln = Draw_CachePic ("gfx/face_invul2");
298 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2");
299 sb_face_quad = Draw_CachePic ("gfx/face_quad");
301 sb_sbar = Draw_CachePic ("gfx/sbar");
302 sb_ibar = Draw_CachePic ("gfx/ibar");
303 sb_scorebar = Draw_CachePic ("gfx/scorebar");
305 //MED 01/04/97 added new hipnotic weapons
306 if (gamemode == GAME_HIPNOTIC)
308 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser");
309 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir");
310 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox");
311 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren");
312 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox");
314 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser");
315 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir");
316 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox");
317 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren");
318 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox");
320 for (i = 0;i < 5;i++)
322 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1));
323 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1));
324 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1));
325 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1));
326 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1));
329 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit");
330 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld");
332 else if (gamemode == GAME_ROGUE)
334 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1");
335 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2");
337 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava");
338 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava");
339 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren");
340 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock");
341 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma");
343 rsb_items[0] = Draw_CachePic ("gfx/r_shield1");
344 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1");
346 // PGM 01/19/97 - team color border
347 rsb_teambord = Draw_CachePic ("gfx/r_teambord");
348 // PGM 01/19/97 - team color border
350 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava");
351 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti");
352 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma");
356 sb_ranking = Draw_CachePic ("gfx/ranking");
357 sb_complete = Draw_CachePic ("gfx/complete");
358 sb_inter = Draw_CachePic ("gfx/inter");
359 sb_finale = Draw_CachePic ("gfx/finale");
362 void sbar_shutdown(void)
366 void sbar_newmap(void)
370 void Sbar_Init (void)
372 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
373 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
374 Cvar_RegisterVariable(&showfps);
375 Cvar_RegisterVariable(&showsound);
376 Cvar_RegisterVariable(&showspeed);
377 Cvar_RegisterVariable(&showtime);
378 Cvar_RegisterVariable(&showtime_format);
379 Cvar_RegisterVariable(&showdate);
380 Cvar_RegisterVariable(&showdate_format);
381 Cvar_RegisterVariable(&sbar_alpha_bg);
382 Cvar_RegisterVariable(&sbar_alpha_fg);
383 Cvar_RegisterVariable(&sbar_hudselector);
384 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
385 Cvar_RegisterVariable(&cl_deathscoreboard);
387 Cvar_RegisterVariable(&crosshair_color_red);
388 Cvar_RegisterVariable(&crosshair_color_green);
389 Cvar_RegisterVariable(&crosshair_color_blue);
390 Cvar_RegisterVariable(&crosshair_color_alpha);
391 Cvar_RegisterVariable(&crosshair_size);
393 if(gamemode == GAME_NEXUIZ)
395 Cvar_RegisterVariable(&sbar_flagstatus_right); // this cvar makes no sense in other games
396 Cvar_RegisterVariable(&sbar_flagstatus_pos); // this cvar makes no sense in other games
399 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
403 //=============================================================================
405 // drawing routines are relative to the status bar location
414 void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
416 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
419 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
421 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
424 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
426 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
433 Draws one solid graphics character
436 void Sbar_DrawCharacter (int x, int y, int num)
438 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);
446 void Sbar_DrawString (int x, int y, char *str)
448 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);
456 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
461 l = sprintf(str, "%i", num);
475 Sbar_DrawPic (x, y, sb_nums[color][frame]);
488 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
496 l = sprintf(str, "%0*i", digits, num);
499 l = sprintf(str, "%i", num);
504 x += (digits-l) * lettersize;
513 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
520 //=============================================================================
523 int Sbar_IsTeammatch()
525 // currently only nexuiz uses the team score board
526 return ((gamemode == GAME_NEXUIZ)
527 && (teamplay.integer > 0));
535 static int fragsort[MAX_SCOREBOARD];
536 static int scoreboardlines;
538 int Sbar_GetSortedPlayerIndex (int index)
540 return index >= 0 && index < scoreboardlines ? fragsort[index] : -1;
543 static scoreboard_t teams[MAX_SCOREBOARD];
544 static int teamsort[MAX_SCOREBOARD];
545 static int teamlines;
546 void Sbar_SortFrags (void)
552 for (i=0 ; i<cl.maxclients ; i++)
554 if (cl.scores[i].name[0])
556 fragsort[scoreboardlines] = i;
561 for (i=0 ; i<scoreboardlines ; i++)
562 for (j=0 ; j<scoreboardlines-1-i ; j++)
563 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
566 fragsort[j] = fragsort[j+1];
571 if (Sbar_IsTeammatch ())
573 // now sort players by teams.
574 for (i=0 ; i<scoreboardlines ; i++)
576 for (j=0 ; j<scoreboardlines-1-i ; j++)
578 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
581 fragsort[j] = fragsort[j+1];
587 // calculate team scores
589 for (i=0 ; i<scoreboardlines ; i++)
591 if (color != (cl.scores[fragsort[i]].colors & 15))
593 const char* teamname;
595 color = cl.scores[fragsort[i]].colors & 15;
601 teamname = "^1Red Team";
604 teamname = "^4Blue Team";
607 teamname = "^6Pink Team";
610 teamname = "^3Yellow Team";
613 teamname = "Total Team Score";
616 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
618 teams[teamlines-1].frags = 0;
619 teams[teamlines-1].colors = color + 16 * color;
622 if (cl.scores[fragsort[i]].frags != -666)
624 // do not add spedcators
625 // (ugly hack for nexuiz)
626 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
630 // now sort teams by scores.
631 for (i=0 ; i<teamlines ; i++)
633 for (i=0 ; i<teamlines ; i++)
635 for (j=0 ; j<teamlines-1-i ; j++)
637 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
640 teamsort[j] = teamsort[j+1];
653 void Sbar_SoloScoreboard (void)
656 char str[80], timestr[40];
658 int minutes, seconds;
661 t = (cl.intermission ? cl.completed_time : cl.time);
662 minutes = (int)(t / 60);
663 seconds = (int)(t - 60*floor(t/60));
665 // monsters and secrets are now both on the top row
666 if (cl.stats[STAT_TOTALMONSTERS])
667 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
668 if (cl.stats[STAT_TOTALSECRETS])
669 Sbar_DrawString(8+22*8, 4, va("Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
671 // figure out the map's filename without path or extension
672 strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
673 if (strrchr(str, '.'))
674 *(strrchr(str, '.')) = 0;
676 // append a : separator and then the full title
677 strlcat(str, ":", sizeof(str));
678 strlcat(str, cl.levelname, sizeof(str));
680 // if there's a newline character, terminate the string there
681 if (strchr(str, '\n'))
682 *(strchr(str, '\n')) = 0;
684 // make the time string
685 timelen = sprintf(timestr, " %i:%02i", minutes, seconds);
687 // truncate the level name if necessary to make room for time
689 if ((int)strlen(str) > max)
692 // print the filename and message
693 Sbar_DrawString(8, 12, str);
696 Sbar_DrawString(8 + max*8, 12, timestr);
700 int minutes, seconds, tens, units;
703 if (gamemode != GAME_NEXUIZ) {
704 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
705 Sbar_DrawString (8, 4, str);
707 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
708 Sbar_DrawString (8, 12, str);
712 minutes = (int)(cl.time / 60);
713 seconds = (int)(cl.time - 60*minutes);
715 units = seconds - 10*tens;
716 sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
717 Sbar_DrawString (184, 4, str);
720 if (gamemode == GAME_NEXUIZ) {
721 l = (int) strlen (cl.worldmodel->name);
722 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
724 l = (int) strlen (cl.levelname);
725 Sbar_DrawString (232 - l*4, 12, cl.levelname);
735 void Sbar_DrawScoreboard (void)
737 Sbar_SoloScoreboard ();
738 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
739 //if (cl.gametype == GAME_DEATHMATCH)
741 Sbar_DeathmatchOverlay ();
744 //=============================================================================
746 // AK to make DrawInventory smaller
747 static void Sbar_DrawWeapon(int nr, float fade, int active)
749 if (sbar_hudselector.integer == 1)
751 // width = 300, height = 100
752 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
754 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);
756 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);
760 // width = 300, height = 100
761 const int w_width = 300, w_height = 100, w_space = 10;
762 const float w_scale = 0.4;
764 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);
765 //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);
774 void Sbar_DrawInventory (void)
781 if (gamemode == GAME_ROGUE)
783 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
784 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
786 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
789 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
792 for (i=0 ; i<7 ; i++)
794 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
796 time = cl.item_gettime[i];
797 flashon = (int)(max(0, cl.time - time)*10);
800 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
806 flashon = (flashon%5) + 2;
808 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
814 if (gamemode == GAME_HIPNOTIC)
816 int grenadeflashing=0;
817 for (i=0 ; i<4 ; i++)
819 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
821 time = max(0, cl.item_gettime[hipweapons[i]]);
822 flashon = (int)((cl.time - time)*10);
825 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
831 flashon = (flashon%5) + 2;
833 // check grenade launcher
836 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
841 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
847 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
849 if (!grenadeflashing)
850 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
853 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
856 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
861 if (gamemode == GAME_ROGUE)
863 // check for powered up weapon.
864 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
866 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
867 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
871 for (i=0 ; i<4 ; i++)
873 sprintf (num, "%4i",cl.stats[STAT_SHELLS+i] );
875 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
877 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
879 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
881 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
885 for (i=0 ; i<6 ; i++)
886 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
888 //MED 01/04/97 changed keys
889 if (gamemode != GAME_HIPNOTIC || (i>1))
890 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
893 //MED 01/04/97 added hipnotic items
895 if (gamemode == GAME_HIPNOTIC)
897 for (i=0 ; i<2 ; i++)
898 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
899 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
902 if (gamemode == GAME_ROGUE)
905 for (i=0 ; i<2 ; i++)
906 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
907 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
912 for (i=0 ; i<4 ; i++)
913 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
914 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
918 //=============================================================================
925 void Sbar_DrawFrags (void)
935 l = min(scoreboardlines, 4);
939 for (i = 0;i < l;i++)
945 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
946 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);
947 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
948 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);
952 sprintf (num, "%3i",f);
954 if (k == cl.viewentity - 1)
956 Sbar_DrawCharacter ( x + 2, -24, 16);
957 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
959 Sbar_DrawCharacter (x + 8, -24, num[0]);
960 Sbar_DrawCharacter (x + 16, -24, num[1]);
961 Sbar_DrawCharacter (x + 24, -24, num[2]);
966 //=============================================================================
974 void Sbar_DrawFace (void)
978 // PGM 01/19/97 - team color drawing
979 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
980 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
986 s = &cl.scores[cl.viewentity - 1];
988 Sbar_DrawPic (112, 0, rsb_teambord);
989 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
990 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);
991 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
992 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);
996 sprintf (num, "%3i",f);
998 if ((s->colors & 0xf0)==0)
1001 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1003 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1005 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1009 Sbar_DrawCharacter ( 109, 3, num[0]);
1010 Sbar_DrawCharacter ( 116, 3, num[1]);
1011 Sbar_DrawCharacter ( 123, 3, num[2]);
1016 // PGM 01/19/97 - team color drawing
1018 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1019 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1020 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1021 Sbar_DrawPic (112, 0, sb_face_quad );
1022 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1023 Sbar_DrawPic (112, 0, sb_face_invis );
1024 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1025 Sbar_DrawPic (112, 0, sb_face_invuln);
1028 f = cl.stats[STAT_HEALTH] / 20;
1030 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1034 void Sbar_ShowFPS(void)
1036 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1037 char soundstring[32];
1039 char timestring[32];
1040 char datestring[32];
1041 char speedstring[32];
1042 qboolean red = false;
1048 if (showfps.integer)
1051 static double nexttime = 0, lasttime = 0;
1052 static double framerate = 0;
1053 static int framecount = 0;
1054 double interval = 0.25;
1057 if (newtime >= nexttime)
1059 framerate = framecount / (newtime - lasttime);
1060 if (nexttime < newtime - interval * 1.5)
1063 nexttime += interval;
1069 if ((red = (calc < 1.0f)))
1070 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1072 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1074 if (showtime.integer)
1075 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1076 if (showdate.integer)
1077 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1078 if (showsound.integer)
1079 dpsnprintf(soundstring, sizeof(soundstring), "%4i/%4i at %3ims\n", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds);
1080 if (showspeed.integer)
1082 double speed, speedxy, f;
1084 speed = VectorLength(cl.movement_velocity);
1085 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1086 switch(showspeed.integer)
1090 if(gamemode == GAME_NEXUIZ)
1099 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1100 // 1qu=1.5in is for non-Nexuiz only - Nexuiz players are overly large, but 1qu=1in fixes that
1105 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1109 f = 0.0254 * 3.6 * 0.6213711922;
1110 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1114 f = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
1115 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1118 dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1120 if (fpsstring[0] || timestring[0] || datestring[0] || speedstring[0])
1124 fps_height = fps_scaley * ((soundstring[0] != 0) + (fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0) + (speedstring[0] != 0));
1125 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1126 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1127 fps_y = vid_conheight.integer - fps_height;
1130 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(soundstring, 0, true, FONT_INFOBAR) * fps_scalex;
1131 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1132 DrawQ_String_Font(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1133 fps_y += fps_scaley;
1137 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(fpsstring, 0, true, FONT_INFOBAR) * fps_scalex;
1138 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1140 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1142 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1143 fps_y += fps_scaley;
1147 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(timestring, 0, true, FONT_INFOBAR) * fps_scalex;
1148 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1149 DrawQ_String_Font(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1150 fps_y += fps_scaley;
1154 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(datestring, 0, true, FONT_INFOBAR) * fps_scalex;
1155 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1156 DrawQ_String_Font(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1157 fps_y += fps_scaley;
1161 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(speedstring, 0, true, FONT_INFOBAR) * fps_scalex;
1162 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1163 DrawQ_String_Font(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1164 fps_y += fps_scaley;
1169 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)
1172 c2 = bound(0, c2, 1);
1173 c1 = bound(0, c1, 1 - c2);
1175 r[1] = rangey + rangeheight * (c2 + c1);
1176 r[2] = rangey + rangeheight * (c2);
1180 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);
1182 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);
1184 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);
1186 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);
1194 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1195 extern cvar_t v_kicktime;
1196 void Sbar_Score (int margin);
1197 void Sbar_Draw (void)
1201 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1204 Sbar_DrawScoreboard ();
1205 else if (cl.intermission == 1)
1207 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1209 Sbar_DrawScoreboard();
1212 Sbar_IntermissionOverlay();
1214 else if (cl.intermission == 2)
1215 Sbar_FinaleOverlay();
1216 else if (gamemode == GAME_DELUXEQUAKE)
1219 else if (gamemode == GAME_SOM)
1221 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1222 Sbar_DrawScoreboard ();
1225 // this is the top left of the sbar area
1227 sbar_y = vid_conheight.integer - 24*3;
1230 if (cl.stats[STAT_ARMOR])
1232 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1233 Sbar_DrawPic(0, 0, somsb_armor[2]);
1234 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1235 Sbar_DrawPic(0, 0, somsb_armor[1]);
1236 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1237 Sbar_DrawPic(0, 0, somsb_armor[0]);
1238 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1242 Sbar_DrawPic(0, 24, somsb_health);
1243 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1246 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1247 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1248 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1249 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1250 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1251 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1252 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1253 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1254 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1255 if (cl.stats[STAT_SHELLS])
1256 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1259 else if (gamemode == GAME_NEXUIZ)
1261 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1263 sbar_x = (vid_conwidth.integer - 640)/2;
1264 sbar_y = vid_conheight.integer - 47;
1265 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1266 Sbar_DrawScoreboard ();
1268 else if (sb_lines && sbar_hudselector.integer == 1)
1272 int redflag, blueflag;
1275 sbar_x = (vid_conwidth.integer - 320)/2;
1276 sbar_y = vid_conheight.integer - 24 - 16;
1278 // calculate intensity to draw weapons bar at
1279 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1280 fade = bound(0.7, fade, 1);
1281 for (i = 0; i < 8;i++)
1282 if (cl.stats[STAT_ITEMS] & (1 << i))
1283 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1284 if((cl.stats[STAT_ITEMS] & (1<<12)))
1285 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1288 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1289 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1290 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1291 if (redflag == 3 && blueflag == 3)
1293 // The Impossible Combination[tm]
1294 // Can only happen in Key Hunt mode...
1295 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128), sb_items[14]);
1300 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64), sb_items[redflag+10]);
1302 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128), sb_items[blueflag+14]);
1306 if (cl.stats[STAT_ARMOR] > 0)
1308 Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1309 if(cl.stats[STAT_ARMOR] > 200)
1310 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1311 else if(cl.stats[STAT_ARMOR] > 100)
1312 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1313 else if(cl.stats[STAT_ARMOR] > 50)
1314 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1315 else if(cl.stats[STAT_ARMOR] > 25)
1316 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1318 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1322 if (cl.stats[STAT_HEALTH] != 0)
1324 Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1325 if(cl.stats[STAT_HEALTH] > 200)
1326 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1327 else if(cl.stats[STAT_HEALTH] > 100)
1328 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1329 else if(cl.stats[STAT_HEALTH] > 50)
1330 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1331 else if(cl.stats[STAT_HEALTH] > 25)
1332 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1334 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1338 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1340 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1341 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1342 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1343 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1344 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1345 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1346 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1347 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1348 if(cl.stats[STAT_AMMO] > 10)
1349 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1351 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1354 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1355 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1358 // The margin can be at most 8 to support 640x480 console size:
1359 // 320 + 2 * (144 + 16) = 640
1365 int redflag, blueflag;
1368 sbar_x = (vid_conwidth.integer - 640)/2;
1369 sbar_y = vid_conheight.integer - 47;
1371 // calculate intensity to draw weapons bar at
1372 fade = 3 - 2 * (cl.time - cl.weapontime);
1375 fade = min(fade, 1);
1376 for (i = 0; i < 8;i++)
1377 if (cl.stats[STAT_ITEMS] & (1 << i))
1378 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1380 if((cl.stats[STAT_ITEMS] & (1<<12)))
1381 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1384 //if (!cl.islocalgame)
1385 // Sbar_DrawFrags ();
1388 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1390 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1393 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1394 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1395 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1396 if (redflag == 3 && blueflag == 3)
1398 // The Impossible Combination[tm]
1399 // Can only happen in Key Hunt mode...
1400 Sbar_DrawPic (x, -179, sb_items[14]);
1405 Sbar_DrawPic (x, -117, sb_items[redflag+10]);
1407 Sbar_DrawPic (x, -177, sb_items[blueflag+14]);
1411 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1414 if(cl.stats[STAT_HEALTH] > 100)
1415 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1416 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1417 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1419 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1421 // AK dont draw ammo for the laser
1422 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1424 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1425 Sbar_DrawPic (519, 0, sb_ammo[0]);
1426 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1427 Sbar_DrawPic (519, 0, sb_ammo[1]);
1428 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1429 Sbar_DrawPic (519, 0, sb_ammo[2]);
1430 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1431 Sbar_DrawPic (519, 0, sb_ammo[3]);
1433 if(cl.stats[STAT_AMMO] <= 10)
1434 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1436 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1441 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1443 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1444 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1449 // Mini scoreboard uses 12*4 per other team, that is, 144
1450 // pixels when there are four teams...
1451 // Nexuiz by default sets vid_conwidth to 800... makes
1453 // so we need to shift it by 64 pixels to the right to fit
1454 // BUT: then it overlaps with the image that gets drawn
1455 // for viewsize 100! Therefore, just account for 3 teams,
1456 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1460 else if (gamemode == GAME_ZYMOTIC)
1463 float scale = 64.0f / 256.0f;
1464 float kickoffset[3];
1465 VectorClear(kickoffset);
1468 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1469 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1471 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1472 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1473 // left1 16, 48 : 126 -66
1474 // left2 16, 128 : 196 -66
1475 // right 176, 48 : 196 -136
1476 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);
1477 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);
1478 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);
1479 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1481 float scale = 128.0f / 256.0f;
1482 float healthstart, healthheight, healthstarttc, healthendtc;
1483 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1484 float ammostart, ammoheight, ammostarttc, ammoendtc;
1485 float clipstart, clipheight, clipstarttc, clipendtc;
1486 float kickoffset[3], offset;
1487 VectorClear(kickoffset);
1490 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1491 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1493 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1494 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1495 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1496 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);
1497 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);
1498 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);
1499 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);
1500 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1501 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1502 healthstart = 204 - healthheight;
1503 shieldstart = healthstart - shieldheight;
1504 healthstarttc = healthstart * (1.0f / 256.0f);
1505 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1506 shieldstarttc = shieldstart * (1.0f / 256.0f);
1507 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1508 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1509 ammostart = 114 - ammoheight;
1510 ammostarttc = ammostart * (1.0f / 256.0f);
1511 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1512 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1513 clipstart = 190 - clipheight;
1514 clipstarttc = clipstart * (1.0f / 256.0f);
1515 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1516 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);
1517 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);
1518 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);
1519 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);
1520 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1521 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1524 else // Quake and others
1526 sbar_x = (vid_conwidth.integer - 320)/2;
1527 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1528 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1529 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1533 if (gamemode != GAME_GOODVSBAD2)
1534 Sbar_DrawInventory ();
1535 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1539 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1541 if (gamemode != GAME_GOODVSBAD2)
1542 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1543 Sbar_DrawScoreboard ();
1547 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1549 // keys (hipnotic only)
1550 //MED 01/04/97 moved keys here so they would not be overwritten
1551 if (gamemode == GAME_HIPNOTIC)
1553 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1554 Sbar_DrawPic (209, 3, sb_items[0]);
1555 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1556 Sbar_DrawPic (209, 12, sb_items[1]);
1559 if (gamemode != GAME_GOODVSBAD2)
1561 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1563 Sbar_DrawNum (24, 0, 666, 3, 1);
1564 Sbar_DrawPic (0, 0, sb_disc);
1568 if (gamemode == GAME_ROGUE)
1570 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1571 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1572 Sbar_DrawPic (0, 0, sb_armor[2]);
1573 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1574 Sbar_DrawPic (0, 0, sb_armor[1]);
1575 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1576 Sbar_DrawPic (0, 0, sb_armor[0]);
1580 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1581 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1582 Sbar_DrawPic (0, 0, sb_armor[2]);
1583 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1584 Sbar_DrawPic (0, 0, sb_armor[1]);
1585 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1586 Sbar_DrawPic (0, 0, sb_armor[0]);
1595 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1598 if (gamemode == GAME_ROGUE)
1600 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1601 Sbar_DrawPic (224, 0, sb_ammo[0]);
1602 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1603 Sbar_DrawPic (224, 0, sb_ammo[1]);
1604 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1605 Sbar_DrawPic (224, 0, sb_ammo[2]);
1606 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1607 Sbar_DrawPic (224, 0, sb_ammo[3]);
1608 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1609 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1610 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1611 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1612 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1613 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1617 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1618 Sbar_DrawPic (224, 0, sb_ammo[0]);
1619 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1620 Sbar_DrawPic (224, 0, sb_ammo[1]);
1621 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1622 Sbar_DrawPic (224, 0, sb_ammo[2]);
1623 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1624 Sbar_DrawPic (224, 0, sb_ammo[3]);
1627 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1629 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1630 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1632 if (gamemode == GAME_TRANSFUSION)
1633 Sbar_MiniDeathmatchOverlay (0, 0);
1635 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1644 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1646 pic = Draw_CachePic (va("gfx/crosshair%i", crosshair.integer));
1647 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);
1650 if (cl_prydoncursor.integer)
1651 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);
1654 //=============================================================================
1658 Sbar_DeathmatchOverlay
1662 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1665 qboolean myself = false;
1667 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1669 if((s - cl.scores) == cl.playerentity - 1)
1671 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1672 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1675 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1677 if (s->qw_spectator)
1679 if (s->qw_ping || s->qw_packetloss)
1680 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 );
1682 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 );
1686 // draw colors behind score
1692 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1693 DrawQ_Fill(x + 14*8*FONT_SBAR->width_of[0], y+1, 40*FONT_SBAR->width_of[0], 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1694 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1695 DrawQ_Fill(x + 14*8*FONT_SBAR->width_of[0], y+4, 40*FONT_SBAR->width_of[0], 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1697 //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);
1698 if (s->qw_ping || s->qw_packetloss)
1699 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 );
1701 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 );
1706 if (s->qw_spectator)
1708 if (s->qw_ping || s->qw_packetloss)
1709 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 );
1711 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 );
1715 // draw colors behind score
1716 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1717 DrawQ_Fill(x + 9*8*FONT_SBAR->width_of[0], y+1, 40*FONT_SBAR->width_of[0], 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1718 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1719 DrawQ_Fill(x + 9*8*FONT_SBAR->width_of[0], y+4, 40*FONT_SBAR->width_of[0], 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1721 //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);
1722 if (s->qw_ping || s->qw_packetloss)
1723 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 );
1725 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 );
1731 void Sbar_DeathmatchOverlay (void)
1733 int i, y, xmin, xmax, ymin, ymax;
1735 // request new ping times every two second
1736 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1738 cl.last_ping_request = realtime;
1739 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1741 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1742 MSG_WriteString(&cls.netcon->message, "pings");
1744 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*/)
1746 // 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
1747 static int ping_anyway_counter = 0;
1748 if(cl.parsingtextexpectingpingforscores == 1)
1750 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1751 if(++ping_anyway_counter >= 5)
1752 cl.parsingtextexpectingpingforscores = 0;
1754 if(cl.parsingtextexpectingpingforscores != 1)
1756 ping_anyway_counter = 0;
1757 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1758 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1759 MSG_WriteString(&cls.netcon->message, "ping");
1764 // 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
1765 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1766 MSG_WriteString(&cls.netcon->message, "pings");
1774 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1776 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1777 xmin = (vid_conwidth.integer - (26 + 15) * 8 * FONT_SBAR->width_of[0]) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1779 xmin = (vid_conwidth.integer - (16 + 25) * 8 * FONT_SBAR->width_of[0]) / 2; // 16 characters until name, then we assume 25 character names (they can be longer but usually aren't)
1780 xmax = vid_conwidth.integer - xmin;
1782 if(gamemode == GAME_NEXUIZ)
1783 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);
1785 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1789 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1791 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 );
1795 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 );
1799 if (Sbar_IsTeammatch ())
1801 // show team scores first
1802 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1803 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1807 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1808 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1813 Sbar_MiniDeathmatchOverlay
1817 void Sbar_MiniDeathmatchOverlay (int x, int y)
1819 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1821 // do not draw this if sbar_miniscoreboard_size is zero
1822 if(sbar_miniscoreboard_size.value == 0)
1824 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1825 if(sbar_miniscoreboard_size.value > 0)
1826 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1831 // decide where to print
1832 if (gamemode == GAME_TRANSFUSION)
1833 numlines = (vid_conwidth.integer - x + 127) / 128;
1835 numlines = (vid_conheight.integer - y + 7) / 8;
1837 // give up if there isn't room
1838 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1842 for (i = 0; i < scoreboardlines; i++)
1843 if (fragsort[i] == cl.playerentity - 1)
1847 range_end = scoreboardlines;
1850 if (gamemode != GAME_TRANSFUSION)
1851 if (Sbar_IsTeammatch ())
1853 // reserve space for the team scores
1854 numlines -= teamlines;
1856 // find first and last player of my team (only draw the team totals and my own team)
1857 range_begin = range_end = i;
1858 myteam = cl.scores[fragsort[i]].colors & 15;
1859 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1861 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1864 // looks better than two players
1874 i = min(i, range_end - numlines);
1875 i = max(i, range_begin);
1877 if (gamemode == GAME_TRANSFUSION)
1879 for (;i < range_end && x < vid_conwidth.integer;i++)
1880 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1884 if(range_end - i < numlines) // won't draw to bottom?
1885 y += 8 * (numlines - (range_end - i)); // bottom align
1886 // show team scores first
1887 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1888 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1890 for (;i < range_end && y < vid_conheight.integer;i++)
1891 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1895 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1897 static int const sortorder[16] =
1916 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1917 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1918 int tc1 = sortorder[t1->colors & 15];
1919 int tc2 = sortorder[t2->colors & 15];
1923 void Sbar_Score (int margin)
1925 int i, me, score, otherleader, place, distribution, minutes, seconds;
1927 int sbar_x_save = sbar_x;
1928 int sbar_y_save = sbar_y;
1930 sbar_y = vid_conheight.value - (32+12);
1933 me = cl.playerentity - 1;
1934 if (me >= 0 && me < cl.maxclients)
1936 if(Sbar_IsTeammatch())
1940 // team1 team3 team4
1944 scoreboard_t *teamcolorsort[16];
1947 for(i = 0; i < teamlines; ++i)
1948 teamcolorsort[i] = &(teams[i]);
1950 // Now sort them by color
1951 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1954 // -12*4: four digits space
1955 place = (teamlines - 1) * (-12 * 4);
1957 for(i = 0; i < teamlines; ++i)
1959 int cindex = teamcolorsort[i]->colors & 15;
1960 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
1961 float cm = max(max(c[0], c[1]), c[2]);
1962 float cr = c[0] / cm;
1963 float cg = c[1] / cm;
1964 float cb = c[2] / cm;
1965 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1967 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1971 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1984 // find leading score other than ourselves, to calculate distribution
1985 // find our place in the scoreboard
1986 score = cl.scores[me].frags;
1987 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1989 if (cl.scores[i].name[0] && i != me)
1991 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1993 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1997 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1999 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2000 else if (place == 2)
2001 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2003 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2004 if (otherleader < 0)
2005 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2006 if (distribution >= 0)
2008 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2009 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2011 else if (distribution >= -5)
2013 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2014 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2018 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2019 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2024 if (cl.statsf[STAT_TIMELIMIT])
2026 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2027 minutes = (int)floor(timeleft / 60);
2028 seconds = (int)(floor(timeleft) - minutes * 60);
2031 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2032 if(sb_colon && sb_colon->tex != r_texture_notexture)
2033 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2034 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2036 else if (minutes >= 1)
2038 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2039 if(sb_colon && sb_colon->tex != r_texture_notexture)
2040 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2041 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2043 else if ((int)(timeleft * 4) & 1)
2044 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2046 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2050 minutes = (int)floor(cl.time / 60);
2051 seconds = (int)(floor(cl.time) - minutes * 60);
2052 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2053 if(sb_colon && sb_colon->tex != r_texture_notexture)
2054 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2055 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2058 sbar_x = sbar_x_save;
2059 sbar_y = sbar_y_save;
2064 Sbar_IntermissionOverlay
2068 void Sbar_IntermissionOverlay (void)
2073 if (cl.gametype == GAME_DEATHMATCH)
2075 Sbar_DeathmatchOverlay ();
2079 sbar_x = (vid_conwidth.integer - 320) >> 1;
2080 sbar_y = (vid_conheight.integer - 200) >> 1;
2082 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2083 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2086 dig = (int)cl.completed_time / 60;
2087 Sbar_DrawNum (160, 64, dig, 3, 0);
2088 num = (int)cl.completed_time - dig*60;
2089 Sbar_DrawPic (234,64,sb_colon);
2090 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2091 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2093 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2094 if (gamemode != GAME_NEXUIZ)
2095 Sbar_DrawPic (232, 104, sb_slash);
2096 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2098 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2099 if (gamemode != GAME_NEXUIZ)
2100 Sbar_DrawPic (232, 144, sb_slash);
2101 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2112 void Sbar_FinaleOverlay (void)
2114 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);