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_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken", true);
177 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost", true);
178 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying", true);
179 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken", true);
180 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost", true);
181 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying", true);
183 sb_sbar = Draw_CachePic("gfx/sbar", true);
184 sb_sbar_minimal = Draw_CachePic("gfx/sbar_minimal", true);
185 sb_sbar_overlay = Draw_CachePic("gfx/sbar_overlay", true);
187 for(i = 0; i < 9;i++)
188 sb_weapons[0][i] = Draw_CachePic(va("gfx/inv_weapon%i",i), true);
190 else if (gamemode == GAME_ZYMOTIC)
192 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center", true);
193 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line", true);
194 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health", true);
195 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip", true);
196 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo", true);
197 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background", true);
198 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1", true);
199 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2", true);
200 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right", true);
204 sb_disc = Draw_CachePic("gfx/disc", true);
206 for (i = 0;i < 10;i++)
208 sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
209 sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i), true);
212 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
213 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus", true);
215 sb_colon = Draw_CachePic ("gfx/num_colon", true);
216 sb_slash = Draw_CachePic ("gfx/num_slash", true);
218 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun", true);
219 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun", true);
220 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun", true);
221 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun", true);
222 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch", true);
223 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch", true);
224 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng", true);
226 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun", true);
227 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun", true);
228 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun", true);
229 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun", true);
230 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch", true);
231 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch", true);
232 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng", true);
234 for (i = 0;i < 5;i++)
236 sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1), true);
237 sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1), true);
238 sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1), true);
239 sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1), true);
240 sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1), true);
241 sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1), true);
242 sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1), true);
245 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
246 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails", true);
247 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
248 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
250 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1", true);
251 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2", true);
252 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3", true);
254 sb_items[0] = Draw_CachePic ("gfx/sb_key1", true);
255 sb_items[1] = Draw_CachePic ("gfx/sb_key2", true);
256 sb_items[2] = Draw_CachePic ("gfx/sb_invis", true);
257 sb_items[3] = Draw_CachePic ("gfx/sb_invuln", true);
258 sb_items[4] = Draw_CachePic ("gfx/sb_suit", true);
259 sb_items[5] = Draw_CachePic ("gfx/sb_quad", true);
261 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1", true);
262 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2", true);
263 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3", true);
264 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4", true);
266 sb_faces[4][0] = Draw_CachePic ("gfx/face1", true);
267 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1", true);
268 sb_faces[3][0] = Draw_CachePic ("gfx/face2", true);
269 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2", true);
270 sb_faces[2][0] = Draw_CachePic ("gfx/face3", true);
271 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3", true);
272 sb_faces[1][0] = Draw_CachePic ("gfx/face4", true);
273 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4", true);
274 sb_faces[0][0] = Draw_CachePic ("gfx/face5", true);
275 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5", true);
277 sb_face_invis = Draw_CachePic ("gfx/face_invis", true);
278 sb_face_invuln = Draw_CachePic ("gfx/face_invul2", true);
279 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2", true);
280 sb_face_quad = Draw_CachePic ("gfx/face_quad", true);
282 sb_sbar = Draw_CachePic ("gfx/sbar", true);
283 sb_ibar = Draw_CachePic ("gfx/ibar", true);
284 sb_scorebar = Draw_CachePic ("gfx/scorebar", true);
286 //MED 01/04/97 added new hipnotic weapons
287 if (gamemode == GAME_HIPNOTIC)
289 hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser", true);
290 hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir", true);
291 hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox", true);
292 hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren", true);
293 hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox", true);
295 hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser", true);
296 hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir", true);
297 hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox", true);
298 hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren", true);
299 hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox", true);
301 for (i = 0;i < 5;i++)
303 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1), true);
304 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1), true);
305 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1), true);
306 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1), true);
307 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1), true);
310 hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit", true);
311 hsb_items[1] = Draw_CachePic ("gfx/sb_eshld", true);
313 else if (gamemode == GAME_ROGUE)
315 rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1", true);
316 rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2", true);
318 rsb_weapons[0] = Draw_CachePic ("gfx/r_lava", true);
319 rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava", true);
320 rsb_weapons[2] = Draw_CachePic ("gfx/r_gren", true);
321 rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock", true);
322 rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma", true);
324 rsb_items[0] = Draw_CachePic ("gfx/r_shield1", true);
325 rsb_items[1] = Draw_CachePic ("gfx/r_agrav1", true);
327 // PGM 01/19/97 - team color border
328 rsb_teambord = Draw_CachePic ("gfx/r_teambord", true);
329 // PGM 01/19/97 - team color border
331 rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava", true);
332 rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti", true);
333 rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma", true);
337 sb_ranking = Draw_CachePic ("gfx/ranking", true);
338 sb_complete = Draw_CachePic ("gfx/complete", true);
339 sb_inter = Draw_CachePic ("gfx/inter", true);
340 sb_finale = Draw_CachePic ("gfx/finale", true);
343 void sbar_shutdown(void)
347 void sbar_newmap(void)
351 void Sbar_Init (void)
353 Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
354 Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
355 Cvar_RegisterVariable(&showfps);
356 Cvar_RegisterVariable(&showtime);
357 Cvar_RegisterVariable(&showtime_format);
358 Cvar_RegisterVariable(&showdate);
359 Cvar_RegisterVariable(&showdate_format);
360 Cvar_RegisterVariable(&sbar_alpha_bg);
361 Cvar_RegisterVariable(&sbar_alpha_fg);
362 Cvar_RegisterVariable(&cl_deathscoreboard);
364 Cvar_RegisterVariable(&crosshair_color_red);
365 Cvar_RegisterVariable(&crosshair_color_green);
366 Cvar_RegisterVariable(&crosshair_color_blue);
367 Cvar_RegisterVariable(&crosshair_color_alpha);
368 Cvar_RegisterVariable(&crosshair_size);
370 R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
374 //=============================================================================
376 // drawing routines are relative to the status bar location
385 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
387 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
390 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
392 DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
399 Draws one solid graphics character
402 void Sbar_DrawCharacter (int x, int y, int num)
404 DrawQ_String (sbar_x + x + 4 , sbar_y + y, va("%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, true);
412 void Sbar_DrawString (int x, int y, char *str)
414 DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, true);
422 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
427 l = sprintf(str, "%i", num);
441 Sbar_DrawPic (x, y, sb_nums[color][frame]);
454 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
459 l = sprintf(str, "%i", num);
464 x += (digits-l) * lettersize;
473 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
480 //=============================================================================
483 int Sbar_IsTeammatch()
485 // currently only nexuiz uses the team score board
486 return ((gamemode == GAME_NEXUIZ)
487 && (teamplay.integer > 0));
495 static int fragsort[MAX_SCOREBOARD];
496 static int scoreboardlines;
498 //[515]: Sbar_GetPlayer for csqc "getplayerkey" func
499 int Sbar_GetPlayer (int index)
504 if(index >= scoreboardlines)
506 index = fragsort[index];
508 if(index >= scoreboardlines)
513 static scoreboard_t teams[MAX_SCOREBOARD];
514 static int teamsort[MAX_SCOREBOARD];
515 static int teamlines;
516 void Sbar_SortFrags (void)
522 for (i=0 ; i<cl.maxclients ; i++)
524 if (cl.scores[i].name[0])
526 fragsort[scoreboardlines] = i;
531 for (i=0 ; i<scoreboardlines ; i++)
532 for (j=0 ; j<scoreboardlines-1-i ; j++)
533 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
536 fragsort[j] = fragsort[j+1];
541 if (Sbar_IsTeammatch ())
543 // now sort players by teams.
544 for (i=0 ; i<scoreboardlines ; i++)
546 for (j=0 ; j<scoreboardlines-1-i ; j++)
548 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
551 fragsort[j] = fragsort[j+1];
557 // calculate team scores
559 for (i=0 ; i<scoreboardlines ; i++)
561 if (color != (cl.scores[fragsort[i]].colors & 15))
563 const char* teamname;
565 color = cl.scores[fragsort[i]].colors & 15;
571 teamname = "^1Red Team";
574 teamname = "^4Blue Team";
577 teamname = "^6Pink Team";
580 teamname = "^3Yellow Team";
583 teamname = "Total Team Score";
586 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
588 teams[teamlines-1].frags = 0;
589 teams[teamlines-1].colors = color + 16 * color;
592 if (cl.scores[fragsort[i]].frags != -666)
594 // do not add spedcators
595 // (ugly hack for nexuiz)
596 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
600 // now sort teams by scores.
601 for (i=0 ; i<teamlines ; i++)
603 for (i=0 ; i<teamlines ; i++)
605 for (j=0 ; j<teamlines-1-i ; j++)
607 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
610 teamsort[j] = teamsort[j+1];
623 void Sbar_SoloScoreboard (void)
626 char str[80], timestr[40];
628 int minutes, seconds;
630 minutes = (int)(cl.time / 60);
631 seconds = (int)(cl.time - 60*floor(cl.time/60));
633 // monsters and secrets are now both on the top row
634 if (gamemode != GAME_NEXUIZ)
635 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i Secrets :%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS], cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
637 // figure out the map's filename without path or extension
638 strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
639 if (strrchr(str, '.'))
640 *(strrchr(str, '.')) = 0;
642 // append a : separator and then the full title
643 strlcat(str, ":", sizeof(str));
644 strlcat(str, cl.levelname, sizeof(str));
646 // make the time string
647 max = 38 - sprintf(timestr, " %i:%02i", minutes, seconds);
649 // if there's a newline character, terminate the string there
650 if (strchr(str, '\n'))
651 *(strchr(str, '\n')) = 0;
653 // pad with spaces to fill the allotted space and append the time
654 i = bound(0, (int)strlen(str), max);
658 strlcat(str, timestr, sizeof(str));
660 // print the line of text
661 Sbar_DrawString(8, 12, str);
665 int minutes, seconds, tens, units;
668 if (gamemode != GAME_NEXUIZ) {
669 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
670 Sbar_DrawString (8, 4, str);
672 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
673 Sbar_DrawString (8, 12, str);
677 minutes = (int)(cl.time / 60);
678 seconds = (int)(cl.time - 60*minutes);
680 units = seconds - 10*tens;
681 sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
682 Sbar_DrawString (184, 4, str);
685 if (gamemode == GAME_NEXUIZ) {
686 l = (int) strlen (cl.worldmodel->name);
687 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
689 l = (int) strlen (cl.levelname);
690 Sbar_DrawString (232 - l*4, 12, cl.levelname);
700 void Sbar_DrawScoreboard (void)
702 Sbar_SoloScoreboard ();
703 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
704 //if (cl.gametype == GAME_DEATHMATCH)
706 Sbar_DeathmatchOverlay ();
709 //=============================================================================
711 // AK to make DrawInventory smaller
712 static void Sbar_DrawWeapon(int nr, float fade, int active)
714 // width = 300, height = 100
715 const int w_width = 300, w_height = 100, w_space = 10;
716 const float w_scale = 0.4;
718 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);
719 //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);
727 void Sbar_DrawInventory (void)
734 if (gamemode == GAME_ROGUE)
736 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
737 Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
739 Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
742 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
745 for (i=0 ; i<7 ; i++)
747 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
749 time = cl.item_gettime[i];
750 flashon = (int)(max(0, cl.time - time)*10);
753 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
759 flashon = (flashon%5) + 2;
761 Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
767 if (gamemode == GAME_HIPNOTIC)
769 int grenadeflashing=0;
770 for (i=0 ; i<4 ; i++)
772 if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
774 time = max(0, cl.item_gettime[hipweapons[i]]);
775 flashon = (int)((cl.time - time)*10);
778 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
784 flashon = (flashon%5) + 2;
786 // check grenade launcher
789 if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
794 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
800 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
802 if (!grenadeflashing)
803 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
806 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
809 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
814 if (gamemode == GAME_ROGUE)
816 // check for powered up weapon.
817 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
819 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
820 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
824 for (i=0 ; i<4 ; i++)
826 sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] );
828 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
830 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
832 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
836 for (i=0 ; i<6 ; i++)
837 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
839 //MED 01/04/97 changed keys
840 if (gamemode != GAME_HIPNOTIC || (i>1))
841 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
844 //MED 01/04/97 added hipnotic items
846 if (gamemode == GAME_HIPNOTIC)
848 for (i=0 ; i<2 ; i++)
849 if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
850 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
853 if (gamemode == GAME_ROGUE)
856 for (i=0 ; i<2 ; i++)
857 if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
858 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
863 for (i=0 ; i<4 ; i++)
864 if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
865 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
869 //=============================================================================
876 void Sbar_DrawFrags (void)
886 l = min(scoreboardlines, 4);
890 for (i = 0;i < l;i++)
896 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
897 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
898 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
899 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
903 sprintf (num, "%3i",f);
905 if (k == cl.viewentity - 1)
907 Sbar_DrawCharacter ( x + 2, -24, 16);
908 Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
910 Sbar_DrawCharacter (x + 8, -24, num[0]);
911 Sbar_DrawCharacter (x + 16, -24, num[1]);
912 Sbar_DrawCharacter (x + 24, -24, num[2]);
917 //=============================================================================
925 void Sbar_DrawFace (void)
929 // PGM 01/19/97 - team color drawing
930 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
931 if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
937 s = &cl.scores[cl.viewentity - 1];
939 Sbar_DrawPic (112, 0, rsb_teambord);
940 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
941 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
942 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
943 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
947 sprintf (num, "%3i",f);
949 if ((s->colors & 0xf0)==0)
952 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
954 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
956 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
960 Sbar_DrawCharacter ( 109, 3, num[0]);
961 Sbar_DrawCharacter ( 116, 3, num[1]);
962 Sbar_DrawCharacter ( 123, 3, num[2]);
967 // PGM 01/19/97 - team color drawing
969 if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
970 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
971 else if (cl.stats[STAT_ITEMS] & IT_QUAD)
972 Sbar_DrawPic (112, 0, sb_face_quad );
973 else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
974 Sbar_DrawPic (112, 0, sb_face_invis );
975 else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
976 Sbar_DrawPic (112, 0, sb_face_invuln);
979 f = cl.stats[STAT_HEALTH] / 20;
981 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
985 void Sbar_ShowFPS(void)
987 float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
991 qboolean red = false;
998 static double nexttime = 0, lasttime = 0;
999 static double framerate = 0;
1000 static int framecount = 0;
1003 if (newtime >= nexttime)
1005 framerate = framecount / (newtime - lasttime);
1007 nexttime = max(nexttime + 1, lasttime - 1);
1013 if ((red = (calc < 1.0f)))
1014 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1016 dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1018 if (showtime.integer)
1019 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1020 if (showdate.integer)
1021 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1022 if (fpsstring[0] || timestring[0])
1026 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
1027 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1028 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1029 fps_y = vid_conheight.integer - fps_height;
1032 fps_x = vid_conwidth.integer - fps_scalex * strlen(fpsstring);
1033 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(fpsstring), fps_scaley, 0, 0, 0, 0.5, 0);
1035 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true);
1037 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1038 fps_y += fps_scaley;
1042 fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
1043 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(timestring), fps_scaley, 0, 0, 0, 0.5, 0);
1044 DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1045 fps_y += fps_scaley;
1049 fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
1050 DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(datestring), fps_scaley, 0, 0, 0, 0.5, 0);
1051 DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1052 fps_y += fps_scaley;
1057 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)
1060 c2 = bound(0, c2, 1);
1061 c1 = bound(0, c1, 1 - c2);
1063 r[1] = rangey + rangeheight * (c2 + c1);
1064 r[2] = rangey + rangeheight * (c2);
1068 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);
1070 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);
1072 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);
1074 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);
1082 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1083 extern cvar_t v_kicktime;
1084 void Sbar_Draw (void)
1088 if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar
1090 if (cl.intermission == 1)
1092 Sbar_IntermissionOverlay();
1095 else if (cl.intermission == 2)
1097 Sbar_FinaleOverlay();
1101 if (gamemode == GAME_NETHERWORLD)
1104 else if (gamemode == GAME_SOM)
1106 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1107 Sbar_DrawScoreboard ();
1110 // this is the top left of the sbar area
1112 sbar_y = vid_conheight.integer - 24*3;
1115 if (cl.stats[STAT_ARMOR])
1117 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1118 Sbar_DrawPic(0, 0, somsb_armor[2]);
1119 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1120 Sbar_DrawPic(0, 0, somsb_armor[1]);
1121 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1122 Sbar_DrawPic(0, 0, somsb_armor[0]);
1123 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1127 Sbar_DrawPic(0, 24, somsb_health);
1128 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1131 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1132 Sbar_DrawPic(0, 48, somsb_ammo[0]);
1133 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1134 Sbar_DrawPic(0, 48, somsb_ammo[1]);
1135 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1136 Sbar_DrawPic(0, 48, somsb_ammo[2]);
1137 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1138 Sbar_DrawPic(0, 48, somsb_ammo[3]);
1139 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1140 if (cl.stats[STAT_SHELLS])
1141 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1144 else if (gamemode == GAME_NEXUIZ)
1146 sbar_y = vid_conheight.integer - 47;
1147 sbar_x = (vid_conwidth.integer - 640)/2;
1149 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1151 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1152 Sbar_DrawScoreboard ();
1158 int redflag, blueflag;
1160 // calculate intensity to draw weapons bar at
1161 fade = 3 - 2 * (cl.time - cl.weapontime);
1164 fade = min(fade, 1);
1165 for (i = 0; i < 8;i++)
1166 if (cl.stats[STAT_ITEMS] & (1 << i))
1167 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1169 if((cl.stats[STAT_ITEMS] & (1<<12)))
1170 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1173 //if (!cl.islocalgame)
1174 // Sbar_DrawFrags ();
1177 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1179 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1182 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1184 Sbar_DrawPic (10 - sbar_x, -85, sb_items[redflag+10]);
1185 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1187 Sbar_DrawPic (10 - sbar_x, -145, sb_items[blueflag+14]);
1190 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1193 if(cl.stats[STAT_HEALTH] > 100)
1194 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1195 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1196 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1198 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1200 // AK dont draw ammo for the laser
1201 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1203 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1204 Sbar_DrawPic (519, 0, sb_ammo[0]);
1205 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1206 Sbar_DrawPic (519, 0, sb_ammo[1]);
1207 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1208 Sbar_DrawPic (519, 0, sb_ammo[2]);
1209 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1210 Sbar_DrawPic (519, 0, sb_ammo[3]);
1212 if(cl.stats[STAT_AMMO] <= 10)
1213 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1215 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1220 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1223 //if (vid_conwidth.integer > 320 && cl.gametype == GAME_DEATHMATCH)
1224 // Sbar_MiniDeathmatchOverlay (0, 17);
1226 else if (gamemode == GAME_ZYMOTIC)
1229 float scale = 64.0f / 256.0f;
1230 float kickoffset[3];
1231 VectorClear(kickoffset);
1234 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1235 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1237 sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1238 sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1239 // left1 16, 48 : 126 -66
1240 // left2 16, 128 : 196 -66
1241 // right 176, 48 : 196 -136
1242 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);
1243 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);
1244 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);
1245 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1247 float scale = 128.0f / 256.0f;
1248 float healthstart, healthheight, healthstarttc, healthendtc;
1249 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1250 float ammostart, ammoheight, ammostarttc, ammoendtc;
1251 float clipstart, clipheight, clipstarttc, clipendtc;
1252 float kickoffset[3], offset;
1253 VectorClear(kickoffset);
1256 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1257 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1259 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1260 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1261 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1262 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);
1263 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);
1264 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);
1265 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);
1266 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1267 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1268 healthstart = 204 - healthheight;
1269 shieldstart = healthstart - shieldheight;
1270 healthstarttc = healthstart * (1.0f / 256.0f);
1271 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1272 shieldstarttc = shieldstart * (1.0f / 256.0f);
1273 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1274 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1275 ammostart = 114 - ammoheight;
1276 ammostarttc = ammostart * (1.0f / 256.0f);
1277 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1278 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1279 clipstart = 190 - clipheight;
1280 clipstarttc = clipstart * (1.0f / 256.0f);
1281 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1282 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);
1283 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);
1284 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);
1285 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);
1286 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1287 DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1290 else // Quake and others
1292 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1293 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1294 //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1295 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1298 sbar_x = (vid_conwidth.integer - 320)/2;
1302 if (gamemode != GAME_GOODVSBAD2)
1303 Sbar_DrawInventory ();
1304 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1308 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1310 if (gamemode != GAME_GOODVSBAD2)
1311 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1312 Sbar_DrawScoreboard ();
1316 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1318 // keys (hipnotic only)
1319 //MED 01/04/97 moved keys here so they would not be overwritten
1320 if (gamemode == GAME_HIPNOTIC)
1322 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1323 Sbar_DrawPic (209, 3, sb_items[0]);
1324 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1325 Sbar_DrawPic (209, 12, sb_items[1]);
1328 if (gamemode != GAME_GOODVSBAD2)
1330 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1332 Sbar_DrawNum (24, 0, 666, 3, 1);
1333 Sbar_DrawPic (0, 0, sb_disc);
1337 if (gamemode == GAME_ROGUE)
1339 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1340 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1341 Sbar_DrawPic (0, 0, sb_armor[2]);
1342 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1343 Sbar_DrawPic (0, 0, sb_armor[1]);
1344 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1345 Sbar_DrawPic (0, 0, sb_armor[0]);
1349 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1350 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1351 Sbar_DrawPic (0, 0, sb_armor[2]);
1352 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1353 Sbar_DrawPic (0, 0, sb_armor[1]);
1354 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1355 Sbar_DrawPic (0, 0, sb_armor[0]);
1364 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1367 if (gamemode == GAME_ROGUE)
1369 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1370 Sbar_DrawPic (224, 0, sb_ammo[0]);
1371 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1372 Sbar_DrawPic (224, 0, sb_ammo[1]);
1373 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1374 Sbar_DrawPic (224, 0, sb_ammo[2]);
1375 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1376 Sbar_DrawPic (224, 0, sb_ammo[3]);
1377 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1378 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1379 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1380 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1381 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1382 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1386 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1387 Sbar_DrawPic (224, 0, sb_ammo[0]);
1388 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1389 Sbar_DrawPic (224, 0, sb_ammo[1]);
1390 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1391 Sbar_DrawPic (224, 0, sb_ammo[2]);
1392 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1393 Sbar_DrawPic (224, 0, sb_ammo[3]);
1396 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1400 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1401 //if (vid_conwidth.integer > 320 && cl.gametype == GAME_DEATHMATCH)
1402 if (!cl.islocalgame && vid_conwidth.integer > 320)
1404 if (gamemode == GAME_TRANSFUSION)
1405 Sbar_MiniDeathmatchOverlay (0, 0);
1407 Sbar_MiniDeathmatchOverlay (324, vid_conheight.integer - sb_lines);
1414 if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1415 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);
1417 if (cl_prydoncursor.integer)
1418 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);
1421 //=============================================================================
1425 Sbar_DeathmatchOverlay
1429 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1433 minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1434 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1436 if (s->qw_spectator)
1438 if (s->qw_ping || s->qw_packetloss)
1439 DrawQ_String(x, y, va("%4i %3i %4i spectator %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1441 DrawQ_String(x, y, va(" %4i spectator %c%s", minutes, (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1445 // draw colors behind score
1446 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1447 DrawQ_Fill(x + 14*8, y+1, 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);
1448 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1449 DrawQ_Fill(x + 14*8, y+4, 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);
1451 //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, NULL, true);
1452 if (s->qw_ping || s->qw_packetloss)
1453 DrawQ_String(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, false );
1455 DrawQ_String(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, false );
1460 if (s->qw_spectator)
1462 if (s->qw_ping || s->qw_packetloss)
1463 DrawQ_String(x, y, va("%4i %3i spect %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1465 DrawQ_String(x, y, va(" spect %c%s", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1469 // draw colors behind score
1470 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1471 DrawQ_Fill(x + 9*8, y+1, 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);
1472 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1473 DrawQ_Fill(x + 9*8, y+4, 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);
1475 //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, NULL, true);
1476 if (s->qw_ping || s->qw_packetloss)
1477 DrawQ_String(x, y, va("%4i %3i %5i %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), (int) s->frags, (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1479 DrawQ_String(x, y, va(" %5i %c%s", (int) s->frags, (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1485 void Sbar_DeathmatchOverlay (void)
1489 // request new ping times every two second
1490 if (cl.last_ping_request < realtime - 2 && cls.netcon)
1492 cl.last_ping_request = realtime;
1493 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1495 MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1496 MSG_WriteString(&cls.netcon->message, "pings");
1498 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)
1500 // 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
1501 static int ping_anyway_counter = 0;
1502 if(cl.parsingtextexpectingpingforscores == 1)
1504 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1505 if(++ping_anyway_counter >= 5)
1506 cl.parsingtextexpectingpingforscores = 0;
1508 if(cl.parsingtextexpectingpingforscores != 1)
1510 ping_anyway_counter = 0;
1511 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1512 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1513 MSG_WriteString(&cls.netcon->message, "ping");
1518 // newer server definitely has pings command, so use it for more efficiency
1519 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1520 MSG_WriteString(&cls.netcon->message, "pings");
1524 DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1530 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1532 x = (vid_conwidth.integer - (26 + 15) * 8) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1533 DrawQ_String(x, y, va("ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1537 x = (vid_conwidth.integer - (16 + 15) * 8) / 2; // 16 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1538 DrawQ_String(x, y, va("ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1542 if (Sbar_IsTeammatch ())
1544 // show team scores first
1545 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1546 y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1550 for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1551 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1556 Sbar_DeathmatchOverlay
1560 void Sbar_MiniDeathmatchOverlay (int x, int y)
1564 // decide where to print
1565 if (gamemode == GAME_TRANSFUSION)
1566 numlines = (vid_conwidth.integer - x + 127) / 128;
1568 numlines = (vid_conheight.integer - y + 7) / 8;
1570 // give up if there isn't room
1571 if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1578 for (i = 0; i < scoreboardlines; i++)
1579 if (fragsort[i] == cl.playerentity - 1)
1584 i = min(i, scoreboardlines - numlines);
1587 if (gamemode == GAME_TRANSFUSION)
1589 for (;i < scoreboardlines && x < vid_conwidth.integer;i++)
1590 x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1594 for (;i < scoreboardlines && y < vid_conheight.integer;i++)
1595 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1601 Sbar_IntermissionOverlay
1605 void Sbar_IntermissionOverlay (void)
1610 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1611 //if (cl.gametype == GAME_DEATHMATCH)
1612 if (!cl.islocalgame)
1614 Sbar_DeathmatchOverlay ();
1618 sbar_x = (vid_conwidth.integer - 320) >> 1;
1619 sbar_y = (vid_conheight.integer - 200) >> 1;
1621 DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1622 DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1625 dig = (int)cl.completed_time / 60;
1626 Sbar_DrawNum (160, 64, dig, 3, 0);
1627 num = (int)cl.completed_time - dig*60;
1628 if (gamemode != GAME_NEXUIZ)
1629 Sbar_DrawPic (234,64,sb_colon);
1630 Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1631 Sbar_DrawPic (266,64,sb_nums[0][num%10]);
1633 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1634 if (gamemode != GAME_NEXUIZ)
1635 Sbar_DrawPic (232, 104, sb_slash);
1636 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1638 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1639 if (gamemode != GAME_NEXUIZ)
1640 Sbar_DrawPic (232, 144, sb_slash);
1641 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1652 void Sbar_FinaleOverlay (void)
1654 DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);