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 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"};
92 cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"};
93 cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"};
94 cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"};
95 cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"};
96 cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
97 cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
98 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)"};
99 cvar_t sbar_miniscoreboard_size = {CVAR_SAVE, "sbar_miniscoreboard_size", "-1", "sets the size of the mini deathmatch overlay in items, or disables it when set to 0, or sets it to a sane default when set to -1"};
100 cvar_t sbar_flagstatus_right = {CVAR_SAVE, "sbar_flagstatus_right", "0", "moves Nexuiz flag status icons to the right"};
101 cvar_t sbar_flagstatus_pos = {CVAR_SAVE, "sbar_flagstatus_pos", "115", "pixel position of the Nexuiz flag status icons, from the bottom"};
103 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
105 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
106 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
107 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
108 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
109 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
111 void Sbar_MiniDeathmatchOverlay (int x, int y);
112 void Sbar_DeathmatchOverlay (void);
113 void Sbar_IntermissionOverlay (void);
114 void Sbar_FinaleOverlay (void);
116 void CL_VM_UpdateShowingScoresState (int showingscores);
126 void Sbar_ShowScores (void)
130 sb_showscores = true;
131 CL_VM_UpdateShowingScoresState(sb_showscores);
141 void Sbar_DontShowScores (void)
143 sb_showscores = false;
144 CL_VM_UpdateShowingScoresState(sb_showscores);
147 void sbar_start(void)
151 if (gamemode == GAME_DELUXEQUAKE)
154 else if (gamemode == GAME_SOM)
156 sb_disc = Draw_CachePic ("gfx/disc");
158 for (i = 0;i < 10;i++)
159 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i));
161 somsb_health = Draw_CachePic ("gfx/hud_health");
162 somsb_ammo[0] = Draw_CachePic ("gfx/sb_shells");
163 somsb_ammo[1] = Draw_CachePic ("gfx/sb_nails");
164 somsb_ammo[2] = Draw_CachePic ("gfx/sb_rocket");
165 somsb_ammo[3] = Draw_CachePic ("gfx/sb_cells");
166 somsb_armor[0] = Draw_CachePic ("gfx/sb_armor1");
167 somsb_armor[1] = Draw_CachePic ("gfx/sb_armor2");
168 somsb_armor[2] = Draw_CachePic ("gfx/sb_armor3");
170 else if (gamemode == GAME_NEXUIZ)
172 for (i = 0;i < 10;i++)
173 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i));
174 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus");
175 sb_colon = Draw_CachePic ("gfx/num_colon");
177 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells");
178 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets");
179 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket");
180 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells");
182 sb_armor[0] = Draw_CachePic ("gfx/sb_armor");
186 sb_health = Draw_CachePic ("gfx/sb_health");
188 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo");
189 sb_items[3] = Draw_CachePic ("gfx/sb_invinc");
190 sb_items[4] = Draw_CachePic ("gfx/sb_energy");
191 sb_items[5] = Draw_CachePic ("gfx/sb_str");
193 sb_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken");
194 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost");
195 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying");
196 sb_items[14] = Draw_CachePic ("gfx/sb_key_carrying");
197 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken");
198 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost");
199 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying");
201 sb_sbar = Draw_CachePic ("gfx/sbar");
202 sb_sbar_minimal = Draw_CachePic ("gfx/sbar_minimal");
203 sb_sbar_overlay = Draw_CachePic ("gfx/sbar_overlay");
205 for(i = 0; i < 9;i++)
206 sb_weapons[0][i] = Draw_CachePic (va("gfx/inv_weapon%i",i));
208 else if (gamemode == GAME_ZYMOTIC)
210 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center");
211 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line");
212 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health");
213 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip");
214 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo");
215 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background");
216 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1");
217 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2");
218 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right");
222 sb_disc = Draw_CachePic ("gfx/disc");
224 for (i = 0;i < 10;i++)
226 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i));
227 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i));
230 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus");
231 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus");
233 sb_colon = Draw_CachePic ("gfx/num_colon");
234 sb_slash = Draw_CachePic ("gfx/num_slash");
236 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun");
237 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun");
238 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun");
239 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun");
240 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch");
241 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch");
242 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng");
244 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun");
245 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun");
246 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun");
247 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun");
248 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch");
249 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch");
250 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng");
252 for (i = 0;i < 5;i++)
254 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1));
255 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1));
256 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1));
257 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1));
258 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1));
259 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1));
260 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1));
263 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells");
264 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails");
265 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket");
266 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells");
268 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1");
269 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2");
270 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3");
272 sb_items[0] = Draw_CachePic ("gfx/sb_key1");
273 sb_items[1] = Draw_CachePic ("gfx/sb_key2");
274 sb_items[2] = Draw_CachePic ("gfx/sb_invis");
275 sb_items[3] = Draw_CachePic ("gfx/sb_invuln");
276 sb_items[4] = Draw_CachePic ("gfx/sb_suit");
277 sb_items[5] = Draw_CachePic ("gfx/sb_quad");
279 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1");
280 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2");
281 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3");
282 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4");
284 sb_faces[4][0] = Draw_CachePic ("gfx/face1");
285 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1");
286 sb_faces[3][0] = Draw_CachePic ("gfx/face2");
287 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2");
288 sb_faces[2][0] = Draw_CachePic ("gfx/face3");
289 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3");
290 sb_faces[1][0] = Draw_CachePic ("gfx/face4");
291 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4");
292 sb_faces[0][0] = Draw_CachePic ("gfx/face5");
293 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5");
295 sb_face_invis = Draw_CachePic ("gfx/face_invis");
296 sb_face_invuln = Draw_CachePic ("gfx/face_invul2");
297 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2");
298 sb_face_quad = Draw_CachePic ("gfx/face_quad");
300 sb_sbar = Draw_CachePic ("gfx/sbar");
301 sb_ibar = Draw_CachePic ("gfx/ibar");
302 sb_scorebar = Draw_CachePic ("gfx/scorebar");
304 //MED 01/04/97 added new hipnotic weapons
305 if (gamemode == GAME_HIPNOTIC)
307 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser");
308 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir");
309 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox");
310 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren");
311 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox");
313 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser");
314 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir");
315 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox");
316 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren");
317 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox");
319 for (i = 0;i < 5;i++)
321 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1));
322 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1));
323 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1));
324 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1));
325 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1));
328 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit");
329 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld");
331 else if (gamemode == GAME_ROGUE)
333 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1");
334 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2");
336 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava");
337 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava");
338 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren");
339 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock");
340 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma");
342 rsb_items[0] = Draw_CachePic ("gfx/r_shield1");
343 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1");
345 // PGM 01/19/97 - team color border
346 rsb_teambord = Draw_CachePic ("gfx/r_teambord");
347 // PGM 01/19/97 - team color border
349 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava");
350 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti");
351 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma");
355 sb_ranking = Draw_CachePic ("gfx/ranking");
356 sb_complete = Draw_CachePic ("gfx/complete");
357 sb_inter = Draw_CachePic ("gfx/inter");
358 sb_finale = Draw_CachePic ("gfx/finale");
361 void sbar_shutdown(void)
365 void sbar_newmap(void)
369 void Sbar_Init (void)
371 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
372 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
373 Cvar_RegisterVariable(&showfps);
374 Cvar_RegisterVariable(&showspeed);
375 Cvar_RegisterVariable(&showtime);
376 Cvar_RegisterVariable(&showtime_format);
377 Cvar_RegisterVariable(&showdate);
378 Cvar_RegisterVariable(&showdate_format);
379 Cvar_RegisterVariable(&sbar_alpha_bg);
380 Cvar_RegisterVariable(&sbar_alpha_fg);
381 Cvar_RegisterVariable(&sbar_hudselector);
382 Cvar_RegisterVariable(&sbar_miniscoreboard_size);
383 Cvar_RegisterVariable(&cl_deathscoreboard);
385 Cvar_RegisterVariable(&crosshair_color_red);
386 Cvar_RegisterVariable(&crosshair_color_green);
387 Cvar_RegisterVariable(&crosshair_color_blue);
388 Cvar_RegisterVariable(&crosshair_color_alpha);
389 Cvar_RegisterVariable(&crosshair_size);
391 if(gamemode == GAME_NEXUIZ)
393 Cvar_RegisterVariable(&sbar_flagstatus_right); // this cvar makes no sense in other games
394 Cvar_RegisterVariable(&sbar_flagstatus_pos); // this cvar makes no sense in other games
397 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
401 //=============================================================================
403 // drawing routines are relative to the status bar location
412 void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
414 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
417 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
419 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
422 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
424 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
431 Draws one solid graphics character
434 void Sbar_DrawCharacter (int x, int y, int num)
436 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);
444 void Sbar_DrawString (int x, int y, char *str)
446 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);
454 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
459 l = sprintf(str, "%i", num);
473 Sbar_DrawPic (x, y, sb_nums[color][frame]);
486 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
494 l = sprintf(str, "%0*i", digits, num);
497 l = sprintf(str, "%i", num);
502 x += (digits-l) * lettersize;
511 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
518 //=============================================================================
521 int Sbar_IsTeammatch()
523 // currently only nexuiz uses the team score board
524 return ((gamemode == GAME_NEXUIZ)
525 && (teamplay.integer > 0));
533 static int fragsort[MAX_SCOREBOARD];
534 static int scoreboardlines;
536 //[515]: Sbar_GetPlayer for csqc "getplayerkey" func
537 int Sbar_GetPlayer (int index)
542 if(index >= scoreboardlines)
544 index = fragsort[index];
546 if(index >= scoreboardlines)
551 static scoreboard_t teams[MAX_SCOREBOARD];
552 static int teamsort[MAX_SCOREBOARD];
553 static int teamlines;
554 void Sbar_SortFrags (void)
560 for (i=0 ; i<cl.maxclients ; i++)
562 if (cl.scores[i].name[0])
564 fragsort[scoreboardlines] = i;
569 for (i=0 ; i<scoreboardlines ; i++)
570 for (j=0 ; j<scoreboardlines-1-i ; j++)
571 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
574 fragsort[j] = fragsort[j+1];
579 if (Sbar_IsTeammatch ())
581 // now sort players by teams.
582 for (i=0 ; i<scoreboardlines ; i++)
584 for (j=0 ; j<scoreboardlines-1-i ; j++)
586 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
589 fragsort[j] = fragsort[j+1];
595 // calculate team scores
597 for (i=0 ; i<scoreboardlines ; i++)
599 if (color != (cl.scores[fragsort[i]].colors & 15))
601 const char* teamname;
603 color = cl.scores[fragsort[i]].colors & 15;
609 teamname = "^1Red Team";
612 teamname = "^4Blue Team";
615 teamname = "^6Pink Team";
618 teamname = "^3Yellow Team";
621 teamname = "Total Team Score";
624 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
626 teams[teamlines-1].frags = 0;
627 teams[teamlines-1].colors = color + 16 * color;
630 if (cl.scores[fragsort[i]].frags != -666)
632 // do not add spedcators
633 // (ugly hack for nexuiz)
634 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
638 // now sort teams by scores.
639 for (i=0 ; i<teamlines ; i++)
641 for (i=0 ; i<teamlines ; i++)
643 for (j=0 ; j<teamlines-1-i ; j++)
645 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
648 teamsort[j] = teamsort[j+1];
661 void Sbar_SoloScoreboard (void)
664 char str[80], timestr[40];
666 int minutes, seconds;
669 t = (cl.intermission ? cl.completed_time : cl.time);
670 minutes = (int)(t / 60);
671 seconds = (int)(t - 60*floor(t/60));
673 // monsters and secrets are now both on the top row
674 if (cl.stats[STAT_TOTALMONSTERS])
675 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
676 if (cl.stats[STAT_TOTALSECRETS])
677 Sbar_DrawString(8+22*8, 4, va("Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
679 // figure out the map's filename without path or extension
680 strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
681 if (strrchr(str, '.'))
682 *(strrchr(str, '.')) = 0;
684 // append a : separator and then the full title
685 strlcat(str, ":", sizeof(str));
686 strlcat(str, cl.levelname, sizeof(str));
688 // if there's a newline character, terminate the string there
689 if (strchr(str, '\n'))
690 *(strchr(str, '\n')) = 0;
692 // make the time string
693 timelen = sprintf(timestr, " %i:%02i", minutes, seconds);
695 // truncate the level name if necessary to make room for time
697 if ((int)strlen(str) > max)
700 // print the filename and message
701 Sbar_DrawString(8, 12, str);
704 Sbar_DrawString(8 + max*8, 12, timestr);
708 int minutes, seconds, tens, units;
711 if (gamemode != GAME_NEXUIZ) {
712 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
713 Sbar_DrawString (8, 4, str);
715 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
716 Sbar_DrawString (8, 12, str);
720 minutes = (int)(cl.time / 60);
721 seconds = (int)(cl.time - 60*minutes);
723 units = seconds - 10*tens;
724 sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
725 Sbar_DrawString (184, 4, str);
728 if (gamemode == GAME_NEXUIZ) {
729 l = (int) strlen (cl.worldmodel->name);
730 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
732 l = (int) strlen (cl.levelname);
733 Sbar_DrawString (232 - l*4, 12, cl.levelname);
743 void Sbar_DrawScoreboard (void)
745 Sbar_SoloScoreboard ();
746 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
747 //if (cl.gametype == GAME_DEATHMATCH)
749 Sbar_DeathmatchOverlay ();
752 //=============================================================================
754 // AK to make DrawInventory smaller
755 static void Sbar_DrawWeapon(int nr, float fade, int active)
757 if (sbar_hudselector.integer == 1)
759 // width = 300, height = 100
760 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
762 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);
764 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);
768 // width = 300, height = 100
769 const int w_width = 300, w_height = 100, w_space = 10;
770 const float w_scale = 0.4;
772 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);
773 //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);
782 void Sbar_DrawInventory (void)
789 if (gamemode == GAME_ROGUE)
791 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
792 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
794 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
797 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
800 for (i=0 ; i<7 ; i++)
802 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
804 time = cl.item_gettime[i];
805 flashon = (int)(max(0, cl.time - time)*10);
808 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
814 flashon = (flashon%5) + 2;
816 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
822 if (gamemode == GAME_HIPNOTIC)
824 int grenadeflashing=0;
825 for (i=0 ; i<4 ; i++)
827 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
829 time = max(0, cl.item_gettime[hipweapons[i]]);
830 flashon = (int)((cl.time - time)*10);
833 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
839 flashon = (flashon%5) + 2;
841 // check grenade launcher
844 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
849 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
855 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
857 if (!grenadeflashing)
858 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
861 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
864 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
869 if (gamemode == GAME_ROGUE)
871 // check for powered up weapon.
872 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
874 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
875 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
879 for (i=0 ; i<4 ; i++)
881 sprintf (num, "%4i",cl.stats[STAT_SHELLS+i] );
883 Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
885 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
887 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
889 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
893 for (i=0 ; i<6 ; i++)
894 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
896 //MED 01/04/97 changed keys
897 if (gamemode != GAME_HIPNOTIC || (i>1))
898 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
901 //MED 01/04/97 added hipnotic items
903 if (gamemode == GAME_HIPNOTIC)
905 for (i=0 ; i<2 ; i++)
906 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
907 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
910 if (gamemode == GAME_ROGUE)
913 for (i=0 ; i<2 ; i++)
914 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
915 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
920 for (i=0 ; i<4 ; i++)
921 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
922 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
926 //=============================================================================
933 void Sbar_DrawFrags (void)
943 l = min(scoreboardlines, 4);
947 for (i = 0;i < l;i++)
953 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
954 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);
955 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
956 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);
960 sprintf (num, "%3i",f);
962 if (k == cl.viewentity - 1)
964 Sbar_DrawCharacter ( x + 2, -24, 16);
965 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
967 Sbar_DrawCharacter (x + 8, -24, num[0]);
968 Sbar_DrawCharacter (x + 16, -24, num[1]);
969 Sbar_DrawCharacter (x + 24, -24, num[2]);
974 //=============================================================================
982 void Sbar_DrawFace (void)
986 // PGM 01/19/97 - team color drawing
987 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
988 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
994 s = &cl.scores[cl.viewentity - 1];
996 Sbar_DrawPic (112, 0, rsb_teambord);
997 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
998 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);
999 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1000 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);
1004 sprintf (num, "%3i",f);
1006 if ((s->colors & 0xf0)==0)
1009 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
1011 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
1013 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
1017 Sbar_DrawCharacter ( 109, 3, num[0]);
1018 Sbar_DrawCharacter ( 116, 3, num[1]);
1019 Sbar_DrawCharacter ( 123, 3, num[2]);
1024 // PGM 01/19/97 - team color drawing
1026 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1027 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1028 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1029 Sbar_DrawPic (112, 0, sb_face_quad );
1030 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1031 Sbar_DrawPic (112, 0, sb_face_invis );
1032 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1033 Sbar_DrawPic (112, 0, sb_face_invuln);
1036 f = cl.stats[STAT_HEALTH] / 20;
1038 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1042 void Sbar_ShowFPS(void)
1044 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1046 char timestring[32];
1047 char datestring[32];
1048 char speedstring[32];
1049 qboolean red = false;
1054 if (showfps.integer)
1057 static double nexttime = 0, lasttime = 0;
1058 static double framerate = 0;
1059 static int framecount = 0;
1060 double interval = 0.25;
1063 if (newtime >= nexttime)
1065 framerate = framecount / (newtime - lasttime);
1066 if (nexttime < newtime - interval * 1.5)
1069 nexttime += interval;
1075 if ((red = (calc < 1.0f)))
1076 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1078 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1080 if (showtime.integer)
1081 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1082 if (showdate.integer)
1083 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
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 * ((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(fpsstring, 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);
1137 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1139 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1140 fps_y += fps_scaley;
1144 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(timestring, 0, true, FONT_INFOBAR) * fps_scalex;
1145 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1146 DrawQ_String_Font(fps_x, fps_y, timestring, 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(datestring, 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, datestring, 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(speedstring, 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, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1161 fps_y += fps_scaley;
1166 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)
1169 c2 = bound(0, c2, 1);
1170 c1 = bound(0, c1, 1 - c2);
1172 r[1] = rangey + rangeheight * (c2 + c1);
1173 r[2] = rangey + rangeheight * (c2);
1177 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);
1179 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);
1181 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);
1183 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);
1191 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1192 extern cvar_t v_kicktime;
1193 void Sbar_Score (int margin);
1194 void Sbar_Draw (void)
1198 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1201 Sbar_DrawScoreboard ();
1202 else if (cl.intermission == 1)
1204 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1206 Sbar_DrawScoreboard();
1209 Sbar_IntermissionOverlay();
1211 else if (cl.intermission == 2)
1212 Sbar_FinaleOverlay();
1213 else if (gamemode == GAME_DELUXEQUAKE)
1216 else if (gamemode == GAME_SOM)
1218 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1219 Sbar_DrawScoreboard ();
1222 // this is the top left of the sbar area
1224 sbar_y = vid_conheight.integer - 24*3;
1227 if (cl.stats[STAT_ARMOR])
1229 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1230 Sbar_DrawPic(0, 0, somsb_armor[2]);
1231 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1232 Sbar_DrawPic(0, 0, somsb_armor[1]);
1233 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1234 Sbar_DrawPic(0, 0, somsb_armor[0]);
1235 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1239 Sbar_DrawPic(0, 24, somsb_health);
1240 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1243 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1244 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1245 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1246 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1247 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1248 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1249 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1250 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1251 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1252 if (cl.stats[STAT_SHELLS])
1253 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1256 else if (gamemode == GAME_NEXUIZ)
1258 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1260 sbar_x = (vid_conwidth.integer - 640)/2;
1261 sbar_y = vid_conheight.integer - 47;
1262 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1263 Sbar_DrawScoreboard ();
1265 else if (sb_lines && sbar_hudselector.integer == 1)
1269 int redflag, blueflag;
1272 sbar_x = (vid_conwidth.integer - 320)/2;
1273 sbar_y = vid_conheight.integer - 24 - 16;
1275 // calculate intensity to draw weapons bar at
1276 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1277 fade = bound(0.7, fade, 1);
1278 for (i = 0; i < 8;i++)
1279 if (cl.stats[STAT_ITEMS] & (1 << i))
1280 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1281 if((cl.stats[STAT_ITEMS] & (1<<12)))
1282 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1285 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1286 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1287 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1288 if (redflag == 3 && blueflag == 3)
1290 // The Impossible Combination[tm]
1291 // Can only happen in Key Hunt mode...
1292 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128), sb_items[14]);
1297 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64), sb_items[redflag+10]);
1299 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128), sb_items[blueflag+14]);
1303 if (cl.stats[STAT_ARMOR] > 0)
1305 Sbar_DrawStretchPic (0, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1306 if(cl.stats[STAT_ARMOR] > 200)
1307 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1308 else if(cl.stats[STAT_ARMOR] > 100)
1309 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1310 else if(cl.stats[STAT_ARMOR] > 50)
1311 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1312 else if(cl.stats[STAT_ARMOR] > 25)
1313 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1315 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1319 if (cl.stats[STAT_HEALTH] != 0)
1321 Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1322 if(cl.stats[STAT_HEALTH] > 200)
1323 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1324 else if(cl.stats[STAT_HEALTH] > 100)
1325 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1326 else if(cl.stats[STAT_HEALTH] > 50)
1327 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1328 else if(cl.stats[STAT_HEALTH] > 25)
1329 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1331 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1335 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1337 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1338 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1339 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1340 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1341 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1342 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1343 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1344 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1345 if(cl.stats[STAT_AMMO] > 10)
1346 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1348 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1351 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1352 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1355 // The margin can be at most 8 to support 640x480 console size:
1356 // 320 + 2 * (144 + 16) = 640
1362 int redflag, blueflag;
1365 sbar_x = (vid_conwidth.integer - 640)/2;
1366 sbar_y = vid_conheight.integer - 47;
1368 // calculate intensity to draw weapons bar at
1369 fade = 3 - 2 * (cl.time - cl.weapontime);
1372 fade = min(fade, 1);
1373 for (i = 0; i < 8;i++)
1374 if (cl.stats[STAT_ITEMS] & (1 << i))
1375 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1377 if((cl.stats[STAT_ITEMS] & (1<<12)))
1378 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1381 //if (!cl.islocalgame)
1382 // Sbar_DrawFrags ();
1385 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1387 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1390 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1391 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1392 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1393 if (redflag == 3 && blueflag == 3)
1395 // The Impossible Combination[tm]
1396 // Can only happen in Key Hunt mode...
1397 Sbar_DrawPic (x, -179, sb_items[14]);
1402 Sbar_DrawPic (x, -117, sb_items[redflag+10]);
1404 Sbar_DrawPic (x, -177, sb_items[blueflag+14]);
1408 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1411 if(cl.stats[STAT_HEALTH] > 100)
1412 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1413 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1414 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1416 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1418 // AK dont draw ammo for the laser
1419 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1421 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1422 Sbar_DrawPic (519, 0, sb_ammo[0]);
1423 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1424 Sbar_DrawPic (519, 0, sb_ammo[1]);
1425 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1426 Sbar_DrawPic (519, 0, sb_ammo[2]);
1427 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1428 Sbar_DrawPic (519, 0, sb_ammo[3]);
1430 if(cl.stats[STAT_AMMO] <= 10)
1431 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1433 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1438 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1440 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1441 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1446 // Mini scoreboard uses 12*4 per other team, that is, 144
1447 // pixels when there are four teams...
1448 // Nexuiz by default sets vid_conwidth to 800... makes
1450 // so we need to shift it by 64 pixels to the right to fit
1451 // BUT: then it overlaps with the image that gets drawn
1452 // for viewsize 100! Therefore, just account for 3 teams,
1453 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1457 else if (gamemode == GAME_ZYMOTIC)
1460 float scale = 64.0f / 256.0f;
1461 float kickoffset[3];
1462 VectorClear(kickoffset);
1465 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1466 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1468 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1469 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1470 // left1 16, 48 : 126 -66
1471 // left2 16, 128 : 196 -66
1472 // right 176, 48 : 196 -136
1473 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);
1474 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);
1475 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);
1476 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1478 float scale = 128.0f / 256.0f;
1479 float healthstart, healthheight, healthstarttc, healthendtc;
1480 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1481 float ammostart, ammoheight, ammostarttc, ammoendtc;
1482 float clipstart, clipheight, clipstarttc, clipendtc;
1483 float kickoffset[3], offset;
1484 VectorClear(kickoffset);
1487 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1488 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1490 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1491 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1492 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1493 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);
1494 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);
1495 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);
1496 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);
1497 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1498 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1499 healthstart = 204 - healthheight;
1500 shieldstart = healthstart - shieldheight;
1501 healthstarttc = healthstart * (1.0f / 256.0f);
1502 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1503 shieldstarttc = shieldstart * (1.0f / 256.0f);
1504 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1505 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1506 ammostart = 114 - ammoheight;
1507 ammostarttc = ammostart * (1.0f / 256.0f);
1508 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1509 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1510 clipstart = 190 - clipheight;
1511 clipstarttc = clipstart * (1.0f / 256.0f);
1512 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1513 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);
1514 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);
1515 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);
1516 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);
1517 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1518 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1521 else // Quake and others
1523 sbar_x = (vid_conwidth.integer - 320)/2;
1524 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1525 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1526 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1530 if (gamemode != GAME_GOODVSBAD2)
1531 Sbar_DrawInventory ();
1532 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1536 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1538 if (gamemode != GAME_GOODVSBAD2)
1539 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1540 Sbar_DrawScoreboard ();
1544 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1546 // keys (hipnotic only)
1547 //MED 01/04/97 moved keys here so they would not be overwritten
1548 if (gamemode == GAME_HIPNOTIC)
1550 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1551 Sbar_DrawPic (209, 3, sb_items[0]);
1552 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1553 Sbar_DrawPic (209, 12, sb_items[1]);
1556 if (gamemode != GAME_GOODVSBAD2)
1558 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1560 Sbar_DrawNum (24, 0, 666, 3, 1);
1561 Sbar_DrawPic (0, 0, sb_disc);
1565 if (gamemode == GAME_ROGUE)
1567 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1568 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1569 Sbar_DrawPic (0, 0, sb_armor[2]);
1570 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1571 Sbar_DrawPic (0, 0, sb_armor[1]);
1572 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1573 Sbar_DrawPic (0, 0, sb_armor[0]);
1577 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1578 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1579 Sbar_DrawPic (0, 0, sb_armor[2]);
1580 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1581 Sbar_DrawPic (0, 0, sb_armor[1]);
1582 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1583 Sbar_DrawPic (0, 0, sb_armor[0]);
1592 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1595 if (gamemode == GAME_ROGUE)
1597 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1598 Sbar_DrawPic (224, 0, sb_ammo[0]);
1599 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1600 Sbar_DrawPic (224, 0, sb_ammo[1]);
1601 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1602 Sbar_DrawPic (224, 0, sb_ammo[2]);
1603 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1604 Sbar_DrawPic (224, 0, sb_ammo[3]);
1605 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1606 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1607 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1608 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1609 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1610 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1614 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1615 Sbar_DrawPic (224, 0, sb_ammo[0]);
1616 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1617 Sbar_DrawPic (224, 0, sb_ammo[1]);
1618 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1619 Sbar_DrawPic (224, 0, sb_ammo[2]);
1620 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1621 Sbar_DrawPic (224, 0, sb_ammo[3]);
1624 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1626 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1627 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1629 if (gamemode == GAME_TRANSFUSION)
1630 Sbar_MiniDeathmatchOverlay (0, 0);
1632 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1641 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1643 pic = Draw_CachePic (va("gfx/crosshair%i", crosshair.integer));
1644 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);
1647 if (cl_prydoncursor.integer)
1648 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);
1651 //=============================================================================
1655 Sbar_DeathmatchOverlay
1659 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1662 qboolean myself = false;
1664 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1666 if((s - cl.scores) == cl.playerentity - 1)
1668 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1669 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1672 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1674 if (s->qw_spectator)
1676 if (s->qw_ping || s->qw_packetloss)
1677 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 );
1679 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 );
1683 // draw colors behind score
1689 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1690 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);
1691 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1692 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);
1694 //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);
1695 if (s->qw_ping || s->qw_packetloss)
1696 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 );
1698 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 );
1703 if (s->qw_spectator)
1705 if (s->qw_ping || s->qw_packetloss)
1706 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 );
1708 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 );
1712 // draw colors behind score
1713 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1714 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);
1715 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1716 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);
1718 //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);
1719 if (s->qw_ping || s->qw_packetloss)
1720 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 );
1722 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 );
1728 void Sbar_DeathmatchOverlay (void)
1730 int i, y, xmin, xmax, ymin, ymax;
1732 // request new ping times every two second
1733 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1735 cl.last_ping_request = realtime;
1736 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1738 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1739 MSG_WriteString(&cls.netcon->message, "pings");
1741 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*/)
1743 // 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
1744 static int ping_anyway_counter = 0;
1745 if(cl.parsingtextexpectingpingforscores == 1)
1747 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1748 if(++ping_anyway_counter >= 5)
1749 cl.parsingtextexpectingpingforscores = 0;
1751 if(cl.parsingtextexpectingpingforscores != 1)
1753 ping_anyway_counter = 0;
1754 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1755 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1756 MSG_WriteString(&cls.netcon->message, "ping");
1761 // 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
1762 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1763 MSG_WriteString(&cls.netcon->message, "pings");
1771 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1773 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1774 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)
1776 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)
1777 xmax = vid_conwidth.integer - xmin;
1779 if(gamemode == GAME_NEXUIZ)
1780 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);
1782 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1786 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1788 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 );
1792 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 );
1796 if (Sbar_IsTeammatch ())
1798 // show team scores first
1799 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1800 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1804 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1805 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1810 Sbar_MiniDeathmatchOverlay
1814 void Sbar_MiniDeathmatchOverlay (int x, int y)
1816 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1818 // do not draw this if sbar_miniscoreboard_size is zero
1819 if(sbar_miniscoreboard_size.value == 0)
1821 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1822 if(sbar_miniscoreboard_size.value > 0)
1823 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1828 // decide where to print
1829 if (gamemode == GAME_TRANSFUSION)
1830 numlines = (vid_conwidth.integer - x + 127) / 128;
1832 numlines = (vid_conheight.integer - y + 7) / 8;
1834 // give up if there isn't room
1835 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1839 for (i = 0; i < scoreboardlines; i++)
1840 if (fragsort[i] == cl.playerentity - 1)
1844 range_end = scoreboardlines;
1847 if (gamemode != GAME_TRANSFUSION)
1848 if (Sbar_IsTeammatch ())
1850 // reserve space for the team scores
1851 numlines -= teamlines;
1853 // find first and last player of my team (only draw the team totals and my own team)
1854 range_begin = range_end = i;
1855 myteam = cl.scores[fragsort[i]].colors & 15;
1856 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1858 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1861 // looks better than two players
1871 i = min(i, range_end - numlines);
1872 i = max(i, range_begin);
1874 if (gamemode == GAME_TRANSFUSION)
1876 for (;i < range_end && x < vid_conwidth.integer;i++)
1877 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1881 if(range_end - i < numlines) // won't draw to bottom?
1882 y += 8 * (numlines - (range_end - i)); // bottom align
1883 // show team scores first
1884 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1885 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1887 for (;i < range_end && y < vid_conheight.integer;i++)
1888 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1892 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1894 static int const sortorder[16] =
1913 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1914 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1915 int tc1 = sortorder[t1->colors & 15];
1916 int tc2 = sortorder[t2->colors & 15];
1920 void Sbar_Score (int margin)
1922 int i, me, score, otherleader, place, distribution, minutes, seconds;
1924 int sbar_x_save = sbar_x;
1925 int sbar_y_save = sbar_y;
1927 sbar_y = vid_conheight.value - (32+12);
1930 me = cl.playerentity - 1;
1931 if (me >= 0 && me < cl.maxclients)
1933 if(Sbar_IsTeammatch())
1937 // team1 team3 team4
1941 scoreboard_t *teamcolorsort[16];
1944 for(i = 0; i < teamlines; ++i)
1945 teamcolorsort[i] = &(teams[i]);
1947 // Now sort them by color
1948 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1951 // -12*4: four digits space
1952 place = (teamlines - 1) * (-12 * 4);
1954 for(i = 0; i < teamlines; ++i)
1956 int cindex = teamcolorsort[i]->colors & 15;
1957 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
1958 float cm = max(max(c[0], c[1]), c[2]);
1959 float cr = c[0] / cm;
1960 float cg = c[1] / cm;
1961 float cb = c[2] / cm;
1962 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1964 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1968 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1981 // find leading score other than ourselves, to calculate distribution
1982 // find our place in the scoreboard
1983 score = cl.scores[me].frags;
1984 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1986 if (cl.scores[i].name[0] && i != me)
1988 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1990 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1994 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1996 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1997 else if (place == 2)
1998 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2000 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2001 if (otherleader < 0)
2002 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2003 if (distribution >= 0)
2005 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2006 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2008 else if (distribution >= -5)
2010 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2011 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2015 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2016 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2021 if (cl.statsf[STAT_TIMELIMIT])
2023 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2024 minutes = (int)floor(timeleft / 60);
2025 seconds = (int)(floor(timeleft) - minutes * 60);
2028 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2029 if(sb_colon && sb_colon->tex != r_texture_notexture)
2030 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2031 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2033 else if (minutes >= 1)
2035 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2036 if(sb_colon && sb_colon->tex != r_texture_notexture)
2037 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2038 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2040 else if ((int)(timeleft * 4) & 1)
2041 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2043 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2047 minutes = (int)floor(cl.time / 60);
2048 seconds = (int)(floor(cl.time) - minutes * 60);
2049 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2050 if(sb_colon && sb_colon->tex != r_texture_notexture)
2051 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2052 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2055 sbar_x = sbar_x_save;
2056 sbar_y = sbar_y_save;
2061 Sbar_IntermissionOverlay
2065 void Sbar_IntermissionOverlay (void)
2070 if (cl.gametype == GAME_DEATHMATCH)
2072 Sbar_DeathmatchOverlay ();
2076 sbar_x = (vid_conwidth.integer - 320) >> 1;
2077 sbar_y = (vid_conheight.integer - 200) >> 1;
2079 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2080 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2083 dig = (int)cl.completed_time / 60;
2084 Sbar_DrawNum (160, 64, dig, 3, 0);
2085 num = (int)cl.completed_time - dig*60;
2086 Sbar_DrawPic (234,64,sb_colon);
2087 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2088 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2090 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2091 if (gamemode != GAME_NEXUIZ)
2092 Sbar_DrawPic (232, 104, sb_slash);
2093 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2095 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2096 if (gamemode != GAME_NEXUIZ)
2097 Sbar_DrawPic (232, 144, sb_slash);
2098 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2109 void Sbar_FinaleOverlay (void)
2111 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);