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