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