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