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(¤t_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