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