intermission: store the current time to completed_time only on the first svc_intermis...
[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, true);
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             i, max;
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 (gamemode != GAME_NEXUIZ)
638                 Sbar_DrawString(8, 4, va("Monsters:%3i /%3i    Secrets :%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS], cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
639
640         // figure out the map's filename without path or extension
641         strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
642         if (strrchr(str, '.'))
643                 *(strrchr(str, '.')) = 0;
644
645         // append a : separator and then the full title
646         strlcat(str, ":", sizeof(str));
647         strlcat(str, cl.levelname, sizeof(str));
648
649         // make the time string
650         max = 38 - sprintf(timestr, " %i:%02i", minutes, seconds);
651
652         // if there's a newline character, terminate the string there
653         if (strchr(str, '\n'))
654                 *(strchr(str, '\n')) = 0;
655
656         // pad with spaces to fill the allotted space and append the time
657         i = bound(0, (int)strlen(str), max);
658         while (i < max)
659                 str[i++] = ' ';
660         str[i] = 0;
661         strlcat(str, timestr, sizeof(str));
662
663         // print the line of text
664         Sbar_DrawString(8, 12, str);
665
666 #else
667         char    str[80];
668         int             minutes, seconds, tens, units;
669         int             l;
670
671         if (gamemode != GAME_NEXUIZ) {
672                 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
673                 Sbar_DrawString (8, 4, str);
674
675                 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
676                 Sbar_DrawString (8, 12, str);
677         }
678
679 // time
680         minutes = (int)(cl.time / 60);
681         seconds = (int)(cl.time - 60*minutes);
682         tens = seconds / 10;
683         units = seconds - 10*tens;
684         sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
685         Sbar_DrawString (184, 4, str);
686
687 // draw level name
688         if (gamemode == GAME_NEXUIZ) {
689                 l = (int) strlen (cl.worldmodel->name);
690                 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
691         } else {
692                 l = (int) strlen (cl.levelname);
693                 Sbar_DrawString (232 - l*4, 12, cl.levelname);
694         }
695 #endif
696 }
697
698 /*
699 ===============
700 Sbar_DrawScoreboard
701 ===============
702 */
703 void Sbar_DrawScoreboard (void)
704 {
705         Sbar_SoloScoreboard ();
706         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
707         //if (cl.gametype == GAME_DEATHMATCH)
708         if (!cl.islocalgame)
709                 Sbar_DeathmatchOverlay ();
710 }
711
712 //=============================================================================
713
714 // AK to make DrawInventory smaller
715 static void Sbar_DrawWeapon(int nr, float fade, int active)
716 {
717         // width = 300, height = 100
718         const int w_width = 300, w_height = 100, w_space = 10;
719         const float w_scale = 0.4;
720
721         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);
722         //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);
723 }
724
725 /*
726 ===============
727 Sbar_DrawInventory
728 ===============
729 */
730 void Sbar_DrawInventory (void)
731 {
732         int i;
733         char num[6];
734         float time;
735         int flashon;
736
737         if (gamemode == GAME_ROGUE)
738         {
739                 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
740                         Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
741                 else
742                         Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
743         }
744         else
745                 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
746
747         // weapons
748         for (i=0 ; i<7 ; i++)
749         {
750                 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
751                 {
752                         time = cl.item_gettime[i];
753                         flashon = (int)(max(0, cl.time - time)*10);
754                         if (flashon >= 10)
755                         {
756                                 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i)  )
757                                         flashon = 1;
758                                 else
759                                         flashon = 0;
760                         }
761                         else
762                                 flashon = (flashon%5) + 2;
763
764                         Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
765                 }
766         }
767
768         // MED 01/04/97
769         // hipnotic weapons
770         if (gamemode == GAME_HIPNOTIC)
771         {
772                 int grenadeflashing=0;
773                 for (i=0 ; i<4 ; i++)
774                 {
775                         if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
776                         {
777                                 time = max(0, cl.item_gettime[hipweapons[i]]);
778                                 flashon = (int)((cl.time - time)*10);
779                                 if (flashon >= 10)
780                                 {
781                                         if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i])  )
782                                                 flashon = 1;
783                                         else
784                                                 flashon = 0;
785                                 }
786                                 else
787                                         flashon = (flashon%5) + 2;
788
789                                 // check grenade launcher
790                                 if (i==2)
791                                 {
792                                         if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
793                                         {
794                                                 if (flashon)
795                                                 {
796                                                         grenadeflashing = 1;
797                                                         Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
798                                                 }
799                                         }
800                                 }
801                                 else if (i==3)
802                                 {
803                                         if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
804                                         {
805                                                 if (!grenadeflashing)
806                                                         Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
807                                         }
808                                         else
809                                                 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
810                                 }
811                                 else
812                                         Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
813                         }
814                 }
815         }
816
817         if (gamemode == GAME_ROGUE)
818         {
819                 // check for powered up weapon.
820                 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
821                         for (i=0;i<5;i++)
822                                 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
823                                         Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
824         }
825
826         // ammo counts
827         for (i=0 ; i<4 ; i++)
828         {
829                 sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] );
830                 if (num[0] != ' ')
831                         Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
832                 if (num[1] != ' ')
833                         Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
834                 if (num[2] != ' ')
835                         Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
836         }
837
838         // items
839         for (i=0 ; i<6 ; i++)
840                 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
841                 {
842                         //MED 01/04/97 changed keys
843                         if (gamemode != GAME_HIPNOTIC || (i>1))
844                                 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
845                 }
846
847         //MED 01/04/97 added hipnotic items
848         // hipnotic items
849         if (gamemode == GAME_HIPNOTIC)
850         {
851                 for (i=0 ; i<2 ; i++)
852                         if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
853                                 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
854         }
855
856         if (gamemode == GAME_ROGUE)
857         {
858                 // new rogue items
859                 for (i=0 ; i<2 ; i++)
860                         if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
861                                 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
862         }
863         else
864         {
865                 // sigils
866                 for (i=0 ; i<4 ; i++)
867                         if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
868                                 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
869         }
870 }
871
872 //=============================================================================
873
874 /*
875 ===============
876 Sbar_DrawFrags
877 ===============
878 */
879 void Sbar_DrawFrags (void)
880 {
881         int i, k, l, x, f;
882         char num[12];
883         scoreboard_t *s;
884         unsigned char *c;
885
886         Sbar_SortFrags ();
887
888         // draw the text
889         l = min(scoreboardlines, 4);
890
891         x = 23 * 8;
892
893         for (i = 0;i < l;i++)
894         {
895                 k = fragsort[i];
896                 s = &cl.scores[k];
897
898                 // draw background
899                 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
900                 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);
901                 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
902                 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);
903
904                 // draw number
905                 f = s->frags;
906                 sprintf (num, "%3i",f);
907
908                 if (k == cl.viewentity - 1)
909                 {
910                         Sbar_DrawCharacter ( x      + 2, -24, 16);
911                         Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
912                 }
913                 Sbar_DrawCharacter (x +  8, -24, num[0]);
914                 Sbar_DrawCharacter (x + 16, -24, num[1]);
915                 Sbar_DrawCharacter (x + 24, -24, num[2]);
916                 x += 32;
917         }
918 }
919
920 //=============================================================================
921
922
923 /*
924 ===============
925 Sbar_DrawFace
926 ===============
927 */
928 void Sbar_DrawFace (void)
929 {
930         int f;
931
932 // PGM 01/19/97 - team color drawing
933 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
934         if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
935         {
936                 char num[12];
937                 scoreboard_t *s;
938                 unsigned char *c;
939
940                 s = &cl.scores[cl.viewentity - 1];
941                 // draw background
942                 Sbar_DrawPic (112, 0, rsb_teambord);
943                 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
944                 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);
945                 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
946                 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);
947
948                 // draw number
949                 f = s->frags;
950                 sprintf (num, "%3i",f);
951
952                 if ((s->colors & 0xf0)==0)
953                 {
954                         if (num[0] != ' ')
955                                 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
956                         if (num[1] != ' ')
957                                 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
958                         if (num[2] != ' ')
959                                 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
960                 }
961                 else
962                 {
963                         Sbar_DrawCharacter ( 109, 3, num[0]);
964                         Sbar_DrawCharacter ( 116, 3, num[1]);
965                         Sbar_DrawCharacter ( 123, 3, num[2]);
966                 }
967
968                 return;
969         }
970 // PGM 01/19/97 - team color drawing
971
972         if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
973                 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
974         else if (cl.stats[STAT_ITEMS] & IT_QUAD)
975                 Sbar_DrawPic (112, 0, sb_face_quad );
976         else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
977                 Sbar_DrawPic (112, 0, sb_face_invis );
978         else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
979                 Sbar_DrawPic (112, 0, sb_face_invuln);
980         else
981         {
982                 f = cl.stats[STAT_HEALTH] / 20;
983                 f = bound(0, f, 4);
984                 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
985         }
986 }
987
988 void Sbar_ShowFPS(void)
989 {
990         float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
991         char fpsstring[32];
992         char timestring[32];
993         char datestring[32];
994         qboolean red = false;
995         fpsstring[0] = 0;
996         timestring[0] = 0;
997         datestring[0] = 0;
998         if (showfps.integer)
999         {
1000                 float calc;
1001                 static double nexttime = 0, lasttime = 0;
1002                 static double framerate = 0;
1003                 static int framecount = 0;
1004                 double newtime;
1005                 newtime = realtime;
1006                 if (newtime >= nexttime)
1007                 {
1008                         framerate = framecount / (newtime - lasttime);
1009                         lasttime = newtime;
1010                         nexttime = max(nexttime + 1, lasttime - 1);
1011                         framecount = 0;
1012                 }
1013                 framecount++;
1014                 calc = framerate;
1015
1016                 if ((red = (calc < 1.0f)))
1017                         dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1018                 else
1019                         dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1020         }
1021         if (showtime.integer)
1022                 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1023         if (showdate.integer)
1024                 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1025         if (fpsstring[0] || timestring[0])
1026         {
1027                 fps_scalex = 12;
1028                 fps_scaley = 12;
1029                 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
1030                 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1031                 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1032                 fps_y = vid_conheight.integer - fps_height;
1033                 if (fpsstring[0])
1034                 {
1035                         fps_x = vid_conwidth.integer - fps_scalex * strlen(fpsstring);
1036                         DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(fpsstring), fps_scaley, 0, 0, 0, 0.5, 0);
1037                         if (red)
1038                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true);
1039                         else
1040                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1041                         fps_y += fps_scaley;
1042                 }
1043                 if (timestring[0])
1044                 {
1045                         fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
1046                         DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(timestring), fps_scaley, 0, 0, 0, 0.5, 0);
1047                         DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1048                         fps_y += fps_scaley;
1049                 }
1050                 if (datestring[0])
1051                 {
1052                         fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
1053                         DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(datestring), fps_scaley, 0, 0, 0, 0.5, 0);
1054                         DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1055                         fps_y += fps_scaley;
1056                 }
1057         }
1058 }
1059
1060 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)
1061 {
1062         float r[5];
1063         c2 = bound(0, c2, 1);
1064         c1 = bound(0, c1, 1 - c2);
1065         r[0] = 0;
1066         r[1] = rangey + rangeheight * (c2 + c1);
1067         r[2] = rangey + rangeheight * (c2);
1068         r[3] = rangey;
1069         r[4] = height;
1070         if (r[1] > r[0])
1071                 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);
1072         if (r[2] > r[1])
1073                 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);
1074         if (r[3] > r[2])
1075                 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);
1076         if (r[4] > r[3])
1077                 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);
1078 }
1079
1080 /*
1081 ===============
1082 Sbar_Draw
1083 ===============
1084 */
1085 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1086 extern cvar_t v_kicktime;
1087 void Sbar_Draw (void)
1088 {
1089         cachepic_t *pic;
1090
1091         if(cl.csqc_vidvars.drawenginesbar)      //[515]: csqc drawsbar
1092         {
1093                 if (cl.intermission == 1)
1094                 {
1095                         if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1096                         {
1097                                 Sbar_DrawScoreboard();
1098                                 return;
1099                         }
1100                         Sbar_IntermissionOverlay();
1101                         return;
1102                 }
1103                 else if (cl.intermission == 2)
1104                 {
1105                         if(gamemode == GAME_NEXUIZ) // Nexuiz allows TAB to override the voting screens to recall the scores
1106                                 if(sb_showscores)
1107                                 {
1108                                         Sbar_DrawScoreboard();
1109                                         return;
1110                                 }
1111                         Sbar_FinaleOverlay();
1112                         return;
1113                 }
1114
1115                 if (gamemode == GAME_NETHERWORLD)
1116                 {
1117                 }
1118                 else if (gamemode == GAME_SOM)
1119                 {
1120                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1121                                 Sbar_DrawScoreboard ();
1122                         else if (sb_lines)
1123                         {
1124                                 // this is the top left of the sbar area
1125                                 sbar_x = 0;
1126                                 sbar_y = vid_conheight.integer - 24*3;
1127
1128                                 // armor
1129                                 if (cl.stats[STAT_ARMOR])
1130                                 {
1131                                         if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1132                                                 Sbar_DrawPic(0, 0, somsb_armor[2]);
1133                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1134                                                 Sbar_DrawPic(0, 0, somsb_armor[1]);
1135                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1136                                                 Sbar_DrawPic(0, 0, somsb_armor[0]);
1137                                         Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1138                                 }
1139
1140                                 // health
1141                                 Sbar_DrawPic(0, 24, somsb_health);
1142                                 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1143
1144                                 // ammo icon
1145                                 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1146                                         Sbar_DrawPic(0, 48, somsb_ammo[0]);
1147                                 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1148                                         Sbar_DrawPic(0, 48, somsb_ammo[1]);
1149                                 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1150                                         Sbar_DrawPic(0, 48, somsb_ammo[2]);
1151                                 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1152                                         Sbar_DrawPic(0, 48, somsb_ammo[3]);
1153                                 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1154                                 if (cl.stats[STAT_SHELLS])
1155                                         Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1156                         }
1157                 }
1158                 else if (gamemode == GAME_NEXUIZ)
1159                 {
1160                         sbar_y = vid_conheight.integer - 47;
1161                         sbar_x = (vid_conwidth.integer - 640)/2;
1162
1163                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1164                         {
1165                                 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1166                                 Sbar_DrawScoreboard ();
1167                         }
1168                         else if (sb_lines)
1169                         {
1170                                 int i;
1171                                 float fade;
1172                                 int redflag, blueflag;
1173
1174                                 // calculate intensity to draw weapons bar at
1175                                 fade = 3 - 2 * (cl.time - cl.weapontime);
1176                                 if (fade > 0)
1177                                 {
1178                                         fade = min(fade, 1);
1179                                         for (i = 0; i < 8;i++)
1180                                                 if (cl.stats[STAT_ITEMS] & (1 << i))
1181                                                         Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1182
1183                                         if((cl.stats[STAT_ITEMS] & (1<<12)))
1184                                                 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1185                                 }
1186
1187                                 //if (!cl.islocalgame)
1188                                 //      Sbar_DrawFrags ();
1189
1190                                 if (sb_lines > 24)
1191                                         Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1192                                 else
1193                                         Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1194
1195                                 // flag icons
1196                                 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1197                                 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1198                                 if (redflag == 3 && blueflag == 3)
1199                                 {
1200                                         // The Impossible Combination[tm]
1201                                         // Can only happen in Key Hunt mode...
1202                                         Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1203                                 }
1204                                 else
1205                                 {
1206                                         if (redflag)
1207                                                 Sbar_DrawPic (10 - sbar_x, -109, sb_items[redflag+10]);
1208                                         if (blueflag)
1209                                                 Sbar_DrawPic (10 - sbar_x, -169, sb_items[blueflag+14]);
1210                                 }
1211
1212                                 // armor
1213                                 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1214
1215                                 // health
1216                                 if(cl.stats[STAT_HEALTH] > 100)
1217                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1218                                 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1219                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1220                                 else
1221                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1222
1223                                 // AK dont draw ammo for the laser
1224                                 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1225                                 {
1226                                         if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1227                                                 Sbar_DrawPic (519, 0, sb_ammo[0]);
1228                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1229                                                 Sbar_DrawPic (519, 0, sb_ammo[1]);
1230                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1231                                                 Sbar_DrawPic (519, 0, sb_ammo[2]);
1232                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1233                                                 Sbar_DrawPic (519, 0, sb_ammo[3]);
1234
1235                                         if(cl.stats[STAT_AMMO] <= 10)
1236                                                 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1237                                         else
1238                                                 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1239
1240                                 }
1241
1242                                 if (sb_lines > 24)
1243                                         DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1244                         }
1245
1246                         //if (vid_conwidth.integer > 320 && cl.gametype == GAME_DEATHMATCH)
1247                         //      Sbar_MiniDeathmatchOverlay (0, 17);
1248                 }
1249                 else if (gamemode == GAME_ZYMOTIC)
1250                 {
1251 #if 1
1252                         float scale = 64.0f / 256.0f;
1253                         float kickoffset[3];
1254                         VectorClear(kickoffset);
1255                         if (v_dmg_time > 0)
1256                         {
1257                                 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1258                                 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1259                         }
1260                         sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1261                         sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1262                         // left1 16, 48 : 126 -66
1263                         // left2 16, 128 : 196 -66
1264                         // right 176, 48 : 196 -136
1265                         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);
1266                         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);
1267                         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);
1268                         DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1269 #else
1270                         float scale = 128.0f / 256.0f;
1271                         float healthstart, healthheight, healthstarttc, healthendtc;
1272                         float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1273                         float ammostart, ammoheight, ammostarttc, ammoendtc;
1274                         float clipstart, clipheight, clipstarttc, clipendtc;
1275                         float kickoffset[3], offset;
1276                         VectorClear(kickoffset);
1277                         if (v_dmg_time > 0)
1278                         {
1279                                 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1280                                 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1281                         }
1282                         sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1283                         sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1284                         offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1285                         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);
1286                         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);
1287                         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);
1288                         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);
1289                         healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1290                         shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1291                         healthstart = 204 - healthheight;
1292                         shieldstart = healthstart - shieldheight;
1293                         healthstarttc = healthstart * (1.0f / 256.0f);
1294                         healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1295                         shieldstarttc = shieldstart * (1.0f / 256.0f);
1296                         shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1297                         ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1298                         ammostart = 114 - ammoheight;
1299                         ammostarttc = ammostart * (1.0f / 256.0f);
1300                         ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1301                         clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1302                         clipstart = 190 - clipheight;
1303                         clipstarttc = clipstart * (1.0f / 256.0f);
1304                         clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1305                         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);
1306                         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);
1307                         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);
1308                         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);
1309                         DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1310                         DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1311 #endif
1312                 }
1313                 else // Quake and others
1314                 {
1315                         sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1316                         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1317                         //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1318                         if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1319                                 sbar_x = 0;
1320                         else
1321                                 sbar_x = (vid_conwidth.integer - 320)/2;
1322
1323                         if (sb_lines > 24)
1324                         {
1325                                 if (gamemode != GAME_GOODVSBAD2)
1326                                         Sbar_DrawInventory ();
1327                                 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1328                                         Sbar_DrawFrags ();
1329                         }
1330
1331                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1332                         {
1333                                 if (gamemode != GAME_GOODVSBAD2)
1334                                         Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1335                                 Sbar_DrawScoreboard ();
1336                         }
1337                         else if (sb_lines)
1338                         {
1339                                 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1340
1341                                 // keys (hipnotic only)
1342                                 //MED 01/04/97 moved keys here so they would not be overwritten
1343                                 if (gamemode == GAME_HIPNOTIC)
1344                                 {
1345                                         if (cl.stats[STAT_ITEMS] & IT_KEY1)
1346                                                 Sbar_DrawPic (209, 3, sb_items[0]);
1347                                         if (cl.stats[STAT_ITEMS] & IT_KEY2)
1348                                                 Sbar_DrawPic (209, 12, sb_items[1]);
1349                                 }
1350                                 // armor
1351                                 if (gamemode != GAME_GOODVSBAD2)
1352                                 {
1353                                         if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1354                                         {
1355                                                 Sbar_DrawNum (24, 0, 666, 3, 1);
1356                                                 Sbar_DrawPic (0, 0, sb_disc);
1357                                         }
1358                                         else
1359                                         {
1360                                                 if (gamemode == GAME_ROGUE)
1361                                                 {
1362                                                         Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1363                                                         if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1364                                                                 Sbar_DrawPic (0, 0, sb_armor[2]);
1365                                                         else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1366                                                                 Sbar_DrawPic (0, 0, sb_armor[1]);
1367                                                         else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1368                                                                 Sbar_DrawPic (0, 0, sb_armor[0]);
1369                                                 }
1370                                                 else
1371                                                 {
1372                                                         Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1373                                                         if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1374                                                                 Sbar_DrawPic (0, 0, sb_armor[2]);
1375                                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1376                                                                 Sbar_DrawPic (0, 0, sb_armor[1]);
1377                                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1378                                                                 Sbar_DrawPic (0, 0, sb_armor[0]);
1379                                                 }
1380                                         }
1381                                 }
1382
1383                                 // face
1384                                 Sbar_DrawFace ();
1385
1386                                 // health
1387                                 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1388
1389                                 // ammo icon
1390                                 if (gamemode == GAME_ROGUE)
1391                                 {
1392                                         if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1393                                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
1394                                         else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1395                                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
1396                                         else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1397                                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
1398                                         else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1399                                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
1400                                         else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1401                                                 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1402                                         else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1403                                                 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1404                                         else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1405                                                 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1406                                 }
1407                                 else
1408                                 {
1409                                         if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1410                                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
1411                                         else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1412                                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
1413                                         else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1414                                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
1415                                         else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1416                                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
1417                                 }
1418
1419                                 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1420
1421                         }
1422
1423                         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1424                         //if (vid_conwidth.integer > 320 && cl.gametype == GAME_DEATHMATCH)
1425                         if (!cl.islocalgame && vid_conwidth.integer > 320)
1426                         {
1427                                 if (gamemode == GAME_TRANSFUSION)
1428                                         Sbar_MiniDeathmatchOverlay (0, 0);
1429                                 else
1430                                         Sbar_MiniDeathmatchOverlay (324, vid_conheight.integer - sb_lines);
1431                         }
1432                 }
1433         }
1434
1435         Sbar_ShowFPS();
1436
1437         if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1438                 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);
1439
1440         if (cl_prydoncursor.integer)
1441                 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);
1442 }
1443
1444 //=============================================================================
1445
1446 /*
1447 ==================
1448 Sbar_DeathmatchOverlay
1449
1450 ==================
1451 */
1452 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1453 {
1454         int minutes;
1455         unsigned char *c;
1456         minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1457         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1458         {
1459                 if (s->qw_spectator)
1460                 {
1461                         if (s->qw_ping || s->qw_packetloss)
1462                                 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 );
1463                         else
1464                                 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 );
1465                 }
1466                 else
1467                 {
1468                         // draw colors behind score
1469                         c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1470                         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);
1471                         c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1472                         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);
1473                         // print the text
1474                         //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);
1475                         if (s->qw_ping || s->qw_packetloss)
1476                                 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 );
1477                         else
1478                                 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 );
1479                 }
1480         }
1481         else
1482         {
1483                 if (s->qw_spectator)
1484                 {
1485                         if (s->qw_ping || s->qw_packetloss)
1486                                 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 );
1487                         else
1488                                 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 );
1489                 }
1490                 else
1491                 {
1492                         // draw colors behind score
1493                         c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1494                         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);
1495                         c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1496                         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);
1497                         // print the text
1498                         //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);
1499                         if (s->qw_ping || s->qw_packetloss)
1500                                 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 );
1501                         else
1502                                 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 );
1503                 }
1504         }
1505         return 8;
1506 }
1507
1508 void Sbar_DeathmatchOverlay (void)
1509 {
1510         int i, x, y;
1511
1512         // request new ping times every two second
1513         if (cl.last_ping_request < realtime - 2 && cls.netcon)
1514         {
1515                 cl.last_ping_request = realtime;
1516                 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1517                 {
1518                         MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1519                         MSG_WriteString(&cls.netcon->message, "pings");
1520                 }
1521                 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*/)
1522                 {
1523                         // 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
1524                         static int ping_anyway_counter = 0;
1525                         if(cl.parsingtextexpectingpingforscores == 1)
1526                         {
1527                                 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1528                                 if(++ping_anyway_counter >= 5)
1529                                         cl.parsingtextexpectingpingforscores = 0;
1530                         }
1531                         if(cl.parsingtextexpectingpingforscores != 1)
1532                         {
1533                                 ping_anyway_counter = 0;
1534                                 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1535                                 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1536                                 MSG_WriteString(&cls.netcon->message, "ping");
1537                         }
1538                 }
1539                 else
1540                 {
1541                         // 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
1542                         MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1543                         MSG_WriteString(&cls.netcon->message, "pings");
1544                 }
1545         }
1546
1547         DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1548
1549         // scores
1550         Sbar_SortFrags ();
1551         // draw the text
1552         y = 40;
1553         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1554         {
1555                 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)
1556                 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 );
1557         }
1558         else
1559         {
1560                 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)
1561                 DrawQ_String(x, y, va("ping pl%% frags  name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1562         }
1563         y += 8;
1564
1565         if (Sbar_IsTeammatch ())
1566         {
1567                 // show team scores first
1568                 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1569                         y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1570                 y += 5;
1571         }
1572
1573         for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1574                 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1575 }
1576
1577 /*
1578 ==================
1579 Sbar_DeathmatchOverlay
1580
1581 ==================
1582 */
1583 void Sbar_MiniDeathmatchOverlay (int x, int y)
1584 {
1585         int i, numlines;
1586
1587         // decide where to print
1588         if (gamemode == GAME_TRANSFUSION)
1589                 numlines = (vid_conwidth.integer - x + 127) / 128;
1590         else
1591                 numlines = (vid_conheight.integer - y + 7) / 8;
1592
1593         // give up if there isn't room
1594         if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1595                 return;
1596
1597         // scores
1598         Sbar_SortFrags ();
1599
1600         //find us
1601         for (i = 0; i < scoreboardlines; i++)
1602                 if (fragsort[i] == cl.playerentity - 1)
1603                         break;
1604
1605         // figure out start
1606         i -= numlines/2;
1607         i = min(i, scoreboardlines - numlines);
1608         i = max(i, 0);
1609
1610         if (gamemode == GAME_TRANSFUSION)
1611         {
1612                 for (;i < scoreboardlines && x < vid_conwidth.integer;i++)
1613                         x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1614         }
1615         else
1616         {
1617                 for (;i < scoreboardlines && y < vid_conheight.integer;i++)
1618                         y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1619         }
1620 }
1621
1622 /*
1623 ==================
1624 Sbar_IntermissionOverlay
1625
1626 ==================
1627 */
1628 void Sbar_IntermissionOverlay (void)
1629 {
1630         int             dig;
1631         int             num;
1632
1633         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1634         //if (cl.gametype == GAME_DEATHMATCH)
1635         if (!cl.islocalgame)
1636         {
1637                 Sbar_DeathmatchOverlay ();
1638                 return;
1639         }
1640
1641         sbar_x = (vid_conwidth.integer - 320) >> 1;
1642         sbar_y = (vid_conheight.integer - 200) >> 1;
1643
1644         DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1645         DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1646
1647 // time
1648         dig = (int)cl.completed_time / 60;
1649         Sbar_DrawNum (160, 64, dig, 3, 0);
1650         num = (int)cl.completed_time - dig*60;
1651         if (gamemode != GAME_NEXUIZ)
1652                 Sbar_DrawPic (234,64,sb_colon);
1653         Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1654         Sbar_DrawPic (266,64,sb_nums[0][num%10]);
1655
1656         Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1657         if (gamemode != GAME_NEXUIZ)
1658                 Sbar_DrawPic (232, 104, sb_slash);
1659         Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1660
1661         Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1662         if (gamemode != GAME_NEXUIZ)
1663                 Sbar_DrawPic (232, 144, sb_slash);
1664         Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1665
1666 }
1667
1668
1669 /*
1670 ==================
1671 Sbar_FinaleOverlay
1672
1673 ==================
1674 */
1675 void Sbar_FinaleOverlay (void)
1676 {
1677         DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1678 }
1679