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