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