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