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