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