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