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