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