]> icculus.org git repositories - divverent/darkplaces.git/blob - sbar.c
fixed a bug with png loading on x86_64 platforms caused by libpng retardedness (it...
[divverent/darkplaces.git] / sbar.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // sbar.c -- status bar code
21
22 #include "quakedef.h"
23
24 cachepic_t *sb_disc;
25
26 #define STAT_MINUS 10 // num frame for '-' stats digit
27 cachepic_t *sb_nums[2][11];
28 cachepic_t *sb_colon, *sb_slash;
29 cachepic_t *sb_ibar;
30 cachepic_t *sb_sbar;
31 cachepic_t *sb_scorebar;
32 // AK only used by NEX
33 cachepic_t *sb_sbar_minimal;
34 cachepic_t *sb_sbar_overlay;
35
36 // AK changed the bound to 9
37 cachepic_t *sb_weapons[7][9]; // 0 is active, 1 is owned, 2-5 are flashes
38 cachepic_t *sb_ammo[4];
39 cachepic_t *sb_sigil[4];
40 cachepic_t *sb_armor[3];
41 cachepic_t *sb_items[32];
42
43 // 0-4 are based on health (in 20 increments)
44 // 0 is static, 1 is temporary animation
45 cachepic_t *sb_faces[5][2];
46
47 cachepic_t *sb_face_invis;
48 cachepic_t *sb_face_quad;
49 cachepic_t *sb_face_invuln;
50 cachepic_t *sb_face_invis_invuln;
51
52 qboolean sb_showscores;
53
54 int sb_lines;                   // scan lines to draw
55
56 cachepic_t *rsb_invbar[2];
57 cachepic_t *rsb_weapons[5];
58 cachepic_t *rsb_items[2];
59 cachepic_t *rsb_ammo[3];
60 cachepic_t *rsb_teambord;               // PGM 01/19/97 - team color border
61
62 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
63 cachepic_t *hsb_weapons[7][5];   // 0 is active, 1 is owned, 2-5 are flashes
64 //MED 01/04/97 added array to simplify weapon parsing
65 int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
66 //MED 01/04/97 added hipnotic items array
67 cachepic_t *hsb_items[2];
68
69 //GAME_SOM stuff:
70 cachepic_t *somsb_health;
71 cachepic_t *somsb_ammo[4];
72 cachepic_t *somsb_armor[3];
73
74 cachepic_t *zymsb_crosshair_center;
75 cachepic_t *zymsb_crosshair_line;
76 cachepic_t *zymsb_crosshair_health;
77 cachepic_t *zymsb_crosshair_ammo;
78 cachepic_t *zymsb_crosshair_clip;
79 cachepic_t *zymsb_crosshair_background;
80 cachepic_t *zymsb_crosshair_left1;
81 cachepic_t *zymsb_crosshair_left2;
82 cachepic_t *zymsb_crosshair_right;
83
84 cachepic_t *sb_ranking;
85 cachepic_t *sb_complete;
86 cachepic_t *sb_inter;
87 cachepic_t *sb_finale;
88
89 cvar_t showfps = {CVAR_SAVE, "showfps", "0", "shows your rendered fps (frames per second)"};
90 cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"};
91 cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"};
92 cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"};
93 cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"};
94 cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"};
95 cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"};
96
97 cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"};
98
99 cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"};
100 cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"};
101 cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"};
102 cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"};
103 cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"};
104
105 void Sbar_MiniDeathmatchOverlay (int x, int y);
106 void Sbar_DeathmatchOverlay (void);
107 void Sbar_IntermissionOverlay (void);
108 void Sbar_FinaleOverlay (void);
109
110
111 /*
112 ===============
113 Sbar_ShowScores
114
115 Tab key down
116 ===============
117 */
118 void Sbar_ShowScores (void)
119 {
120         if (sb_showscores)
121                 return;
122         sb_showscores = true;
123 }
124
125 /*
126 ===============
127 Sbar_DontShowScores
128
129 Tab key up
130 ===============
131 */
132 void Sbar_DontShowScores (void)
133 {
134         sb_showscores = false;
135 }
136
137 void sbar_start(void)
138 {
139         int i;
140
141         if (gamemode == GAME_NETHERWORLD)
142         {
143         }
144         else if (gamemode == GAME_SOM)
145         {
146                 sb_disc = Draw_CachePic("gfx/disc", true);
147
148                 for (i = 0;i < 10;i++)
149                         sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
150
151                 somsb_health = Draw_CachePic("gfx/hud_health", true);
152                 somsb_ammo[0] = Draw_CachePic("gfx/sb_shells", true);
153                 somsb_ammo[1] = Draw_CachePic("gfx/sb_nails", true);
154                 somsb_ammo[2] = Draw_CachePic("gfx/sb_rocket", true);
155                 somsb_ammo[3] = Draw_CachePic("gfx/sb_cells", true);
156                 somsb_armor[0] = Draw_CachePic("gfx/sb_armor1", true);
157                 somsb_armor[1] = Draw_CachePic("gfx/sb_armor2", true);
158                 somsb_armor[2] = Draw_CachePic("gfx/sb_armor3", true);
159         }
160         else if (gamemode == GAME_NEXUIZ)
161         {
162                 for (i = 0;i < 10;i++)
163                         sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
164                 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
165
166                 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
167                 sb_ammo[1] = Draw_CachePic ("gfx/sb_bullets", true);
168                 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
169                 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
170
171                 sb_items[2] = Draw_CachePic ("gfx/sb_slowmo", true);
172                 sb_items[3] = Draw_CachePic ("gfx/sb_invinc", true);
173                 sb_items[4] = Draw_CachePic ("gfx/sb_energy", true);
174                 sb_items[5] = Draw_CachePic ("gfx/sb_str", true);
175
176                 sb_items[11] = Draw_CachePic ("gfx/sb_flag_red_taken", true);
177                 sb_items[12] = Draw_CachePic ("gfx/sb_flag_red_lost", true);
178                 sb_items[13] = Draw_CachePic ("gfx/sb_flag_red_carrying", true);
179                 sb_items[15] = Draw_CachePic ("gfx/sb_flag_blue_taken", true);
180                 sb_items[16] = Draw_CachePic ("gfx/sb_flag_blue_lost", true);
181                 sb_items[17] = Draw_CachePic ("gfx/sb_flag_blue_carrying", true);
182
183                 sb_sbar = Draw_CachePic("gfx/sbar", true);
184                 sb_sbar_minimal = Draw_CachePic("gfx/sbar_minimal", true);
185                 sb_sbar_overlay = Draw_CachePic("gfx/sbar_overlay", true);
186
187                 for(i = 0; i < 9;i++)
188                         sb_weapons[0][i] = Draw_CachePic(va("gfx/inv_weapon%i",i), true);
189         }
190         else if (gamemode == GAME_ZYMOTIC)
191         {
192                 zymsb_crosshair_center = Draw_CachePic ("gfx/hud/crosshair_center", true);
193                 zymsb_crosshair_line = Draw_CachePic ("gfx/hud/crosshair_line", true);
194                 zymsb_crosshair_health = Draw_CachePic ("gfx/hud/crosshair_health", true);
195                 zymsb_crosshair_clip = Draw_CachePic ("gfx/hud/crosshair_clip", true);
196                 zymsb_crosshair_ammo = Draw_CachePic ("gfx/hud/crosshair_ammo", true);
197                 zymsb_crosshair_background = Draw_CachePic ("gfx/hud/crosshair_background", true);
198                 zymsb_crosshair_left1 = Draw_CachePic ("gfx/hud/crosshair_left1", true);
199                 zymsb_crosshair_left2 = Draw_CachePic ("gfx/hud/crosshair_left2", true);
200                 zymsb_crosshair_right = Draw_CachePic ("gfx/hud/crosshair_right", true);
201         }
202         else
203         {
204                 sb_disc = Draw_CachePic("gfx/disc", true);
205
206                 for (i = 0;i < 10;i++)
207                 {
208                         sb_nums[0][i] = Draw_CachePic (va("gfx/num_%i",i), true);
209                         sb_nums[1][i] = Draw_CachePic (va("gfx/anum_%i",i), true);
210                 }
211
212                 sb_nums[0][10] = Draw_CachePic ("gfx/num_minus", true);
213                 sb_nums[1][10] = Draw_CachePic ("gfx/anum_minus", true);
214
215                 sb_colon = Draw_CachePic ("gfx/num_colon", true);
216                 sb_slash = Draw_CachePic ("gfx/num_slash", true);
217
218                 sb_weapons[0][0] = Draw_CachePic ("gfx/inv_shotgun", true);
219                 sb_weapons[0][1] = Draw_CachePic ("gfx/inv_sshotgun", true);
220                 sb_weapons[0][2] = Draw_CachePic ("gfx/inv_nailgun", true);
221                 sb_weapons[0][3] = Draw_CachePic ("gfx/inv_snailgun", true);
222                 sb_weapons[0][4] = Draw_CachePic ("gfx/inv_rlaunch", true);
223                 sb_weapons[0][5] = Draw_CachePic ("gfx/inv_srlaunch", true);
224                 sb_weapons[0][6] = Draw_CachePic ("gfx/inv_lightng", true);
225
226                 sb_weapons[1][0] = Draw_CachePic ("gfx/inv2_shotgun", true);
227                 sb_weapons[1][1] = Draw_CachePic ("gfx/inv2_sshotgun", true);
228                 sb_weapons[1][2] = Draw_CachePic ("gfx/inv2_nailgun", true);
229                 sb_weapons[1][3] = Draw_CachePic ("gfx/inv2_snailgun", true);
230                 sb_weapons[1][4] = Draw_CachePic ("gfx/inv2_rlaunch", true);
231                 sb_weapons[1][5] = Draw_CachePic ("gfx/inv2_srlaunch", true);
232                 sb_weapons[1][6] = Draw_CachePic ("gfx/inv2_lightng", true);
233
234                 for (i = 0;i < 5;i++)
235                 {
236                         sb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_shotgun",i+1), true);
237                         sb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_sshotgun",i+1), true);
238                         sb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_nailgun",i+1), true);
239                         sb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_snailgun",i+1), true);
240                         sb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_rlaunch",i+1), true);
241                         sb_weapons[2+i][5] = Draw_CachePic (va("gfx/inva%i_srlaunch",i+1), true);
242                         sb_weapons[2+i][6] = Draw_CachePic (va("gfx/inva%i_lightng",i+1), true);
243                 }
244
245                 sb_ammo[0] = Draw_CachePic ("gfx/sb_shells", true);
246                 sb_ammo[1] = Draw_CachePic ("gfx/sb_nails", true);
247                 sb_ammo[2] = Draw_CachePic ("gfx/sb_rocket", true);
248                 sb_ammo[3] = Draw_CachePic ("gfx/sb_cells", true);
249
250                 sb_armor[0] = Draw_CachePic ("gfx/sb_armor1", true);
251                 sb_armor[1] = Draw_CachePic ("gfx/sb_armor2", true);
252                 sb_armor[2] = Draw_CachePic ("gfx/sb_armor3", true);
253
254                 sb_items[0] = Draw_CachePic ("gfx/sb_key1", true);
255                 sb_items[1] = Draw_CachePic ("gfx/sb_key2", true);
256                 sb_items[2] = Draw_CachePic ("gfx/sb_invis", true);
257                 sb_items[3] = Draw_CachePic ("gfx/sb_invuln", true);
258                 sb_items[4] = Draw_CachePic ("gfx/sb_suit", true);
259                 sb_items[5] = Draw_CachePic ("gfx/sb_quad", true);
260
261                 sb_sigil[0] = Draw_CachePic ("gfx/sb_sigil1", true);
262                 sb_sigil[1] = Draw_CachePic ("gfx/sb_sigil2", true);
263                 sb_sigil[2] = Draw_CachePic ("gfx/sb_sigil3", true);
264                 sb_sigil[3] = Draw_CachePic ("gfx/sb_sigil4", true);
265
266                 sb_faces[4][0] = Draw_CachePic ("gfx/face1", true);
267                 sb_faces[4][1] = Draw_CachePic ("gfx/face_p1", true);
268                 sb_faces[3][0] = Draw_CachePic ("gfx/face2", true);
269                 sb_faces[3][1] = Draw_CachePic ("gfx/face_p2", true);
270                 sb_faces[2][0] = Draw_CachePic ("gfx/face3", true);
271                 sb_faces[2][1] = Draw_CachePic ("gfx/face_p3", true);
272                 sb_faces[1][0] = Draw_CachePic ("gfx/face4", true);
273                 sb_faces[1][1] = Draw_CachePic ("gfx/face_p4", true);
274                 sb_faces[0][0] = Draw_CachePic ("gfx/face5", true);
275                 sb_faces[0][1] = Draw_CachePic ("gfx/face_p5", true);
276
277                 sb_face_invis = Draw_CachePic ("gfx/face_invis", true);
278                 sb_face_invuln = Draw_CachePic ("gfx/face_invul2", true);
279                 sb_face_invis_invuln = Draw_CachePic ("gfx/face_inv2", true);
280                 sb_face_quad = Draw_CachePic ("gfx/face_quad", true);
281
282                 sb_sbar = Draw_CachePic ("gfx/sbar", true);
283                 sb_ibar = Draw_CachePic ("gfx/ibar", true);
284                 sb_scorebar = Draw_CachePic ("gfx/scorebar", true);
285
286         //MED 01/04/97 added new hipnotic weapons
287                 if (gamemode == GAME_HIPNOTIC)
288                 {
289                         hsb_weapons[0][0] = Draw_CachePic ("gfx/inv_laser", true);
290                         hsb_weapons[0][1] = Draw_CachePic ("gfx/inv_mjolnir", true);
291                         hsb_weapons[0][2] = Draw_CachePic ("gfx/inv_gren_prox", true);
292                         hsb_weapons[0][3] = Draw_CachePic ("gfx/inv_prox_gren", true);
293                         hsb_weapons[0][4] = Draw_CachePic ("gfx/inv_prox", true);
294
295                         hsb_weapons[1][0] = Draw_CachePic ("gfx/inv2_laser", true);
296                         hsb_weapons[1][1] = Draw_CachePic ("gfx/inv2_mjolnir", true);
297                         hsb_weapons[1][2] = Draw_CachePic ("gfx/inv2_gren_prox", true);
298                         hsb_weapons[1][3] = Draw_CachePic ("gfx/inv2_prox_gren", true);
299                         hsb_weapons[1][4] = Draw_CachePic ("gfx/inv2_prox", true);
300
301                         for (i = 0;i < 5;i++)
302                         {
303                                 hsb_weapons[2+i][0] = Draw_CachePic (va("gfx/inva%i_laser",i+1), true);
304                                 hsb_weapons[2+i][1] = Draw_CachePic (va("gfx/inva%i_mjolnir",i+1), true);
305                                 hsb_weapons[2+i][2] = Draw_CachePic (va("gfx/inva%i_gren_prox",i+1), true);
306                                 hsb_weapons[2+i][3] = Draw_CachePic (va("gfx/inva%i_prox_gren",i+1), true);
307                                 hsb_weapons[2+i][4] = Draw_CachePic (va("gfx/inva%i_prox",i+1), true);
308                         }
309
310                         hsb_items[0] = Draw_CachePic ("gfx/sb_wsuit", true);
311                         hsb_items[1] = Draw_CachePic ("gfx/sb_eshld", true);
312                 }
313                 else if (gamemode == GAME_ROGUE)
314                 {
315                         rsb_invbar[0] = Draw_CachePic ("gfx/r_invbar1", true);
316                         rsb_invbar[1] = Draw_CachePic ("gfx/r_invbar2", true);
317
318                         rsb_weapons[0] = Draw_CachePic ("gfx/r_lava", true);
319                         rsb_weapons[1] = Draw_CachePic ("gfx/r_superlava", true);
320                         rsb_weapons[2] = Draw_CachePic ("gfx/r_gren", true);
321                         rsb_weapons[3] = Draw_CachePic ("gfx/r_multirock", true);
322                         rsb_weapons[4] = Draw_CachePic ("gfx/r_plasma", true);
323
324                         rsb_items[0] = Draw_CachePic ("gfx/r_shield1", true);
325                         rsb_items[1] = Draw_CachePic ("gfx/r_agrav1", true);
326
327         // PGM 01/19/97 - team color border
328                         rsb_teambord = Draw_CachePic ("gfx/r_teambord", true);
329         // PGM 01/19/97 - team color border
330
331                         rsb_ammo[0] = Draw_CachePic ("gfx/r_ammolava", true);
332                         rsb_ammo[1] = Draw_CachePic ("gfx/r_ammomulti", true);
333                         rsb_ammo[2] = Draw_CachePic ("gfx/r_ammoplasma", true);
334                 }
335         }
336
337         sb_ranking = Draw_CachePic ("gfx/ranking", true);
338         sb_complete = Draw_CachePic ("gfx/complete", true);
339         sb_inter = Draw_CachePic ("gfx/inter", true);
340         sb_finale = Draw_CachePic ("gfx/finale", true);
341 }
342
343 void sbar_shutdown(void)
344 {
345 }
346
347 void sbar_newmap(void)
348 {
349 }
350
351 void Sbar_Init (void)
352 {
353         Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard");
354         Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard");
355         Cvar_RegisterVariable(&showfps);
356         Cvar_RegisterVariable(&showtime);
357         Cvar_RegisterVariable(&showtime_format);
358         Cvar_RegisterVariable(&showdate);
359         Cvar_RegisterVariable(&showdate_format);
360         Cvar_RegisterVariable(&sbar_alpha_bg);
361         Cvar_RegisterVariable(&sbar_alpha_fg);
362         Cvar_RegisterVariable(&cl_deathscoreboard);
363
364         Cvar_RegisterVariable(&crosshair_color_red);
365         Cvar_RegisterVariable(&crosshair_color_green);
366         Cvar_RegisterVariable(&crosshair_color_blue);
367         Cvar_RegisterVariable(&crosshair_color_alpha);
368         Cvar_RegisterVariable(&crosshair_size);
369
370         R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
371 }
372
373
374 //=============================================================================
375
376 // drawing routines are relative to the status bar location
377
378 int sbar_x, sbar_y;
379
380 /*
381 =============
382 Sbar_DrawPic
383 =============
384 */
385 void Sbar_DrawPic (int x, int y, cachepic_t *pic)
386 {
387         DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
388 }
389
390 void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
391 {
392         DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0);
393 }
394
395 /*
396 ================
397 Sbar_DrawCharacter
398
399 Draws one solid graphics character
400 ================
401 */
402 void Sbar_DrawCharacter (int x, int y, int num)
403 {
404         DrawQ_String (sbar_x + x + 4 , sbar_y + y, va("%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0);
405 }
406
407 /*
408 ================
409 Sbar_DrawString
410 ================
411 */
412 void Sbar_DrawString (int x, int y, char *str)
413 {
414         DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0);
415 }
416
417 /*
418 =============
419 Sbar_DrawNum
420 =============
421 */
422 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
423 {
424         char str[32], *ptr;
425         int l, frame;
426
427         l = sprintf(str, "%i", num);
428         ptr = str;
429         if (l > digits)
430                 ptr += (l-digits);
431         if (l < digits)
432                 x += (digits-l)*24;
433
434         while (*ptr)
435         {
436                 if (*ptr == '-')
437                         frame = STAT_MINUS;
438                 else
439                         frame = *ptr -'0';
440
441                 Sbar_DrawPic (x, y, sb_nums[color][frame]);
442                 x += 24;
443
444                 ptr++;
445         }
446 }
447
448 /*
449 =============
450 Sbar_DrawXNum
451 =============
452 */
453
454 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
455 {
456         char str[32], *ptr;
457         int l, frame;
458
459         l = sprintf(str, "%i", num);
460         ptr = str;
461         if (l > digits)
462                 ptr += (l-digits);
463         if (l < digits)
464                 x += (digits-l) * lettersize;
465
466         while (*ptr)
467         {
468                 if (*ptr == '-')
469                         frame = STAT_MINUS;
470                 else
471                         frame = *ptr -'0';
472
473                 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
474                 x += lettersize;
475
476                 ptr++;
477         }
478 }
479
480 //=============================================================================
481
482
483 int Sbar_IsTeammatch()
484 {
485         // currently only nexuiz uses the team score board
486         return ((gamemode == GAME_NEXUIZ)
487                 && (teamplay.integer > 0));
488 }
489
490 /*
491 ===============
492 Sbar_SortFrags
493 ===============
494 */
495 static int fragsort[MAX_SCOREBOARD];
496 static int scoreboardlines;
497
498 //[515]: Sbar_GetPlayer for csqc "getplayerkey" func
499 int Sbar_GetPlayer (int index)
500 {
501         if(index < 0)
502         {
503                 index = -1-index;
504                 if(index >= scoreboardlines)
505                         return -1;
506                 index = fragsort[index];
507         }
508         if(index >= scoreboardlines)
509                 return -1;
510         return index;
511 }
512
513 static scoreboard_t teams[MAX_SCOREBOARD];
514 static int teamsort[MAX_SCOREBOARD];
515 static int teamlines;
516 void Sbar_SortFrags (void)
517 {
518         int i, j, k, color;
519
520         // sort by frags
521         scoreboardlines = 0;
522         for (i=0 ; i<cl.maxclients ; i++)
523         {
524                 if (cl.scores[i].name[0])
525                 {
526                         fragsort[scoreboardlines] = i;
527                         scoreboardlines++;
528                 }
529         }
530
531         for (i=0 ; i<scoreboardlines ; i++)
532                 for (j=0 ; j<scoreboardlines-1-i ; j++)
533                         if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
534                         {
535                                 k = fragsort[j];
536                                 fragsort[j] = fragsort[j+1];
537                                 fragsort[j+1] = k;
538                         }
539
540         teamlines = 0;
541         if (Sbar_IsTeammatch ())
542         {
543                 // now sort players by teams.
544                 for (i=0 ; i<scoreboardlines ; i++)
545                 {
546                         for (j=0 ; j<scoreboardlines-1-i ; j++)
547                         {
548                                 if (cl.scores[fragsort[j]].colors < cl.scores[fragsort[j+1]].colors)
549                                 {
550                                         k = fragsort[j];
551                                         fragsort[j] = fragsort[j+1];
552                                         fragsort[j+1] = k;
553                                 }
554                         }
555                 }
556
557                 // calculate team scores
558                 color = -1;
559                 for (i=0 ; i<scoreboardlines ; i++)
560                 {
561                         if (color != (cl.scores[fragsort[i]].colors & 15))
562                         {
563                                 const char* teamname;
564
565                                 color = cl.scores[fragsort[i]].colors & 15;
566                                 teamlines++;
567
568                                 switch (color)
569                                 {
570                                         case 4:
571                                                 teamname = "^1Red Team";
572                                                 break;
573                                         case 13:
574                                                 teamname = "^4Blue Team";
575                                                 break;
576                                         case 9:
577                                                 teamname = "^6Pink Team";
578                                                 break;
579                                         case 12:
580                                                 teamname = "^3Yellow Team";
581                                                 break;
582                                         default:
583                                                 teamname = "Total Team Score";
584                                                 break;
585                                 }
586                                 strlcpy(teams[teamlines-1].name, teamname, sizeof(teams[teamlines-1].name));
587
588                                 teams[teamlines-1].frags = 0;
589                                 teams[teamlines-1].colors = color + 16 * color;
590                         }
591
592                         if (cl.scores[fragsort[i]].frags != -666)
593                         {
594                                 // do not add spedcators
595                                 // (ugly hack for nexuiz)
596                                 teams[teamlines-1].frags += cl.scores[fragsort[i]].frags;
597                         }
598                 }
599
600                 // now sort teams by scores.
601                 for (i=0 ; i<teamlines ; i++)
602                         teamsort[i] = i;
603                 for (i=0 ; i<teamlines ; i++)
604                 {
605                         for (j=0 ; j<teamlines-1-i ; j++)
606                         {
607                                 if (teams[teamsort[j]].frags < teams[teamsort[j+1]].frags)
608                                 {
609                                         k = teamsort[j];
610                                         teamsort[j] = teamsort[j+1];
611                                         teamsort[j+1] = k;
612                                 }
613                         }
614                 }
615         }
616 }
617
618 /*
619 ===============
620 Sbar_SoloScoreboard
621 ===============
622 */
623 void Sbar_SoloScoreboard (void)
624 {
625 #if 1
626         char    str[80], timestr[40];
627         int             i, max;
628         int             minutes, seconds;
629
630         minutes = (int)(cl.time / 60);
631         seconds = (int)(cl.time - 60*floor(cl.time/60));
632
633         // monsters and secrets are now both on the top row
634         if (gamemode != GAME_NEXUIZ)
635                 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]));
636
637         // figure out the map's filename without path or extension
638         strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str));
639         if (strrchr(str, '.'))
640                 *(strrchr(str, '.')) = 0;
641
642         // append a : separator and then the full title
643         strlcat(str, ":", sizeof(str));
644         strlcat(str, cl.levelname, sizeof(str));
645
646         // make the time string
647         max = 38 - sprintf(timestr, " %i:%02i", minutes, seconds);
648
649         // if there's a newline character, terminate the string there
650         if (strchr(str, '\n'))
651                 *(strchr(str, '\n')) = 0;
652
653         // pad with spaces to fill the allotted space and append the time
654         i = bound(0, (int)strlen(str), max);
655         while (i < max)
656                 str[i++] = ' ';
657         str[i] = 0;
658         strlcat(str, timestr, sizeof(str));
659
660         // print the line of text
661         Sbar_DrawString(8, 12, str);
662
663 #else
664         char    str[80];
665         int             minutes, seconds, tens, units;
666         int             l;
667
668         if (gamemode != GAME_NEXUIZ) {
669                 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
670                 Sbar_DrawString (8, 4, str);
671
672                 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
673                 Sbar_DrawString (8, 12, str);
674         }
675
676 // time
677         minutes = (int)(cl.time / 60);
678         seconds = (int)(cl.time - 60*minutes);
679         tens = seconds / 10;
680         units = seconds - 10*tens;
681         sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
682         Sbar_DrawString (184, 4, str);
683
684 // draw level name
685         if (gamemode == GAME_NEXUIZ) {
686                 l = (int) strlen (cl.worldmodel->name);
687                 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
688         } else {
689                 l = (int) strlen (cl.levelname);
690                 Sbar_DrawString (232 - l*4, 12, cl.levelname);
691         }
692 #endif
693 }
694
695 /*
696 ===============
697 Sbar_DrawScoreboard
698 ===============
699 */
700 void Sbar_DrawScoreboard (void)
701 {
702         Sbar_SoloScoreboard ();
703         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
704         //if (cl.gametype == GAME_DEATHMATCH)
705         if (!cl.islocalgame)
706                 Sbar_DeathmatchOverlay ();
707 }
708
709 //=============================================================================
710
711 // AK to make DrawInventory smaller
712 static void Sbar_DrawWeapon(int nr, float fade, int active)
713 {
714         // width = 300, height = 100
715         const int w_width = 300, w_height = 100, w_space = 10;
716         const float w_scale = 0.4;
717
718         DrawQ_Pic(vid_conwidth.integer - (w_width + w_space) * w_scale, (w_height + w_space) * w_scale * nr + w_space, sb_weapons[0][nr], w_width * w_scale, w_height * w_scale, (active) ? 1 : 0.6, active ? 1 : 0.6, active ? 1 : 1, fade * sbar_alpha_fg.value, DRAWFLAG_ADDITIVE);
719         //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);
720
721         if (active)
722                 DrawQ_Pic(vid_conwidth.integer - (w_width + w_space) * w_scale, (w_height + w_space) * w_scale * nr + w_space, NULL, w_width * w_scale, w_height * w_scale, 0.3, 0.3, 0.3, fade * sbar_alpha_fg.value, DRAWFLAG_ADDITIVE);
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_Pic (sbar_x + x + 10, sbar_y     - 23, NULL, 28, 4, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
901                 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
902                 DrawQ_Pic (sbar_x + x + 10, sbar_y + 4 - 23, NULL, 28, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
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_Pic (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+3, NULL, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
945                 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
946                 DrawQ_Pic (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+12, NULL, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
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 = Sys_DoubleTime();
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_Pic(fps_x, fps_y, NULL, 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);
1039                         else
1040                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0);
1041                         fps_y += fps_scaley;
1042                 }
1043                 if (timestring[0])
1044                 {
1045                         fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
1046                         DrawQ_Pic(fps_x, fps_y, NULL, 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);
1048                         fps_y += fps_scaley;
1049                 }
1050                 if (datestring[0])
1051                 {
1052                         fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
1053                         DrawQ_Pic(fps_x, fps_y, NULL, 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);
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                         Sbar_IntermissionOverlay();
1096                         return;
1097                 }
1098                 else if (cl.intermission == 2)
1099                 {
1100                         Sbar_FinaleOverlay();
1101                         return;
1102                 }
1103
1104                 if (gamemode == GAME_NETHERWORLD)
1105                 {
1106                 }
1107                 else if (gamemode == GAME_SOM)
1108                 {
1109                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1110                                 Sbar_DrawScoreboard ();
1111                         else if (sb_lines)
1112                         {
1113                                 // this is the top left of the sbar area
1114                                 sbar_x = 0;
1115                                 sbar_y = vid_conheight.integer - 24*3;
1116
1117                                 // armor
1118                                 if (cl.stats[STAT_ARMOR])
1119                                 {
1120                                         if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1121                                                 Sbar_DrawPic(0, 0, somsb_armor[2]);
1122                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1123                                                 Sbar_DrawPic(0, 0, somsb_armor[1]);
1124                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1125                                                 Sbar_DrawPic(0, 0, somsb_armor[0]);
1126                                         Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1127                                 }
1128
1129                                 // health
1130                                 Sbar_DrawPic(0, 24, somsb_health);
1131                                 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1132
1133                                 // ammo icon
1134                                 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1135                                         Sbar_DrawPic(0, 48, somsb_ammo[0]);
1136                                 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1137                                         Sbar_DrawPic(0, 48, somsb_ammo[1]);
1138                                 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1139                                         Sbar_DrawPic(0, 48, somsb_ammo[2]);
1140                                 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1141                                         Sbar_DrawPic(0, 48, somsb_ammo[3]);
1142                                 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1143                                 if (cl.stats[STAT_SHELLS])
1144                                         Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1145                         }
1146                 }
1147                 else if (gamemode == GAME_NEXUIZ)
1148                 {
1149                         sbar_y = vid_conheight.integer - 47;
1150                         sbar_x = (vid_conwidth.integer - 640)/2;
1151
1152                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1153                         {
1154                                 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1155                                 Sbar_DrawScoreboard ();
1156                         }
1157                         else if (sb_lines)
1158                         {
1159                                 int i;
1160                                 double time;
1161                                 float fade;
1162                                 int redflag, blueflag;
1163
1164                                 // we have a max time 2s (min time = 0)
1165                                 if ((time = max(0, cl.time - cl.weapontime)) < 2)
1166                                 {
1167                                         fade = (1.0 - 0.5 * time);
1168                                         fade *= fade;
1169                                         for (i = 0; i < 8;i++)
1170                                                 if (cl.stats[STAT_ITEMS] & (1 << i))
1171                                                         Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1172
1173                                         if((cl.stats[STAT_ITEMS] & (1<<12)))
1174                                                 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1175                                 }
1176
1177                                 //if (!cl.islocalgame)
1178                                 //      Sbar_DrawFrags ();
1179
1180                                 if (sb_lines > 24)
1181                                         Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1182                                 else
1183                                         Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1184
1185                                 // flag icons
1186                                 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1187                                 if (redflag)
1188                                         Sbar_DrawPic (10, -85, sb_items[redflag+10]);
1189                                 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1190                                 if (blueflag)
1191                                         Sbar_DrawPic (10, -145, sb_items[blueflag+14]);
1192
1193                                 // armor
1194                                 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1195
1196                                 // health
1197                                 if(cl.stats[STAT_HEALTH] > 100)
1198                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1199                                 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1200                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1201                                 else
1202                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1203
1204                                 // AK dont draw ammo for the laser
1205                                 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1206                                 {
1207                                         if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1208                                                 Sbar_DrawPic (519, 0, sb_ammo[0]);
1209                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1210                                                 Sbar_DrawPic (519, 0, sb_ammo[1]);
1211                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1212                                                 Sbar_DrawPic (519, 0, sb_ammo[2]);
1213                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1214                                                 Sbar_DrawPic (519, 0, sb_ammo[3]);
1215
1216                                         if(cl.stats[STAT_AMMO] <= 10)
1217                                                 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1218                                         else
1219                                                 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1220
1221                                 }
1222
1223                                 if (sb_lines > 24)
1224                                         DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1225                         }
1226
1227                         //if (vid_conwidth.integer > 320 && cl.gametype == GAME_DEATHMATCH)
1228                         //      Sbar_MiniDeathmatchOverlay (0, 17);
1229                 }
1230                 else if (gamemode == GAME_ZYMOTIC)
1231                 {
1232 #if 1
1233                         float scale = 64.0f / 256.0f;
1234                         float kickoffset[3];
1235                         VectorClear(kickoffset);
1236                         if (v_dmg_time > 0)
1237                         {
1238                                 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1239                                 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1240                         }
1241                         sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1242                         sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1243                         // left1 16, 48 : 126 -66
1244                         // left2 16, 128 : 196 -66
1245                         // right 176, 48 : 196 -136
1246                         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);
1247                         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);
1248                         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);
1249                         DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1250 #else
1251                         float scale = 128.0f / 256.0f;
1252                         float healthstart, healthheight, healthstarttc, healthendtc;
1253                         float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1254                         float ammostart, ammoheight, ammostarttc, ammoendtc;
1255                         float clipstart, clipheight, clipstarttc, clipendtc;
1256                         float kickoffset[3], offset;
1257                         VectorClear(kickoffset);
1258                         if (v_dmg_time > 0)
1259                         {
1260                                 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1261                                 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1262                         }
1263                         sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1264                         sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1265                         offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1266                         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);
1267                         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);
1268                         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);
1269                         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);
1270                         healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1271                         shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1272                         healthstart = 204 - healthheight;
1273                         shieldstart = healthstart - shieldheight;
1274                         healthstarttc = healthstart * (1.0f / 256.0f);
1275                         healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1276                         shieldstarttc = shieldstart * (1.0f / 256.0f);
1277                         shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1278                         ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1279                         ammostart = 114 - ammoheight;
1280                         ammostarttc = ammostart * (1.0f / 256.0f);
1281                         ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1282                         clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1283                         clipstart = 190 - clipheight;
1284                         clipstarttc = clipstart * (1.0f / 256.0f);
1285                         clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1286                         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);
1287                         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);
1288                         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);
1289                         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);
1290                         DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1291                         DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1292 #endif
1293                 }
1294                 else // Quake and others
1295                 {
1296                         sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1297                         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1298                         //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1299                         if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1300                                 sbar_x = 0;
1301                         else
1302                                 sbar_x = (vid_conwidth.integer - 320)/2;
1303
1304                         if (sb_lines > 24)
1305                         {
1306                                 if (gamemode != GAME_GOODVSBAD2)
1307                                         Sbar_DrawInventory ();
1308                                 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1309                                         Sbar_DrawFrags ();
1310                         }
1311
1312                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1313                         {
1314                                 if (gamemode != GAME_GOODVSBAD2)
1315                                         Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1316                                 Sbar_DrawScoreboard ();
1317                         }
1318                         else if (sb_lines)
1319                         {
1320                                 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1321
1322                                 // keys (hipnotic only)
1323                                 //MED 01/04/97 moved keys here so they would not be overwritten
1324                                 if (gamemode == GAME_HIPNOTIC)
1325                                 {
1326                                         if (cl.stats[STAT_ITEMS] & IT_KEY1)
1327                                                 Sbar_DrawPic (209, 3, sb_items[0]);
1328                                         if (cl.stats[STAT_ITEMS] & IT_KEY2)
1329                                                 Sbar_DrawPic (209, 12, sb_items[1]);
1330                                 }
1331                                 // armor
1332                                 if (gamemode != GAME_GOODVSBAD2)
1333                                 {
1334                                         if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1335                                         {
1336                                                 Sbar_DrawNum (24, 0, 666, 3, 1);
1337                                                 Sbar_DrawPic (0, 0, sb_disc);
1338                                         }
1339                                         else
1340                                         {
1341                                                 if (gamemode == GAME_ROGUE)
1342                                                 {
1343                                                         Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1344                                                         if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1345                                                                 Sbar_DrawPic (0, 0, sb_armor[2]);
1346                                                         else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1347                                                                 Sbar_DrawPic (0, 0, sb_armor[1]);
1348                                                         else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1349                                                                 Sbar_DrawPic (0, 0, sb_armor[0]);
1350                                                 }
1351                                                 else
1352                                                 {
1353                                                         Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1354                                                         if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1355                                                                 Sbar_DrawPic (0, 0, sb_armor[2]);
1356                                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1357                                                                 Sbar_DrawPic (0, 0, sb_armor[1]);
1358                                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1359                                                                 Sbar_DrawPic (0, 0, sb_armor[0]);
1360                                                 }
1361                                         }
1362                                 }
1363
1364                                 // face
1365                                 Sbar_DrawFace ();
1366
1367                                 // health
1368                                 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1369
1370                                 // ammo icon
1371                                 if (gamemode == GAME_ROGUE)
1372                                 {
1373                                         if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1374                                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
1375                                         else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1376                                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
1377                                         else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1378                                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
1379                                         else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1380                                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
1381                                         else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1382                                                 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1383                                         else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1384                                                 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1385                                         else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1386                                                 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1387                                 }
1388                                 else
1389                                 {
1390                                         if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1391                                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
1392                                         else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1393                                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
1394                                         else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1395                                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
1396                                         else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1397                                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
1398                                 }
1399
1400                                 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1401
1402                         }
1403
1404                         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1405                         //if (vid_conwidth.integer > 320 && cl.gametype == GAME_DEATHMATCH)
1406                         if (!cl.islocalgame && vid_conwidth.integer > 320)
1407                         {
1408                                 if (gamemode == GAME_TRANSFUSION)
1409                                         Sbar_MiniDeathmatchOverlay (0, 0);
1410                                 else
1411                                         Sbar_MiniDeathmatchOverlay (324, vid_conheight.integer - sb_lines);
1412                         }
1413                 }
1414         }
1415
1416         Sbar_ShowFPS();
1417
1418         if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1419                 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);
1420
1421         if (cl_prydoncursor.integer)
1422                 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);
1423 }
1424
1425 //=============================================================================
1426
1427 /*
1428 ==================
1429 Sbar_DeathmatchOverlay
1430
1431 ==================
1432 */
1433 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1434 {
1435         int minutes;
1436         unsigned char *c;
1437         minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1438         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1439         {
1440                 if (s->qw_spectator)
1441                 {
1442                         if (s->qw_ping || s->qw_packetloss)
1443                                 DrawQ_ColoredString(x, y, va("%4i %3i %4i spectator  %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1444                         else
1445                                 DrawQ_ColoredString(x, y, va("         %4i spectator  %c%s", minutes, (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1446                 }
1447                 else
1448                 {
1449                         // draw colors behind score
1450                         c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1451                         DrawQ_Pic(x + 14*8, y+1, NULL, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1452                         c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1453                         DrawQ_Pic(x + 14*8, y+4, NULL, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1454                         // print the text
1455                         //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);
1456                         if (s->qw_ping || s->qw_packetloss)
1457                                 DrawQ_ColoredString(x, y, va("%4i %3i %4i %5i %-4s %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1458                         else
1459                                 DrawQ_ColoredString(x, y, va("         %4i %5i %-4s %c%s", minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1460                 }
1461         }
1462         else
1463         {
1464                 if (s->qw_spectator)
1465                 {
1466                         if (s->qw_ping || s->qw_packetloss)
1467                                 DrawQ_ColoredString(x, y, va("%4i %3i spect %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1468                         else
1469                                 DrawQ_ColoredString(x, y, va("         spect %c%s", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1470                 }
1471                 else
1472                 {
1473                         // draw colors behind score
1474                         c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1475                         DrawQ_Pic(x + 9*8, y+1, NULL, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1476                         c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1477                         DrawQ_Pic(x + 9*8, y+4, NULL, 40, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1478                         // print the text
1479                         //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);
1480                         if (s->qw_ping || s->qw_packetloss)
1481                                 DrawQ_ColoredString(x, y, va("%4i %3i %5i %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), (int) s->frags, (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1482                         else
1483                                 DrawQ_ColoredString(x, y, va("         %5i %c%s", (int) s->frags, (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1484                 }
1485         }
1486         return 8;
1487 }
1488
1489 void Sbar_DeathmatchOverlay (void)
1490 {
1491         int i, x, y;
1492
1493         // request new ping times every two second
1494         if (cl.last_ping_request < realtime - 2 && cls.netcon)
1495         {
1496                 cl.last_ping_request = realtime;
1497                 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1498                 {
1499                         MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1500                         MSG_WriteString(&cls.netcon->message, "pings");
1501                 }
1502                 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)
1503                 {
1504                         // 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
1505                         static int ping_anyway_counter = 0;
1506                         if(cl.parsingtextexpectingpingforscores == 1)
1507                         {
1508                                 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1509                                 if(++ping_anyway_counter >= 5)
1510                                         cl.parsingtextexpectingpingforscores = 0;
1511                         }
1512                         if(cl.parsingtextexpectingpingforscores != 1)
1513                         {
1514                                 ping_anyway_counter = 0;
1515                                 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1516                                 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1517                                 MSG_WriteString(&cls.netcon->message, "ping");
1518                         }
1519                 }
1520                 else
1521                 {
1522                         // newer server definitely has pings command, so use it for more efficiency
1523                         MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1524                         MSG_WriteString(&cls.netcon->message, "pings");
1525                 }
1526         }
1527
1528         DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1529
1530         // scores
1531         Sbar_SortFrags ();
1532         // draw the text
1533         y = 40;
1534         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1535         {
1536                 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)
1537                 DrawQ_ColoredString(x, y, va("ping pl%% time frags team  name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1538         }
1539         else
1540         {
1541                 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)
1542                 DrawQ_ColoredString(x, y, va("ping pl%% frags  name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1543         }
1544         y += 8;
1545
1546         if (Sbar_IsTeammatch ())
1547         {
1548                 // show team scores first
1549                 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1550                         y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1551                 y += 5;
1552         }
1553
1554         for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1555                 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1556 }
1557
1558 /*
1559 ==================
1560 Sbar_DeathmatchOverlay
1561
1562 ==================
1563 */
1564 void Sbar_MiniDeathmatchOverlay (int x, int y)
1565 {
1566         int i, numlines;
1567
1568         // decide where to print
1569         if (gamemode == GAME_TRANSFUSION)
1570                 numlines = (vid_conwidth.integer - x + 127) / 128;
1571         else
1572                 numlines = (vid_conheight.integer - y + 7) / 8;
1573
1574         // give up if there isn't room
1575         if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1576                 return;
1577
1578         // scores
1579         Sbar_SortFrags ();
1580
1581         //find us
1582         for (i = 0; i < scoreboardlines; i++)
1583                 if (fragsort[i] == cl.playerentity - 1)
1584                         break;
1585
1586         // figure out start
1587         i -= numlines/2;
1588         i = min(i, scoreboardlines - numlines);
1589         i = max(i, 0);
1590
1591         if (gamemode == GAME_TRANSFUSION)
1592         {
1593                 for (;i < scoreboardlines && x < vid_conwidth.integer;i++)
1594                         x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1595         }
1596         else
1597         {
1598                 for (;i < scoreboardlines && y < vid_conheight.integer;i++)
1599                         y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1600         }
1601 }
1602
1603 /*
1604 ==================
1605 Sbar_IntermissionOverlay
1606
1607 ==================
1608 */
1609 void Sbar_IntermissionOverlay (void)
1610 {
1611         int             dig;
1612         int             num;
1613
1614         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1615         //if (cl.gametype == GAME_DEATHMATCH)
1616         if (!cl.islocalgame)
1617         {
1618                 Sbar_DeathmatchOverlay ();
1619                 return;
1620         }
1621
1622         sbar_x = (vid_conwidth.integer - 320) >> 1;
1623         sbar_y = (vid_conheight.integer - 200) >> 1;
1624
1625         DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1626         DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1627
1628 // time
1629         dig = (int)cl.completed_time / 60;
1630         Sbar_DrawNum (160, 64, dig, 3, 0);
1631         num = (int)cl.completed_time - dig*60;
1632         if (gamemode != GAME_NEXUIZ)
1633                 Sbar_DrawPic (234,64,sb_colon);
1634         Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1635         Sbar_DrawPic (266,64,sb_nums[0][num%10]);
1636
1637         Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1638         if (gamemode != GAME_NEXUIZ)
1639                 Sbar_DrawPic (232, 104, sb_slash);
1640         Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1641
1642         Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1643         if (gamemode != GAME_NEXUIZ)
1644                 Sbar_DrawPic (232, 144, sb_slash);
1645         Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1646
1647 }
1648
1649
1650 /*
1651 ==================
1652 Sbar_FinaleOverlay
1653
1654 ==================
1655 */
1656 void Sbar_FinaleOverlay (void)
1657 {
1658         DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1659 }
1660