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