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];
47 cachepic_t *sb_face_invis;
48 cachepic_t *sb_face_quad;
49 cachepic_t *sb_face_invuln;
50 cachepic_t *sb_face_invis_invuln;
52 qboolean sb_showscores;
54 int sb_lines; // scan lines to draw
56 cachepic_t *rsb_invbar[2];
57 cachepic_t *rsb_weapons[5];
58 cachepic_t *rsb_items[2];
59 cachepic_t *rsb_ammo[3];
60 cachepic_t *rsb_teambord; // PGM 01/19/97 - team color border
62 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
63 cachepic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
64 //MED 01/04/97 added array to simplify weapon parsing
65 int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
66 //MED 01/04/97 added hipnotic items array
67 cachepic_t *hsb_items[2];
70 cachepic_t *somsb_health;
71 cachepic_t *somsb_ammo[4];
72 cachepic_t *somsb_armor[3];
74 cachepic_t *zymsb_crosshair_center;
75 cachepic_t *zymsb_crosshair_line;
76 cachepic_t *zymsb_crosshair_health;
77 cachepic_t *zymsb_crosshair_ammo;
78 cachepic_t *zymsb_crosshair_clip;
79 cachepic_t *zymsb_crosshair_background;
80 cachepic_t *zymsb_crosshair_left1;
81 cachepic_t *zymsb_crosshair_left2;
82 cachepic_t *zymsb_crosshair_right;
84 cachepic_t *sb_ranking;
85 cachepic_t *sb_complete;
87 cachepic_t *sb_finale;
89 cvar_t showfps = {CVAR_SAVE, "showfps", "0", "shows your rendered fps (frames per second)"};
90 cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"};
91 cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"};
92 cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"};
93 cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"};
94 cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
95 cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
97 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
99 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
100 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
101 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
102 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
103 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
105 void Sbar_MiniDeathmatchOverlay (int x, int y);
106 void Sbar_DeathmatchOverlay (void);
107 void Sbar_IntermissionOverlay (void);
108 void Sbar_FinaleOverlay (void);
118 void Sbar_ShowScores (void)
122 sb_showscores = true;
132 void Sbar_DontShowScores (void)
134 sb_showscores = false;
137 void sbar_start(void)
141 if (gamemode == GAME_NETHERWORLD)
144 else if (gamemode == GAME_SOM)
146 sb_disc = Draw_CachePic("gfx/disc", true);
148 for (i = 0;i < 10;i++)
149 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
151 somsb_health = Draw_CachePic("gfx/hud_health", true);
152 somsb_ammo[0] = Draw_CachePic("gfx/sb_shells", true);
153 somsb_ammo[1] = Draw_CachePic("gfx/sb_nails", true);
154 somsb_ammo[2] = Draw_CachePic("gfx/sb_rocket", true);
155 somsb_ammo[3] = Draw_CachePic("gfx/sb_cells", true);
156 somsb_armor[0] = Draw_CachePic("gfx/sb_armor1", true);
157 somsb_armor[1] = Draw_CachePic("gfx/sb_armor2", true);
158 somsb_armor[2] = Draw_CachePic("gfx/sb_armor3", true);
160 else if (gamemode == GAME_NEXUIZ)
162 for (i = 0;i < 10;i++)
163 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
164 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
166 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
167 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets", true);
168 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
169 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
171 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo", true);
172 sb_items[3] = Draw_CachePic ("gfx/sb_invinc", true);
173 sb_items[4] = Draw_CachePic ("gfx/sb_energy", true);
174 sb_items[5] = Draw_CachePic ("gfx/sb_str", true);
176 sb_sbar = Draw_CachePic("gfx/sbar", true);
177 sb_sbar_minimal = Draw_CachePic("gfx/sbar_minimal", true);
178 sb_sbar_overlay = Draw_CachePic("gfx/sbar_overlay", true);
180 for(i = 0; i < 9;i++)
181 sb_weapons[0][i] = Draw_CachePic(va("gfx/inv_weapon%i",i), true);
183 else if (gamemode == GAME_ZYMOTIC)
185 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center", true);
186 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line", true);
187 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health", true);
188 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip", true);
189 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo", true);
190 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background", true);
191 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1", true);
192 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2", true);
193 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right", true);
197 sb_disc = Draw_CachePic("gfx/disc", true);
199 for (i = 0;i < 10;i++)
201 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
202 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i), true);
205 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
206 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus", true);
208 sb_colon = Draw_CachePic ("gfx/num_colon", true);
209 sb_slash = Draw_CachePic ("gfx/num_slash", true);
211 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun", true);
212 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun", true);
213 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun", true);
214 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun", true);
215 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch", true);
216 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch", true);
217 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng", true);
219 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun", true);
220 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun", true);
221 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun", true);
222 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun", true);
223 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch", true);
224 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch", true);
225 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng", true);
227 for (i = 0;i < 5;i++)
229 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1), true);
230 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1), true);
231 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1), true);
232 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1), true);
233 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1), true);
234 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1), true);
235 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1), true);
238 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
239 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails", true);
240 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
241 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
243 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1", true);
244 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2", true);
245 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3", true);
247 sb_items[0] = Draw_CachePic ("gfx/sb_key1", true);
248 sb_items[1] = Draw_CachePic ("gfx/sb_key2", true);
249 sb_items[2] = Draw_CachePic ("gfx/sb_invis", true);
250 sb_items[3] = Draw_CachePic ("gfx/sb_invuln", true);
251 sb_items[4] = Draw_CachePic ("gfx/sb_suit", true);
252 sb_items[5] = Draw_CachePic ("gfx/sb_quad", true);
254 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1", true);
255 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2", true);
256 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3", true);
257 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4", true);
259 sb_faces[4][0] = Draw_CachePic ("gfx/face1", true);
260 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1", true);
261 sb_faces[3][0] = Draw_CachePic ("gfx/face2", true);
262 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2", true);
263 sb_faces[2][0] = Draw_CachePic ("gfx/face3", true);
264 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3", true);
265 sb_faces[1][0] = Draw_CachePic ("gfx/face4", true);
266 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4", true);
267 sb_faces[0][0] = Draw_CachePic ("gfx/face5", true);
268 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5", true);
270 sb_face_invis = Draw_CachePic ("gfx/face_invis", true);
271 sb_face_invuln = Draw_CachePic ("gfx/face_invul2", true);
272 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2", true);
273 sb_face_quad = Draw_CachePic ("gfx/face_quad", true);
275 sb_sbar = Draw_CachePic ("gfx/sbar", true);
276 sb_ibar = Draw_CachePic ("gfx/ibar", true);
277 sb_scorebar = Draw_CachePic ("gfx/scorebar", true);
279 //MED 01/04/97 added new hipnotic weapons
280 if (gamemode == GAME_HIPNOTIC)
282 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser", true);
283 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir", true);
284 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox", true);
285 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren", true);
286 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox", true);
288 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser", true);
289 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir", true);
290 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox", true);
291 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren", true);
292 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox", true);
294 for (i = 0;i < 5;i++)
296 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1), true);
297 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1), true);
298 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1), true);
299 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1), true);
300 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1), true);
303 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit", true);
304 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld", true);
306 else if (gamemode == GAME_ROGUE)
308 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1", true);
309 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2", true);
311 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava", true);
312 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava", true);
313 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren", true);
314 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock", true);
315 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma", true);
317 rsb_items[0] = Draw_CachePic ("gfx/r_shield1", true);
318 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1", true);
320 // PGM 01/19/97 - team color border
321 rsb_teambord = Draw_CachePic ("gfx/r_teambord", true);
322 // PGM 01/19/97 - team color border
324 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava", true);
325 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti", true);
326 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma", true);
330 sb_ranking = Draw_CachePic ("gfx/ranking", true);
331 sb_complete = Draw_CachePic ("gfx/complete", true);
332 sb_inter = Draw_CachePic ("gfx/inter", true);
333 sb_finale = Draw_CachePic ("gfx/finale", true);
336 void sbar_shutdown(void)
340 void sbar_newmap(void)
344 void Sbar_Init (void)
346 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
347 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
348 Cvar_RegisterVariable(&showfps);
349 Cvar_RegisterVariable(&showtime);
350 Cvar_RegisterVariable(&showtime_format);
351 Cvar_RegisterVariable(&showdate);
352 Cvar_RegisterVariable(&showdate_format);
353 Cvar_RegisterVariable(&sbar_alpha_bg);
354 Cvar_RegisterVariable(&sbar_alpha_fg);
355 Cvar_RegisterVariable(&cl_deathscoreboard);
357 Cvar_RegisterVariable(&crosshair_color_red);
358 Cvar_RegisterVariable(&crosshair_color_green);
359 Cvar_RegisterVariable(&crosshair_color_blue);
360 Cvar_RegisterVariable(&crosshair_color_alpha);
361 Cvar_RegisterVariable(&crosshair_size);
363 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
367 //=============================================================================
369 // drawing routines are relative to the status bar location
378 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
380 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
383 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
385 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
392 Draws one solid graphics character
395 void Sbar_DrawCharacter (int x, int y, int num)
397 DrawQ_String (sbar_x + x + 4 , sbar_y + y, va("%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0);
405 void Sbar_DrawString (int x, int y, char *str)
407 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0);
415 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
420 l = sprintf(str, "%i", num);
434 Sbar_DrawPic (x, y, sb_nums[color][frame]);
447 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
452 l = sprintf(str, "%i", num);
457 x += (digits-l) * lettersize;
466 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
473 //=============================================================================
476 int Sbar_IsTeammatch()
478 // currently only nexuiz uses the team score board
479 return ((gamemode == GAME_NEXUIZ)
480 && (teamplay.integer > 0));
488 static int fragsort[MAX_SCOREBOARD];
489 static int scoreboardlines;
491 //[515]: Sbar_GetPlayer for csqc "getplayerkey" func
492 int Sbar_GetPlayer (int index)
497 if(index >= scoreboardlines)
499 index = fragsort[index];
501 if(index >= scoreboardlines)
506 static scoreboard_t teams[MAX_SCOREBOARD];
507 static int teamsort[MAX_SCOREBOARD];
508 static int teamlines;
509 void Sbar_SortFrags (void)
515 for (i=0 ; i<cl.maxclients ; i++)
517 if (cl.scores[i].name[0])
519 fragsort[scoreboardlines] = i;
524 for (i=0 ; i<scoreboardlines ; i++)
525 for (j=0 ; j<scoreboardlines-1-i ; j++)
526 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
529 fragsort[j] = fragsort[j+1];
534 if (Sbar_IsTeammatch ())
536 // now sort players by teams.
537 for (i=0 ; i<scoreboardlines ; i++)
539 for (j=0 ; j<scoreboardlines-1-i ; j++)
541 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
544 fragsort[j] = fragsort[j+1];
550 // calculate team scores
552 for (i=0 ; i<scoreboardlines ; i++)
554 if (color != (cl.scores[fragsort[i]].colors & 15))
556 color = cl.scores[fragsort[i]].colors & 15;
560 strcpy(teams[teamlines-1].name, "^1Red Team");
561 else if (color == 13)
562 strcpy(teams[teamlines-1].name, "^4Blue Team");
564 strcpy(teams[teamlines-1].name, "^6Pink Team");
565 else if (color == 12)
566 strcpy(teams[teamlines-1].name, "^3Yellow Team");
568 strcpy(teams[teamlines-1].name, "Total Team Score");
570 teams[teamlines-1].frags = 0;
571 teams[teamlines-1].colors = color + 16 * color;
574 if (cl.scores[fragsort[i]].frags != -666)
576 // do not add spedcators
577 // (ugly hack for nexuiz)
578 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
582 // now sort teams by scores.
583 for (i=0 ; i<teamlines ; i++)
585 for (i=0 ; i<teamlines ; i++)
587 for (j=0 ; j<teamlines-1-i ; j++)
589 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
592 teamsort[j] = teamsort[j+1];
605 void Sbar_SoloScoreboard (void)
608 int minutes, seconds, tens, units;
611 if (gamemode != GAME_NEXUIZ) {
612 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
613 Sbar_DrawString (8, 4, str);
615 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
616 Sbar_DrawString (8, 12, str);
620 minutes = (int)(cl.time / 60);
621 seconds = (int)(cl.time - 60*minutes);
623 units = seconds - 10*tens;
624 sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
625 Sbar_DrawString (184, 4, str);
628 if (gamemode == GAME_NEXUIZ) {
629 l = (int) strlen (cl.worldmodel->name);
630 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
632 l = (int) strlen (cl.levelname);
633 Sbar_DrawString (232 - l*4, 12, cl.levelname);
642 void Sbar_DrawScoreboard (void)
644 Sbar_SoloScoreboard ();
645 if (cl.gametype == GAME_DEATHMATCH)
646 Sbar_DeathmatchOverlay ();
649 //=============================================================================
651 // AK to make DrawInventory smaller
652 static void Sbar_DrawWeapon(int nr, float fade, int active)
654 // width = 300, height = 100
655 const int w_width = 300, w_height = 100, w_space = 10;
656 const float w_scale = 0.4;
658 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_ADDITIVE);
659 //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);
662 DrawQ_Pic(vid_conwidth.integer - (w_width + w_space) * w_scale, (w_height + w_space) * w_scale * nr + w_space, NULL, w_width * w_scale, w_height * w_scale, 0.3, 0.3, 0.3, fade * sbar_alpha_fg.value, DRAWFLAG_ADDITIVE);
670 void Sbar_DrawInventory (void)
677 if (gamemode == GAME_ROGUE)
679 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
680 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
682 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
685 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
688 for (i=0 ; i<7 ; i++)
690 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
692 time = cl.item_gettime[i];
693 flashon = (int)((cl.time - time)*10);
696 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
702 flashon = (flashon%5) + 2;
704 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
710 if (gamemode == GAME_HIPNOTIC)
712 int grenadeflashing=0;
713 for (i=0 ; i<4 ; i++)
715 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
717 time = cl.item_gettime[hipweapons[i]];
718 flashon = (int)((cl.time - time)*10);
721 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
727 flashon = (flashon%5) + 2;
729 // check grenade launcher
732 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
737 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
743 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
745 if (!grenadeflashing)
746 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
749 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
752 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
757 if (gamemode == GAME_ROGUE)
759 // check for powered up weapon.
760 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
762 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
763 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
767 for (i=0 ; i<4 ; i++)
769 sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] );
771 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
773 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
775 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
779 for (i=0 ; i<6 ; i++)
780 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
782 //MED 01/04/97 changed keys
783 if (gamemode != GAME_HIPNOTIC || (i>1))
784 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
787 //MED 01/04/97 added hipnotic items
789 if (gamemode == GAME_HIPNOTIC)
791 for (i=0 ; i<2 ; i++)
792 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
793 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
796 if (gamemode == GAME_ROGUE)
799 for (i=0 ; i<2 ; i++)
800 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
801 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
806 for (i=0 ; i<4 ; i++)
807 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
808 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
812 //=============================================================================
819 void Sbar_DrawFrags (void)
829 l = min(scoreboardlines, 4);
833 for (i = 0;i < l;i++)
839 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
840 DrawQ_Pic (sbar_x + x + 10, sbar_y - 23, NULL, 28, 4, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
841 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
842 DrawQ_Pic (sbar_x + x + 10, sbar_y + 4 - 23, NULL, 28, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
846 sprintf (num, "%3i",f);
848 if (k == cl.viewentity - 1)
850 Sbar_DrawCharacter ( x + 2, -24, 16);
851 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
853 Sbar_DrawCharacter (x + 8, -24, num[0]);
854 Sbar_DrawCharacter (x + 16, -24, num[1]);
855 Sbar_DrawCharacter (x + 24, -24, num[2]);
860 //=============================================================================
868 void Sbar_DrawFace (void)
872 // PGM 01/19/97 - team color drawing
873 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
874 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
880 s = &cl.scores[cl.viewentity - 1];
882 Sbar_DrawPic (112, 0, rsb_teambord);
883 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
884 DrawQ_Pic (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+3, NULL, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
885 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
886 DrawQ_Pic (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+12, NULL, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
890 sprintf (num, "%3i",f);
892 if ((s->colors & 0xf0)==0)
895 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
897 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
899 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
903 Sbar_DrawCharacter ( 109, 3, num[0]);
904 Sbar_DrawCharacter ( 116, 3, num[1]);
905 Sbar_DrawCharacter ( 123, 3, num[2]);
910 // PGM 01/19/97 - team color drawing
912 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
913 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
914 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
915 Sbar_DrawPic (112, 0, sb_face_quad );
916 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
917 Sbar_DrawPic (112, 0, sb_face_invis );
918 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
919 Sbar_DrawPic (112, 0, sb_face_invuln);
922 f = cl.stats[STAT_HEALTH] / 20;
924 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
928 void Sbar_ShowFPS(void)
930 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
934 qboolean red = false;
941 static double nexttime = 0, lasttime = 0;
942 static double framerate = 0;
943 static int framecount = 0;
945 newtime = Sys_DoubleTime();
946 if (newtime >= nexttime)
948 framerate = framecount / (newtime - lasttime);
950 nexttime = max(nexttime + 1, lasttime - 1);
956 if ((red = (calc < 1.0f)))
957 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
959 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
961 if (showtime.integer)
962 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
963 if (showdate.integer)
964 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
965 if (fpsstring[0] || timestring[0])
969 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
970 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
971 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
972 fps_y = vid_conheight.integer - fps_height;
975 fps_x = vid_conwidth.integer - fps_scalex * strlen(fpsstring);
976 DrawQ_Pic(fps_x, fps_y, NULL, fps_scalex * strlen(fpsstring), fps_scaley, 0, 0, 0, 0.5, 0);
978 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0);
980 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0);
985 fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
986 DrawQ_Pic(fps_x, fps_y, NULL, fps_scalex * strlen(timestring), fps_scaley, 0, 0, 0, 0.5, 0);
987 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0);
992 fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
993 DrawQ_Pic(fps_x, fps_y, NULL, fps_scalex * strlen(datestring), fps_scaley, 0, 0, 0, 0.5, 0);
994 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0);
1000 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)
1003 c2 = bound(0, c2, 1);
1004 c1 = bound(0, c1, 1 - c2);
1006 r[1] = rangey + rangeheight * (c2 + c1);
1007 r[2] = rangey + rangeheight * (c2);
1011 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);
1013 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);
1015 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);
1017 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);
1025 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1026 extern cvar_t v_kicktime;
1027 void Sbar_Draw (void)
1031 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1033 if (cl.intermission == 1)
1035 Sbar_IntermissionOverlay();
1038 else if (cl.intermission == 2)
1040 Sbar_FinaleOverlay();
1044 if (gamemode == GAME_NETHERWORLD)
1047 else if (gamemode == GAME_SOM)
1049 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1050 Sbar_DrawScoreboard ();
1053 // this is the top left of the sbar area
1055 sbar_y = vid_conheight.integer - 24*3;
1058 if (cl.stats[STAT_ARMOR])
1060 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1061 Sbar_DrawPic(0, 0, somsb_armor[2]);
1062 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1063 Sbar_DrawPic(0, 0, somsb_armor[1]);
1064 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1065 Sbar_DrawPic(0, 0, somsb_armor[0]);
1066 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1070 Sbar_DrawPic(0, 24, somsb_health);
1071 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1074 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1075 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1076 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1077 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1078 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1079 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1080 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1081 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1082 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1083 if (cl.stats[STAT_SHELLS])
1084 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1087 else if (gamemode == GAME_NEXUIZ)
1089 sbar_y = vid_conheight.integer - 47;
1090 sbar_x = (vid_conwidth.integer - 640)/2;
1092 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1094 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1095 Sbar_DrawScoreboard ();
1103 // we have a max time 2s (min time = 0)
1104 if ((time = cl.time - cl.weapontime) < 2)
1106 fade = (1.0 - 0.5 * time);
1108 for (i = 0; i < 8;i++)
1109 if (cl.stats[STAT_ITEMS] & (1 << i))
1110 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1112 if((cl.stats[STAT_ITEMS] & (1<<12)))
1113 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1116 //if (!cl.islocalgame)
1117 // Sbar_DrawFrags ();
1120 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1122 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1125 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1127 // Nexuiz has no anum pics
1128 //Sbar_DrawNum (36, 0, 666, 3, 1);
1129 // Nexuiz has no disc pic
1130 //Sbar_DrawPic (0, 0, sb_disc);
1134 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1137 if(cl.stats[STAT_HEALTH] > 100)
1138 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1139 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1140 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1142 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1144 // AK dont draw ammo for the laser
1145 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1147 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1148 Sbar_DrawPic (519, 0, sb_ammo[0]);
1149 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1150 Sbar_DrawPic (519, 0, sb_ammo[1]);
1151 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1152 Sbar_DrawPic (519, 0, sb_ammo[2]);
1153 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1154 Sbar_DrawPic (519, 0, sb_ammo[3]);
1156 if(cl.stats[STAT_AMMO] <= 10)
1157 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1159 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1164 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1167 //if (vid_conwidth.integer > 320 && cl.gametype == GAME_DEATHMATCH)
1168 // Sbar_MiniDeathmatchOverlay (0, 17);
1170 else if (gamemode == GAME_ZYMOTIC)
1173 float scale = 64.0f / 256.0f;
1174 float kickoffset[3];
1175 VectorClear(kickoffset);
1178 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1179 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1181 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1182 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1183 // left1 16, 48 : 126 -66
1184 // left2 16, 128 : 196 -66
1185 // right 176, 48 : 196 -136
1186 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);
1187 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);
1188 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);
1189 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1191 float scale = 128.0f / 256.0f;
1192 float healthstart, healthheight, healthstarttc, healthendtc;
1193 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1194 float ammostart, ammoheight, ammostarttc, ammoendtc;
1195 float clipstart, clipheight, clipstarttc, clipendtc;
1196 float kickoffset[3], offset;
1197 VectorClear(kickoffset);
1200 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1201 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1203 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1204 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1205 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1206 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);
1207 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);
1208 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);
1209 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);
1210 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1211 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1212 healthstart = 204 - healthheight;
1213 shieldstart = healthstart - shieldheight;
1214 healthstarttc = healthstart * (1.0f / 256.0f);
1215 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1216 shieldstarttc = shieldstart * (1.0f / 256.0f);
1217 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1218 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1219 ammostart = 114 - ammoheight;
1220 ammostarttc = ammostart * (1.0f / 256.0f);
1221 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1222 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1223 clipstart = 190 - clipheight;
1224 clipstarttc = clipstart * (1.0f / 256.0f);
1225 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1226 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);
1227 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);
1228 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);
1229 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);
1230 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1231 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1234 else // Quake and others
1236 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1237 if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1240 sbar_x = (vid_conwidth.integer - 320)/2;
1244 if (gamemode != GAME_GOODVSBAD2)
1245 Sbar_DrawInventory ();
1246 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1250 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1252 if (gamemode != GAME_GOODVSBAD2)
1253 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1254 Sbar_DrawScoreboard ();
1258 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1260 // keys (hipnotic only)
1261 //MED 01/04/97 moved keys here so they would not be overwritten
1262 if (gamemode == GAME_HIPNOTIC)
1264 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1265 Sbar_DrawPic (209, 3, sb_items[0]);
1266 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1267 Sbar_DrawPic (209, 12, sb_items[1]);
1270 if (gamemode != GAME_GOODVSBAD2)
1272 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1274 Sbar_DrawNum (24, 0, 666, 3, 1);
1275 Sbar_DrawPic (0, 0, sb_disc);
1279 if (gamemode == GAME_ROGUE)
1281 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1282 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1283 Sbar_DrawPic (0, 0, sb_armor[2]);
1284 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1285 Sbar_DrawPic (0, 0, sb_armor[1]);
1286 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1287 Sbar_DrawPic (0, 0, sb_armor[0]);
1291 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1292 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1293 Sbar_DrawPic (0, 0, sb_armor[2]);
1294 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1295 Sbar_DrawPic (0, 0, sb_armor[1]);
1296 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1297 Sbar_DrawPic (0, 0, sb_armor[0]);
1306 Sbar_DrawNum (154, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1309 if (gamemode == GAME_ROGUE)
1311 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1312 Sbar_DrawPic (224, 0, sb_ammo[0]);
1313 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1314 Sbar_DrawPic (224, 0, sb_ammo[1]);
1315 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1316 Sbar_DrawPic (224, 0, sb_ammo[2]);
1317 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1318 Sbar_DrawPic (224, 0, sb_ammo[3]);
1319 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1320 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1321 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1322 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1323 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1324 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1328 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1329 Sbar_DrawPic (224, 0, sb_ammo[0]);
1330 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1331 Sbar_DrawPic (224, 0, sb_ammo[1]);
1332 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1333 Sbar_DrawPic (224, 0, sb_ammo[2]);
1334 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1335 Sbar_DrawPic (224, 0, sb_ammo[3]);
1338 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1342 if (vid_conwidth.integer > 320 && cl.gametype == GAME_DEATHMATCH)
1344 if (gamemode == GAME_TRANSFUSION)
1345 Sbar_MiniDeathmatchOverlay (0, 0);
1347 Sbar_MiniDeathmatchOverlay (324, vid_conheight.integer - sb_lines);
1354 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1355 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);
1357 if (cl_prydoncursor.integer)
1358 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);
1361 //=============================================================================
1365 Sbar_DeathmatchOverlay
1369 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1373 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : realtime - s->qw_entertime) / 60.0);
1374 if (s->qw_spectator)
1376 if (s->qw_ping || s->qw_packetloss)
1377 DrawQ_ColoredString(x, y, va("%4i %3i %4i spect %-4s %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, cl.qw_teamplay ? s->qw_team : "", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1379 DrawQ_ColoredString(x, y, va(" %4i spect %-4s %c%s", minutes, cl.qw_teamplay ? s->qw_team : "", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1383 // draw colors behind score
1384 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1385 DrawQ_Pic(x + 14*8, y+1, NULL, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1386 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1387 DrawQ_Pic(x + 14*8, y+4, NULL, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1389 //DrawQ_String(x, y, va("%c%4i %s", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1390 if (s->qw_ping || s->qw_packetloss)
1391 DrawQ_ColoredString(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 : "", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1393 DrawQ_ColoredString(x, y, va(" %4i %5i %-4s %c%s", minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1398 void Sbar_DeathmatchOverlay (void)
1402 // request new ping times every two second
1403 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1405 cl.last_ping_request = realtime;
1406 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1408 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1409 MSG_WriteString(&cls.netcon->message, "pings");
1411 else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6 || cls.protocol == PROTOCOL_DARKPLACES7)
1413 // 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
1414 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1415 MSG_WriteString(&cls.netcon->message, "ping");
1419 // newer server definitely has pings command, so use it for more efficiency
1420 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1421 MSG_WriteString(&cls.netcon->message, "pings");
1425 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1430 x = (vid_conwidth.integer - (6 + 18 + 15) * 8) / 2;
1432 DrawQ_ColoredString(x, y, va("ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1435 if (Sbar_IsTeammatch ())
1437 // show team scores first
1438 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1439 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1443 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1444 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1449 Sbar_DeathmatchOverlay
1453 void Sbar_MiniDeathmatchOverlay (int x, int y)
1457 // decide where to print
1458 if (gamemode == GAME_TRANSFUSION)
1459 numlines = (vid_conwidth.integer - x + 127) / 128;
1461 numlines = (vid_conheight.integer - y + 7) / 8;
1463 // give up if there isn't room
1464 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1471 for (i = 0; i < scoreboardlines; i++)
1472 if (fragsort[i] == cl.playerentity - 1)
1477 i = min(i, scoreboardlines - numlines);
1480 if (gamemode == GAME_TRANSFUSION)
1482 for (;i < scoreboardlines && x < vid_conwidth.integer;i++)
1483 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1487 for (;i < scoreboardlines && y < vid_conheight.integer;i++)
1488 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1494 Sbar_IntermissionOverlay
1498 void Sbar_IntermissionOverlay (void)
1503 if (cl.gametype == GAME_DEATHMATCH)
1505 Sbar_DeathmatchOverlay ();
1509 sbar_x = (vid_conwidth.integer - 320) >> 1;
1510 sbar_y = (vid_conheight.integer - 200) >> 1;
1512 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1513 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1516 dig = (int)cl.completed_time / 60;
1517 Sbar_DrawNum (160, 64, dig, 3, 0);
1518 num = (int)cl.completed_time - dig*60;
1519 if (gamemode != GAME_NEXUIZ)
1520 Sbar_DrawPic (234,64,sb_colon);
1521 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1522 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
1524 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1525 if (gamemode != GAME_NEXUIZ)
1526 Sbar_DrawPic (232, 104, sb_slash);
1527 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1529 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1530 if (gamemode != GAME_NEXUIZ)
1531 Sbar_DrawPic (232, 144, sb_slash);
1532 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1543 void Sbar_FinaleOverlay (void)
1545 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);