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