]> icculus.org git repositories - divverent/darkplaces.git/blob - sbar.c
and now I see that the added frags counter requires shifting the flag status icons...
[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, "%3i",cl.stats[STAT_SHELLS+i] );
867                 if (num[0] != ' ')
868                         Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
869                 if (num[1] != ' ')
870                         Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
871                 if (num[2] != ' ')
872                         Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
873         }
874
875         // items
876         for (i=0 ; i<6 ; i++)
877                 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
878                 {
879                         //MED 01/04/97 changed keys
880                         if (gamemode != GAME_HIPNOTIC || (i>1))
881                                 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
882                 }
883
884         //MED 01/04/97 added hipnotic items
885         // hipnotic items
886         if (gamemode == GAME_HIPNOTIC)
887         {
888                 for (i=0 ; i<2 ; i++)
889                         if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
890                                 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
891         }
892
893         if (gamemode == GAME_ROGUE)
894         {
895                 // new rogue items
896                 for (i=0 ; i<2 ; i++)
897                         if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
898                                 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
899         }
900         else
901         {
902                 // sigils
903                 for (i=0 ; i<4 ; i++)
904                         if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
905                                 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
906         }
907 }
908
909 //=============================================================================
910
911 /*
912 ===============
913 Sbar_DrawFrags
914 ===============
915 */
916 void Sbar_DrawFrags (void)
917 {
918         int i, k, l, x, f;
919         char num[12];
920         scoreboard_t *s;
921         unsigned char *c;
922
923         Sbar_SortFrags ();
924
925         // draw the text
926         l = min(scoreboardlines, 4);
927
928         x = 23 * 8;
929
930         for (i = 0;i < l;i++)
931         {
932                 k = fragsort[i];
933                 s = &cl.scores[k];
934
935                 // draw background
936                 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
937                 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);
938                 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
939                 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);
940
941                 // draw number
942                 f = s->frags;
943                 sprintf (num, "%3i",f);
944
945                 if (k == cl.viewentity - 1)
946                 {
947                         Sbar_DrawCharacter ( x      + 2, -24, 16);
948                         Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
949                 }
950                 Sbar_DrawCharacter (x +  8, -24, num[0]);
951                 Sbar_DrawCharacter (x + 16, -24, num[1]);
952                 Sbar_DrawCharacter (x + 24, -24, num[2]);
953                 x += 32;
954         }
955 }
956
957 //=============================================================================
958
959
960 /*
961 ===============
962 Sbar_DrawFace
963 ===============
964 */
965 void Sbar_DrawFace (void)
966 {
967         int f;
968
969 // PGM 01/19/97 - team color drawing
970 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
971         if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
972         {
973                 char num[12];
974                 scoreboard_t *s;
975                 unsigned char *c;
976
977                 s = &cl.scores[cl.viewentity - 1];
978                 // draw background
979                 Sbar_DrawPic (112, 0, rsb_teambord);
980                 c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
981                 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);
982                 c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
983                 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);
984
985                 // draw number
986                 f = s->frags;
987                 sprintf (num, "%3i",f);
988
989                 if ((s->colors & 0xf0)==0)
990                 {
991                         if (num[0] != ' ')
992                                 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
993                         if (num[1] != ' ')
994                                 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
995                         if (num[2] != ' ')
996                                 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
997                 }
998                 else
999                 {
1000                         Sbar_DrawCharacter ( 109, 3, num[0]);
1001                         Sbar_DrawCharacter ( 116, 3, num[1]);
1002                         Sbar_DrawCharacter ( 123, 3, num[2]);
1003                 }
1004
1005                 return;
1006         }
1007 // PGM 01/19/97 - team color drawing
1008
1009         if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
1010                 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
1011         else if (cl.stats[STAT_ITEMS] & IT_QUAD)
1012                 Sbar_DrawPic (112, 0, sb_face_quad );
1013         else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
1014                 Sbar_DrawPic (112, 0, sb_face_invis );
1015         else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1016                 Sbar_DrawPic (112, 0, sb_face_invuln);
1017         else
1018         {
1019                 f = cl.stats[STAT_HEALTH] / 20;
1020                 f = bound(0, f, 4);
1021                 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
1022         }
1023 }
1024
1025 void Sbar_ShowFPS(void)
1026 {
1027         float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
1028         char fpsstring[32];
1029         char timestring[32];
1030         char datestring[32];
1031         qboolean red = false;
1032         fpsstring[0] = 0;
1033         timestring[0] = 0;
1034         datestring[0] = 0;
1035         if (showfps.integer)
1036         {
1037                 float calc;
1038                 static double nexttime = 0, lasttime = 0;
1039                 static double framerate = 0;
1040                 static int framecount = 0;
1041                 double newtime;
1042                 newtime = realtime;
1043                 if (newtime >= nexttime)
1044                 {
1045                         framerate = framecount / (newtime - lasttime);
1046                         lasttime = newtime;
1047                         nexttime = max(nexttime + 1, lasttime - 1);
1048                         framecount = 0;
1049                 }
1050                 framecount++;
1051                 calc = framerate;
1052
1053                 if ((red = (calc < 1.0f)))
1054                         dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
1055                 else
1056                         dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
1057         }
1058         if (showtime.integer)
1059                 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
1060         if (showdate.integer)
1061                 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
1062         if (fpsstring[0] || timestring[0])
1063         {
1064                 fps_scalex = 12;
1065                 fps_scaley = 12;
1066                 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
1067                 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
1068                 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
1069                 fps_y = vid_conheight.integer - fps_height;
1070                 if (fpsstring[0])
1071                 {
1072                         fps_x = vid_conwidth.integer - fps_scalex * strlen(fpsstring);
1073                         DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(fpsstring), fps_scaley, 0, 0, 0, 0.5, 0);
1074                         if (red)
1075                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true);
1076                         else
1077                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1078                         fps_y += fps_scaley;
1079                 }
1080                 if (timestring[0])
1081                 {
1082                         fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
1083                         DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(timestring), fps_scaley, 0, 0, 0, 0.5, 0);
1084                         DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1085                         fps_y += fps_scaley;
1086                 }
1087                 if (datestring[0])
1088                 {
1089                         fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
1090                         DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(datestring), fps_scaley, 0, 0, 0, 0.5, 0);
1091                         DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true);
1092                         fps_y += fps_scaley;
1093                 }
1094         }
1095 }
1096
1097 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)
1098 {
1099         float r[5];
1100         c2 = bound(0, c2, 1);
1101         c1 = bound(0, c1, 1 - c2);
1102         r[0] = 0;
1103         r[1] = rangey + rangeheight * (c2 + c1);
1104         r[2] = rangey + rangeheight * (c2);
1105         r[3] = rangey;
1106         r[4] = height;
1107         if (r[1] > r[0])
1108                 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);
1109         if (r[2] > r[1])
1110                 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);
1111         if (r[3] > r[2])
1112                 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);
1113         if (r[4] > r[3])
1114                 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);
1115 }
1116
1117 /*
1118 ===============
1119 Sbar_Draw
1120 ===============
1121 */
1122 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
1123 extern cvar_t v_kicktime;
1124 void Sbar_Score (int margin);
1125 void Sbar_Draw (void)
1126 {
1127         cachepic_t *pic;
1128
1129         if(cl.csqc_vidvars.drawenginesbar)      //[515]: csqc drawsbar
1130         {
1131                 if (sb_showscores)
1132                         Sbar_DrawScoreboard ();
1133                 else if (cl.intermission == 1)
1134                 {
1135                         if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name)
1136                         {
1137                                 Sbar_DrawScoreboard();
1138                                 return;
1139                         }
1140                         Sbar_IntermissionOverlay();
1141                 }
1142                 else if (cl.intermission == 2)
1143                         Sbar_FinaleOverlay();
1144                 else if (gamemode == GAME_NETHERWORLD)
1145                 {
1146                 }
1147                 else if (gamemode == GAME_SOM)
1148                 {
1149                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1150                                 Sbar_DrawScoreboard ();
1151                         else if (sb_lines)
1152                         {
1153                                 // this is the top left of the sbar area
1154                                 sbar_x = 0;
1155                                 sbar_y = vid_conheight.integer - 24*3;
1156
1157                                 // armor
1158                                 if (cl.stats[STAT_ARMOR])
1159                                 {
1160                                         if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1161                                                 Sbar_DrawPic(0, 0, somsb_armor[2]);
1162                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1163                                                 Sbar_DrawPic(0, 0, somsb_armor[1]);
1164                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1165                                                 Sbar_DrawPic(0, 0, somsb_armor[0]);
1166                                         Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1167                                 }
1168
1169                                 // health
1170                                 Sbar_DrawPic(0, 24, somsb_health);
1171                                 Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1172
1173                                 // ammo icon
1174                                 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1175                                         Sbar_DrawPic(0, 48, somsb_ammo[0]);
1176                                 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1177                                         Sbar_DrawPic(0, 48, somsb_ammo[1]);
1178                                 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1179                                         Sbar_DrawPic(0, 48, somsb_ammo[2]);
1180                                 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1181                                         Sbar_DrawPic(0, 48, somsb_ammo[3]);
1182                                 Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
1183                                 if (cl.stats[STAT_SHELLS])
1184                                         Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
1185                         }
1186                 }
1187                 else if (gamemode == GAME_NEXUIZ)
1188                 {
1189                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1190                         {
1191                                 sbar_x = (vid_conwidth.integer - 640)/2;
1192                                 sbar_y = vid_conheight.integer - 47;
1193                                 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1194                                 Sbar_DrawScoreboard ();
1195                         }
1196                         else if (sb_lines && sbar_hudselector.integer == 1)
1197                         {
1198                                 int i;
1199                                 float fade;
1200                                 int redflag, blueflag;
1201
1202                                 sbar_x = (vid_conwidth.integer - 320)/2;
1203                                 sbar_y = vid_conheight.integer - 24 - 16;
1204
1205                                 // calculate intensity to draw weapons bar at
1206                                 fade = 3.2 - 2 * (cl.time - cl.weapontime);
1207                                 fade = bound(0.7, fade, 1);
1208                                 for (i = 0; i < 8;i++)
1209                                         if (cl.stats[STAT_ITEMS] & (1 << i))
1210                                                 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1211                                 if((cl.stats[STAT_ITEMS] & (1<<12)))
1212                                         Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1213
1214                                 // flag icons
1215                                 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1216                                 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1217                                 if (redflag == 3 && blueflag == 3)
1218                                 {
1219                                         // The Impossible Combination[tm]
1220                                         // Can only happen in Key Hunt mode...
1221                                         Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1222                                 }
1223                                 else
1224                                 {
1225                                         if (redflag)
1226                                                 Sbar_DrawPic (10 - sbar_x, -117, sb_items[redflag+10]);
1227                                         if (blueflag)
1228                                                 Sbar_DrawPic (10 - sbar_x, -177, sb_items[blueflag+14]);
1229                                 }
1230
1231                                 // armor
1232                                 if (cl.stats[STAT_ARMOR] > 0)
1233                                 {
1234                                         Sbar_DrawStretchPic (0, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24);
1235                                         if(cl.stats[STAT_ARMOR] > 100)
1236                                                 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,1,1,0,1,0);
1237                                         else if(cl.stats[STAT_ARMOR] > 25)
1238                                                 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0);
1239                                         else
1240                                                 Sbar_DrawXNum(24,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0);
1241                                 }
1242
1243                                 // health
1244                                 if (cl.stats[STAT_HEALTH] != 0)
1245                                 {
1246                                         Sbar_DrawStretchPic (112, 0, sb_health, sbar_alpha_fg.value, 24, 24);
1247                                         if(cl.stats[STAT_HEALTH] > 100)
1248                                                 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,1,1,0,1,0);
1249                                         else if(cl.stats[STAT_HEALTH] > 25)
1250                                                 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1251                                         else
1252                                                 Sbar_DrawXNum(136,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1253                                 }
1254
1255                                 // ammo
1256                                 if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0)
1257                                 {
1258                                         if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1259                                                 Sbar_DrawStretchPic (224, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24);
1260                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1261                                                 Sbar_DrawStretchPic (224, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24);
1262                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1263                                                 Sbar_DrawStretchPic (224, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24);
1264                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1265                                                 Sbar_DrawStretchPic (224, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24);
1266                                         if(cl.stats[STAT_AMMO] > 10)
1267                                                 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0);
1268                                         else
1269                                                 Sbar_DrawXNum(248, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0);
1270                                 }
1271
1272                                 if (sbar_x + 320 + 160 <= vid_conwidth.integer)
1273                                         Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y);
1274                                 if (sbar_x > 0)
1275                                         Sbar_Score(16);
1276                                         // The margin can be at most 8 to support 640x480 console size:
1277                                         //   320 + 2 * (144 + 16) = 640
1278                         }
1279                         else if (sb_lines)
1280                         {
1281                                 int i;
1282                                 float fade;
1283                                 int redflag, blueflag;
1284
1285                                 sbar_x = (vid_conwidth.integer - 640)/2;
1286                                 sbar_y = vid_conheight.integer - 47;
1287
1288                                 // calculate intensity to draw weapons bar at
1289                                 fade = 3 - 2 * (cl.time - cl.weapontime);
1290                                 if (fade > 0)
1291                                 {
1292                                         fade = min(fade, 1);
1293                                         for (i = 0; i < 8;i++)
1294                                                 if (cl.stats[STAT_ITEMS] & (1 << i))
1295                                                         Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1296
1297                                         if((cl.stats[STAT_ITEMS] & (1<<12)))
1298                                                 Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1299                                 }
1300
1301                                 //if (!cl.islocalgame)
1302                                 //      Sbar_DrawFrags ();
1303
1304                                 if (sb_lines > 24)
1305                                         Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1306                                 else
1307                                         Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1308
1309                                 // flag icons
1310                                 redflag = ((cl.stats[STAT_ITEMS]>>15) & 3);
1311                                 blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3);
1312                                 if (redflag == 3 && blueflag == 3)
1313                                 {
1314                                         // The Impossible Combination[tm]
1315                                         // Can only happen in Key Hunt mode...
1316                                         Sbar_DrawPic (10 - sbar_x, -179, sb_items[14]);
1317                                 }
1318                                 else
1319                                 {
1320                                         if (redflag)
1321                                                 Sbar_DrawPic (10 - sbar_x, -117, sb_items[redflag+10]);
1322                                         if (blueflag)
1323                                                 Sbar_DrawPic (10 - sbar_x, -177, sb_items[blueflag+14]);
1324                                 }
1325
1326                                 // armor
1327                                 Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1328
1329                                 // health
1330                                 if(cl.stats[STAT_HEALTH] > 100)
1331                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1332                                 else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1333                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1334                                 else
1335                                         Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1336
1337                                 // AK dont draw ammo for the laser
1338                                 if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1339                                 {
1340                                         if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1341                                                 Sbar_DrawPic (519, 0, sb_ammo[0]);
1342                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1343                                                 Sbar_DrawPic (519, 0, sb_ammo[1]);
1344                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1345                                                 Sbar_DrawPic (519, 0, sb_ammo[2]);
1346                                         else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1347                                                 Sbar_DrawPic (519, 0, sb_ammo[3]);
1348
1349                                         if(cl.stats[STAT_AMMO] <= 10)
1350                                                 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1351                                         else
1352                                                 Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1353
1354                                 }
1355
1356                                 if (sb_lines > 24)
1357                                         DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1358
1359                                 if (sbar_x + 600 + 160 <= vid_conwidth.integer)
1360                                         Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y);
1361
1362                                 if (sbar_x > 0)
1363                                         Sbar_Score(-16);
1364                                         // Because:
1365                                         //   Mini scoreboard uses 12*4 per other team, that is, 144
1366                                         //   pixels when there are four teams...
1367                                         //   Nexuiz by default sets vid_conwidth to 800... makes
1368                                         //   sbar_x == 80...
1369                                         //   so we need to shift it by 64 pixels to the right to fit
1370                                         //   BUT: then it overlaps with the image that gets drawn
1371                                         //   for viewsize 100! Therefore, just account for 3 teams,
1372                                         //   that is, 96 pixels mini scoreboard size, needing 16 pixels
1373                                         //   to the right!
1374                         }
1375                 }
1376                 else if (gamemode == GAME_ZYMOTIC)
1377                 {
1378 #if 1
1379                         float scale = 64.0f / 256.0f;
1380                         float kickoffset[3];
1381                         VectorClear(kickoffset);
1382                         if (v_dmg_time > 0)
1383                         {
1384                                 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1385                                 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1386                         }
1387                         sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]);
1388                         sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]);
1389                         // left1 16, 48 : 126 -66
1390                         // left2 16, 128 : 196 -66
1391                         // right 176, 48 : 196 -136
1392                         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);
1393                         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);
1394                         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);
1395                         DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1396 #else
1397                         float scale = 128.0f / 256.0f;
1398                         float healthstart, healthheight, healthstarttc, healthendtc;
1399                         float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1400                         float ammostart, ammoheight, ammostarttc, ammoendtc;
1401                         float clipstart, clipheight, clipstarttc, clipendtc;
1402                         float kickoffset[3], offset;
1403                         VectorClear(kickoffset);
1404                         if (v_dmg_time > 0)
1405                         {
1406                                 kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1407                                 kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1408                         }
1409                         sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1410                         sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1411                         offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1412                         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);
1413                         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);
1414                         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);
1415                         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);
1416                         healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1417                         shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1418                         healthstart = 204 - healthheight;
1419                         shieldstart = healthstart - shieldheight;
1420                         healthstarttc = healthstart * (1.0f / 256.0f);
1421                         healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1422                         shieldstarttc = shieldstart * (1.0f / 256.0f);
1423                         shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1424                         ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1425                         ammostart = 114 - ammoheight;
1426                         ammostarttc = ammostart * (1.0f / 256.0f);
1427                         ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1428                         clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1429                         clipstart = 190 - clipheight;
1430                         clipstarttc = clipstart * (1.0f / 256.0f);
1431                         clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1432                         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);
1433                         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);
1434                         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);
1435                         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);
1436                         DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1437                         DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1438 #endif
1439                 }
1440                 else // Quake and others
1441                 {
1442                         sbar_x = (vid_conwidth.integer - 320)/2;
1443                         sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1444                         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1445                         //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1446
1447                         if (sb_lines > 24)
1448                         {
1449                                 if (gamemode != GAME_GOODVSBAD2)
1450                                         Sbar_DrawInventory ();
1451                                 if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1452                                         Sbar_DrawFrags ();
1453                         }
1454
1455                         if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1456                         {
1457                                 if (gamemode != GAME_GOODVSBAD2)
1458                                         Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1459                                 Sbar_DrawScoreboard ();
1460                         }
1461                         else if (sb_lines)
1462                         {
1463                                 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1464
1465                                 // keys (hipnotic only)
1466                                 //MED 01/04/97 moved keys here so they would not be overwritten
1467                                 if (gamemode == GAME_HIPNOTIC)
1468                                 {
1469                                         if (cl.stats[STAT_ITEMS] & IT_KEY1)
1470                                                 Sbar_DrawPic (209, 3, sb_items[0]);
1471                                         if (cl.stats[STAT_ITEMS] & IT_KEY2)
1472                                                 Sbar_DrawPic (209, 12, sb_items[1]);
1473                                 }
1474                                 // armor
1475                                 if (gamemode != GAME_GOODVSBAD2)
1476                                 {
1477                                         if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1478                                         {
1479                                                 Sbar_DrawNum (24, 0, 666, 3, 1);
1480                                                 Sbar_DrawPic (0, 0, sb_disc);
1481                                         }
1482                                         else
1483                                         {
1484                                                 if (gamemode == GAME_ROGUE)
1485                                                 {
1486                                                         Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1487                                                         if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1488                                                                 Sbar_DrawPic (0, 0, sb_armor[2]);
1489                                                         else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1490                                                                 Sbar_DrawPic (0, 0, sb_armor[1]);
1491                                                         else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1492                                                                 Sbar_DrawPic (0, 0, sb_armor[0]);
1493                                                 }
1494                                                 else
1495                                                 {
1496                                                         Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1497                                                         if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1498                                                                 Sbar_DrawPic (0, 0, sb_armor[2]);
1499                                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1500                                                                 Sbar_DrawPic (0, 0, sb_armor[1]);
1501                                                         else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1502                                                                 Sbar_DrawPic (0, 0, sb_armor[0]);
1503                                                 }
1504                                         }
1505                                 }
1506
1507                                 // face
1508                                 Sbar_DrawFace ();
1509
1510                                 // health
1511                                 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1512
1513                                 // ammo icon
1514                                 if (gamemode == GAME_ROGUE)
1515                                 {
1516                                         if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1517                                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
1518                                         else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1519                                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
1520                                         else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1521                                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
1522                                         else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1523                                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
1524                                         else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1525                                                 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1526                                         else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1527                                                 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1528                                         else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1529                                                 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1530                                 }
1531                                 else
1532                                 {
1533                                         if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1534                                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
1535                                         else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1536                                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
1537                                         else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1538                                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
1539                                         else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1540                                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
1541                                 }
1542
1543                                 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1544
1545                         }
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         Sbar_ShowFPS();
1560
1561         if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && crosshair.integer <= NUMCROSSHAIRS && !cl.intermission && !r_letterbox.value && (pic = r_crosshairs[crosshair.integer]))
1562                 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);
1563
1564         if (cl_prydoncursor.integer)
1565                 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);
1566 }
1567
1568 //=============================================================================
1569
1570 /*
1571 ==================
1572 Sbar_DeathmatchOverlay
1573
1574 ==================
1575 */
1576 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1577 {
1578         int minutes;
1579         qboolean myself = false;
1580         unsigned char *c;
1581         minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0);
1582
1583         if((s - cl.scores) == cl.playerentity - 1)
1584                 myself = true;
1585         if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD)
1586                 if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15))
1587                         myself = true;
1588
1589         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1590         {
1591                 if (s->qw_spectator)
1592                 {
1593                         if (s->qw_ping || s->qw_packetloss)
1594                                 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 );
1595                         else
1596                                 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 );
1597                 }
1598                 else
1599                 {
1600                         // draw colors behind score
1601                         c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1602                         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);
1603                         c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1604                         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);
1605                         // print the text
1606                         //DrawQ_String(x, y, va("%c%4i %s", myself ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, true);
1607                         if (s->qw_ping || s->qw_packetloss)
1608                                 DrawQ_String(x, y, va("%4i %3i %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 );
1609                         else
1610                                 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 );
1611                 }
1612         }
1613         else
1614         {
1615                 if (s->qw_spectator)
1616                 {
1617                         if (s->qw_ping || s->qw_packetloss)
1618                                 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 );
1619                         else
1620                                 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 );
1621                 }
1622                 else
1623                 {
1624                         // draw colors behind score
1625                         c = (unsigned char *)&palette_complete[(s->colors & 0xf0) + 8];
1626                         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);
1627                         c = (unsigned char *)&palette_complete[((s->colors & 15)<<4) + 8];
1628                         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);
1629                         // print the text
1630                         //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);
1631                         if (s->qw_ping || s->qw_packetloss)
1632                                 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 );
1633                         else
1634                                 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 );
1635                 }
1636         }
1637         return 8;
1638 }
1639
1640 void Sbar_DeathmatchOverlay (void)
1641 {
1642         int i, x, y;
1643
1644         // request new ping times every two second
1645         if (cl.last_ping_request < realtime - 2 && cls.netcon)
1646         {
1647                 cl.last_ping_request = realtime;
1648                 if (cls.protocol == PROTOCOL_QUAKEWORLD)
1649                 {
1650                         MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
1651                         MSG_WriteString(&cls.netcon->message, "pings");
1652                 }
1653                 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*/)
1654                 {
1655                         // 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
1656                         static int ping_anyway_counter = 0;
1657                         if(cl.parsingtextexpectingpingforscores == 1)
1658                         {
1659                                 Con_DPrintf("want to send ping, but still waiting for other reply\n");
1660                                 if(++ping_anyway_counter >= 5)
1661                                         cl.parsingtextexpectingpingforscores = 0;
1662                         }
1663                         if(cl.parsingtextexpectingpingforscores != 1)
1664                         {
1665                                 ping_anyway_counter = 0;
1666                                 cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report
1667                                 MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1668                                 MSG_WriteString(&cls.netcon->message, "ping");
1669                         }
1670                 }
1671                 else
1672                 {
1673                         // 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
1674                         MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
1675                         MSG_WriteString(&cls.netcon->message, "pings");
1676                 }
1677         }
1678
1679         DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1680
1681         // scores
1682         Sbar_SortFrags ();
1683         // draw the text
1684         y = 40;
1685         if (cls.protocol == PROTOCOL_QUAKEWORLD)
1686         {
1687                 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)
1688                 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 );
1689         }
1690         else
1691         {
1692                 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)
1693                 DrawQ_String(x, y, va("ping pl%% frags  name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false );
1694         }
1695         y += 8;
1696
1697         if (Sbar_IsTeammatch ())
1698         {
1699                 // show team scores first
1700                 for (i = 0;i < teamlines && y < vid_conheight.integer;i++)
1701                         y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), x, y);
1702                 y += 5;
1703         }
1704
1705         for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1706                 y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1707 }
1708
1709 /*
1710 ==================
1711 Sbar_MiniDeathmatchOverlay
1712
1713 ==================
1714 */
1715 void Sbar_MiniDeathmatchOverlay (int x, int y)
1716 {
1717         int i, j, numlines, range_begin, range_end, myteam, teamsep;
1718
1719         // do not draw this if sbar_miniscoreboard_size is zero
1720         if(sbar_miniscoreboard_size.value == 0)
1721                 return;
1722         // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0)
1723         if(sbar_miniscoreboard_size.value > 0)
1724                 y = vid_conheight.integer - sbar_miniscoreboard_size.value * 8;
1725
1726         // scores
1727         Sbar_SortFrags ();
1728
1729         // decide where to print
1730         if (gamemode == GAME_TRANSFUSION)
1731                 numlines = (vid_conwidth.integer - x + 127) / 128;
1732         else
1733                 numlines = (vid_conheight.integer - y + 7) / 8;
1734
1735         // give up if there isn't room
1736         if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1737                 return;
1738
1739         //find us
1740         for (i = 0; i < scoreboardlines; i++)
1741                 if (fragsort[i] == cl.playerentity - 1)
1742                         break;
1743
1744         range_begin = 0;
1745         range_end = scoreboardlines;
1746         teamsep = 0;
1747
1748         if (gamemode != GAME_TRANSFUSION)
1749                 if (Sbar_IsTeammatch ())
1750                 {
1751                         // reserve space for the team scores
1752                         numlines -= teamlines;
1753
1754                         // find first and last player of my team (only draw the team totals and my own team)
1755                         range_begin = range_end = i;
1756                         myteam = cl.scores[fragsort[i]].colors & 15;
1757                         while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam)
1758                                 --range_begin;
1759                         while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam)
1760                                 ++range_end;
1761
1762                         // looks better than two players
1763                         if(numlines == 2)
1764                         {
1765                                 teamsep = 8;
1766                                 numlines = 1;
1767                         }
1768                 }
1769
1770         // figure out start
1771         i -= numlines/2;
1772         i = min(i, range_end - numlines);
1773         i = max(i, range_begin);
1774
1775         if (gamemode == GAME_TRANSFUSION)
1776         {
1777                 for (;i < range_end && x < vid_conwidth.integer;i++)
1778                         x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1779         }
1780         else
1781         {
1782                 if(range_end - i < numlines) // won't draw to bottom?
1783                         y += 8 * (numlines - (range_end - i)); // bottom align
1784                 // show team scores first
1785                 for (j = 0;j < teamlines && y < vid_conheight.integer;j++)
1786                         y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y);
1787                 y += teamsep;
1788                 for (;i < range_end && y < vid_conheight.integer;i++)
1789                         y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1790         }
1791 }
1792
1793 int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
1794 {
1795         static int const sortorder[16] =
1796         {
1797                 1001,
1798                 1002,
1799                 1003,
1800                 1004,
1801                 1, // red
1802                 1005,
1803                 1006,
1804                 1007,
1805                 1008,
1806                 4, // pink
1807                 1009,
1808                 1010,
1809                 3, // yellow
1810                 2, // blue
1811                 1011,
1812                 1012
1813         };
1814         const scoreboard_t *t1 = *(scoreboard_t **) t1_;
1815         const scoreboard_t *t2 = *(scoreboard_t **) t2_;
1816         int tc1 = sortorder[t1->colors & 15];
1817         int tc2 = sortorder[t2->colors & 15];
1818         return tc1 - tc2;
1819 }
1820
1821 void Sbar_Score (int margin)
1822 {
1823         int i, me, score, otherleader, place, distribution, minutes, seconds;
1824         double timeleft;
1825         int sbar_x_save = sbar_x;
1826         int sbar_y_save = sbar_y;
1827
1828         sbar_y = vid_conheight.value - (32+12);
1829         sbar_x -= margin;
1830
1831         me = cl.playerentity - 1;
1832         if (me >= 0 && me < cl.maxclients)
1833         {
1834                 if(Sbar_IsTeammatch())
1835                 {
1836                         // Layout:
1837                         //
1838                         //   team1 team3 team4
1839                         //
1840                         //         TEAM2
1841
1842                         scoreboard_t *teamcolorsort[16];
1843
1844                         Sbar_SortFrags();
1845                         for(i = 0; i < teamlines; ++i)
1846                                 teamcolorsort[i] = &(teams[i]);
1847
1848                         // Now sort them by color
1849                         qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare);
1850
1851                         // : margin
1852                         // -12*4: four digits space
1853                         place = (teamlines - 1) * (-12 * 4);
1854
1855                         for(i = 0; i < teamlines; ++i)
1856                         {
1857                                 int cindex = teamcolorsort[i]->colors & 15;
1858                                 unsigned char *c = (unsigned char *)&palette_complete[(cindex << 4) + 8];
1859                                 float cm = max(max(c[0], c[1]), c[2]);
1860                                 float cr = c[0] / cm;
1861                                 float cg = c[1] / cm;
1862                                 float cb = c[2] / cm;
1863                                 if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team
1864                                 {
1865                                         Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0);
1866                                 }
1867                                 else // other team
1868                                 {
1869                                         Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0);
1870                                         place += 4 * 12;
1871                                 }
1872                         }
1873                 }
1874                 else
1875                 {
1876                         // Layout:
1877                         //
1878                         //   leading  place
1879                         //
1880                         //        FRAGS
1881                         //
1882                         // find leading score other than ourselves, to calculate distribution
1883                         // find our place in the scoreboard
1884                         score = cl.scores[me].frags;
1885                         for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++)
1886                         {
1887                                 if (cl.scores[i].name[0] && i != me)
1888                                 {
1889                                         if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags)
1890                                                 otherleader = i;
1891                                         if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me))
1892                                                 place++;
1893                                 }
1894                         }
1895                         distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0;
1896                         if (place == 1)
1897                                 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0);
1898                         else if (place == 2)
1899                                 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0);
1900                         else
1901                                 Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0);
1902                         if (otherleader < 0)
1903                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 1, 1, 1, 0);
1904                         if (distribution >= 0)
1905                         {
1906                                 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0);
1907                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 1, 1, 1, 0);
1908                         }
1909                         else if (distribution >= -5)
1910                         {
1911                                 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0);
1912                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 1, 0, 1, 0);
1913                         }
1914                         else
1915                         {
1916                                 Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0);
1917                                 Sbar_DrawXNum(-32*4,   0, score, 4, 32, 1, 0, 0, 1, 0);
1918                         }
1919                 }
1920         }
1921
1922         if (cl.statsf[STAT_TIMELIMIT])
1923         {
1924                 timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time);
1925                 minutes = (int)floor(timeleft / 60);
1926                 seconds = (int)(floor(timeleft) - minutes * 60);
1927                 if (minutes >= 5)
1928                 {
1929                         Sbar_DrawXNum(-12*6, 32, minutes,  3, 12, 1, 1, 1, 1, 0);
1930                         if(sb_colon && sb_colon->tex != r_texture_notexture)
1931                                 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1932                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1933                 }
1934                 else if (minutes >= 1)
1935                 {
1936                         Sbar_DrawXNum(-12*6, 32, minutes,  3, 12, 1, 1, 0, 1, 0);
1937                         if(sb_colon && sb_colon->tex != r_texture_notexture)
1938                                 DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0);
1939                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0);
1940                 }
1941                 else if ((int)(timeleft * 4) & 1)
1942                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1943                 else
1944                         Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0);
1945         }
1946         else
1947         {
1948                 minutes = (int)floor(cl.time / 60);
1949                 seconds = (int)(floor(cl.time) - minutes * 60);
1950                 Sbar_DrawXNum(-12*6, 32, minutes,  3, 12, 1, 1, 1, 1, 0);
1951                 if(sb_colon && sb_colon->tex != r_texture_notexture)
1952                         DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0);
1953                 Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0);
1954         }
1955
1956         sbar_x = sbar_x_save;
1957         sbar_y = sbar_y_save;
1958 }
1959
1960 /*
1961 ==================
1962 Sbar_IntermissionOverlay
1963
1964 ==================
1965 */
1966 void Sbar_IntermissionOverlay (void)
1967 {
1968         int             dig;
1969         int             num;
1970
1971         // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
1972         //if (cl.gametype == GAME_DEATHMATCH)
1973         if (!cl.islocalgame)
1974         {
1975                 Sbar_DeathmatchOverlay ();
1976                 return;
1977         }
1978
1979         sbar_x = (vid_conwidth.integer - 320) >> 1;
1980         sbar_y = (vid_conheight.integer - 200) >> 1;
1981
1982         DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1983         DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1984
1985 // time
1986         dig = (int)cl.completed_time / 60;
1987         Sbar_DrawNum (160, 64, dig, 3, 0);
1988         num = (int)cl.completed_time - dig*60;
1989         Sbar_DrawPic (234,64,sb_colon);
1990         Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1991         Sbar_DrawPic (266,64,sb_nums[0][num%10]);
1992
1993         Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1994         if (gamemode != GAME_NEXUIZ)
1995                 Sbar_DrawPic (232, 104, sb_slash);
1996         Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1997
1998         Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1999         if (gamemode != GAME_NEXUIZ)
2000                 Sbar_DrawPic (232, 144, sb_slash);
2001         Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
2002
2003 }
2004
2005
2006 /*
2007 ==================
2008 Sbar_FinaleOverlay
2009
2010 ==================
2011 */
2012 void Sbar_FinaleOverlay (void)
2013 {
2014         DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
2015 }
2016