]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - sbar.c
b537bcd3776cd3c9a391163e7127c50eaa358f8c
[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 (IS_OLDNEXUIZ_DERIVED(gamemode))
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 (IS_OLDNEXUIZ_DERIVED(gamemode)
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 (IS_OLDNEXUIZ_DERIVED(gamemode)) {
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 (IS_OLDNEXUIZ_DERIVED(gamemode)) {
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(IS_NEXUIZ_DERIVED(gamemode))
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(!IS_NEXUIZ_DERIVED(gamemode))
1050                                 *conversion_factor *= 1.5;
1051                         // 1qu=1.5in is for non-Nexuiz/Xonotic only - Nexuiz/Xonotic players are overly large, but 1qu=1in fixes that
1052                         break;
1053                 case 3:
1054                         *unit = "km/h";
1055                         *conversion_factor = 0.0254 * 3.6;
1056                         if(!IS_NEXUIZ_DERIVED(gamemode))
1057                                 *conversion_factor *= 1.5;
1058                         break;
1059                 case 4:
1060                         *unit = "mph";
1061                         *conversion_factor = 0.0254 * 3.6 * 0.6213711922;
1062                         if(!IS_NEXUIZ_DERIVED(gamemode))
1063                                 *conversion_factor *= 1.5;
1064                         break;
1065                 case 5:
1066                         *unit = "knots";
1067                         *conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
1068                         if(!IS_NEXUIZ_DERIVED(gamemode))
1069                                 *conversion_factor *= 1.5;
1070                         break;
1071         }
1072 }
1073
1074 static double showfps_nexttime = 0, showfps_lasttime = -1;
1075 static double showfps_framerate = 0;
1076 static int showfps_framecount = 0;
1077
1078 void Sbar_ShowFPS_Update(void)
1079 {
1080         double interval = 1;
1081         double newtime;
1082         newtime = realtime;
1083         if (newtime >= showfps_nexttime)
1084         {
1085                 showfps_framerate = showfps_framecount / (newtime - showfps_lasttime);
1086                 if (showfps_nexttime < newtime - interval * 1.5)
1087                         showfps_nexttime = newtime;
1088                 showfps_lasttime = newtime;
1089                 showfps_nexttime += interval;
1090                 showfps_framecount = 0;
1091         }
1092         showfps_framecount++;
1093 }
1094
1095 void Sbar_ShowFPS(void)
1096 {
1097         float fps_x, fps_y, fps_scalex, fps_scaley, fps_strings = 0;
1098         char soundstring[32];
1099         char fpsstring[32];
1100         char timestring[32];
1101         char datestring[32];
1102         char timedemostring1[32];
1103         char timedemostring2[32];
1104         char speedstring[32];
1105         char blurstring[32];
1106         char topspeedstring[48];
1107         char texstring[MAX_QPATH];
1108         qboolean red = false;
1109         soundstring[0] = 0;
1110         fpsstring[0] = 0;
1111         timedemostring1[0] = 0;
1112         timedemostring2[0] = 0;
1113         timestring[0] = 0;
1114         datestring[0] = 0;
1115         speedstring[0] = 0;
1116         blurstring[0] = 0;
1117         texstring[0] = 0;
1118         topspeedstring[0] = 0;
1119         if (showfps.integer)
1120         {
1121                 red = (showfps_framerate < 1.0f);
1122                 if(showfps.integer == 2)
1123                         dpsnprintf(fpsstring, sizeof(fpsstring), "%7.3f mspf", (1000.0 / showfps_framerate));
1124                 else if (red)
1125                         dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0 / showfps_framerate + 0.5));
1126                 else
1127                         dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(showfps_framerate + 0.5));
1128                 fps_strings++;
1129                 if (cls.timedemo)
1130                 {
1131                         dpsnprintf(timedemostring1, sizeof(timedemostring1), "frame%4i %f", cls.td_frames, realtime - cls.td_starttime);
1132                         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);
1133                         fps_strings++;
1134                         fps_strings++;
1135                 }
1136         }
1137         if (showtime.integer)
1138         {
1139                 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1140                 fps_strings++;
1141         }
1142         if (showdate.integer)
1143         {
1144                 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1145                 fps_strings++;
1146         }
1147         if (showblur.integer)
1148         {
1149                 dpsnprintf(blurstring, sizeof(blurstring), "%3i%% blur", (int)(cl.motionbluralpha * 100));
1150                 fps_strings++;
1151         }
1152         if (showsound.integer)
1153         {
1154                 dpsnprintf(soundstring, sizeof(soundstring), "%4i/4%i at %3ims", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds);
1155                 fps_strings++;
1156         }
1157         if (showspeed.integer || showtopspeed.integer)
1158         {
1159                 double speed, speedxy, f;
1160                 const char *unit;
1161                 speed = VectorLength(cl.movement_velocity);
1162                 speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]);
1163                 if (showspeed.integer)
1164                 {
1165                         get_showspeed_unit(showspeed.integer, &f, &unit);
1166                         dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit);
1167                         fps_strings++;
1168                 }
1169                 if (showtopspeed.integer)
1170                 {
1171                         qboolean topspeed_latched = false, topspeedxy_latched = false;
1172                         get_showspeed_unit(showtopspeed.integer, &f, &unit);
1173                         if (speed >= topspeed || current_time - top_time > 3)
1174                         {
1175                                 topspeed = speed;
1176                                 time(&top_time);
1177                         }
1178                         else
1179                                 topspeed_latched = true;
1180                         if (speedxy >= topspeedxy || current_time - topxy_time > 3)
1181                         {
1182                                 topspeedxy = speedxy;
1183                                 time(&topxy_time);
1184                         }
1185                         else
1186                                 topspeedxy_latched = true;
1187                         dpsnprintf(topspeedstring, sizeof(topspeedstring), "%s%.0f%s (%s%.0f%s) %s",
1188                                 topspeed_latched ? "^1" : "^xf88", f*topspeed, "^xf88",
1189                                 topspeedxy_latched ? "^1" : "^xf88", f*topspeedxy, "^xf88",
1190                                 unit);
1191                         time(&current_time);
1192                         fps_strings++;
1193                 }
1194         }
1195         if (showtex.integer)
1196         {
1197                 vec3_t org;
1198                 vec3_t dest;
1199                 vec3_t temp;
1200                 trace_t trace;
1201
1202                 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, org);
1203                 VectorSet(temp, 65536, 0, 0);
1204                 Matrix4x4_Transform(&r_refdef.view.matrix, temp, dest);
1205                 trace.hittexture = NULL; // to make sure
1206                 // TODO change this trace to be stopped by anything "visible" (i.e. with a drawsurface), but not stuff like weapclip
1207                 // probably needs adding a new SUPERCONTENTS type
1208                 trace = CL_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, true, false, NULL, true, true);
1209                 if(trace.hittexture)
1210                         strlcpy(texstring, trace.hittexture->name, sizeof(texstring));
1211                 else
1212                         strlcpy(texstring, "(no texture hit)", sizeof(texstring));
1213                 fps_strings++;
1214         }
1215         if (fps_strings)
1216         {
1217                 fps_scalex = 12;
1218                 fps_scaley = 12;
1219                 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1220                 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_strings*fps_scaley);
1221                 fps_y = vid_conheight.integer - sbar_info_pos.integer - fps_strings*fps_scaley;
1222                 if (soundstring[0])
1223                 {
1224                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(soundstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1225                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1226                         DrawQ_String(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1227                         fps_y += fps_scaley;
1228                 }
1229                 if (fpsstring[0])
1230                 {
1231                         r_draw2d_force = true;
1232                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(fpsstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1233                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1234                         if (red)
1235                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR);
1236                         else
1237                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1238                         fps_y += fps_scaley;
1239                         r_draw2d_force = false;
1240                 }
1241                 if (timedemostring1[0])
1242                 {
1243                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring1, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1244                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1245                         DrawQ_String(fps_x, fps_y, timedemostring1, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1246                         fps_y += fps_scaley;
1247                 }
1248                 if (timedemostring2[0])
1249                 {
1250                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(timedemostring2, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1251                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1252                         DrawQ_String(fps_x, fps_y, timedemostring2, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1253                         fps_y += fps_scaley;
1254                 }
1255                 if (timestring[0])
1256                 {
1257                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(timestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1258                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1259                         DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1260                         fps_y += fps_scaley;
1261                 }
1262                 if (datestring[0])
1263                 {
1264                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(datestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1265                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1266                         DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1267                         fps_y += fps_scaley;
1268                 }
1269                 if (speedstring[0])
1270                 {
1271                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(speedstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1272                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1273                         DrawQ_String(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1274                         fps_y += fps_scaley;
1275                 }
1276                 if (topspeedstring[0])
1277                 {
1278                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(topspeedstring, 0, fps_scalex, fps_scaley, false, FONT_INFOBAR);
1279                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1280                         DrawQ_String(fps_x, fps_y, topspeedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR);
1281                         fps_y += fps_scaley;
1282                 }
1283                 if (blurstring[0])
1284                 {
1285                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(blurstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1286                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1287                         DrawQ_String(fps_x, fps_y, blurstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1288                         fps_y += fps_scaley;
1289                 }
1290                 if (texstring[0])
1291                 {
1292                         fps_x = vid_conwidth.integer - DrawQ_TextWidth(texstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
1293                         DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
1294                         DrawQ_String(fps_x, fps_y, texstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR);
1295                         fps_y += fps_scaley;
1296                 }
1297         }
1298 }
1299
1300 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)
1301 {
1302         float r[5];
1303         c2 = bound(0, c2, 1);
1304         c1 = bound(0, c1, 1 - c2);
1305         r[0] = 0;
1306         r[1] = rangey + rangeheight * (c2 + c1);
1307         r[2] = rangey + rangeheight * (c2);
1308         r[3] = rangey;
1309         r[4] = height;
1310         if (r[1] > r[0])
1311                 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);
1312         if (r[2] > r[1])
1313                 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);
1314         if (r[3] > r[2])
1315                 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);
1316         if (r[4] > r[3])
1317                 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);
1318 }
1319
1320 /*
1321 ===============
1322 Sbar_Draw
1323 ===============
1324 */
1325 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1326 extern cvar_t v_kicktime;
1327 void Sbar_Score (int margin);
1328 void Sbar_Draw (void)
1329 {
1330         cachepic_t *pic;
1331         char vabuf[1024];
1332
1333         if(cl.csqc_vidvars.drawenginesbar)      //[515]: csqc drawsbar
1334         {
1335                 if (sb_showscores)
1336                         Sbar_DrawScoreboard ();
1337                 else if (cl.intermission == 1)
1338                 {
1339                         if(IS_OLDNEXUIZ_DERIVED(gamemode)) // display full scoreboard (that is, show scores + map name)
1340                         {
1341                                 Sbar_DrawScoreboard();
1342                                 return;
1343                         }
1344                         Sbar_IntermissionOverlay();
1345                 }
1346                 else if (cl.intermission == 2)
1347                         Sbar_FinaleOverlay();
1348                 else if (gamemode == GAME_DELUXEQUAKE)
1349                 {
1350                 }
1351                 else if (IS_OLDNEXUIZ_DERIVED(gamemode))
1352                 {
1353                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1354                         {
1355                                 sbar_x = (vid_conwidth.integer - 640)/2;
1356                                 sbar_y = vid_conheight.integer - 47;
1357                                 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1358                                 Sbar_DrawScoreboard ();
1359                         }
1360                         else if (sb_lines && sbar_hudselector.integer == 1)
1361                         {
1362                                 int i;
1363                                 float fade;
1364                                 int redflag, blueflag;
1365                                 float x;
1366
1367                                 sbar_x = (vid_conwidth.integer - 320)/2;
1368                                 sbar_y = vid_conheight.integer - 24 - 16;
1369
1370                                 // calculate intensity to draw weapons bar at
1371                                 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1372                                 fade = bound(0.7, fade, 1);
1373                                 for (i = 0; i < 8;i++)
1374                                         if (cl.stats[STAT_ITEMS] & (1 << i))
1375                                                 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1376                                 if((cl.stats[STAT_ITEMS] & (1<<12)))
1377                                         Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1378
1379                                 // flag icons
1380                                 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1381                                 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1382                                 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1383                                 if (redflag == 3 && blueflag == 3)
1384                                 {
1385                                         // The Impossible Combination[tm]
1386                                         // Can only happen in Key Hunt mode...
1387                                         Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[14]);
1388                                 }
1389                                 else
1390                                 {
1391                                         if (redflag)
1392                                                 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64)), sb_items[redflag+10]);
1393                                         if (blueflag)
1394                                                 Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[blueflag+14]);
1395                                 }
1396
1397                                 // armor
1398                                 if (cl.stats[STAT_ARMOR] > 0)
1399                                 {
1400                                         Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1401                                         if(cl.stats[STAT_ARMOR] > 200)
1402                                                 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0);
1403                                         else if(cl.stats[STAT_ARMOR] > 100)
1404                                                 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0);
1405                                         else if(cl.stats[STAT_ARMOR] > 50)
1406                                                 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1407                                         else if(cl.stats[STAT_ARMOR] > 25)
1408                                                 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0);
1409                                         else
1410                                                 Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1411                                 }
1412
1413                                 // health
1414                                 if (cl.stats[STAT_HEALTH] != 0)
1415                                 {
1416                                         Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1417                                         if(cl.stats[STAT_HEALTH] > 200)
1418                                                 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0);
1419                                         else if(cl.stats[STAT_HEALTH] > 100)
1420                                                 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0);
1421                                         else if(cl.stats[STAT_HEALTH] > 50)
1422                                                 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1423                                         else if(cl.stats[STAT_HEALTH] > 25)
1424                                                 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0);
1425                                         else
1426                                                 Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1427                                 }
1428
1429                                 // ammo
1430                                 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1431                                 {
1432                                         if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1433                                                 Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1434                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1435                                                 Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1436                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1437                                                 Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1438                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1439                                                 Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1440                                         if(cl.stats[STAT_AMMO] > 10)
1441                                                 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1442                                         else
1443                                                 Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1444                                 }
1445
1446                                 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1447                                         Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1448                                 if (sbar_x > 0)
1449                                         Sbar_Score(16);
1450                                         // The margin can be at most 8 to support 640x480 console size:
1451                                         //   320 + 2 * (144 + 16) = 640
1452                         }
1453                         else if (sb_lines)
1454                         {
1455                                 int i;
1456                                 float fade;
1457                                 int redflag, blueflag;
1458                                 float x;
1459
1460                                 sbar_x = (vid_conwidth.integer - 640)/2;
1461                                 sbar_y = vid_conheight.integer - 47;
1462
1463                                 // calculate intensity to draw weapons bar at
1464                                 fade = 3 - 2 * (cl.time - cl.weapontime);
1465                                 if (fade > 0)
1466                                 {
1467                                         fade = min(fade, 1);
1468                                         for (i = 0; i < 8;i++)
1469                                                 if (cl.stats[STAT_ITEMS] & (1 << i))
1470                                                         Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1471
1472                                         if((cl.stats[STAT_ITEMS] & (1<<12)))
1473                                                 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1474                                 }
1475
1476                                 //if (!cl.islocalgame)
1477                                 //      Sbar_DrawFrags ();
1478
1479                                 if (sb_lines > 24)
1480                                         Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1481                                 else
1482                                         Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1483
1484                                 // flag icons
1485                                 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1486                                 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1487                                 x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x;
1488                                 if (redflag == 3 && blueflag == 3)
1489                                 {
1490                                         // The Impossible Combination[tm]
1491                                         // Can only happen in Key Hunt mode...
1492                                         Sbar_DrawPic ((int) x, -179, sb_items[14]);
1493                                 }
1494                                 else
1495                                 {
1496                                         if (redflag)
1497                                                 Sbar_DrawPic ((int) x, -117, sb_items[redflag+10]);
1498                                         if (blueflag)
1499                                                 Sbar_DrawPic ((int) x, -177, sb_items[blueflag+14]);
1500                                 }
1501
1502                                 // armor
1503                                 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1504
1505                                 // health
1506                                 if(cl.stats[STAT_HEALTH] > 100)
1507                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1508                                 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1509                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1510                                 else
1511                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1512
1513                                 // AK dont draw ammo for the laser
1514                                 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1515                                 {
1516                                         if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1517                                                 Sbar_DrawPic (519, 0, sb_ammo[0]);
1518                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1519                                                 Sbar_DrawPic (519, 0, sb_ammo[1]);
1520                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1521                                                 Sbar_DrawPic (519, 0, sb_ammo[2]);
1522                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1523                                                 Sbar_DrawPic (519, 0, sb_ammo[3]);
1524
1525                                         if(cl.stats[STAT_AMMO] <= 10)
1526                                                 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1527                                         else
1528                                                 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1529
1530                                 }
1531
1532                                 if (sb_lines > 24)
1533                                         DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1534
1535                                 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1536                                         Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1537
1538                                 if (sbar_x > 0)
1539                                         Sbar_Score(-16);
1540                                         // Because:
1541                                         //   Mini scoreboard uses 12*4 per other team, that is, 144
1542                                         //   pixels when there are four teams...
1543                                         //   Nexuiz by default sets vid_conwidth to 800... makes
1544                                         //   sbar_x == 80...
1545                                         //   so we need to shift it by 64 pixels to the right to fit
1546                                         //   BUT: then it overlaps with the image that gets drawn
1547                                         //   for viewsize 100! Therefore, just account for 3 teams,
1548                                         //   that is, 96 pixels mini scoreboard size, needing 16 pixels
1549                                         //   to the right!
1550                         }
1551                 }
1552                 else if (gamemode == GAME_ZYMOTIC)
1553                 {
1554 #if 1
1555                         float scale = 64.0f / 256.0f;
1556                         float kickoffset[3];
1557                         VectorClear(kickoffset);
1558                         if (v_dmg_time > 0)
1559                         {
1560                                 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1561                                 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1562                         }
1563                         sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1564                         sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1565                         // left1 16, 48 : 126 -66
1566                         // left2 16, 128 : 196 -66
1567                         // right 176, 48 : 196 -136
1568                         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);
1569                         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);
1570                         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);
1571                         DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1572 #else
1573                         float scale = 128.0f / 256.0f;
1574                         float healthstart, healthheight, healthstarttc, healthendtc;
1575                         float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1576                         float ammostart, ammoheight, ammostarttc, ammoendtc;
1577                         float clipstart, clipheight, clipstarttc, clipendtc;
1578                         float kickoffset[3], offset;
1579                         VectorClear(kickoffset);
1580                         if (v_dmg_time > 0)
1581                         {
1582                                 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1583                                 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1584                         }
1585                         sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1586                         sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1587                         offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1588                         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);
1589                         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);
1590                         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);
1591                         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);
1592                         healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1593                         shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1594                         healthstart = 204 - healthheight;
1595                         shieldstart = healthstart - shieldheight;
1596                         healthstarttc = healthstart * (1.0f / 256.0f);
1597                         healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1598                         shieldstarttc = shieldstart * (1.0f / 256.0f);
1599                         shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1600                         ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1601                         ammostart = 114 - ammoheight;
1602                         ammostarttc = ammostart * (1.0f / 256.0f);
1603                         ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1604                         clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1605                         clipstart = 190 - clipheight;
1606                         clipstarttc = clipstart * (1.0f / 256.0f);
1607                         clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1608                         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);
1609                         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);
1610                         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);
1611                         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);
1612                         DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1613                         DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1614 #endif
1615                 }
1616                 else // Quake and others
1617                 {
1618                         sbar_x = (vid_conwidth.integer - 320)/2;
1619                         sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1620                         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1621                         //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1622
1623                         if (sb_lines > 24)
1624                         {
1625                                 if (gamemode != GAME_GOODVSBAD2)
1626                                         Sbar_DrawInventory ();
1627                                 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1628                                         Sbar_DrawFrags ();
1629                         }
1630
1631                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1632                         {
1633                                 if (gamemode != GAME_GOODVSBAD2)
1634                                         Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1635                                 Sbar_DrawScoreboard ();
1636                         }
1637                         else if (sb_lines)
1638                         {
1639                                 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1640
1641                                 // keys (hipnotic only)
1642                                 //MED 01/04/97 moved keys here so they would not be overwritten
1643                                 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH)
1644                                 {
1645                                         if (cl.stats[STAT_ITEMS] & IT_KEY1)
1646                                                 Sbar_DrawPic (209, 3, sb_items[0]);
1647                                         if (cl.stats[STAT_ITEMS] & IT_KEY2)
1648                                                 Sbar_DrawPic (209, 12, sb_items[1]);
1649                                 }
1650                                 // armor
1651                                 if (gamemode != GAME_GOODVSBAD2)
1652                                 {
1653                                         if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1654                                         {
1655                                                 Sbar_DrawNum (24, 0, 666, 3, 1);
1656                                                 Sbar_DrawPic (0, 0, sb_disc);
1657                                         }
1658                                         else
1659                                         {
1660                                                 if (gamemode == GAME_ROGUE)
1661                                                 {
1662                                                         Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1663                                                         if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1664                                                                 Sbar_DrawPic (0, 0, sb_armor[2]);
1665                                                         else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1666                                                                 Sbar_DrawPic (0, 0, sb_armor[1]);
1667                                                         else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1668                                                                 Sbar_DrawPic (0, 0, sb_armor[0]);
1669                                                 }
1670                                                 else
1671                                                 {
1672                                                         Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1673                                                         if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1674                                                                 Sbar_DrawPic (0, 0, sb_armor[2]);
1675                                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1676                                                                 Sbar_DrawPic (0, 0, sb_armor[1]);
1677                                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1678                                                                 Sbar_DrawPic (0, 0, sb_armor[0]);
1679                                                 }
1680                                         }
1681                                 }
1682
1683                                 // face
1684                                 Sbar_DrawFace ();
1685
1686                                 // health
1687                                 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1688
1689                                 // ammo icon
1690                                 if (gamemode == GAME_ROGUE)
1691                                 {
1692                                         if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1693                                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
1694                                         else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1695                                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
1696                                         else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1697                                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
1698                                         else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1699                                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
1700                                         else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1701                                                 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1702                                         else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1703                                                 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1704                                         else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1705                                                 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1706                                 }
1707                                 else
1708                                 {
1709                                         if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1710                                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
1711                                         else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1712                                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
1713                                         else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1714                                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
1715                                         else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1716                                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
1717                                 }
1718
1719                                 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1720
1721                                 // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1722                                 if ((!cl.islocalgame || cl.gametype != GAME_COOP))
1723                                 {
1724                                         if (gamemode == GAME_TRANSFUSION)
1725                                                 Sbar_MiniDeathmatchOverlay (0, 0);
1726                                         else
1727                                                 Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8);
1728                                         Sbar_Score(24);
1729                                 }
1730                         }
1731                 }
1732         }
1733
1734         if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
1735         {
1736                 pic = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/crosshair%i", crosshair.integer));
1737                 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);
1738         }
1739
1740         if (cl_prydoncursor.integer > 0)
1741                 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);
1742 }
1743
1744 //=============================================================================
1745
1746 /*
1747 ==================
1748 Sbar_DeathmatchOverlay
1749
1750 ==================
1751 */
1752 static float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1753 {
1754         int minutes;
1755         qboolean myself = false;
1756         unsigned char *c;
1757         char vabuf[1024];
1758         minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1759
1760         if((s - cl.scores) == cl.playerentity - 1)
1761                 myself = true;
1762         if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1763                 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1764                         myself = true;
1765
1766         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1767         {
1768                 if (s->qw_spectator)
1769                 {
1770                         if (s->qw_ping || s->qw_packetloss)
1771                                 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 );
1772                         else
1773                                 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 );
1774                 }
1775                 else
1776                 {
1777                         // draw colors behind score
1778                         //
1779                         //
1780                         //
1781                         //
1782                         //
1783                         c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1784                         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);
1785                         c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1786                         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);
1787                         // print the text
1788                         //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);
1789                         if (s->qw_ping || s->qw_packetloss)
1790                                 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 );
1791                         else
1792                                 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 );
1793                 }
1794         }
1795         else
1796         {
1797                 if (s->qw_spectator)
1798                 {
1799                         if (s->qw_ping || s->qw_packetloss)
1800                                 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 );
1801                         else
1802                                 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 );
1803                 }
1804                 else
1805                 {
1806                         // draw colors behind score
1807                         c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4];
1808                         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);
1809                         c = palette_rgb_shirtscoreboard[s->colors & 0xf];
1810                         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);
1811                         // print the text
1812                         //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);
1813                         if (s->qw_ping || s->qw_packetloss)
1814                                 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 );
1815                         else
1816                                 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 );
1817                 }
1818         }
1819         return 8;
1820 }
1821
1822 void Sbar_DeathmatchOverlay (void)
1823 {
1824         int i, y, xmin, xmax, ymin, ymax;
1825         char vabuf[1024];
1826
1827         // request new ping times every two second
1828         if (cl.last_ping_request < realtime - 2 && cls.netcon)
1829         {
1830                 cl.last_ping_request = realtime;
1831                 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1832                 {
1833                         MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1834                         MSG_WriteString(&cls.netcon->message, "pings");
1835                 }
1836                 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*/)
1837                 {
1838                         // 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
1839                         static int ping_anyway_counter = 0;
1840                         if(cl.parsingtextexpectingpingforscores == 1)
1841                         {
1842                                 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1843                                 if(++ping_anyway_counter >= 5)
1844                                         cl.parsingtextexpectingpingforscores = 0;
1845                         }
1846                         if(cl.parsingtextexpectingpingforscores != 1)
1847                         {
1848                                 ping_anyway_counter = 0;
1849                                 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1850                                 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1851                                 MSG_WriteString(&cls.netcon->message, "ping");
1852                         }
1853                 }
1854                 else
1855                 {
1856                         // 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
1857                         MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1858                         MSG_WriteString(&cls.netcon->message, "pings");
1859                 }
1860         }
1861
1862         // scores
1863         Sbar_SortFrags ();
1864
1865         ymin = 8;
1866         ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1;
1867
1868         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1869                 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)
1870         else
1871                 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)
1872         xmax = vid_conwidth.integer - xmin;
1873
1874         if(IS_OLDNEXUIZ_DERIVED(gamemode))
1875                 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);
1876
1877         DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1878
1879         // draw the text
1880         y = 40;
1881         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1882         {
1883                 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 );
1884         }
1885         else
1886         {
1887                 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 );
1888         }
1889         y += 8;
1890
1891         if (Sbar_IsTeammatch ())
1892         {
1893                 // show team scores first
1894                 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1895                         y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y);
1896                 y += 5;
1897         }
1898
1899         for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1900                 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y);
1901 }
1902
1903 /*
1904 ==================
1905 Sbar_MiniDeathmatchOverlay
1906
1907 ==================
1908 */
1909 void Sbar_MiniDeathmatchOverlay (int x, int y)
1910 {
1911         int i, j, numlines, range_begin, range_end, myteam, teamsep;
1912
1913         // do not draw this if sbar_miniscoreboard_size is zero
1914         if(sbar_miniscoreboard_size.value == 0)
1915                 return;
1916         // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1917         if(sbar_miniscoreboard_size.value > 0)
1918                 y = (int) (vid_conheight.integer - sbar_miniscoreboard_size.value * 8);
1919
1920         // scores
1921         Sbar_SortFrags ();
1922
1923         // decide where to print
1924         if (gamemode == GAME_TRANSFUSION)
1925                 numlines = (vid_conwidth.integer - x + 127) / 128;
1926         else
1927                 numlines = (vid_conheight.integer - y + 7) / 8;
1928
1929         // give up if there isn't room
1930         if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1931                 return;
1932
1933         //find us
1934         for (i = 0; i < scoreboardlines; i++)
1935                 if (fragsort[i] == cl.playerentity - 1)
1936                         break;
1937
1938         range_begin = 0;
1939         range_end = scoreboardlines;
1940         teamsep = 0;
1941
1942         if (gamemode != GAME_TRANSFUSION)
1943                 if (Sbar_IsTeammatch ())
1944                 {
1945                         // reserve space for the team scores
1946                         numlines -= teamlines;
1947
1948                         // find first and last player of my team (only draw the team totals and my own team)
1949                         range_begin = range_end = i;
1950                         myteam = cl.scores[fragsort[i]].colors & 15;
1951                         while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1952                                 --range_begin;
1953                         while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1954                                 ++range_end;
1955
1956                         // looks better than two players
1957                         if(numlines == 2)
1958                         {
1959                                 teamsep = 8;
1960                                 numlines = 1;
1961                         }
1962                 }
1963
1964         // figure out start
1965         i -= numlines/2;
1966         i = min(i, range_end - numlines);
1967         i = max(i, range_begin);
1968
1969         if (gamemode == GAME_TRANSFUSION)
1970         {
1971                 for (;i < range_end && x < vid_conwidth.integer;i++)
1972                         x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1973         }
1974         else
1975         {
1976                 if(range_end - i < numlines) // won't draw to bottom?
1977                         y += 8 * (numlines - (range_end - i)); // bottom align
1978                 // show team scores first
1979                 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1980                         y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1981                 y += teamsep;
1982                 for (;i < range_end && y < vid_conheight.integer;i++)
1983                         y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1984         }
1985 }
1986
1987 static int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1988 {
1989         static int const sortorder[16] =
1990         {
1991                 1001,
1992                 1002,
1993                 1003,
1994                 1004,
1995                 1, // red
1996                 1005,
1997                 1006,
1998                 1007,
1999                 1008,
2000                 4, // pink
2001                 1009,
2002                 1010,
2003                 3, // yellow
2004                 2, // blue
2005                 1011,
2006                 1012
2007         };
2008         const scoreboard_t *t1 = *(scoreboard_t **) t1_;
2009         const scoreboard_t *t2 = *(scoreboard_t **) t2_;
2010         int tc1 = sortorder[t1->colors & 15];
2011         int tc2 = sortorder[t2->colors & 15];
2012         return tc1 - tc2;
2013 }
2014
2015 void Sbar_Score (int margin)
2016 {
2017         int i, me, score, otherleader, place, distribution, minutes, seconds;
2018         double timeleft;
2019         int sbar_x_save = sbar_x;
2020         int sbar_y_save = sbar_y;
2021
2022
2023         sbar_y = (int) (vid_conheight.value - (32+12));
2024         sbar_x -= margin;
2025
2026         me = cl.playerentity - 1;
2027         if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients)
2028         {
2029                 if(Sbar_IsTeammatch())
2030                 {
2031                         // Layout:
2032                         //
2033                         //   team1 team3 team4
2034                         //
2035                         //         TEAM2
2036
2037                         scoreboard_t *teamcolorsort[16];
2038
2039                         Sbar_SortFrags();
2040                         for(i = 0; i < teamlines; ++i)
2041                                 teamcolorsort[i] = &(teams[i]);
2042
2043                         // Now sort them by color
2044                         qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
2045
2046                         // : margin
2047                         // -12*4: four digits space
2048                         place = (teamlines - 1) * (-12 * 4);
2049
2050                         for(i = 0; i < teamlines; ++i)
2051                         {
2052                                 int cindex = teamcolorsort[i]->colors & 15;
2053                                 unsigned char *c = palette_rgb_shirtscoreboard[cindex];
2054                                 float cm = max(max(c[0], c[1]), c[2]);
2055                                 float cr = c[0] / cm;
2056                                 float cg = c[1] / cm;
2057                                 float cb = c[2] / cm;
2058                                 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
2059                                 {
2060                                         Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
2061                                 }
2062                                 else // other team
2063                                 {
2064                                         Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
2065                                         place += 4 * 12;
2066                                 }
2067                         }
2068                 }
2069                 else
2070                 {
2071                         // Layout:
2072                         //
2073                         //   leading  place
2074                         //
2075                         //        FRAGS
2076                         //
2077                         // find leading score other than ourselves, to calculate distribution
2078                         // find our place in the scoreboard
2079                         score = cl.scores[me].frags;
2080                         for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
2081                         {
2082                                 if (cl.scores[i].name[0] && i != me)
2083                                 {
2084                                         if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
2085                                                 otherleader = i;
2086                                         if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
2087                                                 place++;
2088                                 }
2089                         }
2090                         distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
2091                         if (place == 1)
2092                                 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
2093                         else if (place == 2)
2094                                 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
2095                         else
2096                                 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
2097                         if (otherleader < 0)
2098                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 1, 1, 1, 0);
2099                         if (distribution >= 0)
2100                         {
2101                                 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
2102                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 1, 1, 1, 0);
2103                         }
2104                         else if (distribution >= -5)
2105                         {
2106                                 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
2107                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 1, 0, 1, 0);
2108                         }
2109                         else
2110                         {
2111                                 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
2112                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 0, 0, 1, 0);
2113                         }
2114                 }
2115         }
2116
2117         if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT])
2118         {
2119                 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
2120                 minutes = (int)floor(timeleft / 60);
2121                 seconds = (int)(floor(timeleft) - minutes * 60);
2122                 if (minutes >= 5)
2123                 {
2124                         Sbar_DrawXNum(-12*6, 32, minutes,  3, 12, 1, 1, 1, 1, 0);
2125                         if(sb_colon && sb_colon->tex != r_texture_notexture)
2126                                 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2127                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2128                 }
2129                 else if (minutes >= 1)
2130                 {
2131                         Sbar_DrawXNum(-12*6, 32, minutes,  3, 12, 1, 1, 0, 1, 0);
2132                         if(sb_colon && sb_colon->tex != r_texture_notexture)
2133                                 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
2134                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
2135                 }
2136                 else if ((int)(timeleft * 4) & 1)
2137                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2138                 else
2139                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
2140         }
2141         else if (sbar_gametime.integer)
2142         {
2143                 minutes = (int)floor(cl.time / 60);
2144                 seconds = (int)(floor(cl.time) - minutes * 60);
2145                 Sbar_DrawXNum(-12*6, 32, minutes,  3, 12, 1, 1, 1, 1, 0);
2146                 if(sb_colon && sb_colon->tex != r_texture_notexture)
2147                         DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
2148                 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
2149         }
2150
2151         sbar_x = sbar_x_save;
2152         sbar_y = sbar_y_save;
2153 }
2154
2155 /*
2156 ==================
2157 Sbar_IntermissionOverlay
2158
2159 ==================
2160 */
2161 void Sbar_IntermissionOverlay (void)
2162 {
2163         int             dig;
2164         int             num;
2165
2166         if (cl.gametype == GAME_DEATHMATCH)
2167         {
2168                 Sbar_DeathmatchOverlay ();
2169                 return;
2170         }
2171
2172         sbar_x = (vid_conwidth.integer - 320) >> 1;
2173         sbar_y = (vid_conheight.integer - 200) >> 1;
2174
2175         DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2176         DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2177
2178 // time
2179         dig = (int)cl.completed_time / 60;
2180         Sbar_DrawNum (160, 64, dig, 3, 0);
2181         num = (int)cl.completed_time - dig*60;
2182         Sbar_DrawPic (234,64,sb_colon);
2183         Sbar_DrawPic (246,64,sb_nums[0][num/10]);
2184         Sbar_DrawPic (266,64,sb_nums[0][num%10]);
2185
2186 // LA: Display as "a" instead of "a/b" if b is 0
2187         if(cl.stats[STAT_TOTALSECRETS])
2188         {
2189                 Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
2190                 if (!IS_OLDNEXUIZ_DERIVED(gamemode))
2191                         Sbar_DrawPic (232, 104, sb_slash);
2192                 Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
2193         }
2194         else
2195         {
2196                 Sbar_DrawNum (240, 104, cl.stats[STAT_SECRETS], 3, 0);
2197         }
2198
2199         if(cl.stats[STAT_TOTALMONSTERS])
2200         {
2201                 Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
2202                 if (!IS_OLDNEXUIZ_DERIVED(gamemode))
2203                         Sbar_DrawPic (232, 144, sb_slash);
2204                 Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2205         }
2206         else
2207         {
2208                 Sbar_DrawNum (240, 144, cl.stats[STAT_MONSTERS], 3, 0);
2209         }
2210 }
2211
2212
2213 /*
2214 ==================
2215 Sbar_FinaleOverlay
2216
2217 ==================
2218 */
2219 void Sbar_FinaleOverlay (void)
2220 {
2221         DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2222 }
2223