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