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