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