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