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", true);
158 for (i = 0;i < 10;i++)
159 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
161 somsb_health = Draw_CachePic("gfx/hud_health", true);
162 somsb_ammo[0] = Draw_CachePic("gfx/sb_shells", true);
163 somsb_ammo[1] = Draw_CachePic("gfx/sb_nails", true);
164 somsb_ammo[2] = Draw_CachePic("gfx/sb_rocket", true);
165 somsb_ammo[3] = Draw_CachePic("gfx/sb_cells", true);
166 somsb_armor[0] = Draw_CachePic("gfx/sb_armor1", true);
167 somsb_armor[1] = Draw_CachePic("gfx/sb_armor2", true);
168 somsb_armor[2] = Draw_CachePic("gfx/sb_armor3", true);
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), true);
174 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
175 sb_colon = Draw_CachePic ("gfx/num_colon", true);
177 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
178 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets", true);
179 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
180 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
182 sb_armor[0] = Draw_CachePic ("gfx/sb_armor", true);
186 sb_health = Draw_CachePic ("gfx/sb_health", true);
188 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo", true);
189 sb_items[3] = Draw_CachePic ("gfx/sb_invinc", true);
190 sb_items[4] = Draw_CachePic ("gfx/sb_energy", true);
191 sb_items[5] = Draw_CachePic ("gfx/sb_str", true);
193 sb_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken", true);
194 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost", true);
195 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying", true);
196 sb_items[14] = Draw_CachePic ("gfx/sb_key_carrying", true);
197 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken", true);
198 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost", true);
199 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying", true);
201 sb_sbar = Draw_CachePic("gfx/sbar", true);
202 sb_sbar_minimal = Draw_CachePic("gfx/sbar_minimal", true);
203 sb_sbar_overlay = Draw_CachePic("gfx/sbar_overlay", true);
205 for(i = 0; i < 9;i++)
206 sb_weapons[0][i] = Draw_CachePic(va("gfx/inv_weapon%i",i), true);
208 else if (gamemode == GAME_ZYMOTIC)
210 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center", true);
211 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line", true);
212 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health", true);
213 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip", true);
214 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo", true);
215 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background", true);
216 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1", true);
217 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2", true);
218 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right", true);
222 sb_disc = Draw_CachePic("gfx/disc", true);
224 for (i = 0;i < 10;i++)
226 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
227 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i), true);
230 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
231 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus", true);
233 sb_colon = Draw_CachePic ("gfx/num_colon", true);
234 sb_slash = Draw_CachePic ("gfx/num_slash", true);
236 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun", true);
237 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun", true);
238 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun", true);
239 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun", true);
240 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch", true);
241 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch", true);
242 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng", true);
244 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun", true);
245 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun", true);
246 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun", true);
247 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun", true);
248 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch", true);
249 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch", true);
250 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng", true);
252 for (i = 0;i < 5;i++)
254 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1), true);
255 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1), true);
256 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1), true);
257 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1), true);
258 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1), true);
259 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1), true);
260 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1), true);
263 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
264 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails", true);
265 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
266 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
268 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1", true);
269 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2", true);
270 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3", true);
272 sb_items[0] = Draw_CachePic ("gfx/sb_key1", true);
273 sb_items[1] = Draw_CachePic ("gfx/sb_key2", true);
274 sb_items[2] = Draw_CachePic ("gfx/sb_invis", true);
275 sb_items[3] = Draw_CachePic ("gfx/sb_invuln", true);
276 sb_items[4] = Draw_CachePic ("gfx/sb_suit", true);
277 sb_items[5] = Draw_CachePic ("gfx/sb_quad", true);
279 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1", true);
280 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2", true);
281 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3", true);
282 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4", true);
284 sb_faces[4][0] = Draw_CachePic ("gfx/face1", true);
285 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1", true);
286 sb_faces[3][0] = Draw_CachePic ("gfx/face2", true);
287 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2", true);
288 sb_faces[2][0] = Draw_CachePic ("gfx/face3", true);
289 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3", true);
290 sb_faces[1][0] = Draw_CachePic ("gfx/face4", true);
291 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4", true);
292 sb_faces[0][0] = Draw_CachePic ("gfx/face5", true);
293 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5", true);
295 sb_face_invis = Draw_CachePic ("gfx/face_invis", true);
296 sb_face_invuln = Draw_CachePic ("gfx/face_invul2", true);
297 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2", true);
298 sb_face_quad = Draw_CachePic ("gfx/face_quad", true);
300 sb_sbar = Draw_CachePic ("gfx/sbar", true);
301 sb_ibar = Draw_CachePic ("gfx/ibar", true);
302 sb_scorebar = Draw_CachePic ("gfx/scorebar", true);
304 //MED 01/04/97 added new hipnotic weapons
305 if (gamemode == GAME_HIPNOTIC)
307 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser", true);
308 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir", true);
309 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox", true);
310 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren", true);
311 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox", true);
313 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser", true);
314 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir", true);
315 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox", true);
316 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren", true);
317 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox", true);
319 for (i = 0;i < 5;i++)
321 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1), true);
322 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1), true);
323 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1), true);
324 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1), true);
325 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1), true);
328 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit", true);
329 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld", true);
331 else if (gamemode == GAME_ROGUE)
333 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1", true);
334 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2", true);
336 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava", true);
337 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava", true);
338 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren", true);
339 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock", true);
340 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma", true);
342 rsb_items[0] = Draw_CachePic ("gfx/r_shield1", true);
343 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1", true);
345 // PGM 01/19/97 - team color border
346 rsb_teambord = Draw_CachePic ("gfx/r_teambord", true);
347 // PGM 01/19/97 - team color border
349 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava", true);
350 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti", true);
351 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma", true);
355 sb_ranking = Draw_CachePic ("gfx/ranking", true);
356 sb_complete = Draw_CachePic ("gfx/complete", true);
357 sb_inter = Draw_CachePic ("gfx/inter", true);
358 sb_finale = Draw_CachePic ("gfx/finale", true);
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;
1062 if (newtime >= nexttime)
1064 framerate = framecount / (newtime - lasttime);
1066 nexttime = max(nexttime + 1, lasttime - 1);
1072 if ((red = (calc < 1.0f)))
1073 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1075 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1077 if (showtime.integer)
1078 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1079 if (showdate.integer)
1080 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1081 if (showspeed.integer)
1083 double speed, speedxy, f;
1085 speed = VectorLength(cl.movement_velocity);
1086 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1087 switch(showspeed.integer)
1091 if(gamemode == GAME_NEXUIZ)
1100 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1101 // 1qu=1.5in is for non-Nexuiz only - Nexuiz players are overly large, but 1qu=1in fixes that
1106 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1110 f = 0.0254 * 3.6 * 0.6213711922;
1111 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1115 f = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
1116 if(gamemode != GAME_NEXUIZ) f *= 1.5;
1119 dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1121 if (fpsstring[0] || timestring[0] || datestring[0] || speedstring[0])
1125 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0) + (speedstring[0] != 0));
1126 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1127 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1128 fps_y = vid_conheight.integer - fps_height;
1131 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(fpsstring, 0, true, FONT_INFOBAR) * fps_scalex;
1132 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1134 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1136 DrawQ_String_Font(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1137 fps_y += fps_scaley;
1141 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(timestring, 0, true, FONT_INFOBAR) * fps_scalex;
1142 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1143 DrawQ_String_Font(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1144 fps_y += fps_scaley;
1148 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(datestring, 0, true, FONT_INFOBAR) * fps_scalex;
1149 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1150 DrawQ_String_Font(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1151 fps_y += fps_scaley;
1155 fps_x = vid_conwidth.integer - DrawQ_TextWidth_Font(speedstring, 0, true, FONT_INFOBAR) * fps_scalex;
1156 DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1157 DrawQ_String_Font(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1158 fps_y += fps_scaley;
1163 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)
1166 c2 = bound(0, c2, 1);
1167 c1 = bound(0, c1, 1 - c2);
1169 r[1] = rangey + rangeheight * (c2 + c1);
1170 r[2] = rangey + rangeheight * (c2);
1174 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);
1176 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);
1178 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);
1180 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);
1188 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1189 extern cvar_t v_kicktime;
1190 void Sbar_Score (int margin);
1191 void Sbar_Draw (void)
1195 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1198 Sbar_DrawScoreboard ();
1199 else if (cl.intermission == 1)
1201 if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1203 Sbar_DrawScoreboard();
1206 Sbar_IntermissionOverlay();
1208 else if (cl.intermission == 2)
1209 Sbar_FinaleOverlay();
1210 else if (gamemode == GAME_DELUXEQUAKE)
1213 else if (gamemode == GAME_SOM)
1215 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1216 Sbar_DrawScoreboard ();
1219 // this is the top left of the sbar area
1221 sbar_y = vid_conheight.integer - 24*3;
1224 if (cl.stats[STAT_ARMOR])
1226 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1227 Sbar_DrawPic(0, 0, somsb_armor[2]);
1228 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1229 Sbar_DrawPic(0, 0, somsb_armor[1]);
1230 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1231 Sbar_DrawPic(0, 0, somsb_armor[0]);
1232 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1236 Sbar_DrawPic(0, 24, somsb_health);
1237 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1240 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1241 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1242 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1243 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1244 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1245 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1246 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1247 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1248 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1249 if (cl.stats[STAT_SHELLS])
1250 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1253 else if (gamemode == GAME_NEXUIZ)
1255 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1257 sbar_x = (vid_conwidth.integer - 640)/2;
1258 sbar_y = vid_conheight.integer - 47;
1259 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1260 Sbar_DrawScoreboard ();
1262 else if (sb_lines && sbar_hudselector.integer == 1)
1266 int redflag, blueflag;
1269 sbar_x = (vid_conwidth.integer - 320)/2;
1270 sbar_y = vid_conheight.integer - 24 - 16;
1272 // calculate intensity to draw weapons bar at
1273 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1274 fade = bound(0.7, fade, 1);
1275 for (i = 0; i < 8;i++)
1276 if (cl.stats[STAT_ITEMS] & (1 << i))
1277 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1278 if((cl.stats[STAT_ITEMS] & (1<<12)))
1279 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1282 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1283 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1284 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1285 if (redflag == 3 && blueflag == 3)
1287 // The Impossible Combination[tm]
1288 // Can only happen in Key Hunt mode...
1289 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128), sb_items[14]);
1294 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64), sb_items[redflag+10]);
1296 Sbar_DrawPic (x, (vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128), sb_items[blueflag+14]);
1300 if (cl.stats[STAT_ARMOR] > 0)
1302 Sbar_DrawStretchPic (0, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1303 if(cl.stats[STAT_ARMOR] > 200)
1304 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1305 else if(cl.stats[STAT_ARMOR] > 100)
1306 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1307 else if(cl.stats[STAT_ARMOR] > 50)
1308 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1309 else if(cl.stats[STAT_ARMOR] > 25)
1310 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1312 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1316 if (cl.stats[STAT_HEALTH] != 0)
1318 Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1319 if(cl.stats[STAT_HEALTH] > 200)
1320 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1321 else if(cl.stats[STAT_HEALTH] > 100)
1322 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1323 else if(cl.stats[STAT_HEALTH] > 50)
1324 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1325 else if(cl.stats[STAT_HEALTH] > 25)
1326 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1328 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1332 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1334 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1335 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1336 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1337 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1338 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1339 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1340 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1341 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1342 if(cl.stats[STAT_AMMO] > 10)
1343 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1345 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1348 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1349 Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1352 // The margin can be at most 8 to support 640x480 console size:
1353 // 320 + 2 * (144 + 16) = 640
1359 int redflag, blueflag;
1362 sbar_x = (vid_conwidth.integer - 640)/2;
1363 sbar_y = vid_conheight.integer - 47;
1365 // calculate intensity to draw weapons bar at
1366 fade = 3 - 2 * (cl.time - cl.weapontime);
1369 fade = min(fade, 1);
1370 for (i = 0; i < 8;i++)
1371 if (cl.stats[STAT_ITEMS] & (1 << i))
1372 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1374 if((cl.stats[STAT_ITEMS] & (1<<12)))
1375 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1378 //if (!cl.islocalgame)
1379 // Sbar_DrawFrags ();
1382 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1384 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1387 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1388 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1389 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1390 if (redflag == 3 && blueflag == 3)
1392 // The Impossible Combination[tm]
1393 // Can only happen in Key Hunt mode...
1394 Sbar_DrawPic (x, -179, sb_items[14]);
1399 Sbar_DrawPic (x, -117, sb_items[redflag+10]);
1401 Sbar_DrawPic (x, -177, sb_items[blueflag+14]);
1405 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1408 if(cl.stats[STAT_HEALTH] > 100)
1409 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1410 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1411 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1413 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1415 // AK dont draw ammo for the laser
1416 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1418 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1419 Sbar_DrawPic (519, 0, sb_ammo[0]);
1420 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1421 Sbar_DrawPic (519, 0, sb_ammo[1]);
1422 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1423 Sbar_DrawPic (519, 0, sb_ammo[2]);
1424 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1425 Sbar_DrawPic (519, 0, sb_ammo[3]);
1427 if(cl.stats[STAT_AMMO] <= 10)
1428 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1430 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1435 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1437 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1438 Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1443 // Mini scoreboard uses 12*4 per other team, that is, 144
1444 // pixels when there are four teams...
1445 // Nexuiz by default sets vid_conwidth to 800... makes
1447 // so we need to shift it by 64 pixels to the right to fit
1448 // BUT: then it overlaps with the image that gets drawn
1449 // for viewsize 100! Therefore, just account for 3 teams,
1450 // that is, 96 pixels mini scoreboard size, needing 16 pixels
1454 else if (gamemode == GAME_ZYMOTIC)
1457 float scale = 64.0f / 256.0f;
1458 float kickoffset[3];
1459 VectorClear(kickoffset);
1462 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1463 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1465 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1466 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1467 // left1 16, 48 : 126 -66
1468 // left2 16, 128 : 196 -66
1469 // right 176, 48 : 196 -136
1470 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);
1471 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);
1472 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);
1473 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1475 float scale = 128.0f / 256.0f;
1476 float healthstart, healthheight, healthstarttc, healthendtc;
1477 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1478 float ammostart, ammoheight, ammostarttc, ammoendtc;
1479 float clipstart, clipheight, clipstarttc, clipendtc;
1480 float kickoffset[3], offset;
1481 VectorClear(kickoffset);
1484 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1485 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1487 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1488 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1489 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1490 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);
1491 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);
1492 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);
1493 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);
1494 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1495 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1496 healthstart = 204 - healthheight;
1497 shieldstart = healthstart - shieldheight;
1498 healthstarttc = healthstart * (1.0f / 256.0f);
1499 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1500 shieldstarttc = shieldstart * (1.0f / 256.0f);
1501 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1502 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1503 ammostart = 114 - ammoheight;
1504 ammostarttc = ammostart * (1.0f / 256.0f);
1505 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1506 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1507 clipstart = 190 - clipheight;
1508 clipstarttc = clipstart * (1.0f / 256.0f);
1509 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1510 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);
1511 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);
1512 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);
1513 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);
1514 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1515 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1518 else // Quake and others
1520 sbar_x = (vid_conwidth.integer - 320)/2;
1521 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1522 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1523 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1527 if (gamemode != GAME_GOODVSBAD2)
1528 Sbar_DrawInventory ();
1529 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1533 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1535 if (gamemode != GAME_GOODVSBAD2)
1536 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1537 Sbar_DrawScoreboard ();
1541 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1543 // keys (hipnotic only)
1544 //MED 01/04/97 moved keys here so they would not be overwritten
1545 if (gamemode == GAME_HIPNOTIC)
1547 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1548 Sbar_DrawPic (209, 3, sb_items[0]);
1549 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1550 Sbar_DrawPic (209, 12, sb_items[1]);
1553 if (gamemode != GAME_GOODVSBAD2)
1555 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1557 Sbar_DrawNum (24, 0, 666, 3, 1);
1558 Sbar_DrawPic (0, 0, sb_disc);
1562 if (gamemode == GAME_ROGUE)
1564 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1565 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1566 Sbar_DrawPic (0, 0, sb_armor[2]);
1567 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1568 Sbar_DrawPic (0, 0, sb_armor[1]);
1569 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1570 Sbar_DrawPic (0, 0, sb_armor[0]);
1574 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1575 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1576 Sbar_DrawPic (0, 0, sb_armor[2]);
1577 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1578 Sbar_DrawPic (0, 0, sb_armor[1]);
1579 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1580 Sbar_DrawPic (0, 0, sb_armor[0]);
1589 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1592 if (gamemode == GAME_ROGUE)
1594 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1595 Sbar_DrawPic (224, 0, sb_ammo[0]);
1596 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1597 Sbar_DrawPic (224, 0, sb_ammo[1]);
1598 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1599 Sbar_DrawPic (224, 0, sb_ammo[2]);
1600 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1601 Sbar_DrawPic (224, 0, sb_ammo[3]);
1602 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1603 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1604 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1605 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1606 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1607 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1611 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1612 Sbar_DrawPic (224, 0, sb_ammo[0]);
1613 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1614 Sbar_DrawPic (224, 0, sb_ammo[1]);
1615 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1616 Sbar_DrawPic (224, 0, sb_ammo[2]);
1617 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1618 Sbar_DrawPic (224, 0, sb_ammo[3]);
1621 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1623 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1624 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1626 if (gamemode == GAME_TRANSFUSION)
1627 Sbar_MiniDeathmatchOverlay (0, 0);
1629 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1638 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1640 pic = Draw_CachePic(va("gfx/crosshair%i", crosshair.integer), true);
1641 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);
1644 if (cl_prydoncursor.integer)
1645 DrawQ_Pic((cl.cmd.cursor_screen[0] + 1) * 0.5 * vid_conwidth.integer, (cl.cmd.cursor_screen[1] + 1) * 0.5 * vid_conheight.integer, Draw_CachePic(va("gfx/prydoncursor%03i", cl_prydoncursor.integer), true), 0, 0, 1, 1, 1, 1, 0);
1648 //=============================================================================
1652 Sbar_DeathmatchOverlay
1656 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1659 qboolean myself = false;
1661 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1663 if((s - cl.scores) == cl.playerentity - 1)
1665 if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1666 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1669 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1671 if (s->qw_spectator)
1673 if (s->qw_ping || s->qw_packetloss)
1674 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 );
1676 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 );
1680 // draw colors behind score
1686 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1687 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);
1688 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1689 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);
1691 //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);
1692 if (s->qw_ping || s->qw_packetloss)
1693 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 );
1695 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 );
1700 if (s->qw_spectator)
1702 if (s->qw_ping || s->qw_packetloss)
1703 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 );
1705 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 );
1709 // draw colors behind score
1710 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1711 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);
1712 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1713 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);
1715 //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);
1716 if (s->qw_ping || s->qw_packetloss)
1717 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 );
1719 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 );
1725 void Sbar_DeathmatchOverlay (void)
1727 int i, y, xmin, xmax, ymin, ymax;
1729 // request new ping times every two second
1730 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1732 cl.last_ping_request = realtime;
1733 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1735 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1736 MSG_WriteString(&cls.netcon->message, "pings");
1738 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*/)
1740 // 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
1741 static int ping_anyway_counter = 0;
1742 if(cl.parsingtextexpectingpingforscores == 1)
1744 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1745 if(++ping_anyway_counter >= 5)
1746 cl.parsingtextexpectingpingforscores = 0;
1748 if(cl.parsingtextexpectingpingforscores != 1)
1750 ping_anyway_counter = 0;
1751 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1752 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1753 MSG_WriteString(&cls.netcon->message, "ping");
1758 // 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
1759 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1760 MSG_WriteString(&cls.netcon->message, "pings");
1768 ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1770 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1771 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)
1773 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)
1774 xmax = vid_conwidth.integer - xmin;
1776 if(gamemode == GAME_NEXUIZ)
1777 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);
1779 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1783 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1785 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 );
1789 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 );
1793 if (Sbar_IsTeammatch ())
1795 // show team scores first
1796 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1797 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1801 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1802 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1807 Sbar_MiniDeathmatchOverlay
1811 void Sbar_MiniDeathmatchOverlay (int x, int y)
1813 int i, j, numlines, range_begin, range_end, myteam, teamsep;
1815 // do not draw this if sbar_miniscoreboard_size is zero
1816 if(sbar_miniscoreboard_size.value == 0)
1818 // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1819 if(sbar_miniscoreboard_size.value > 0)
1820 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1825 // decide where to print
1826 if (gamemode == GAME_TRANSFUSION)
1827 numlines = (vid_conwidth.integer - x + 127) / 128;
1829 numlines = (vid_conheight.integer - y + 7) / 8;
1831 // give up if there isn't room
1832 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1836 for (i = 0; i < scoreboardlines; i++)
1837 if (fragsort[i] == cl.playerentity - 1)
1841 range_end = scoreboardlines;
1844 if (gamemode != GAME_TRANSFUSION)
1845 if (Sbar_IsTeammatch ())
1847 // reserve space for the team scores
1848 numlines -= teamlines;
1850 // find first and last player of my team (only draw the team totals and my own team)
1851 range_begin = range_end = i;
1852 myteam = cl.scores[fragsort[i]].colors & 15;
1853 while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1855 while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1858 // looks better than two players
1868 i = min(i, range_end - numlines);
1869 i = max(i, range_begin);
1871 if (gamemode == GAME_TRANSFUSION)
1873 for (;i < range_end && x < vid_conwidth.integer;i++)
1874 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1878 if(range_end - i < numlines) // won't draw to bottom?
1879 y += 8 * (numlines - (range_end - i)); // bottom align
1880 // show team scores first
1881 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1882 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1884 for (;i < range_end && y < vid_conheight.integer;i++)
1885 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1889 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1891 static int const sortorder[16] =
1910 const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1911 const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1912 int tc1 = sortorder[t1->colors & 15];
1913 int tc2 = sortorder[t2->colors & 15];
1917 void Sbar_Score (int margin)
1919 int i, me, score, otherleader, place, distribution, minutes, seconds;
1921 int sbar_x_save = sbar_x;
1922 int sbar_y_save = sbar_y;
1924 sbar_y = vid_conheight.value - (32+12);
1927 me = cl.playerentity - 1;
1928 if (me >= 0 && me < cl.maxclients)
1930 if(Sbar_IsTeammatch())
1934 // team1 team3 team4
1938 scoreboard_t *teamcolorsort[16];
1941 for(i = 0; i < teamlines; ++i)
1942 teamcolorsort[i] = &(teams[i]);
1944 // Now sort them by color
1945 qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1948 // -12*4: four digits space
1949 place = (teamlines - 1) * (-12 * 4);
1951 for(i = 0; i < teamlines; ++i)
1953 int cindex = teamcolorsort[i]->colors & 15;
1954 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
1955 float cm = max(max(c[0], c[1]), c[2]);
1956 float cr = c[0] / cm;
1957 float cg = c[1] / cm;
1958 float cb = c[2] / cm;
1959 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1961 Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1965 Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1978 // find leading score other than ourselves, to calculate distribution
1979 // find our place in the scoreboard
1980 score = cl.scores[me].frags;
1981 for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1983 if (cl.scores[i].name[0] && i != me)
1985 if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1987 if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1991 distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1993 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1994 else if (place == 2)
1995 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
1997 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
1998 if (otherleader < 0)
1999 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2000 if (distribution >= 0)
2002 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2003 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0);
2005 else if (distribution >= -5)
2007 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2008 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0);
2012 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2013 Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0);
2018 if (cl.statsf[STAT_TIMELIMIT])
2020 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2021 minutes = (int)floor(timeleft / 60);
2022 seconds = (int)(floor(timeleft) - minutes * 60);
2025 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2026 if(sb_colon && sb_colon->tex != r_texture_notexture)
2027 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2028 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2030 else if (minutes >= 1)
2032 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0);
2033 if(sb_colon && sb_colon->tex != r_texture_notexture)
2034 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2035 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2037 else if ((int)(timeleft * 4) & 1)
2038 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2040 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2044 minutes = (int)floor(cl.time / 60);
2045 seconds = (int)(floor(cl.time) - minutes * 60);
2046 Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0);
2047 if(sb_colon && sb_colon->tex != r_texture_notexture)
2048 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2049 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2052 sbar_x = sbar_x_save;
2053 sbar_y = sbar_y_save;
2058 Sbar_IntermissionOverlay
2062 void Sbar_IntermissionOverlay (void)
2067 if (cl.gametype == GAME_DEATHMATCH)
2069 Sbar_DeathmatchOverlay ();
2073 sbar_x = (vid_conwidth.integer - 320) >> 1;
2074 sbar_y = (vid_conheight.integer - 200) >> 1;
2076 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2077 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2080 dig = (int)cl.completed_time / 60;
2081 Sbar_DrawNum (160, 64, dig, 3, 0);
2082 num = (int)cl.completed_time - dig*60;
2083 Sbar_DrawPic (234,64,sb_colon);
2084 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2085 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2087 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2088 if (gamemode != GAME_NEXUIZ)
2089 Sbar_DrawPic (232, 104, sb_slash);
2090 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2092 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2093 if (gamemode != GAME_NEXUIZ)
2094 Sbar_DrawPic (232, 144, sb_slash);
2095 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2106 void Sbar_FinaleOverlay (void)
2108 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);