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