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