43888d5e6d6b18261313740a2e2217cf990c0575
[xonotic/darkplaces.git] / sbar.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // sbar.c -- status bar code
21
22 #include "quakedef.h"
23 #include <time.h>
24 #include "cl_collision.h"
25 #include "csprogs.h"
26
27 cachepic_t *sb_disc;
28
29 #define STAT_MINUS 10 // num frame for '-' stats digit
30 cachepic_t *sb_nums[2][11];
31 cachepic_t *sb_colon, *sb_slash;
32 cachepic_t *sb_ibar;
33 cachepic_t *sb_sbar;
34 cachepic_t *sb_scorebar;
35 // AK only used by NEX
36 cachepic_t *sb_sbar_minimal;
37 cachepic_t *sb_sbar_overlay;
38
39 // AK changed the bound to 9
40 cachepic_t *sb_weapons[7][9]; // 0 is active, 1 is owned, 2-5 are flashes
41 cachepic_t *sb_ammo[4];
42 cachepic_t *sb_sigil[4];
43 cachepic_t *sb_armor[3];
44 cachepic_t *sb_items[32];
45
46 // 0-4 are based on health (in 20 increments)
47 // 0 is static, 1 is temporary animation
48 cachepic_t *sb_faces[5][2];
49 cachepic_t *sb_health; // GAME_NEXUIZ
50
51 cachepic_t *sb_face_invis;
52 cachepic_t *sb_face_quad;
53 cachepic_t *sb_face_invuln;
54 cachepic_t *sb_face_invis_invuln;
55
56 qboolean sb_showscores;
57
58 int sb_lines;                   // scan lines to draw
59
60 cachepic_t *rsb_invbar[2];
61 cachepic_t *rsb_weapons[5];
62 cachepic_t *rsb_items[2];
63 cachepic_t *rsb_ammo[3];
64 cachepic_t *rsb_teambord;               // PGM 01/19/97 - team color border
65
66 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
67 cachepic_t *hsb_weapons[7][5];   // 0 is active, 1 is owned, 2-5 are flashes
68 //MED 01/04/97 added array to simplify weapon parsing
69 int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
70 //MED 01/04/97 added hipnotic items array
71 cachepic_t *hsb_items[2];
72
73 cachepic_t *zymsb_crosshair_center;
74 cachepic_t *zymsb_crosshair_line;
75 cachepic_t *zymsb_crosshair_health;
76 cachepic_t *zymsb_crosshair_ammo;
77 cachepic_t *zymsb_crosshair_clip;
78 cachepic_t *zymsb_crosshair_background;
79 cachepic_t *zymsb_crosshair_left1;
80 cachepic_t *zymsb_crosshair_left2;
81 cachepic_t *zymsb_crosshair_right;
82
83 cachepic_t *sb_ranking;
84 cachepic_t *sb_complete;
85 cachepic_t *sb_inter;
86 cachepic_t *sb_finale;
87
88 cvar_t showfps = {CVAR_SAVE, "showfps", "0", "shows your rendered fps (frames per second)"};
89 cvar_t showsound = {CVAR_SAVE, "showsound", "0", "shows number of active sound sources, sound latency, and other statistics"};
90 cvar_t showblur = {CVAR_SAVE, "showblur", "0", "shows the current alpha level of motionblur"};
91 cvar_t showspeed = {CVAR_SAVE, "showspeed", "0", "shows your current speed (qu per second); number selects unit: 1 = qu/s, 2 = m/s, 3 = km/h, 4 = mph, 5 = knots"};
92 cvar_t showtopspeed = {CVAR_SAVE, "showtopspeed", "0", "shows your top speed (kept on screen for max 3 seconds); value -1 takes over the unit from showspeed, otherwise it's an unit number just like in showspeed"};
93 cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"};
94 cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"};
95 cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"};
96 cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"};
97 cvar_t showtex = {0, "showtex", "0", "shows the name of the texture on the crosshair (for map debugging)"};
98 cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
99 cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
100 cvar_t sbar_hudselector = {CVAR_SAVE, "sbar_hudselector", "0", "selects which of the builtin hud layouts to use (meaning is somewhat dependent on gamemode, so nexuiz has a very different set of hud layouts than quake for example)"};
101 cvar_t sbar_scorerank = {CVAR_SAVE, "sbar_scorerank", "1", "shows an overlay for your score (or team score) and rank in the scoreboard"};
102 cvar_t sbar_gametime = {CVAR_SAVE, "sbar_gametime", "1", "shows an overlay for the time left in the current match/level (or current game time if there is no timelimit set)"};
103 cvar_t sbar_miniscoreboard_size = {CVAR_SAVE, "sbar_miniscoreboard_size", "-1", "sets the size of the mini deathmatch overlay in items, or disables it when set to 0, or sets it to a sane default when set to -1"};
104 cvar_t sbar_flagstatus_right = {CVAR_SAVE, "sbar_flagstatus_right", "0", "moves Nexuiz flag status icons to the right"};
105 cvar_t sbar_flagstatus_pos = {CVAR_SAVE, "sbar_flagstatus_pos", "115", "pixel position of the Nexuiz flag status icons, from the bottom"};
106 cvar_t sbar_info_pos = {CVAR_SAVE, "sbar_info_pos", "0", "pixel position of the info strings (such as showfps), from the bottom"};
107
108 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
109
110 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
111 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
112 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
113 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
114 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
115
116 static void Sbar_MiniDeathmatchOverlay (int x, int y);
117 static void Sbar_DeathmatchOverlay (void);
118 static void Sbar_IntermissionOverlay (void);
119 static void Sbar_FinaleOverlay (void);
120
121
122
123 /*
124 ===============
125 Sbar_ShowScores
126
127 Tab key down
128 ===============
129 */
130 static void Sbar_ShowScores (void)
131 {
132         if (sb_showscores)
133                 return;
134         sb_showscores = true;
135         CL_VM_UpdateShowingScoresState(sb_showscores);
136 }
137
138 /*
139 ===============
140 Sbar_DontShowScores
141
142 Tab key up
143 ===============
144 */
145 static void Sbar_DontShowScores (void)
146 {
147         sb_showscores = false;
148         CL_VM_UpdateShowingScoresState(sb_showscores);
149 }
150
151 static void sbar_start(void)
152 {
153         char vabuf[1024];
154         int i;
155
156         if (gamemode == GAME_DELUXEQUAKE || gamemode == GAME_BLOODOMNICIDE)
157         {
158         }
159         else if (gamemode == GAME_NEXUIZ)
160         {
161                 for (i = 0;i < 10;i++)
162                         sb_nums[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/num_%i",i), CACHEPICFLAG_QUIET);
163                 sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET);
164                 sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET);
165
166                 sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
167                 sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_bullets", CACHEPICFLAG_QUIET);
168                 sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
169                 sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
170
171                 sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor", CACHEPICFLAG_QUIET);
172                 sb_armor[1] = NULL;
173                 sb_armor[2] = NULL;
174
175                 sb_health = Draw_CachePic_Flags ("gfx/sb_health", CACHEPICFLAG_QUIET);
176
177                 sb_items[2] = Draw_CachePic_Flags ("gfx/sb_slowmo", CACHEPICFLAG_QUIET);
178                 sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invinc", CACHEPICFLAG_QUIET);
179                 sb_items[4] = Draw_CachePic_Flags ("gfx/sb_energy", CACHEPICFLAG_QUIET);
180                 sb_items[5] = Draw_CachePic_Flags ("gfx/sb_str", CACHEPICFLAG_QUIET);
181
182                 sb_items[11] = Draw_CachePic_Flags ("gfx/sb_flag_red_taken", CACHEPICFLAG_QUIET);
183                 sb_items[12] = Draw_CachePic_Flags ("gfx/sb_flag_red_lost", CACHEPICFLAG_QUIET);
184                 sb_items[13] = Draw_CachePic_Flags ("gfx/sb_flag_red_carrying", CACHEPICFLAG_QUIET);
185                 sb_items[14] = Draw_CachePic_Flags ("gfx/sb_key_carrying", CACHEPICFLAG_QUIET);
186                 sb_items[15] = Draw_CachePic_Flags ("gfx/sb_flag_blue_taken", CACHEPICFLAG_QUIET);
187                 sb_items[16] = Draw_CachePic_Flags ("gfx/sb_flag_blue_lost", CACHEPICFLAG_QUIET);
188                 sb_items[17] = Draw_CachePic_Flags ("gfx/sb_flag_blue_carrying", CACHEPICFLAG_QUIET);
189
190                 sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET);
191                 sb_sbar_minimal = Draw_CachePic_Flags ("gfx/sbar_minimal", CACHEPICFLAG_QUIET);
192                 sb_sbar_overlay = Draw_CachePic_Flags ("gfx/sbar_overlay", CACHEPICFLAG_QUIET);
193
194                 for(i = 0; i < 9;i++)
195                         sb_weapons[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inv_weapon%i",i), CACHEPICFLAG_QUIET);
196         }
197         else if (gamemode == GAME_ZYMOTIC)
198         {
199                 zymsb_crosshair_center = Draw_CachePic_Flags ("gfx/hud/crosshair_center", CACHEPICFLAG_QUIET);
200                 zymsb_crosshair_line = Draw_CachePic_Flags ("gfx/hud/crosshair_line", CACHEPICFLAG_QUIET);
201                 zymsb_crosshair_health = Draw_CachePic_Flags ("gfx/hud/crosshair_health", CACHEPICFLAG_QUIET);
202                 zymsb_crosshair_clip = Draw_CachePic_Flags ("gfx/hud/crosshair_clip", CACHEPICFLAG_QUIET);
203                 zymsb_crosshair_ammo = Draw_CachePic_Flags ("gfx/hud/crosshair_ammo", CACHEPICFLAG_QUIET);
204                 zymsb_crosshair_background = Draw_CachePic_Flags ("gfx/hud/crosshair_background", CACHEPICFLAG_QUIET);
205                 zymsb_crosshair_left1 = Draw_CachePic_Flags ("gfx/hud/crosshair_left1", CACHEPICFLAG_QUIET);
206                 zymsb_crosshair_left2 = Draw_CachePic_Flags ("gfx/hud/crosshair_left2", CACHEPICFLAG_QUIET);
207                 zymsb_crosshair_right = Draw_CachePic_Flags ("gfx/hud/crosshair_right", CACHEPICFLAG_QUIET);
208         }
209         else
210         {
211                 sb_disc = Draw_CachePic_Flags ("gfx/disc", CACHEPICFLAG_QUIET);
212
213                 for (i = 0;i < 10;i++)
214                 {
215                         sb_nums[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/num_%i",i), CACHEPICFLAG_QUIET);
216                         sb_nums[1][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/anum_%i",i), CACHEPICFLAG_QUIET);
217                 }
218
219                 sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET);
220                 sb_nums[1][10] = Draw_CachePic_Flags ("gfx/anum_minus", CACHEPICFLAG_QUIET);
221
222                 sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET);
223                 sb_slash = Draw_CachePic_Flags ("gfx/num_slash", CACHEPICFLAG_QUIET);
224
225                 sb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_shotgun", CACHEPICFLAG_QUIET);
226                 sb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_sshotgun", CACHEPICFLAG_QUIET);
227                 sb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_nailgun", CACHEPICFLAG_QUIET);
228                 sb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_snailgun", CACHEPICFLAG_QUIET);
229                 sb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_rlaunch", CACHEPICFLAG_QUIET);
230                 sb_weapons[0][5] = Draw_CachePic_Flags ("gfx/inv_srlaunch", CACHEPICFLAG_QUIET);
231                 sb_weapons[0][6] = Draw_CachePic_Flags ("gfx/inv_lightng", CACHEPICFLAG_QUIET);
232
233                 sb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_shotgun", CACHEPICFLAG_QUIET);
234                 sb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_sshotgun", CACHEPICFLAG_QUIET);
235                 sb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_nailgun", CACHEPICFLAG_QUIET);
236                 sb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_snailgun", CACHEPICFLAG_QUIET);
237                 sb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_rlaunch", CACHEPICFLAG_QUIET);
238                 sb_weapons[1][5] = Draw_CachePic_Flags ("gfx/inv2_srlaunch", CACHEPICFLAG_QUIET);
239                 sb_weapons[1][6] = Draw_CachePic_Flags ("gfx/inv2_lightng", CACHEPICFLAG_QUIET);
240
241                 for (i = 0;i < 5;i++)
242                 {
243                         sb_weapons[2+i][0] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_shotgun",i+1), CACHEPICFLAG_QUIET);
244                         sb_weapons[2+i][1] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_sshotgun",i+1), CACHEPICFLAG_QUIET);
245                         sb_weapons[2+i][2] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_nailgun",i+1), CACHEPICFLAG_QUIET);
246                         sb_weapons[2+i][3] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_snailgun",i+1), CACHEPICFLAG_QUIET);
247                         sb_weapons[2+i][4] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_rlaunch",i+1), CACHEPICFLAG_QUIET);
248                         sb_weapons[2+i][5] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_srlaunch",i+1), CACHEPICFLAG_QUIET);
249                         sb_weapons[2+i][6] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_lightng",i+1), CACHEPICFLAG_QUIET);
250                 }
251
252                 sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
253                 sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_nails", CACHEPICFLAG_QUIET);
254                 sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET);
255                 sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET);
256
257                 sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor1", CACHEPICFLAG_QUIET);
258                 sb_armor[1] = Draw_CachePic_Flags ("gfx/sb_armor2", CACHEPICFLAG_QUIET);
259                 sb_armor[2] = Draw_CachePic_Flags ("gfx/sb_armor3", CACHEPICFLAG_QUIET);
260
261                 sb_items[0] = Draw_CachePic_Flags ("gfx/sb_key1", CACHEPICFLAG_QUIET);
262                 sb_items[1] = Draw_CachePic_Flags ("gfx/sb_key2", CACHEPICFLAG_QUIET);
263                 sb_items[2] = Draw_CachePic_Flags ("gfx/sb_invis", CACHEPICFLAG_QUIET);
264                 sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invuln", CACHEPICFLAG_QUIET);
265                 sb_items[4] = Draw_CachePic_Flags ("gfx/sb_suit", CACHEPICFLAG_QUIET);
266                 sb_items[5] = Draw_CachePic_Flags ("gfx/sb_quad", CACHEPICFLAG_QUIET);
267
268                 sb_sigil[0] = Draw_CachePic_Flags ("gfx/sb_sigil1", CACHEPICFLAG_QUIET);
269                 sb_sigil[1] = Draw_CachePic_Flags ("gfx/sb_sigil2", CACHEPICFLAG_QUIET);
270                 sb_sigil[2] = Draw_CachePic_Flags ("gfx/sb_sigil3", CACHEPICFLAG_QUIET);
271                 sb_sigil[3] = Draw_CachePic_Flags ("gfx/sb_sigil4", CACHEPICFLAG_QUIET);
272
273                 sb_faces[4][0] = Draw_CachePic_Flags ("gfx/face1", CACHEPICFLAG_QUIET);
274                 sb_faces[4][1] = Draw_CachePic_Flags ("gfx/face_p1", CACHEPICFLAG_QUIET);
275                 sb_faces[3][0] = Draw_CachePic_Flags ("gfx/face2", CACHEPICFLAG_QUIET);
276                 sb_faces[3][1] = Draw_CachePic_Flags ("gfx/face_p2", CACHEPICFLAG_QUIET);
277                 sb_faces[2][0] = Draw_CachePic_Flags ("gfx/face3", CACHEPICFLAG_QUIET);
278                 sb_faces[2][1] = Draw_CachePic_Flags ("gfx/face_p3", CACHEPICFLAG_QUIET);
279                 sb_faces[1][0] = Draw_CachePic_Flags ("gfx/face4", CACHEPICFLAG_QUIET);
280                 sb_faces[1][1] = Draw_CachePic_Flags ("gfx/face_p4", CACHEPICFLAG_QUIET);
281                 sb_faces[0][0] = Draw_CachePic_Flags ("gfx/face5", CACHEPICFLAG_QUIET);
282                 sb_faces[0][1] = Draw_CachePic_Flags ("gfx/face_p5", CACHEPICFLAG_QUIET);
283
284                 sb_face_invis = Draw_CachePic_Flags ("gfx/face_invis", CACHEPICFLAG_QUIET);
285                 sb_face_invuln = Draw_CachePic_Flags ("gfx/face_invul2", CACHEPICFLAG_QUIET);
286                 sb_face_invis_invuln = Draw_CachePic_Flags ("gfx/face_inv2", CACHEPICFLAG_QUIET);
287                 sb_face_quad = Draw_CachePic_Flags ("gfx/face_quad", CACHEPICFLAG_QUIET);
288
289                 sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET);
290                 sb_ibar = Draw_CachePic_Flags ("gfx/ibar", CACHEPICFLAG_QUIET);
291                 sb_scorebar = Draw_CachePic_Flags ("gfx/scorebar", CACHEPICFLAG_QUIET);
292
293         //MED 01/04/97 added new hipnotic weapons
294                 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
295                 {
296                         hsb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_laser", CACHEPICFLAG_QUIET);
297                         hsb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_mjolnir", CACHEPICFLAG_QUIET);
298                         hsb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_gren_prox", CACHEPICFLAG_QUIET);
299                         hsb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_prox_gren", CACHEPICFLAG_QUIET);
300                         hsb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_prox", CACHEPICFLAG_QUIET);
301
302                         hsb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_laser", CACHEPICFLAG_QUIET);
303                         hsb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_mjolnir", CACHEPICFLAG_QUIET);
304                         hsb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_gren_prox", CACHEPICFLAG_QUIET);
305                         hsb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_prox_gren", CACHEPICFLAG_QUIET);
306                         hsb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_prox", CACHEPICFLAG_QUIET);
307
308                         for (i = 0;i < 5;i++)
309                         {
310                                 hsb_weapons[2+i][0] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_laser",i+1), CACHEPICFLAG_QUIET);
311                                 hsb_weapons[2+i][1] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_mjolnir",i+1), CACHEPICFLAG_QUIET);
312                                 hsb_weapons[2+i][2] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_gren_prox",i+1), CACHEPICFLAG_QUIET);
313                                 hsb_weapons[2+i][3] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_prox_gren",i+1), CACHEPICFLAG_QUIET);
314                                 hsb_weapons[2+i][4] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_prox",i+1), CACHEPICFLAG_QUIET);
315                         }
316
317                         hsb_items[0] = Draw_CachePic_Flags ("gfx/sb_wsuit", CACHEPICFLAG_QUIET);
318                         hsb_items[1] = Draw_CachePic_Flags ("gfx/sb_eshld", CACHEPICFLAG_QUIET);
319                 }
320                 else if (gamemode == GAME_ROGUE)
321                 {
322                         rsb_invbar[0] = Draw_CachePic_Flags ("gfx/r_invbar1", CACHEPICFLAG_QUIET);
323                         rsb_invbar[1] = Draw_CachePic_Flags ("gfx/r_invbar2", CACHEPICFLAG_QUIET);
324
325                         rsb_weapons[0] = Draw_CachePic_Flags ("gfx/r_lava", CACHEPICFLAG_QUIET);
326                         rsb_weapons[1] = Draw_CachePic_Flags ("gfx/r_superlava", CACHEPICFLAG_QUIET);
327                         rsb_weapons[2] = Draw_CachePic_Flags ("gfx/r_gren", CACHEPICFLAG_QUIET);
328                         rsb_weapons[3] = Draw_CachePic_Flags ("gfx/r_multirock", CACHEPICFLAG_QUIET);
329                         rsb_weapons[4] = Draw_CachePic_Flags ("gfx/r_plasma", CACHEPICFLAG_QUIET);
330
331                         rsb_items[0] = Draw_CachePic_Flags ("gfx/r_shield1", CACHEPICFLAG_QUIET);
332                         rsb_items[1] = Draw_CachePic_Flags ("gfx/r_agrav1", CACHEPICFLAG_QUIET);
333
334         // PGM 01/19/97 - team color border
335                         rsb_teambord = Draw_CachePic_Flags ("gfx/r_teambord", CACHEPICFLAG_QUIET);
336         // PGM 01/19/97 - team color border
337
338                         rsb_ammo[0] = Draw_CachePic_Flags ("gfx/r_ammolava", CACHEPICFLAG_QUIET);
339                         rsb_ammo[1] = Draw_CachePic_Flags ("gfx/r_ammomulti", CACHEPICFLAG_QUIET);
340                         rsb_ammo[2] = Draw_CachePic_Flags ("gfx/r_ammoplasma", CACHEPICFLAG_QUIET);
341                 }
342         }
343
344         sb_ranking = Draw_CachePic_Flags ("gfx/ranking", CACHEPICFLAG_QUIET);
345         sb_complete = Draw_CachePic_Flags ("gfx/complete", CACHEPICFLAG_QUIET);
346         sb_inter = Draw_CachePic_Flags ("gfx/inter", CACHEPICFLAG_QUIET);
347         sb_finale = Draw_CachePic_Flags ("gfx/finale", CACHEPICFLAG_QUIET);
348 }
349
350 static void sbar_shutdown(void)
351 {
352 }
353
354 static void sbar_newmap(void)
355 {
356 }
357
358 void Sbar_Init (void)
359 {
360         Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
361         Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
362         Cvar_RegisterVariable(&showfps);
363         Cvar_RegisterVariable(&showsound);
364         Cvar_RegisterVariable(&showblur);
365         Cvar_RegisterVariable(&showspeed);
366         Cvar_RegisterVariable(&showtopspeed);
367         Cvar_RegisterVariable(&showtime);
368         Cvar_RegisterVariable(&showtime_format);
369         Cvar_RegisterVariable(&showdate);
370         Cvar_RegisterVariable(&showdate_format);
371         Cvar_RegisterVariable(&showtex);
372         Cvar_RegisterVariable(&sbar_alpha_bg);
373         Cvar_RegisterVariable(&sbar_alpha_fg);
374         Cvar_RegisterVariable(&sbar_hudselector);
375         Cvar_RegisterVariable(&sbar_scorerank);
376         Cvar_RegisterVariable(&sbar_gametime);
377         Cvar_RegisterVariable(&sbar_miniscoreboard_size);
378         Cvar_RegisterVariable(&sbar_info_pos);
379         Cvar_RegisterVariable(&cl_deathscoreboard);
380
381         Cvar_RegisterVariable(&crosshair_color_red);
382         Cvar_RegisterVariable(&crosshair_color_green);
383         Cvar_RegisterVariable(&crosshair_color_blue);
384         Cvar_RegisterVariable(&crosshair_color_alpha);
385         Cvar_RegisterVariable(&crosshair_size);
386
387         Cvar_RegisterVariable(&sbar_flagstatus_right); // (GAME_NEXUZI ONLY)
388         Cvar_RegisterVariable(&sbar_flagstatus_pos); // (GAME_NEXUIZ ONLY)
389
390         R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap, NULL, NULL);
391 }
392
393
394 //=============================================================================
395
396 // drawing routines are relative to the status bar location
397
398 int sbar_x, sbar_y;
399
400 /*
401 =============
402 Sbar_DrawPic
403 =============
404 */
405 static void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
406 {
407         DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0);
408 }
409
410 static void Sbar_DrawPic (int x, int y, cachepic_t *pic)
411 {
412         DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
413 }
414
415 static void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
416 {
417         DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
418 }
419
420 /*
421 ================
422 Sbar_DrawCharacter
423
424 Draws one solid graphics character
425 ================
426 */
427 static void Sbar_DrawCharacter (int x, int y, int num)
428 {
429         char vabuf[1024];
430         DrawQ_String (sbar_x + x + 4 , sbar_y + y, va(vabuf, sizeof(vabuf), "%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, true, FONT_SBAR);
431 }
432
433 /*
434 ================
435 Sbar_DrawString
436 ================
437 */
438 static void Sbar_DrawString (int x, int y, char *str)
439 {
440         DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR);
441 }
442
443 /*
444 =============
445 Sbar_DrawNum
446 =============
447 */
448 static void Sbar_DrawNum (int x, int y, int num, int digits, int color)
449 {
450         char str[32], *ptr;
451         int l, frame;
452
453         l = dpsnprintf(str, sizeof(str), "%i", num);
454         ptr = str;
455         if (l > digits)
456                 ptr += (l-digits);
457         if (l < digits)
458                 x += (digits-l)*24;
459
460         while (*ptr)
461         {
462                 if (*ptr == '-')
463                         frame = STAT_MINUS;
464                 else
465                         frame = *ptr -'0';
466
467                 Sbar_DrawPic (x, y, sb_nums[color][frame]);
468                 x += 24;
469
470                 ptr++;
471         }
472 }
473
474 /*
475 =============
476 Sbar_DrawXNum
477 =============
478 */
479
480 static void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
481 {
482         char str[32], *ptr;
483         int l, frame;
484
485         if (digits < 0)
486         {
487                 digits = -digits;
488                 l = dpsnprintf(str, sizeof(str), "%0*i", digits, num);
489         }
490         else
491                 l = dpsnprintf(str, sizeof(str), "%i", num);
492         ptr = str;
493         if (l > digits)
494                 ptr += (l-digits);
495         if (l < digits)
496                 x += (digits-l) * lettersize;
497
498         while (*ptr)
499         {
500                 if (*ptr == '-')
501                         frame = STAT_MINUS;
502                 else
503                         frame = *ptr -'0';
504
505                 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
506                 x += lettersize;
507
508                 ptr++;
509         }
510 }
511
512 //=============================================================================
513
514
515 static int Sbar_IsTeammatch(void)
516 {
517         // currently only nexuiz uses the team score board
518         return ((gamemode == GAME_NEXUIZ)
519                 && (teamplay.integer > 0));
520 }
521
522 /*
523 ===============
524 Sbar_SortFrags
525 ===============
526 */
527 static int fragsort[MAX_SCOREBOARD];
528 static int scoreboardlines;
529
530 int Sbar_GetSortedPlayerIndex (int index)
531 {
532         return index >= 0 && index < scoreboardlines ? fragsort[index] : -1;
533 }
534
535 static scoreboard_t teams[MAX_SCOREBOARD];
536 static int teamsort[MAX_SCOREBOARD];
537 static int teamlines;
538 void Sbar_SortFrags (void)
539 {
540         int i, j, k, color;
541
542         // sort by frags
543         scoreboardlines = 0;
544         for (i=0 ; i<cl.maxclients ; i++)
545         {
546                 if (cl.scores[i].name[0])
547                 {
548                         fragsort[scoreboardlines] = i;
549                         scoreboardlines++;
550                 }
551         }
552
553         for (i=0 ; i<scoreboardlines ; i++)
554                 for (j=0 ; j<scoreboardlines-1-i ; j++)
555                         if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
556                         {
557                                 k = fragsort[j];
558                                 fragsort[j] = fragsort[j+1];
559                                 fragsort[j+1] = k;
560                         }
561
562         teamlines = 0;
563         if (Sbar_IsTeammatch ())
564         {
565                 // now sort players by teams.
566                 for (i=0 ; i<scoreboardlines ; i++)
567                 {
568                         for (j=0 ; j<scoreboardlines-1-i ; j++)
569                         {
570                                 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
571                                 {
572                                         k = fragsort[j];
573                                         fragsort[j] = fragsort[j+1];
574                                         fragsort[j+1] = k;
575                                 }
576                         }
577                 }
578
579                 // calculate team scores
580                 color = -1;
581                 for (i=0 ; i<scoreboardlines ; i++)
582                 {
583                         if (color != (cl.scores[fragsort[i]].colors & 15))
584                         {
585                                 const char* teamname;
586
587                                 color = cl.scores[fragsort[i]].colors & 15;
588                                 teamlines++;
589
590                                 switch (color)
591                                 {
592                                         case 4:
593                                                 teamname = "^1Red Team";
594                                                 break;
595                                         case 13:
596                                                 teamname = "^4Blue Team";
597                                                 break;
598                                         case 9:
599                                                 teamname = "^6Pink Team";
600                                                 break;
601                                         case 12:
602                                                 teamname = "^3Yellow Team";
603                                                 break;
604                                         default:
605                                                 teamname = "Total Team Score";
606                                                 break;
607                                 }
608                                 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
609
610                                 teams[teamlines-1].frags = 0;
611                                 teams[teamlines-1].colors = color + 16 * color;
612                         }
613
614                         if (cl.scores[fragsort[i]].frags != -666)
615                         {
616                                 // do not add spedcators
617                                 // (ugly hack for nexuiz)
618                                 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
619                         }
620                 }
621
622                 // now sort teams by scores.
623                 for (i=0 ; i<teamlines ; i++)
624                         teamsort[i] = i;
625                 for (i=0 ; i<teamlines ; i++)
626                 {
627                         for (j=0 ; j<teamlines-1-i ; j++)
628                         {
629                                 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
630                                 {
631                                         k = teamsort[j];
632                                         teamsort[j] = teamsort[j+1];
633                                         teamsort[j+1] = k;
634                                 }
635                         }
636                 }
637         }
638 }
639
640 /*
641 ===============
642 Sbar_SoloScoreboard
643 ===============
644 */
645 static void Sbar_SoloScoreboard (void)
646 {
647 #if 1
648         char    str[80], timestr[40];
649         int             max, timelen;
650         int             minutes, seconds;
651         double  t;
652         char vabuf[1024];
653
654         t = (cl.intermission ? cl.completed_time : cl.time);
655         minutes = (int)(t / 60);
656         seconds = (int)(t - 60*floor(t/60));
657
658         // monsters and secrets are now both on the top row
659         if (cl.stats[STAT_TOTALMONSTERS])
660                 Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
661         else if (cl.stats[STAT_MONSTERS]) // LA: Display something if monsters_killed is non-zero, but total_monsters is zero
662                 Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i", cl.stats[STAT_MONSTERS]));
663
664         if (cl.stats[STAT_TOTALSECRETS])
665                 Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
666         else if (cl.stats[STAT_SECRETS]) // LA: And similarly for secrets
667                 Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i", cl.stats[STAT_SECRETS]));
668
669         // format is like this: e1m1:The Sligpate Complex
670         dpsnprintf(str, sizeof(str), "%s:%s", cl.worldbasename, cl.worldmessage);
671
672         // if there's a newline character, terminate the string there
673         if (strchr(str, '\n'))
674                 *(strchr(str, '\n')) = 0;
675
676         // make the time string
677         timelen = dpsnprintf(timestr, sizeof(timestr), " %i:%02i", minutes, seconds);
678
679         // truncate the level name if necessary to make room for time
680         max = 38 - timelen;
681         if ((int)strlen(str) > max)
682                 str[max] = 0;
683
684         // print the filename and message
685         Sbar_DrawString(8, 12, str);
686
687         // print the time
688         Sbar_DrawString(8 + max*8, 12, timestr);
689
690 #else
691         char    str[80];
692         int             minutes, seconds, tens, units;
693         int             l;
694
695         if (gamemode != GAME_NEXUIZ) {
696                 dpsnprintf (str, sizeof(str), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
697                 Sbar_DrawString (8, 4, str);
698
699                 dpsnprintf (str, sizeof(str), "Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
700                 Sbar_DrawString (8, 12, str);
701         }
702
703 // time
704         minutes = (int)(cl.time / 60);
705         seconds = (int)(cl.time - 60*minutes);
706         tens = seconds / 10;
707         units = seconds - 10*tens;
708         dpsnprintf (str, sizeof(str), "Time :%3i:%i%i", minutes, tens, units);
709         Sbar_DrawString (184, 4, str);
710
711 // draw level name
712         if (gamemode == GAME_NEXUIZ) {
713                 l = (int) strlen (cl.worldname);
714                 Sbar_DrawString (232 - l*4, 12, cl.worldname);
715         } else {
716                 l = (int) strlen (cl.worldmessage);
717                 Sbar_DrawString (232 - l*4, 12, cl.worldmessage);
718         }
719 #endif
720 }
721
722 /*
723 ===============
724 Sbar_DrawScoreboard
725 ===============
726 */
727 static void Sbar_DrawScoreboard (void)
728 {
729         Sbar_SoloScoreboard ();
730         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
731         //if (cl.gametype == GAME_DEATHMATCH)
732         if (!cl.islocalgame)
733                 Sbar_DeathmatchOverlay ();
734 }
735
736 //=============================================================================
737
738 // AK to make DrawInventory smaller
739 static void Sbar_DrawWeapon(int nr, float fade, int active)
740 {
741         char vabuf[1024];
742         if (sbar_hudselector.integer == 1)
743         {
744                 // width = 300, height = 100
745                 const int w_width = 32, w_height = 12, w_space = 2, font_size = 8;
746
747                 DrawQ_Pic((vid_conwidth.integer - w_width * 9) * 0.5 + w_width * nr, vid_conheight.integer - w_height, sb_weapons[0][nr], w_width, w_height, (active) ? 1 : 0.6, active ? 1 : 0.6, active ? 1 : 0.6, (active ? 1 : 0.6) * fade * sbar_alpha_fg.value, DRAWFLAG_NORMAL);
748                 // FIXME ??
749                 DrawQ_String((vid_conwidth.integer - w_width * 9) * 0.5 + w_width * nr + w_space, vid_conheight.integer - w_height + w_space, va(vabuf, sizeof(vabuf), "%i",nr+1), 0, font_size, font_size, 1, 1, 0, sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT);
750         }
751         else
752         {
753                 // width = 300, height = 100
754                 const int w_width = 300, w_height = 100, w_space = 10;
755                 const float w_scale = 0.4;
756
757                 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);
758                 //DrawQ_String(vid_conwidth.integer - (w_space + font_size ), (w_height + w_space) * w_scale * nr + w_space, va(vabuf, sizeof(vabuf), "%i",nr+1), 0, font_size, font_size, 1, 0, 0, fade, 0, NULL, true, FONT_DEFAULT);
759         }
760 }
761
762 /*
763 ===============
764 Sbar_DrawInventory
765 ===============
766 */
767 static void Sbar_DrawInventory (void)
768 {
769         int i;
770         char num[6];
771         float time;
772         int flashon;
773
774         if (gamemode == GAME_ROGUE)
775         {
776                 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
777                         Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
778                 else
779                         Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
780         }
781         else
782                 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
783
784         // weapons
785         for (i=0 ; i<7 ; i++)
786         {
787                 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
788                 {
789                         time = cl.item_gettime[i];
790                         flashon = (int)(max(0, cl.time - time)*10);
791                         if (flashon >= 10)
792                         {
793                                 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i)  )
794                                         flashon = 1;
795                                 else
796                                         flashon = 0;
797                         }
798                         else
799                                 flashon = (flashon%5) + 2;
800
801                         Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
802                 }
803         }
804
805         // MED 01/04/97
806         // hipnotic weapons
807         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
808         {
809                 int grenadeflashing=0;
810                 for (i=0 ; i<4 ; i++)
811                 {
812                         if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
813                         {
814                                 time = max(0, cl.item_gettime[hipweapons[i]]);
815                                 flashon = (int)((cl.time - time)*10);
816                                 if (flashon >= 10)
817                                 {
818                                         if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i])  )
819                                                 flashon = 1;
820                                         else
821                                                 flashon = 0;
822                                 }
823                                 else
824                                         flashon = (flashon%5) + 2;
825
826                                 // check grenade launcher
827                                 if (i==2)
828                                 {
829                                         if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
830                                         {
831                                                 if (flashon)
832                                                 {
833                                                         grenadeflashing = 1;
834                                                         Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
835                                                 }
836                                         }
837                                 }
838                                 else if (i==3)
839                                 {
840                                         if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
841                                         {
842                                                 if (!grenadeflashing)
843                                                         Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
844                                         }
845                                         else
846                                                 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
847                                 }
848                                 else
849                                         Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
850                         }
851                 }
852         }
853
854         if (gamemode == GAME_ROGUE)
855         {
856                 // check for powered up weapon.
857                 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
858                         for (i=0;i<5;i++)
859                                 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
860                                         Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
861         }
862
863         // ammo counts
864         for (i=0 ; i<4 ; i++)
865         {
866                 dpsnprintf (num, sizeof(num), "%4i",cl.stats[STAT_SHELLS+i] );
867                 if (num[0] != ' ')
868                         Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0');
869                 if (num[1] != ' ')
870                         Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0');
871                 if (num[2] != ' ')
872                         Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0');
873                 if (num[3] != ' ')
874                         Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0');
875         }
876
877         // items
878         for (i=0 ; i<6 ; i++)
879                 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
880                 {
881                         //MED 01/04/97 changed keys
882                         if (!(gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH) || (i>1))
883                                 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
884                 }
885
886         //MED 01/04/97 added hipnotic items
887         // hipnotic items
888         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
889         {
890                 for (i=0 ; i<2 ; i++)
891                         if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
892                                 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
893         }
894
895         if (gamemode == GAME_ROGUE)
896         {
897                 // new rogue items
898                 for (i=0 ; i<2 ; i++)
899                         if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
900                                 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
901         }
902         else
903         {
904                 // sigils
905                 for (i=0 ; i<4 ; i++)
906                         if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
907                                 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
908         }
909 }
910
911 //=============================================================================
912
913 /*
914 ===============
915 Sbar_DrawFrags
916 ===============
917 */
918 static void Sbar_DrawFrags (void)
919 {
920         int i, k, l, x, f;
921         char num[12];
922         scoreboard_t *s;
923         unsigned char *c;
924
925         Sbar_SortFrags ();
926
927         // draw the text
928         l = min(scoreboardlines, 4);
929
930         x = 23 * 8;
931
932         for (i = 0;i < l;i++)
933         {
934                 k = fragsort[i];
935                 s = &cl.scores[k];
936
937                 // draw background
938                 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
939                 DrawQ_Fill (sbar_x + x + 10, sbar_y     - 23, 28, 4, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
940                 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
941                 DrawQ_Fill (sbar_x + x + 10, sbar_y + 4 - 23, 28, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
942
943                 // draw number
944                 f = s->frags;
945                 dpsnprintf (num, sizeof(num), "%3i",f);
946
947                 if (k == cl.viewentity - 1)
948                 {
949                         Sbar_DrawCharacter ( x      + 2, -24, 16);
950                         Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
951                 }
952                 Sbar_DrawCharacter (x +  8, -24, num[0]);
953                 Sbar_DrawCharacter (x + 16, -24, num[1]);
954                 Sbar_DrawCharacter (x + 24, -24, num[2]);
955                 x += 32;
956         }
957 }
958
959 //=============================================================================
960
961
962 /*
963 ===============
964 Sbar_DrawFace
965 ===============
966 */
967 static void Sbar_DrawFace (void)
968 {
969         int f;
970
971 // PGM 01/19/97 - team color drawing
972 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
973         if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
974         {
975                 char num[12];
976                 scoreboard_t *s;
977                 unsigned char *c;
978
979                 s = &cl.scores[cl.viewentity - 1];
980                 // draw background
981                 Sbar_DrawPic (112, 0, rsb_teambord);
982                 c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
983                 DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+3, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
984                 c = palette_rgb_shirtscoreboard[s->colors & 0xf];
985                 DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+12, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
986
987                 // draw number
988                 f = s->frags;
989                 dpsnprintf (num, sizeof(num), "%3i",f);
990
991                 if ((s->colors & 0xf0)==0)
992                 {
993                         if (num[0] != ' ')
994                                 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
995                         if (num[1] != ' ')
996                                 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
997                         if (num[2] != ' ')
998                                 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
999                 }
1000                 else
1001                 {
1002                         Sbar_DrawCharacter ( 109, 3, num[0]);
1003                         Sbar_DrawCharacter ( 116, 3, num[1]);
1004                         Sbar_DrawCharacter ( 123, 3, num[2]);
1005                 }
1006
1007                 return;
1008         }
1009 // PGM 01/19/97 - team color drawing
1010
1011         if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1012                 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1013         else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1014                 Sbar_DrawPic (112, 0, sb_face_quad );
1015         else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1016                 Sbar_DrawPic (112, 0, sb_face_invis );
1017         else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1018                 Sbar_DrawPic (112, 0, sb_face_invuln);
1019         else
1020         {
1021                 f = cl.stats[STAT_HEALTH] / 20;
1022                 f = bound(0, f, 4);
1023                 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1024         }
1025 }
1026 double topspeed = 0;
1027 double topspeedxy = 0;
1028 time_t current_time = 3;
1029 time_t top_time = 0;
1030 time_t topxy_time = 0;
1031
1032 static void get_showspeed_unit(int unitnumber, double *conversion_factor, const char **unit)
1033 {
1034         if(unitnumber < 0)
1035                 unitnumber = showspeed.integer;
1036         switch(unitnumber)
1037         {
1038                 default:
1039                 case 1:
1040                         if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC)
1041                                 *unit = "in/s";
1042                         else
1043                                 *unit = "qu/s";
1044                         *conversion_factor = 1.0;
1045                         break;
1046                 case 2:
1047                         *unit = "m/s";
1048                         *conversion_factor = 0.0254;
1049                         if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1050                         // 1qu=1.5in is for non-Nexuiz/Xonotic only - Nexuiz/Xonotic players are overly large, but 1qu=1in fixes that
1051                         break;
1052                 case 3:
1053                         *unit = "km/h";
1054                         *conversion_factor = 0.0254 * 3.6;
1055                         if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1056                         break;
1057                 case 4:
1058                         *unit = "mph";
1059                         *conversion_factor = 0.0254 * 3.6 * 0.6213711922;
1060                         if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1061                         break;
1062                 case 5:
1063                         *unit = "knots";
1064                         *conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
1065                         if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5;
1066                         break;
1067         }
1068 }
1069
1070 static double showfps_nexttime = 0, showfps_lasttime = -1;
1071 static double showfps_framerate = 0;
1072 static int showfps_framecount = 0;
1073
1074 void Sbar_ShowFPS_Update(void)
1075 {
1076         double interval = 1;
1077         double newtime;
1078         newtime = realtime;
1079         if (newtime >= showfps_nexttime)
1080         {
1081                 showfps_framerate = showfps_framecount / (newtime - showfps_lasttime);
1082                 if (showfps_nexttime < newtime - interval * 1.5)
1083                         showfps_nexttime = newtime;
1084                 showfps_lasttime = newtime;
1085                 showfps_nexttime += interval;
1086                 showfps_framecount = 0;
1087         }
1088         showfps_framecount++;
1089 }
1090
1091 void Sbar_ShowFPS(void)
1092 {
1093         float fps_x, fps_y, fps_scalex, fps_scaley, fps_strings = 0;
1094         char soundstring[32];
1095         char fpsstring[32];
1096         char timestring[32];
1097         char datestring[32];
1098         char timedemostring1[32];
1099         char timedemostring2[32];
1100         char speedstring[32];
1101         char blurstring[32];
1102         char topspeedstring[48];
1103         char texstring[MAX_QPATH];
1104         qboolean red = false;
1105         soundstring[0] = 0;
1106         fpsstring[0] = 0;
1107         timedemostring1[0] = 0;
1108         timedemostring2[0] = 0;
1109         timestring[0] = 0;
1110         datestring[0] = 0;
1111         speedstring[0] = 0;
1112         blurstring[0] = 0;
1113         texstring[0] = 0;
1114         topspeedstring[0] = 0;
1115         if (showfps.integer)
1116         {
1117                 red = (showfps_framerate < 1.0f);
1118                 if(showfps.integer == 2)
1119                         dpsnprintf(fpsstring, sizeof(fpsstring), "%7.3f mspf", (1000.0 / showfps_framerate));
1120                 else if (red)
1121                         dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0 / showfps_framerate + 0.5));
1122                 else
1123                         dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(showfps_framerate + 0.5));
1124                 fps_strings++;
1125                 if (cls.timedemo)
1126                 {
1127                         dpsnprintf(timedemostring1, sizeof(timedemostring1), "frame%4i %f", cls.td_frames, realtime - cls.td_starttime);
1128                         dpsnprintf(timedemostring2, sizeof(timedemostring2), "%i seconds %3.0f/%3.0f/%3.0f fps", cls.td_onesecondavgcount, cls.td_onesecondminfps, cls.td_onesecondavgfps / max(1, cls.td_onesecondavgcount), cls.td_onesecondmaxfps);
1129                         fps_strings++;
1130                         fps_strings++;
1131                 }
1132         }
1133         if (showtime.integer)
1134         {
1135                 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1136                 fps_strings++;
1137         }
1138         if (showdate.integer)
1139         {
1140                 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1141                 fps_strings++;
1142         }
1143         if (showblur.integer)
1144         {
1145                 dpsnprintf(blurstring, sizeof(blurstring), "%3i%% blur", (int)(cl.motionbluralpha * 100));
1146                 fps_strings++;
1147         }
1148         if (showsound.integer)
1149         {
1150                 dpsnprintf(soundstring, sizeof(soundstring), "%4i/4%i at %3ims", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds);
1151                 fps_strings++;
1152         }
1153         if (showspeed.integer || showtopspeed.integer)
1154         {
1155                 double speed, speedxy, f;
1156                 const char *unit;
1157                 speed = VectorLength(cl.movement_velocity);
1158                 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1159                 if (showspeed.integer)
1160                 {
1161                         get_showspeed_unit(showspeed.integer, &f, &unit);
1162                         dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1163                         fps_strings++;
1164                 }
1165                 if (showtopspeed.integer)
1166                 {
1167                         qboolean topspeed_latched = false, topspeedxy_latched = false;
1168                         get_showspeed_unit(showtopspeed.integer, &f, &unit);
1169                         if (speed >= topspeed || current_time - top_time > 3)
1170                         {
1171                                 topspeed = speed;
1172                                 time(&top_time);
1173                         }
1174                         else
1175                                 topspeed_latched = true;
1176                         if (speedxy >= topspeedxy || current_time - topxy_time > 3)
1177                         {
1178                                 topspeedxy = speedxy;
1179                                 time(&topxy_time);
1180                         }
1181                         else
1182                                 topspeedxy_latched = true;
1183                         dpsnprintf(topspeedstring, sizeof(topspeedstring), "%s%.0f%s (%s%.0f%s) %s",
1184                                 topspeed_latched ? "^1" : "^xf88", f*topspeed, "^xf88",
1185                                 topspeedxy_latched ? "^1" : "^xf88", f*topspeedxy, "^xf88",
1186                                 unit);
1187                         time(&current_time);
1188                         fps_strings++;
1189                 }
1190         }
1191         if (showtex.integer)
1192         {
1193                 vec3_t org;
1194                 vec3_t dest;
1195                 vec3_t temp;
1196                 trace_t trace;
1197
1198                 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, org);
1199                 VectorSet(temp, 65536, 0, 0);
1200                 Matrix4x4_Transform(&r_refdef.view.matrix, temp, dest);
1201                 trace.hittexture = NULL; // to make sure
1202                 // TODO change this trace to be stopped by anything "visible" (i.e. with a drawsurface), but not stuff like weapclip
1203                 // probably needs adding a new SUPERCONTENTS type
1204                 trace = CL_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, true, false, NULL, true, true);
1205                 if(trace.hittexture)
1206                         strlcpy(texstring, trace.hittexture->name, sizeof(texstring));
1207                 else
1208                         strlcpy(texstring, "(no texture hit)", sizeof(texstring));
1209                 fps_strings++;
1210         }
1211         if (fps_strings)
1212         {
1213                 fps_scalex = 12;
1214                 fps_scaley = 12;
1215                 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1216                 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_strings*fps_scaley);
1217                 fps_y = vid_conheight.integer - sbar_info_pos.integer - fps_strings*fps_scaley;
1218                 if (soundstring[0])
1219                 {
1220                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(soundstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1221                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1222                         DrawQ_String(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1223                         fps_y += fps_scaley;
1224                 }
1225                 if (fpsstring[0])
1226                 {
1227                         r_draw2d_force = true;
1228                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(fpsstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1229                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1230                         if (red)
1231                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1232                         else
1233                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1234                         fps_y += fps_scaley;
1235                         r_draw2d_force = false;
1236                 }
1237                 if (timedemostring1[0])
1238                 {
1239                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring1, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1240                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1241                         DrawQ_String(fps_x, fps_y, timedemostring1, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1242                         fps_y += fps_scaley;
1243                 }
1244                 if (timedemostring2[0])
1245                 {
1246                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring2, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1247                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1248                         DrawQ_String(fps_x, fps_y, timedemostring2, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1249                         fps_y += fps_scaley;
1250                 }
1251                 if (timestring[0])
1252                 {
1253                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(timestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1254                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1255                         DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1256                         fps_y += fps_scaley;
1257                 }
1258                 if (datestring[0])
1259                 {
1260                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(datestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1261                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1262                         DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1263                         fps_y += fps_scaley;
1264                 }
1265                 if (speedstring[0])
1266                 {
1267                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(speedstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1268                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1269                         DrawQ_String(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1270                         fps_y += fps_scaley;
1271                 }
1272                 if (topspeedstring[0])
1273                 {
1274                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(topspeedstring, 0, fps_scalex, fps_scaley, false, FONT_INFOBAR);
1275                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1276                         DrawQ_String(fps_x, fps_y, topspeedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR);
1277                         fps_y += fps_scaley;
1278                 }
1279                 if (blurstring[0])
1280                 {
1281                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(blurstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1282                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1283                         DrawQ_String(fps_x, fps_y, blurstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1284                         fps_y += fps_scaley;
1285                 }
1286                 if (texstring[0])
1287                 {
1288                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(texstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1289                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1290                         DrawQ_String(fps_x, fps_y, texstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1291                         fps_y += fps_scaley;
1292                 }
1293         }
1294 }
1295
1296 static 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)
1297 {
1298         float r[5];
1299         c2 = bound(0, c2, 1);
1300         c1 = bound(0, c1, 1 - c2);
1301         r[0] = 0;
1302         r[1] = rangey + rangeheight * (c2 + c1);
1303         r[2] = rangey + rangeheight * (c2);
1304         r[3] = rangey;
1305         r[4] = height;
1306         if (r[1] > r[0])
1307                 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);
1308         if (r[2] > r[1])
1309                 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);
1310         if (r[3] > r[2])
1311                 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);
1312         if (r[4] > r[3])
1313                 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);
1314 }
1315
1316 /*
1317 ===============
1318 Sbar_Draw
1319 ===============
1320 */
1321 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1322 extern cvar_t v_kicktime;
1323 void Sbar_Score (int margin);
1324 void Sbar_Draw (void)
1325 {
1326         cachepic_t *pic;
1327         char vabuf[1024];
1328
1329         if(cl.csqc_vidvars.drawenginesbar)      //[515]: csqc drawsbar
1330         {
1331                 if (sb_showscores)
1332                         Sbar_DrawScoreboard ();
1333                 else if (cl.intermission == 1)
1334                 {
1335                         if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1336                         {
1337                                 Sbar_DrawScoreboard();
1338                                 return;
1339                         }
1340                         Sbar_IntermissionOverlay();
1341                 }
1342                 else if (cl.intermission == 2)
1343                         Sbar_FinaleOverlay();
1344                 else if (gamemode == GAME_DELUXEQUAKE)
1345                 {
1346                 }
1347                 else if (gamemode == GAME_NEXUIZ)
1348                 {
1349                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1350                         {
1351                                 sbar_x = (vid_conwidth.integer - 640)/2;
1352                                 sbar_y = vid_conheight.integer - 47;
1353                                 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1354                                 Sbar_DrawScoreboard ();
1355                         }
1356                         else if (sb_lines && sbar_hudselector.integer == 1)
1357                         {
1358                                 int i;
1359                                 float fade;
1360                                 int redflag, blueflag;
1361                                 float x;
1362
1363                                 sbar_x = (vid_conwidth.integer - 320)/2;
1364                                 sbar_y = vid_conheight.integer - 24 - 16;
1365
1366                                 // calculate intensity to draw weapons bar at
1367                                 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1368                                 fade = bound(0.7, fade, 1);
1369                                 for (i = 0; i < 8;i++)
1370                                         if (cl.stats[STAT_ITEMS] & (1 << i))
1371                                                 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1372                                 if((cl.stats[STAT_ITEMS] & (1<<12)))
1373                                         Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1374
1375                                 // flag icons
1376                                 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1377                                 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1378                                 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1379                                 if (redflag == 3 && blueflag == 3)
1380                                 {
1381                                         // The Impossible Combination[tm]
1382                                         // Can only happen in Key Hunt mode...
1383                                         Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[14]);
1384                                 }
1385                                 else
1386                                 {
1387                                         if (redflag)
1388                                                 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64)), sb_items[redflag+10]);
1389                                         if (blueflag)
1390                                                 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[blueflag+14]);
1391                                 }
1392
1393                                 // armor
1394                                 if (cl.stats[STAT_ARMOR] > 0)
1395                                 {
1396                                         Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1397                                         if(cl.stats[STAT_ARMOR] > 200)
1398                                                 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1399                                         else if(cl.stats[STAT_ARMOR] > 100)
1400                                                 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1401                                         else if(cl.stats[STAT_ARMOR] > 50)
1402                                                 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1403                                         else if(cl.stats[STAT_ARMOR] > 25)
1404                                                 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1405                                         else
1406                                                 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1407                                 }
1408
1409                                 // health
1410                                 if (cl.stats[STAT_HEALTH] != 0)
1411                                 {
1412                                         Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1413                                         if(cl.stats[STAT_HEALTH] > 200)
1414                                                 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1415                                         else if(cl.stats[STAT_HEALTH] > 100)
1416                                                 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1417                                         else if(cl.stats[STAT_HEALTH] > 50)
1418                                                 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1419                                         else if(cl.stats[STAT_HEALTH] > 25)
1420                                                 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1421                                         else
1422                                                 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1423                                 }
1424
1425                                 // ammo
1426                                 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1427                                 {
1428                                         if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1429                                                 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1430                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1431                                                 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1432                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1433                                                 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1434                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1435                                                 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1436                                         if(cl.stats[STAT_AMMO] > 10)
1437                                                 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1438                                         else
1439                                                 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1440                                 }
1441
1442                                 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1443                                         Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1444                                 if (sbar_x > 0)
1445                                         Sbar_Score(16);
1446                                         // The margin can be at most 8 to support 640x480 console size:
1447                                         //   320 + 2 * (144 + 16) = 640
1448                         }
1449                         else if (sb_lines)
1450                         {
1451                                 int i;
1452                                 float fade;
1453                                 int redflag, blueflag;
1454                                 float x;
1455
1456                                 sbar_x = (vid_conwidth.integer - 640)/2;
1457                                 sbar_y = vid_conheight.integer - 47;
1458
1459                                 // calculate intensity to draw weapons bar at
1460                                 fade = 3 - 2 * (cl.time - cl.weapontime);
1461                                 if (fade > 0)
1462                                 {
1463                                         fade = min(fade, 1);
1464                                         for (i = 0; i < 8;i++)
1465                                                 if (cl.stats[STAT_ITEMS] & (1 << i))
1466                                                         Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1467
1468                                         if((cl.stats[STAT_ITEMS] & (1<<12)))
1469                                                 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1470                                 }
1471
1472                                 //if (!cl.islocalgame)
1473                                 //      Sbar_DrawFrags ();
1474
1475                                 if (sb_lines > 24)
1476                                         Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1477                                 else
1478                                         Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1479
1480                                 // flag icons
1481                                 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1482                                 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1483                                 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1484                                 if (redflag == 3 && blueflag == 3)
1485                                 {
1486                                         // The Impossible Combination[tm]
1487                                         // Can only happen in Key Hunt mode...
1488                                         Sbar_DrawPic ((int) x, -179, sb_items[14]);
1489                                 }
1490                                 else
1491                                 {
1492                                         if (redflag)
1493                                                 Sbar_DrawPic ((int) x, -117, sb_items[redflag+10]);
1494                                         if (blueflag)
1495                                                 Sbar_DrawPic ((int) x, -177, sb_items[blueflag+14]);
1496                                 }
1497
1498                                 // armor
1499                                 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1500
1501                                 // health
1502                                 if(cl.stats[STAT_HEALTH] > 100)
1503                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1504                                 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1505                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1506                                 else
1507                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1508
1509                                 // AK dont draw ammo for the laser
1510                                 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1511                                 {
1512                                         if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1513                                                 Sbar_DrawPic (519, 0, sb_ammo[0]);
1514                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1515                                                 Sbar_DrawPic (519, 0, sb_ammo[1]);
1516                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1517                                                 Sbar_DrawPic (519, 0, sb_ammo[2]);
1518                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1519                                                 Sbar_DrawPic (519, 0, sb_ammo[3]);
1520
1521                                         if(cl.stats[STAT_AMMO] <= 10)
1522                                                 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1523                                         else
1524                                                 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1525
1526                                 }
1527
1528                                 if (sb_lines > 24)
1529                                         DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1530
1531                                 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1532                                         Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1533
1534                                 if (sbar_x > 0)
1535                                         Sbar_Score(-16);
1536                                         // Because:
1537                                         //   Mini scoreboard uses 12*4 per other team, that is, 144
1538                                         //   pixels when there are four teams...
1539                                         //   Nexuiz by default sets vid_conwidth to 800... makes
1540                                         //   sbar_x == 80...
1541                                         //   so we need to shift it by 64 pixels to the right to fit
1542                                         //   BUT: then it overlaps with the image that gets drawn
1543                                         //   for viewsize 100! Therefore, just account for 3 teams,
1544                                         //   that is, 96 pixels mini scoreboard size, needing 16 pixels
1545                                         //   to the right!
1546                         }
1547                 }
1548                 else if (gamemode == GAME_ZYMOTIC)
1549                 {
1550 #if 1
1551                         float scale = 64.0f / 256.0f;
1552                         float kickoffset[3];
1553                         VectorClear(kickoffset);
1554                         if (v_dmg_time > 0)
1555                         {
1556                                 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1557                                 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1558                         }
1559                         sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1560                         sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1561                         // left1 16, 48 : 126 -66
1562                         // left2 16, 128 : 196 -66
1563                         // right 176, 48 : 196 -136
1564                         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);
1565                         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);
1566                         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);
1567                         DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1568 #else
1569                         float scale = 128.0f / 256.0f;
1570                         float healthstart, healthheight, healthstarttc, healthendtc;
1571                         float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1572                         float ammostart, ammoheight, ammostarttc, ammoendtc;
1573                         float clipstart, clipheight, clipstarttc, clipendtc;
1574                         float kickoffset[3], offset;
1575                         VectorClear(kickoffset);
1576                         if (v_dmg_time > 0)
1577                         {
1578                                 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1579                                 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1580                         }
1581                         sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1582                         sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1583                         offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1584                         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);
1585                         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);
1586                         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);
1587                         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);
1588                         healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1589                         shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1590                         healthstart = 204 - healthheight;
1591                         shieldstart = healthstart - shieldheight;
1592                         healthstarttc = healthstart * (1.0f / 256.0f);
1593                         healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1594                         shieldstarttc = shieldstart * (1.0f / 256.0f);
1595                         shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1596                         ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1597                         ammostart = 114 - ammoheight;
1598                         ammostarttc = ammostart * (1.0f / 256.0f);
1599                         ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1600                         clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1601                         clipstart = 190 - clipheight;
1602                         clipstarttc = clipstart * (1.0f / 256.0f);
1603                         clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1604                         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);
1605                         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);
1606                         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);
1607                         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);
1608                         DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1609                         DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1610 #endif
1611                 }
1612                 else // Quake and others
1613                 {
1614                         sbar_x = (vid_conwidth.integer - 320)/2;
1615                         sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1616                         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1617                         //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1618
1619                         if (sb_lines > 24)
1620                         {
1621                                 if (gamemode != GAME_GOODVSBAD2)
1622                                         Sbar_DrawInventory ();
1623                                 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1624                                         Sbar_DrawFrags ();
1625                         }
1626
1627                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1628                         {
1629                                 if (gamemode != GAME_GOODVSBAD2)
1630                                         Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1631                                 Sbar_DrawScoreboard ();
1632                         }
1633                         else if (sb_lines)
1634                         {
1635                                 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1636
1637                                 // keys (hipnotic only)
1638                                 //MED 01/04/97 moved keys here so they would not be overwritten
1639                                 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
1640                                 {
1641                                         if (cl.stats[STAT_ITEMS] & IT_KEY1)
1642                                                 Sbar_DrawPic (209, 3, sb_items[0]);
1643                                         if (cl.stats[STAT_ITEMS] & IT_KEY2)
1644                                                 Sbar_DrawPic (209, 12, sb_items[1]);
1645                                 }
1646                                 // armor
1647                                 if (gamemode != GAME_GOODVSBAD2)
1648                                 {
1649                                         if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1650                                         {
1651                                                 Sbar_DrawNum (24, 0, 666, 3, 1);
1652                                                 Sbar_DrawPic (0, 0, sb_disc);
1653                                         }
1654                                         else
1655                                         {
1656                                                 if (gamemode == GAME_ROGUE)
1657                                                 {
1658                                                         Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1659                                                         if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1660                                                                 Sbar_DrawPic (0, 0, sb_armor[2]);
1661                                                         else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1662                                                                 Sbar_DrawPic (0, 0, sb_armor[1]);
1663                                                         else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1664                                                                 Sbar_DrawPic (0, 0, sb_armor[0]);
1665                                                 }
1666                                                 else
1667                                                 {
1668                                                         Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1669                                                         if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1670                                                                 Sbar_DrawPic (0, 0, sb_armor[2]);
1671                                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1672                                                                 Sbar_DrawPic (0, 0, sb_armor[1]);
1673                                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1674                                                                 Sbar_DrawPic (0, 0, sb_armor[0]);
1675                                                 }
1676                                         }
1677                                 }
1678
1679                                 // face
1680                                 Sbar_DrawFace ();
1681
1682                                 // health
1683                                 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1684
1685                                 // ammo icon
1686                                 if (gamemode == GAME_ROGUE)
1687                                 {
1688                                         if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1689                                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
1690                                         else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1691                                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
1692                                         else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1693                                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
1694                                         else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1695                                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
1696                                         else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1697                                                 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1698                                         else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1699                                                 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1700                                         else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1701                                                 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1702                                 }
1703                                 else
1704                                 {
1705                                         if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1706                                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
1707                                         else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1708                                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
1709                                         else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1710                                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
1711                                         else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1712                                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
1713                                 }
1714
1715                                 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1716
1717                                 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1718                                 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1719                                 {
1720                                         if (gamemode == GAME_TRANSFUSION)
1721                                                 Sbar_MiniDeathmatchOverlay (0, 0);
1722                                         else
1723                                                 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1724                                         Sbar_Score(24);
1725                                 }
1726                         }
1727                 }
1728         }
1729
1730         if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1731         {
1732                 pic = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/crosshair%i", crosshair.integer));
1733                 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);
1734         }
1735
1736         if (cl_prydoncursor.integer > 0)
1737                 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(vabuf, sizeof(vabuf), "gfx/prydoncursor%03i", cl_prydoncursor.integer)), 0, 0, 1, 1, 1, 1, 0);
1738 }
1739
1740 //=============================================================================
1741
1742 /*
1743 ==================
1744 Sbar_DeathmatchOverlay
1745
1746 ==================
1747 */
1748 static float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1749 {
1750         int minutes;
1751         qboolean myself = false;
1752         unsigned char *c;
1753         char vabuf[1024];
1754         minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1755
1756         if((s - cl.scores) == cl.playerentity - 1)
1757                 myself = true;
1758         if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1759                 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1760                         myself = true;
1761
1762         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1763         {
1764                 if (s->qw_spectator)
1765                 {
1766                         if (s->qw_ping || s->qw_packetloss)
1767                                 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i %4i spectator  %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1768                         else
1769                                 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "         %4i spectator  %c%s", minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1770                 }
1771                 else
1772                 {
1773                         // draw colors behind score
1774                         //
1775                         //
1776                         //
1777                         //
1778                         //
1779                         c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1780                         DrawQ_Fill(x + 14*8*FONT_SBAR->maxwidth, y+1, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1781                         c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1782                         DrawQ_Fill(x + 14*8*FONT_SBAR->maxwidth, y+4, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1783                         // print the text
1784                         //DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%c%4i %s", myself ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT);
1785                         if (s->qw_ping || s->qw_packetloss)
1786                                 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i %4i %5i %-4s %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1787                         else
1788                                 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "         %4i %5i %-4s %c%s", minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1789                 }
1790         }
1791         else
1792         {
1793                 if (s->qw_spectator)
1794                 {
1795                         if (s->qw_ping || s->qw_packetloss)
1796                                 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i spect %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1797                         else
1798                                 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "         spect %c%s", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1799                 }
1800                 else
1801                 {
1802                         // draw colors behind score
1803                         c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1804                         DrawQ_Fill(x + 9*8*FONT_SBAR->maxwidth, y+1, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1805                         c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1806                         DrawQ_Fill(x + 9*8*FONT_SBAR->maxwidth, y+4, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0);
1807                         // print the text
1808                         //DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%c%4i %s", myself ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT);
1809                         if (s->qw_ping || s->qw_packetloss)
1810                                 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i %5i %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1811                         else
1812                                 DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "         %5i %c%s", (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1813                 }
1814         }
1815         return 8;
1816 }
1817
1818 void Sbar_DeathmatchOverlay (void)
1819 {
1820         int i, y, xmin, xmax, ymin, ymax;
1821         char vabuf[1024];
1822
1823         // request new ping times every two second
1824         if (cl.last_ping_request < realtime - 2 && cls.netcon)
1825         {
1826                 cl.last_ping_request = realtime;
1827                 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1828                 {
1829                         MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1830                         MSG_WriteString(&cls.netcon->message, "pings");
1831                 }
1832                 else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6/* || cls.protocol == PROTOCOL_DARKPLACES7*/)
1833                 {
1834                         // 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
1835                         static int ping_anyway_counter = 0;
1836                         if(cl.parsingtextexpectingpingforscores == 1)
1837                         {
1838                                 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1839                                 if(++ping_anyway_counter >= 5)
1840                                         cl.parsingtextexpectingpingforscores = 0;
1841                         }
1842                         if(cl.parsingtextexpectingpingforscores != 1)
1843                         {
1844                                 ping_anyway_counter = 0;
1845                                 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1846                                 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1847                                 MSG_WriteString(&cls.netcon->message, "ping");
1848                         }
1849                 }
1850                 else
1851                 {
1852                         // newer server definitely has pings command, so use it for more efficiency, avoids ping reports spamming the console if they are misparsed, and saves a little bandwidth
1853                         MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1854                         MSG_WriteString(&cls.netcon->message, "pings");
1855                 }
1856         }
1857
1858         // scores
1859         Sbar_SortFrags ();
1860
1861         ymin = 8;
1862         ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1863
1864         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1865                 xmin = (int) (vid_conwidth.integer - (26 + 15) * 8 * FONT_SBAR->maxwidth) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't)
1866         else
1867                 xmin = (int) (vid_conwidth.integer - (16 + 25) * 8 * FONT_SBAR->maxwidth) / 2; // 16 characters until name, then we assume 25 character names (they can be longer but usually aren't)
1868         xmax = vid_conwidth.integer - xmin;
1869
1870         if(gamemode == GAME_NEXUIZ)
1871                 DrawQ_Pic (xmin - 8, ymin - 8, 0, xmax-xmin+1 + 2*8, ymax-ymin+1 + 2*8, 0, 0, 0, sbar_alpha_bg.value, 0);
1872
1873         DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1874
1875         // draw the text
1876         y = 40;
1877         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1878         {
1879                 DrawQ_String(xmin, y, va(vabuf, sizeof(vabuf), "ping pl%% time frags team  name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1880         }
1881         else
1882         {
1883                 DrawQ_String(xmin, y, va(vabuf, sizeof(vabuf), "ping pl%% frags  name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
1884         }
1885         y += 8;
1886
1887         if (Sbar_IsTeammatch ())
1888         {
1889                 // show team scores first
1890                 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1891                         y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1892                 y += 5;
1893         }
1894
1895         for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1896                 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1897 }
1898
1899 /*
1900 ==================
1901 Sbar_MiniDeathmatchOverlay
1902
1903 ==================
1904 */
1905 void Sbar_MiniDeathmatchOverlay (int x, int y)
1906 {
1907         int i, j, numlines, range_begin, range_end, myteam, teamsep;
1908
1909         // do not draw this if sbar_miniscoreboard_size is zero
1910         if(sbar_miniscoreboard_size.value == 0)
1911                 return;
1912         // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1913         if(sbar_miniscoreboard_size.value > 0)
1914                 y = (int) (vid_conheight.integer - sbar_miniscoreboard_size.value * 8);
1915
1916         // scores
1917         Sbar_SortFrags ();
1918
1919         // decide where to print
1920         if (gamemode == GAME_TRANSFUSION)
1921                 numlines = (vid_conwidth.integer - x + 127) / 128;
1922         else
1923                 numlines = (vid_conheight.integer - y + 7) / 8;
1924
1925         // give up if there isn't room
1926         if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1927                 return;
1928
1929         //find us
1930         for (i = 0; i < scoreboardlines; i++)
1931                 if (fragsort[i] == cl.playerentity - 1)
1932                         break;
1933
1934         range_begin = 0;
1935         range_end = scoreboardlines;
1936         teamsep = 0;
1937
1938         if (gamemode != GAME_TRANSFUSION)
1939                 if (Sbar_IsTeammatch ())
1940                 {
1941                         // reserve space for the team scores
1942                         numlines -= teamlines;
1943
1944                         // find first and last player of my team (only draw the team totals and my own team)
1945                         range_begin = range_end = i;
1946                         myteam = cl.scores[fragsort[i]].colors & 15;
1947                         while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1948                                 --range_begin;
1949                         while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1950                                 ++range_end;
1951
1952                         // looks better than two players
1953                         if(numlines == 2)
1954                         {
1955                                 teamsep = 8;
1956                                 numlines = 1;
1957                         }
1958                 }
1959
1960         // figure out start
1961         i -= numlines/2;
1962         i = min(i, range_end - numlines);
1963         i = max(i, range_begin);
1964
1965         if (gamemode == GAME_TRANSFUSION)
1966         {
1967                 for (;i < range_end && x < vid_conwidth.integer;i++)
1968                         x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1969         }
1970         else
1971         {
1972                 if(range_end - i < numlines) // won't draw to bottom?
1973                         y += 8 * (numlines - (range_end - i)); // bottom align
1974                 // show team scores first
1975                 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1976                         y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1977                 y += teamsep;
1978                 for (;i < range_end && y < vid_conheight.integer;i++)
1979                         y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1980         }
1981 }
1982
1983 static int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1984 {
1985         static int const sortorder[16] =
1986         {
1987                 1001,
1988                 1002,
1989                 1003,
1990                 1004,
1991                 1, // red
1992                 1005,
1993                 1006,
1994                 1007,
1995                 1008,
1996                 4, // pink
1997                 1009,
1998                 1010,
1999                 3, // yellow
2000                 2, // blue
2001                 1011,
2002                 1012
2003         };
2004         const scoreboard_t *t1 = *(scoreboard_t **) t1_;
2005         const scoreboard_t *t2 = *(scoreboard_t **) t2_;
2006         int tc1 = sortorder[t1->colors & 15];
2007         int tc2 = sortorder[t2->colors & 15];
2008         return tc1 - tc2;
2009 }
2010
2011 void Sbar_Score (int margin)
2012 {
2013         int i, me, score, otherleader, place, distribution, minutes, seconds;
2014         double timeleft;
2015         int sbar_x_save = sbar_x;
2016         int sbar_y_save = sbar_y;
2017
2018
2019         sbar_y = (int) (vid_conheight.value - (32+12));
2020         sbar_x -= margin;
2021
2022         me = cl.playerentity - 1;
2023         if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients)
2024         {
2025                 if(Sbar_IsTeammatch())
2026                 {
2027                         // Layout:
2028                         //
2029                         //   team1 team3 team4
2030                         //
2031                         //         TEAM2
2032
2033                         scoreboard_t *teamcolorsort[16];
2034
2035                         Sbar_SortFrags();
2036                         for(i = 0; i < teamlines; ++i)
2037                                 teamcolorsort[i] = &(teams[i]);
2038
2039                         // Now sort them by color
2040                         qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
2041
2042                         // : margin
2043                         // -12*4: four digits space
2044                         place = (teamlines - 1) * (-12 * 4);
2045
2046                         for(i = 0; i < teamlines; ++i)
2047                         {
2048                                 int cindex = teamcolorsort[i]->colors & 15;
2049                                 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
2050                                 float cm = max(max(c[0], c[1]), c[2]);
2051                                 float cr = c[0] / cm;
2052                                 float cg = c[1] / cm;
2053                                 float cb = c[2] / cm;
2054                                 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
2055                                 {
2056                                         Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
2057                                 }
2058                                 else // other team
2059                                 {
2060                                         Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
2061                                         place += 4 * 12;
2062                                 }
2063                         }
2064                 }
2065                 else
2066                 {
2067                         // Layout:
2068                         //
2069                         //   leading  place
2070                         //
2071                         //        FRAGS
2072                         //
2073                         // find leading score other than ourselves, to calculate distribution
2074                         // find our place in the scoreboard
2075                         score = cl.scores[me].frags;
2076                         for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
2077                         {
2078                                 if (cl.scores[i].name[0] && i != me)
2079                                 {
2080                                         if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
2081                                                 otherleader = i;
2082                                         if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
2083                                                 place++;
2084                                 }
2085                         }
2086                         distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
2087                         if (place == 1)
2088                                 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2089                         else if (place == 2)
2090                                 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2091                         else
2092                                 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2093                         if (otherleader < 0)
2094                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 1, 1, 1, 0);
2095                         if (distribution >= 0)
2096                         {
2097                                 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2098                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 1, 1, 1, 0);
2099                         }
2100                         else if (distribution >= -5)
2101                         {
2102                                 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2103                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 1, 0, 1, 0);
2104                         }
2105                         else
2106                         {
2107                                 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2108                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 0, 0, 1, 0);
2109                         }
2110                 }
2111         }
2112
2113         if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT])
2114         {
2115                 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2116                 minutes = (int)floor(timeleft / 60);
2117                 seconds = (int)(floor(timeleft) - minutes * 60);
2118                 if (minutes >= 5)
2119                 {
2120                         Sbar_DrawXNum(-12*6, 32, minutes,  3, 12, 1, 1, 1, 1, 0);
2121                         if(sb_colon && sb_colon->tex != r_texture_notexture)
2122                                 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2123                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2124                 }
2125                 else if (minutes >= 1)
2126                 {
2127                         Sbar_DrawXNum(-12*6, 32, minutes,  3, 12, 1, 1, 0, 1, 0);
2128                         if(sb_colon && sb_colon->tex != r_texture_notexture)
2129                                 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2130                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2131                 }
2132                 else if ((int)(timeleft * 4) & 1)
2133                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2134                 else
2135                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2136         }
2137         else if (sbar_gametime.integer)
2138         {
2139                 minutes = (int)floor(cl.time / 60);
2140                 seconds = (int)(floor(cl.time) - minutes * 60);
2141                 Sbar_DrawXNum(-12*6, 32, minutes,  3, 12, 1, 1, 1, 1, 0);
2142                 if(sb_colon && sb_colon->tex != r_texture_notexture)
2143                         DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2144                 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2145         }
2146
2147         sbar_x = sbar_x_save;
2148         sbar_y = sbar_y_save;
2149 }
2150
2151 /*
2152 ==================
2153 Sbar_IntermissionOverlay
2154
2155 ==================
2156 */
2157 void Sbar_IntermissionOverlay (void)
2158 {
2159         int             dig;
2160         int             num;
2161
2162         if (cl.gametype == GAME_DEATHMATCH)
2163         {
2164                 Sbar_DeathmatchOverlay ();
2165                 return;
2166         }
2167
2168         sbar_x = (vid_conwidth.integer - 320) >> 1;
2169         sbar_y = (vid_conheight.integer - 200) >> 1;
2170
2171         DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2172         DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2173
2174 // time
2175         dig = (int)cl.completed_time / 60;
2176         Sbar_DrawNum (160, 64, dig, 3, 0);
2177         num = (int)cl.completed_time - dig*60;
2178         Sbar_DrawPic (234,64,sb_colon);
2179         Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2180         Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2181
2182 // LA: Display as "a" instead of "a/b" if b is 0
2183         if(cl.stats[STAT_TOTALSECRETS])
2184         {
2185                 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2186                 if (gamemode != GAME_NEXUIZ)
2187                         Sbar_DrawPic (232, 104, sb_slash);
2188                 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2189         }
2190         else
2191         {
2192                 Sbar_DrawNum (240, 104, cl.stats[STAT_SECRETS], 3, 0);
2193         }
2194
2195         if(cl.stats[STAT_TOTALMONSTERS])
2196         {
2197                 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2198                 if (gamemode != GAME_NEXUIZ)
2199                         Sbar_DrawPic (232, 144, sb_slash);
2200                 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2201         }
2202         else
2203         {
2204                 Sbar_DrawNum (240, 144, cl.stats[STAT_MONSTERS], 3, 0);
2205         }
2206 }
2207
2208
2209 /*
2210 ==================
2211 Sbar_FinaleOverlay
2212
2213 ==================
2214 */
2215 void Sbar_FinaleOverlay (void)
2216 {
2217         DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2218 }
2219