]> icculus.org git repositories - divverent/darkplaces.git/blob - sbar.c
fix stupid bug introduced by merging CL_DecayLights into CL_UpdateLights, fixed by...
[divverent/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
24 typedef struct sbarpic_s
25 {
26         char name[32];
27 }
28 sbarpic_t;
29
30 static sbarpic_t sbarpics[256];
31 static int numsbarpics;
32
33 static sbarpic_t *Sbar_NewPic(const char *name)
34 {
35         strcpy(sbarpics[numsbarpics].name, name);
36         // precache it
37         // FIXME: precache on every renderer restart (or move this to client)
38         Draw_CachePic(sbarpics[numsbarpics].name, true);
39         return sbarpics + (numsbarpics++);
40 }
41
42 sbarpic_t *sb_disc;
43
44 #define STAT_MINUS 10 // num frame for '-' stats digit
45 sbarpic_t *sb_nums[2][11];
46 sbarpic_t *sb_colon, *sb_slash;
47 sbarpic_t *sb_ibar;
48 sbarpic_t *sb_sbar;
49 sbarpic_t *sb_scorebar;
50 // AK only used by NEX
51 sbarpic_t *sb_sbar_minimal;
52 sbarpic_t *sb_sbar_overlay;
53
54 // AK changed the bound to 9
55 sbarpic_t *sb_weapons[7][9]; // 0 is active, 1 is owned, 2-5 are flashes
56 sbarpic_t *sb_ammo[4];
57 sbarpic_t *sb_sigil[4];
58 sbarpic_t *sb_armor[3];
59 sbarpic_t *sb_items[32];
60
61 // 0-4 are based on health (in 20 increments)
62 // 0 is static, 1 is temporary animation
63 sbarpic_t *sb_faces[5][2];
64
65 sbarpic_t *sb_face_invis;
66 sbarpic_t *sb_face_quad;
67 sbarpic_t *sb_face_invuln;
68 sbarpic_t *sb_face_invis_invuln;
69
70 qboolean sb_showscores;
71
72 int sb_lines;                   // scan lines to draw
73
74 sbarpic_t *rsb_invbar[2];
75 sbarpic_t *rsb_weapons[5];
76 sbarpic_t *rsb_items[2];
77 sbarpic_t *rsb_ammo[3];
78 sbarpic_t *rsb_teambord;                // PGM 01/19/97 - team color border
79
80 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
81 sbarpic_t *hsb_weapons[7][5];   // 0 is active, 1 is owned, 2-5 are flashes
82 //MED 01/04/97 added array to simplify weapon parsing
83 int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
84 //MED 01/04/97 added hipnotic items array
85 sbarpic_t *hsb_items[2];
86
87 //GAME_SOM stuff:
88 sbarpic_t *somsb_health;
89 sbarpic_t *somsb_ammo[4];
90 sbarpic_t *somsb_armor[3];
91
92 sbarpic_t *zymsb_crosshair_dot;
93 sbarpic_t *zymsb_crosshair_line;
94 sbarpic_t *zymsb_crosshair_health;
95 sbarpic_t *zymsb_crosshair_ammo;
96 sbarpic_t *zymsb_crosshair_clip;
97 sbarpic_t *zymsb_crosshair_background;
98
99 cvar_t  showfps = {CVAR_SAVE, "showfps", "0"};
100 cvar_t  showtime = {CVAR_SAVE, "showtime", "0"};
101 cvar_t  showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S"};
102 cvar_t  showdate = {CVAR_SAVE, "showdate", "0"};
103 cvar_t  showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d"};
104 cvar_t  sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4"};
105 cvar_t  sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1"};
106
107 cvar_t  cl_deathscoreboard = {0, "cl_deathscoreboard", "1"};
108
109 void Sbar_MiniDeathmatchOverlay (int x, int y);
110 void Sbar_DeathmatchOverlay (void);
111 void Sbar_IntermissionOverlay (void);
112 void Sbar_FinaleOverlay (void);
113
114
115 /*
116 ===============
117 Sbar_ShowScores
118
119 Tab key down
120 ===============
121 */
122 void Sbar_ShowScores (void)
123 {
124         if (sb_showscores)
125                 return;
126         sb_showscores = true;
127 }
128
129 /*
130 ===============
131 Sbar_DontShowScores
132
133 Tab key up
134 ===============
135 */
136 void Sbar_DontShowScores (void)
137 {
138         sb_showscores = false;
139 }
140
141 void sbar_start(void)
142 {
143         int i;
144
145         numsbarpics = 0;
146
147         if (gamemode == GAME_SOM)
148         {
149                 sb_disc = Sbar_NewPic("gfx/disc");
150
151                 for (i = 0;i < 10;i++)
152                         sb_nums[0][i] = Sbar_NewPic (va("gfx/num_%i",i));
153
154                 somsb_health = Sbar_NewPic("gfx/hud_health");
155                 somsb_ammo[0] = Sbar_NewPic("gfx/sb_shells");
156                 somsb_ammo[1] = Sbar_NewPic("gfx/sb_nails");
157                 somsb_ammo[2] = Sbar_NewPic("gfx/sb_rocket");
158                 somsb_ammo[3] = Sbar_NewPic("gfx/sb_cells");
159                 somsb_armor[0] = Sbar_NewPic("gfx/sb_armor1");
160                 somsb_armor[1] = Sbar_NewPic("gfx/sb_armor2");
161                 somsb_armor[2] = Sbar_NewPic("gfx/sb_armor3");
162         }
163         else if (gamemode == GAME_NEXUIZ)
164         {
165                 for (i = 0;i < 10;i++)
166                         sb_nums[0][i] = Sbar_NewPic (va("gfx/num_%i",i));
167                 sb_nums[0][10] = Sbar_NewPic ("gfx/num_minus");
168
169                 sb_ammo[0] = Sbar_NewPic ("gfx/sb_shells");
170                 sb_ammo[1] = Sbar_NewPic ("gfx/sb_bullets");
171                 sb_ammo[2] = Sbar_NewPic ("gfx/sb_rocket");
172                 sb_ammo[3] = Sbar_NewPic ("gfx/sb_cells");
173
174                 sb_items[2] = Sbar_NewPic ("gfx/sb_slowmo");
175                 sb_items[3] = Sbar_NewPic ("gfx/sb_invinc");
176                 sb_items[4] = Sbar_NewPic ("gfx/sb_energy");
177                 sb_items[5] = Sbar_NewPic ("gfx/sb_str");
178
179                 sb_sbar = Sbar_NewPic("gfx/sbar");
180                 sb_sbar_minimal = Sbar_NewPic("gfx/sbar_minimal");
181                 sb_sbar_overlay = Sbar_NewPic("gfx/sbar_overlay");
182
183                 for(i = 0; i < 9;i++)
184                         sb_weapons[0][i] = Sbar_NewPic(va("gfx/inv_weapon%i",i));
185         }
186         else if (gamemode == GAME_ZYMOTIC)
187         {
188                 zymsb_crosshair_dot = Sbar_NewPic ("gfx/hud/crosshair_dot");
189                 zymsb_crosshair_line = Sbar_NewPic ("gfx/hud/crosshair_line");
190                 zymsb_crosshair_health = Sbar_NewPic ("gfx/hud/crosshair_health");
191                 zymsb_crosshair_clip = Sbar_NewPic ("gfx/hud/crosshair_clip");
192                 zymsb_crosshair_ammo = Sbar_NewPic ("gfx/hud/crosshair_ammo");
193                 zymsb_crosshair_background = Sbar_NewPic ("gfx/hud/crosshair_background");
194         }
195         else
196         {
197                 sb_disc = Sbar_NewPic("gfx/disc");
198
199                 for (i = 0;i < 10;i++)
200                 {
201                         sb_nums[0][i] = Sbar_NewPic (va("gfx/num_%i",i));
202                         sb_nums[1][i] = Sbar_NewPic (va("gfx/anum_%i",i));
203                 }
204
205                 sb_nums[0][10] = Sbar_NewPic ("gfx/num_minus");
206                 sb_nums[1][10] = Sbar_NewPic ("gfx/anum_minus");
207
208                 sb_colon = Sbar_NewPic ("gfx/num_colon");
209                 sb_slash = Sbar_NewPic ("gfx/num_slash");
210
211                 sb_weapons[0][0] = Sbar_NewPic ("gfx/inv_shotgun");
212                 sb_weapons[0][1] = Sbar_NewPic ("gfx/inv_sshotgun");
213                 sb_weapons[0][2] = Sbar_NewPic ("gfx/inv_nailgun");
214                 sb_weapons[0][3] = Sbar_NewPic ("gfx/inv_snailgun");
215                 sb_weapons[0][4] = Sbar_NewPic ("gfx/inv_rlaunch");
216                 sb_weapons[0][5] = Sbar_NewPic ("gfx/inv_srlaunch");
217                 sb_weapons[0][6] = Sbar_NewPic ("gfx/inv_lightng");
218
219                 sb_weapons[1][0] = Sbar_NewPic ("gfx/inv2_shotgun");
220                 sb_weapons[1][1] = Sbar_NewPic ("gfx/inv2_sshotgun");
221                 sb_weapons[1][2] = Sbar_NewPic ("gfx/inv2_nailgun");
222                 sb_weapons[1][3] = Sbar_NewPic ("gfx/inv2_snailgun");
223                 sb_weapons[1][4] = Sbar_NewPic ("gfx/inv2_rlaunch");
224                 sb_weapons[1][5] = Sbar_NewPic ("gfx/inv2_srlaunch");
225                 sb_weapons[1][6] = Sbar_NewPic ("gfx/inv2_lightng");
226
227                 for (i = 0;i < 5;i++)
228                 {
229                         sb_weapons[2+i][0] = Sbar_NewPic (va("gfx/inva%i_shotgun",i+1));
230                         sb_weapons[2+i][1] = Sbar_NewPic (va("gfx/inva%i_sshotgun",i+1));
231                         sb_weapons[2+i][2] = Sbar_NewPic (va("gfx/inva%i_nailgun",i+1));
232                         sb_weapons[2+i][3] = Sbar_NewPic (va("gfx/inva%i_snailgun",i+1));
233                         sb_weapons[2+i][4] = Sbar_NewPic (va("gfx/inva%i_rlaunch",i+1));
234                         sb_weapons[2+i][5] = Sbar_NewPic (va("gfx/inva%i_srlaunch",i+1));
235                         sb_weapons[2+i][6] = Sbar_NewPic (va("gfx/inva%i_lightng",i+1));
236                 }
237
238                 sb_ammo[0] = Sbar_NewPic ("gfx/sb_shells");
239                 sb_ammo[1] = Sbar_NewPic ("gfx/sb_nails");
240                 sb_ammo[2] = Sbar_NewPic ("gfx/sb_rocket");
241                 sb_ammo[3] = Sbar_NewPic ("gfx/sb_cells");
242
243                 sb_armor[0] = Sbar_NewPic ("gfx/sb_armor1");
244                 sb_armor[1] = Sbar_NewPic ("gfx/sb_armor2");
245                 sb_armor[2] = Sbar_NewPic ("gfx/sb_armor3");
246
247                 sb_items[0] = Sbar_NewPic ("gfx/sb_key1");
248                 sb_items[1] = Sbar_NewPic ("gfx/sb_key2");
249                 sb_items[2] = Sbar_NewPic ("gfx/sb_invis");
250                 sb_items[3] = Sbar_NewPic ("gfx/sb_invuln");
251                 sb_items[4] = Sbar_NewPic ("gfx/sb_suit");
252                 sb_items[5] = Sbar_NewPic ("gfx/sb_quad");
253
254                 sb_sigil[0] = Sbar_NewPic ("gfx/sb_sigil1");
255                 sb_sigil[1] = Sbar_NewPic ("gfx/sb_sigil2");
256                 sb_sigil[2] = Sbar_NewPic ("gfx/sb_sigil3");
257                 sb_sigil[3] = Sbar_NewPic ("gfx/sb_sigil4");
258
259                 sb_faces[4][0] = Sbar_NewPic ("gfx/face1");
260                 sb_faces[4][1] = Sbar_NewPic ("gfx/face_p1");
261                 sb_faces[3][0] = Sbar_NewPic ("gfx/face2");
262                 sb_faces[3][1] = Sbar_NewPic ("gfx/face_p2");
263                 sb_faces[2][0] = Sbar_NewPic ("gfx/face3");
264                 sb_faces[2][1] = Sbar_NewPic ("gfx/face_p3");
265                 sb_faces[1][0] = Sbar_NewPic ("gfx/face4");
266                 sb_faces[1][1] = Sbar_NewPic ("gfx/face_p4");
267                 sb_faces[0][0] = Sbar_NewPic ("gfx/face5");
268                 sb_faces[0][1] = Sbar_NewPic ("gfx/face_p5");
269
270                 sb_face_invis = Sbar_NewPic ("gfx/face_invis");
271                 sb_face_invuln = Sbar_NewPic ("gfx/face_invul2");
272                 sb_face_invis_invuln = Sbar_NewPic ("gfx/face_inv2");
273                 sb_face_quad = Sbar_NewPic ("gfx/face_quad");
274
275                 sb_sbar = Sbar_NewPic ("gfx/sbar");
276                 sb_ibar = Sbar_NewPic ("gfx/ibar");
277                 sb_scorebar = Sbar_NewPic ("gfx/scorebar");
278
279         //MED 01/04/97 added new hipnotic weapons
280                 if (gamemode == GAME_HIPNOTIC)
281                 {
282                         hsb_weapons[0][0] = Sbar_NewPic ("gfx/inv_laser");
283                         hsb_weapons[0][1] = Sbar_NewPic ("gfx/inv_mjolnir");
284                         hsb_weapons[0][2] = Sbar_NewPic ("gfx/inv_gren_prox");
285                         hsb_weapons[0][3] = Sbar_NewPic ("gfx/inv_prox_gren");
286                         hsb_weapons[0][4] = Sbar_NewPic ("gfx/inv_prox");
287
288                         hsb_weapons[1][0] = Sbar_NewPic ("gfx/inv2_laser");
289                         hsb_weapons[1][1] = Sbar_NewPic ("gfx/inv2_mjolnir");
290                         hsb_weapons[1][2] = Sbar_NewPic ("gfx/inv2_gren_prox");
291                         hsb_weapons[1][3] = Sbar_NewPic ("gfx/inv2_prox_gren");
292                         hsb_weapons[1][4] = Sbar_NewPic ("gfx/inv2_prox");
293
294                         for (i = 0;i < 5;i++)
295                         {
296                                 hsb_weapons[2+i][0] = Sbar_NewPic (va("gfx/inva%i_laser",i+1));
297                                 hsb_weapons[2+i][1] = Sbar_NewPic (va("gfx/inva%i_mjolnir",i+1));
298                                 hsb_weapons[2+i][2] = Sbar_NewPic (va("gfx/inva%i_gren_prox",i+1));
299                                 hsb_weapons[2+i][3] = Sbar_NewPic (va("gfx/inva%i_prox_gren",i+1));
300                                 hsb_weapons[2+i][4] = Sbar_NewPic (va("gfx/inva%i_prox",i+1));
301                         }
302
303                         hsb_items[0] = Sbar_NewPic ("gfx/sb_wsuit");
304                         hsb_items[1] = Sbar_NewPic ("gfx/sb_eshld");
305                 }
306                 else if (gamemode == GAME_ROGUE)
307                 {
308                         rsb_invbar[0] = Sbar_NewPic ("gfx/r_invbar1");
309                         rsb_invbar[1] = Sbar_NewPic ("gfx/r_invbar2");
310
311                         rsb_weapons[0] = Sbar_NewPic ("gfx/r_lava");
312                         rsb_weapons[1] = Sbar_NewPic ("gfx/r_superlava");
313                         rsb_weapons[2] = Sbar_NewPic ("gfx/r_gren");
314                         rsb_weapons[3] = Sbar_NewPic ("gfx/r_multirock");
315                         rsb_weapons[4] = Sbar_NewPic ("gfx/r_plasma");
316
317                         rsb_items[0] = Sbar_NewPic ("gfx/r_shield1");
318                         rsb_items[1] = Sbar_NewPic ("gfx/r_agrav1");
319
320         // PGM 01/19/97 - team color border
321                         rsb_teambord = Sbar_NewPic ("gfx/r_teambord");
322         // PGM 01/19/97 - team color border
323
324                         rsb_ammo[0] = Sbar_NewPic ("gfx/r_ammolava");
325                         rsb_ammo[1] = Sbar_NewPic ("gfx/r_ammomulti");
326                         rsb_ammo[2] = Sbar_NewPic ("gfx/r_ammoplasma");
327                 }
328         }
329 }
330
331 void sbar_shutdown(void)
332 {
333 }
334
335 void sbar_newmap(void)
336 {
337 }
338
339 void Sbar_Init (void)
340 {
341         Cmd_AddCommand ("+showscores", Sbar_ShowScores);
342         Cmd_AddCommand ("-showscores", Sbar_DontShowScores);
343         Cvar_RegisterVariable (&showfps);
344         Cvar_RegisterVariable (&showtime);
345         Cvar_RegisterVariable (&showtime_format);
346         Cvar_RegisterVariable (&showdate);
347         Cvar_RegisterVariable (&showdate_format);
348         Cvar_RegisterVariable (&sbar_alpha_bg);
349         Cvar_RegisterVariable (&sbar_alpha_fg);
350         Cvar_RegisterVariable (&cl_deathscoreboard);
351
352         R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap);
353 }
354
355
356 //=============================================================================
357
358 // drawing routines are relative to the status bar location
359
360 int sbar_x, sbar_y;
361
362 /*
363 =============
364 Sbar_DrawPic
365 =============
366 */
367 void Sbar_DrawPic (int x, int y, sbarpic_t *sbarpic)
368 {
369         DrawQ_Pic (sbar_x + x, sbar_y + y, sbarpic->name, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0);
370 }
371
372 void Sbar_DrawAlphaPic (int x, int y, sbarpic_t *sbarpic, float alpha)
373 {
374         DrawQ_Pic (sbar_x + x, sbar_y + y, sbarpic->name, 0, 0, 1, 1, 1, alpha, 0);
375 }
376
377 /*
378 ================
379 Sbar_DrawCharacter
380
381 Draws one solid graphics character
382 ================
383 */
384 void Sbar_DrawCharacter (int x, int y, int num)
385 {
386         DrawQ_String (sbar_x + x + 4 , sbar_y + y, va("%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0);
387 }
388
389 /*
390 ================
391 Sbar_DrawString
392 ================
393 */
394 void Sbar_DrawString (int x, int y, char *str)
395 {
396         DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0);
397 }
398
399 /*
400 =============
401 Sbar_DrawNum
402 =============
403 */
404 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
405 {
406         char str[32], *ptr;
407         int l, frame;
408
409         l = sprintf(str, "%i", num);
410         ptr = str;
411         if (l > digits)
412                 ptr += (l-digits);
413         if (l < digits)
414                 x += (digits-l)*24;
415
416         while (*ptr)
417         {
418                 if (*ptr == '-')
419                         frame = STAT_MINUS;
420                 else
421                         frame = *ptr -'0';
422
423                 Sbar_DrawPic (x, y, sb_nums[color][frame]);
424                 x += 24;
425
426                 ptr++;
427         }
428 }
429
430 /*
431 =============
432 Sbar_DrawXNum
433 =============
434 */
435
436 void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
437 {
438         char str[32], *ptr;
439         int l, frame;
440
441         l = sprintf(str, "%i", num);
442         ptr = str;
443         if (l > digits)
444                 ptr += (l-digits);
445         if (l < digits)
446                 x += (digits-l) * lettersize;
447
448         while (*ptr)
449         {
450                 if (*ptr == '-')
451                         frame = STAT_MINUS;
452                 else
453                         frame = *ptr -'0';
454
455                 DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame]->name,lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags);
456                 x += lettersize;
457
458                 ptr++;
459         }
460 }
461
462 //=============================================================================
463
464
465 /*
466 ===============
467 Sbar_SortFrags
468 ===============
469 */
470 static int fragsort[MAX_SCOREBOARD];
471 static int scoreboardlines;
472 void Sbar_SortFrags (void)
473 {
474         int             i, j, k;
475
476 // sort by frags
477         scoreboardlines = 0;
478         for (i=0 ; i<cl.maxclients ; i++)
479         {
480                 if (cl.scores[i].name[0])
481                 {
482                         fragsort[scoreboardlines] = i;
483                         scoreboardlines++;
484                 }
485         }
486
487         for (i=0 ; i<scoreboardlines ; i++)
488                 for (j=0 ; j<scoreboardlines-1-i ; j++)
489                         if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
490                         {
491                                 k = fragsort[j];
492                                 fragsort[j] = fragsort[j+1];
493                                 fragsort[j+1] = k;
494                         }
495 }
496
497 /*
498 ===============
499 Sbar_SoloScoreboard
500 ===============
501 */
502 void Sbar_SoloScoreboard (void)
503 {
504         char    str[80];
505         int             minutes, seconds, tens, units;
506         int             l;
507
508         if (gamemode != GAME_NEXUIZ) {
509                 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
510                 Sbar_DrawString (8, 4, str);
511
512                 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
513                 Sbar_DrawString (8, 12, str);
514         }
515
516 // time
517         minutes = cl.time / 60;
518         seconds = cl.time - 60*minutes;
519         tens = seconds / 10;
520         units = seconds - 10*tens;
521         sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
522         Sbar_DrawString (184, 4, str);
523
524 // draw level name
525         if (gamemode == GAME_NEXUIZ) {
526                 l = (int) strlen (cl.worldmodel->name);
527                 Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name);
528         } else {
529                 l = (int) strlen (cl.levelname);
530                 Sbar_DrawString (232 - l*4, 12, cl.levelname);
531         }
532 }
533
534 /*
535 ===============
536 Sbar_DrawScoreboard
537 ===============
538 */
539 void Sbar_DrawScoreboard (void)
540 {
541         Sbar_SoloScoreboard ();
542         if (cl.gametype == GAME_DEATHMATCH)
543                 Sbar_DeathmatchOverlay ();
544 }
545
546 //=============================================================================
547
548 // AK to make DrawInventory smaller
549 static void Sbar_DrawWeapon(int nr, float fade, int active)
550 {
551         // width = 300, height = 100
552         const int w_width = 300, w_height = 100, w_space = 10;
553         const float w_scale = 0.4;
554
555         DrawQ_Pic(vid_conwidth.integer - (w_width + w_space) * w_scale, (w_height + w_space) * w_scale * nr + w_space, sb_weapons[0][nr]->name, 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_ADDITIVE);
556         //DrawQ_String(vid_conwidth.integer - (w_space + font_size ), (w_height + w_space) * w_scale * nr + w_space, va("%i",nr+1), 0, font_size, font_size, 1, 0, 0, fade, 0);
557
558         if (active)
559                 DrawQ_Fill(vid_conwidth.integer - (w_width + w_space) * w_scale, (w_height + w_space) * w_scale * nr + w_space, w_width * w_scale, w_height * w_scale, 0.3, 0.3, 0.3, fade * sbar_alpha_fg.value, DRAWFLAG_ADDITIVE);
560 }
561
562 /*
563 ===============
564 Sbar_DrawInventory
565 ===============
566 */
567 void Sbar_DrawInventory (void)
568 {
569         int i;
570         char num[6];
571         float time;
572         int flashon;
573
574         if (gamemode == GAME_ROGUE)
575         {
576                 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
577                         Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value);
578                 else
579                         Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value);
580         }
581         else
582                 Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value);
583
584         // weapons
585         for (i=0 ; i<7 ; i++)
586         {
587                 if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<i) )
588                 {
589                         time = cl.item_gettime[i];
590                         flashon = (int)((cl.time - time)*10);
591                         if (flashon >= 10)
592                         {
593                                 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i)  )
594                                         flashon = 1;
595                                 else
596                                         flashon = 0;
597                         }
598                         else
599                                 flashon = (flashon%5) + 2;
600
601                         Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
602                 }
603         }
604
605         // MED 01/04/97
606         // hipnotic weapons
607         if (gamemode == GAME_HIPNOTIC)
608         {
609                 int grenadeflashing=0;
610                 for (i=0 ; i<4 ; i++)
611                 {
612                         if (cl.stats[STAT_ITEMS] & (1<<hipweapons[i]) )
613                         {
614                                 time = cl.item_gettime[hipweapons[i]];
615                                 flashon = (int)((cl.time - time)*10);
616                                 if (flashon >= 10)
617                                 {
618                                         if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i])  )
619                                                 flashon = 1;
620                                         else
621                                                 flashon = 0;
622                                 }
623                                 else
624                                         flashon = (flashon%5) + 2;
625
626                                 // check grenade launcher
627                                 if (i==2)
628                                 {
629                                         if (cl.stats[STAT_ITEMS] & HIT_PROXIMITY_GUN)
630                                         {
631                                                 if (flashon)
632                                                 {
633                                                         grenadeflashing = 1;
634                                                         Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
635                                                 }
636                                         }
637                                 }
638                                 else if (i==3)
639                                 {
640                                         if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<<4))
641                                         {
642                                                 if (!grenadeflashing)
643                                                         Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
644                                         }
645                                         else
646                                                 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
647                                 }
648                                 else
649                                         Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
650                         }
651                 }
652         }
653
654         if (gamemode == GAME_ROGUE)
655         {
656                 // check for powered up weapon.
657                 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
658                         for (i=0;i<5;i++)
659                                 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
660                                         Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
661         }
662
663         // ammo counts
664         for (i=0 ; i<4 ; i++)
665         {
666                 sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] );
667                 if (num[0] != ' ')
668                         Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
669                 if (num[1] != ' ')
670                         Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
671                 if (num[2] != ' ')
672                         Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
673         }
674
675         // items
676         for (i=0 ; i<6 ; i++)
677                 if (cl.stats[STAT_ITEMS] & (1<<(17+i)))
678                 {
679                         //MED 01/04/97 changed keys
680                         if (gamemode != GAME_HIPNOTIC || (i>1))
681                                 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
682                 }
683
684         //MED 01/04/97 added hipnotic items
685         // hipnotic items
686         if (gamemode == GAME_HIPNOTIC)
687         {
688                 for (i=0 ; i<2 ; i++)
689                         if (cl.stats[STAT_ITEMS] & (1<<(24+i)))
690                                 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
691         }
692
693         if (gamemode == GAME_ROGUE)
694         {
695                 // new rogue items
696                 for (i=0 ; i<2 ; i++)
697                         if (cl.stats[STAT_ITEMS] & (1<<(29+i)))
698                                 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
699         }
700         else
701         {
702                 // sigils
703                 for (i=0 ; i<4 ; i++)
704                         if (cl.stats[STAT_ITEMS] & (1<<(28+i)))
705                                 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
706         }
707 }
708
709 //=============================================================================
710
711 /*
712 ===============
713 Sbar_DrawFrags
714 ===============
715 */
716 void Sbar_DrawFrags (void)
717 {
718         int i, k, l, x, f;
719         char num[12];
720         scoreboard_t *s;
721         qbyte *c;
722
723         Sbar_SortFrags ();
724
725         // draw the text
726         l = min(scoreboardlines, 4);
727
728         x = 23 * 8;
729
730         for (i = 0;i < l;i++)
731         {
732                 k = fragsort[i];
733                 s = &cl.scores[k];
734
735                 // draw background
736                 c = (qbyte *)&palette_complete[(s->colors & 0xf0) + 8];
737                 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
738                 c = (qbyte *)&palette_complete[((s->colors & 15)<<4) + 8];
739                 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
740
741                 // draw number
742                 f = s->frags;
743                 sprintf (num, "%3i",f);
744
745                 if (k == cl.viewentity - 1)
746                 {
747                         Sbar_DrawCharacter ( x      + 2, -24, 16);
748                         Sbar_DrawCharacter ( x + 32 - 4, -24, 17);
749                 }
750                 Sbar_DrawCharacter (x +  8, -24, num[0]);
751                 Sbar_DrawCharacter (x + 16, -24, num[1]);
752                 Sbar_DrawCharacter (x + 24, -24, num[2]);
753                 x += 32;
754         }
755 }
756
757 //=============================================================================
758
759
760 /*
761 ===============
762 Sbar_DrawFace
763 ===============
764 */
765 void Sbar_DrawFace (void)
766 {
767         int f;
768
769 // PGM 01/19/97 - team color drawing
770 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
771         if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7))
772         {
773                 char num[12];
774                 scoreboard_t *s;
775                 qbyte *c;
776
777                 s = &cl.scores[cl.viewentity - 1];
778                 // draw background
779                 Sbar_DrawPic (112, 0, rsb_teambord);
780                 c = (qbyte *)&palette_complete[(s->colors & 0xf0) + 8];
781                 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
782                 c = (qbyte *)&palette_complete[((s->colors & 15)<<4) + 8];
783                 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), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
784
785                 // draw number
786                 f = s->frags;
787                 sprintf (num, "%3i",f);
788
789                 if ((s->colors & 0xf0)==0)
790                 {
791                         if (num[0] != ' ')
792                                 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
793                         if (num[1] != ' ')
794                                 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
795                         if (num[2] != ' ')
796                                 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
797                 }
798                 else
799                 {
800                         Sbar_DrawCharacter ( 109, 3, num[0]);
801                         Sbar_DrawCharacter ( 116, 3, num[1]);
802                         Sbar_DrawCharacter ( 123, 3, num[2]);
803                 }
804
805                 return;
806         }
807 // PGM 01/19/97 - team color drawing
808
809         if ( (cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
810                 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
811         else if (cl.stats[STAT_ITEMS] & IT_QUAD)
812                 Sbar_DrawPic (112, 0, sb_face_quad );
813         else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
814                 Sbar_DrawPic (112, 0, sb_face_invis );
815         else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
816                 Sbar_DrawPic (112, 0, sb_face_invuln);
817         else
818         {
819                 f = cl.stats[STAT_HEALTH] / 20;
820                 f = bound(0, f, 4);
821                 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
822         }
823 }
824
825 void Sbar_ShowFPS(void)
826 {
827         float fps_x, fps_y, fps_scalex, fps_scaley, fps_height;
828         char fpsstring[32];
829         char timestring[32];
830         char datestring[32];
831         qboolean red = false;
832         fpsstring[0] = 0;
833         timestring[0] = 0;
834         datestring[0] = 0;
835         if (showfps.integer)
836         {
837                 float calc;
838                 if (showfps.integer > 1)
839                 {
840                         static double currtime, frametimes[32];
841                         double newtime, total;
842                         int count, i;
843                         static int framecycle = 0;
844
845                         newtime = Sys_DoubleTime();
846                         frametimes[framecycle] = newtime - currtime;
847                         total = 0;
848                         count = 0;
849                         while(total < 0.2 && count < 32 && frametimes[i = (framecycle - count) & 31])
850                         {
851                                 total += frametimes[i];
852                                 count++;
853                         }
854                         framecycle++;
855                         framecycle &= 31;
856                         if (showfps.integer == 2)
857                                 calc = (((double)count / total) + 0.5);
858                         else // showfps 3, rapid update
859                                 calc = ((1.0 / (newtime - currtime)) + 0.5);
860                         currtime = newtime;
861                 }
862                 else
863                 {
864                         static double nexttime = 0, lasttime = 0;
865                         static float framerate = 0;
866                         static int framecount = 0;
867                         double newtime;
868                         newtime = Sys_DoubleTime();
869                         if (newtime >= nexttime)
870                         {
871                                 framerate = ((float)framecount / (newtime - lasttime) + 0.5);
872                                 lasttime = newtime;
873                                 nexttime = max(nexttime + 1, lasttime - 1);
874                                 framecount = 0;
875                         }
876                         framecount++;
877                         calc = framerate;
878                 }
879
880                 if ((red = (calc < 1.0f)))
881                         dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0f / calc + 0.5));
882                 else
883                         dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(calc + 0.5));
884         }
885         if (showtime.integer)
886                 strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring));
887         if (showdate.integer)
888                 strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring));
889         if (fpsstring[0] || timestring[0])
890         {
891                 fps_scalex = 12;
892                 fps_scaley = 12;
893                 fps_height = fps_scaley * ((fpsstring[0] != 0) + (timestring[0] != 0) + (datestring[0] != 0));
894                 //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar
895                 //fps_y = bound(0, fps_y, vid_conheight.integer - fps_height);
896                 fps_y = vid_conheight.integer - fps_height;
897                 if (fpsstring[0])
898                 {
899                         fps_x = vid_conwidth.integer - fps_scalex * strlen(fpsstring);
900                         DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(fpsstring), fps_scaley, 0, 0, 0, 0.5, 0);
901                         if (red)
902                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0);
903                         else
904                                 DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0);
905                         fps_y += fps_scaley;
906                 }
907                 if (timestring[0])
908                 {
909                         fps_x = vid_conwidth.integer - fps_scalex * strlen(timestring);
910                         DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(timestring), fps_scaley, 0, 0, 0, 0.5, 0);
911                         DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0);
912                         fps_y += fps_scaley;
913                 }
914                 if (datestring[0])
915                 {
916                         fps_x = vid_conwidth.integer - fps_scalex * strlen(datestring);
917                         DrawQ_Fill(fps_x, fps_y, fps_scalex * strlen(datestring), fps_scaley, 0, 0, 0, 0.5, 0);
918                         DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0);
919                         fps_y += fps_scaley;
920                 }
921         }
922 }
923
924 /*
925 ===============
926 Sbar_Draw
927 ===============
928 */
929 extern float v_dmg_time, v_dmg_roll, v_dmg_pitch;
930 extern cvar_t v_kicktime;
931 void Sbar_Draw (void)
932 {
933         if (cl.intermission == 1)
934         {
935                 Sbar_IntermissionOverlay();
936                 return;
937         }
938         else if (cl.intermission == 2)
939         {
940                 Sbar_FinaleOverlay();
941                 return;
942         }
943
944         if (gamemode == GAME_SOM)
945         {
946                 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
947                         Sbar_DrawScoreboard ();
948                 else if (sb_lines)
949                 {
950                         // this is the top left of the sbar area
951                         sbar_x = 0;
952                         sbar_y = vid_conheight.integer - 24*3;
953
954                         // armor
955                         if (cl.stats[STAT_ARMOR])
956                         {
957                                 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
958                                         Sbar_DrawPic(0, 0, somsb_armor[2]);
959                                 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
960                                         Sbar_DrawPic(0, 0, somsb_armor[1]);
961                                 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
962                                         Sbar_DrawPic(0, 0, somsb_armor[0]);
963                                 Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
964                         }
965
966                         // health
967                         Sbar_DrawPic(0, 24, somsb_health);
968                         Sbar_DrawNum(24, 24, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
969
970                         // ammo icon
971                         if (cl.stats[STAT_ITEMS] & IT_SHELLS)
972                                 Sbar_DrawPic(0, 48, somsb_ammo[0]);
973                         else if (cl.stats[STAT_ITEMS] & IT_NAILS)
974                                 Sbar_DrawPic(0, 48, somsb_ammo[1]);
975                         else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
976                                 Sbar_DrawPic(0, 48, somsb_ammo[2]);
977                         else if (cl.stats[STAT_ITEMS] & IT_CELLS)
978                                 Sbar_DrawPic(0, 48, somsb_ammo[3]);
979                         Sbar_DrawNum(24, 48, cl.stats[STAT_AMMO], 3, false);
980                         if (cl.stats[STAT_SHELLS])
981                                 Sbar_DrawNum(24 + 3*24, 48, cl.stats[STAT_SHELLS], 1, true);
982                 }
983         }
984         else if (gamemode == GAME_NEXUIZ)
985         {
986                 sbar_y = vid_conheight.integer - 47;
987                 sbar_x = (vid_conwidth.integer - 640)/2;
988
989                 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
990                 {
991                         Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
992                         Sbar_DrawScoreboard ();
993                 }
994                 else if (sb_lines)
995                 {
996                         int i;
997                         double time;
998                         float fade;
999
1000                         // we have a max time 2s (min time = 0)
1001                         if ((time = cl.time - cl.weapontime) < 2)
1002                         {
1003                                 fade = (1.0 - 0.5 * time);
1004                                 fade *= fade;
1005                                 for (i = 0; i < 8;i++)
1006                                         if (cl.stats[STAT_ITEMS] & (1 << i))
1007                                                 Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON]));
1008
1009                                 if((cl.stats[STAT_ITEMS] & (1<<12)))
1010                                         Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1));
1011                         }
1012
1013                         //if (!cl.islocalgame)
1014                         //      Sbar_DrawFrags ();
1015
1016                         if (sb_lines > 24)
1017                                 Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value);
1018                         else
1019                                 Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value);
1020
1021                         // special items
1022                         if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1023                         {
1024                                 // Nexuiz has no anum pics
1025                                 //Sbar_DrawNum (36, 0, 666, 3, 1);
1026                                 // Nexuiz has no disc pic
1027                                 //Sbar_DrawPic (0, 0, sb_disc);
1028                         }
1029
1030                         // armor
1031                         Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0);
1032
1033                         // health
1034                         if(cl.stats[STAT_HEALTH] > 100)
1035                                 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0);
1036                         else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5)
1037                                 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0);
1038                         else
1039                                 Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0);
1040
1041                         // AK dont draw ammo for the laser
1042                         if(cl.stats[STAT_ACTIVEWEAPON] != 12)
1043                         {
1044                                 if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS)
1045                                         Sbar_DrawPic (519, 0, sb_ammo[0]);
1046                                 else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS)
1047                                         Sbar_DrawPic (519, 0, sb_ammo[1]);
1048                                 else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS)
1049                                         Sbar_DrawPic (519, 0, sb_ammo[2]);
1050                                 else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS)
1051                                         Sbar_DrawPic (519, 0, sb_ammo[3]);
1052
1053                                 if(cl.stats[STAT_AMMO] <= 10)
1054                                         Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0);
1055                                 else
1056                                         Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0);
1057
1058                         }
1059
1060                         if (sb_lines > 24)
1061                                 DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay->name,0,0,1,1,1,1,DRAWFLAG_MODULATE);
1062                 }
1063
1064                 //if (vid_conwidth.integer > 320 && cl.gametype == GAME_DEATHMATCH)
1065                 //      Sbar_MiniDeathmatchOverlay (0, 17);
1066         }
1067         else if (gamemode == GAME_ZYMOTIC)
1068         {
1069                 float scale = 128.0f / 256.0f;
1070                 float healthstart, healthheight, healthstarttc, healthendtc;
1071                 float shieldstart, shieldheight, shieldstarttc, shieldendtc;
1072                 float ammostart, ammoheight, ammostarttc, ammoendtc;
1073                 float clipstart, clipheight, clipstarttc, clipendtc;
1074                 float kickoffset[3], offset;
1075                 VectorClear(kickoffset);
1076                 if (v_dmg_time > 0)
1077                 {
1078                         kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale;
1079                         kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale;
1080                 }
1081                 sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0];
1082                 sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1];
1083                 offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?)
1084                 DrawQ_SuperPic(sbar_x +  120           * scale, sbar_y + ( 88 - offset) * scale, zymsb_crosshair_line->name, 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);
1085                 DrawQ_SuperPic(sbar_x + (132 + offset) * scale, sbar_y + 120            * scale, zymsb_crosshair_line->name, 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);
1086                 DrawQ_SuperPic(sbar_x +  120           * scale, sbar_y + (132 + offset) * scale, zymsb_crosshair_line->name, 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);
1087                 DrawQ_SuperPic(sbar_x + ( 88 - offset) * scale, sbar_y + 120            * scale, zymsb_crosshair_line->name, 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);
1088                 healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f);
1089                 shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f);
1090                 healthstart = 204 - healthheight;
1091                 shieldstart = healthstart - shieldheight;
1092                 healthstarttc = healthstart * (1.0f / 256.0f);
1093                 healthendtc = (healthstart + healthheight) * (1.0f / 256.0f);
1094                 shieldstarttc = shieldstart * (1.0f / 256.0f);
1095                 shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f);
1096                 ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f);
1097                 ammostart = 114 - ammoheight;
1098                 ammostarttc = ammostart * (1.0f / 256.0f);
1099                 ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f);
1100                 clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f);
1101                 clipstart = 190 - clipheight;
1102                 clipstarttc = clipstart * (1.0f / 256.0f);
1103                 clipendtc = (clipstart + clipheight) * (1.0f / 256.0f);
1104                 if (healthheight > 0) DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + healthstart * scale, zymsb_crosshair_health->name, 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);
1105                 if (shieldheight > 0) DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + shieldstart * scale, zymsb_crosshair_health->name, 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);
1106                 if (ammoheight > 0)   DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + ammostart   * scale, zymsb_crosshair_ammo->name,   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);
1107                 if (clipheight > 0)   DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + clipstart   * scale, zymsb_crosshair_clip->name,   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);
1108                 DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background->name, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL);
1109         }
1110         else // Quake and others
1111         {
1112                 sbar_y = vid_conheight.integer - SBAR_HEIGHT;
1113                 if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION)
1114                         sbar_x = 0;
1115                 else
1116                         sbar_x = (vid_conwidth.integer - 320)/2;
1117
1118                 if (sb_lines > 24)
1119                 {
1120                         if (gamemode != GAME_GOODVSBAD2)
1121                                 Sbar_DrawInventory ();
1122                         if (!cl.islocalgame && gamemode != GAME_TRANSFUSION)
1123                                 Sbar_DrawFrags ();
1124                 }
1125
1126                 if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer))
1127                 {
1128                         if (gamemode != GAME_GOODVSBAD2)
1129                                 Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value);
1130                         Sbar_DrawScoreboard ();
1131                 }
1132                 else if (sb_lines)
1133                 {
1134                         Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value);
1135
1136                         // keys (hipnotic only)
1137                         //MED 01/04/97 moved keys here so they would not be overwritten
1138                         if (gamemode == GAME_HIPNOTIC)
1139                         {
1140                                 if (cl.stats[STAT_ITEMS] & IT_KEY1)
1141                                         Sbar_DrawPic (209, 3, sb_items[0]);
1142                                 if (cl.stats[STAT_ITEMS] & IT_KEY2)
1143                                         Sbar_DrawPic (209, 12, sb_items[1]);
1144                         }
1145                         // armor
1146                         if (gamemode != GAME_GOODVSBAD2)
1147                         {
1148                                 if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
1149                                 {
1150                                         Sbar_DrawNum (24, 0, 666, 3, 1);
1151                                         Sbar_DrawPic (0, 0, sb_disc);
1152                                 }
1153                                 else
1154                                 {
1155                                         if (gamemode == GAME_ROGUE)
1156                                         {
1157                                                 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1158                                                 if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
1159                                                         Sbar_DrawPic (0, 0, sb_armor[2]);
1160                                                 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
1161                                                         Sbar_DrawPic (0, 0, sb_armor[1]);
1162                                                 else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
1163                                                         Sbar_DrawPic (0, 0, sb_armor[0]);
1164                                         }
1165                                         else
1166                                         {
1167                                                 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
1168                                                 if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
1169                                                         Sbar_DrawPic (0, 0, sb_armor[2]);
1170                                                 else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
1171                                                         Sbar_DrawPic (0, 0, sb_armor[1]);
1172                                                 else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
1173                                                         Sbar_DrawPic (0, 0, sb_armor[0]);
1174                                         }
1175                                 }
1176                         }
1177
1178                         // face
1179                         Sbar_DrawFace ();
1180
1181                         // health
1182                         Sbar_DrawNum (154, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
1183
1184                         // ammo icon
1185                         if (gamemode == GAME_ROGUE)
1186                         {
1187                                 if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
1188                                         Sbar_DrawPic (224, 0, sb_ammo[0]);
1189                                 else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
1190                                         Sbar_DrawPic (224, 0, sb_ammo[1]);
1191                                 else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
1192                                         Sbar_DrawPic (224, 0, sb_ammo[2]);
1193                                 else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
1194                                         Sbar_DrawPic (224, 0, sb_ammo[3]);
1195                                 else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
1196                                         Sbar_DrawPic (224, 0, rsb_ammo[0]);
1197                                 else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
1198                                         Sbar_DrawPic (224, 0, rsb_ammo[1]);
1199                                 else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
1200                                         Sbar_DrawPic (224, 0, rsb_ammo[2]);
1201                         }
1202                         else
1203                         {
1204                                 if (cl.stats[STAT_ITEMS] & IT_SHELLS)
1205                                         Sbar_DrawPic (224, 0, sb_ammo[0]);
1206                                 else if (cl.stats[STAT_ITEMS] & IT_NAILS)
1207                                         Sbar_DrawPic (224, 0, sb_ammo[1]);
1208                                 else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
1209                                         Sbar_DrawPic (224, 0, sb_ammo[2]);
1210                                 else if (cl.stats[STAT_ITEMS] & IT_CELLS)
1211                                         Sbar_DrawPic (224, 0, sb_ammo[3]);
1212                         }
1213
1214                         Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
1215
1216                 }
1217
1218                 if (vid_conwidth.integer > 320 && cl.gametype == GAME_DEATHMATCH)
1219                 {
1220                         if (gamemode == GAME_TRANSFUSION)
1221                                 Sbar_MiniDeathmatchOverlay (0, 0);
1222                         else
1223                                 Sbar_MiniDeathmatchOverlay (324, vid_conheight.integer - sb_lines);
1224                 }
1225         }
1226
1227         Sbar_ShowFPS();
1228
1229         R_Draw2DCrosshair();
1230
1231         if (cl_prydoncursor.integer)
1232                 DrawQ_Pic((cl.cmd.cursor_screen[0] + 1) * 0.5 * vid_conwidth.integer, (cl.cmd.cursor_screen[1] + 1) * 0.5 * vid_conheight.integer, va("gfx/prydoncursor%03i", cl_prydoncursor.integer), 0, 0, 1, 1, 1, 1, 0);
1233 }
1234
1235 //=============================================================================
1236
1237 /*
1238 ==================
1239 Sbar_DeathmatchOverlay
1240
1241 ==================
1242 */
1243 float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
1244 {
1245         qbyte *c;
1246         // draw colors behind score
1247         c = (qbyte *)&palette_complete[(s->colors & 0xf0) + 8];
1248         DrawQ_Fill(x + 8, y+1, 32, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1249         c = (qbyte *)&palette_complete[((s->colors & 15)<<4) + 8];
1250         DrawQ_Fill(x + 8, y+4, 32, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), c[3] * (1.0f / 255.0f) * sbar_alpha_fg.value, 0);
1251         // print the text
1252         //DrawQ_String(x, y, va("%c%4i %s", (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1253         // FIXME: use a constant for this color tag instead
1254         DrawQ_ColoredString(x, y, va("%c%4i %s" STRING_COLOR_DEFAULT_STR, (s - cl.scores) == cl.playerentity - 1 ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL );
1255         return 8;
1256 }
1257
1258 void Sbar_DeathmatchOverlay (void)
1259 {
1260         int i, x, y;
1261         cachepic_t *pic;
1262
1263         pic = Draw_CachePic ("gfx/ranking", true);
1264         DrawQ_Pic ((vid_conwidth.integer - pic->width)/2, 8, "gfx/ranking", 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1265
1266         // scores
1267         Sbar_SortFrags ();
1268         // draw the text
1269         x = (vid_conwidth.integer - (6 + 15) * 8) / 2;
1270         y = 40;
1271         for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++)
1272                 y += Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1273 }
1274
1275 /*
1276 ==================
1277 Sbar_DeathmatchOverlay
1278
1279 ==================
1280 */
1281 void Sbar_MiniDeathmatchOverlay (int x, int y)
1282 {
1283         int i, numlines;
1284
1285         // decide where to print
1286         if (gamemode == GAME_TRANSFUSION)
1287                 numlines = (vid_conwidth.integer - x + 127) / 128;
1288         else
1289                 numlines = (vid_conheight.integer - y + 7) / 8;
1290
1291         // give up if there isn't room
1292         if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1)
1293                 return;
1294
1295         // scores
1296         Sbar_SortFrags ();
1297
1298         //find us
1299         for (i = 0; i < scoreboardlines; i++)
1300                 if (fragsort[i] == cl.playerentity - 1)
1301                         break;
1302
1303         // figure out start
1304         i -= numlines/2;
1305         i = min(i, scoreboardlines - numlines);
1306         i = max(i, 0);
1307
1308         if (gamemode == GAME_TRANSFUSION)
1309         {
1310                 for (;i < scoreboardlines && x < vid_conwidth.integer;i++)
1311                         x += 128 + Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1312         }
1313         else
1314         {
1315                 for (;i < scoreboardlines && y < vid_conheight.integer;i++)
1316                         y += Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y);
1317         }
1318 }
1319
1320 /*
1321 ==================
1322 Sbar_IntermissionOverlay
1323
1324 ==================
1325 */
1326 void Sbar_IntermissionOverlay (void)
1327 {
1328         int             dig;
1329         int             num;
1330
1331         if (cl.gametype == GAME_DEATHMATCH)
1332         {
1333                 Sbar_DeathmatchOverlay ();
1334                 return;
1335         }
1336
1337         sbar_x = (vid_conwidth.integer - 320) >> 1;
1338         sbar_y = (vid_conheight.integer - 200) >> 1;
1339
1340         DrawQ_Pic (sbar_x + 64, sbar_y + 24, "gfx/complete", 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1341         DrawQ_Pic (sbar_x + 0, sbar_y + 56, "gfx/inter", 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1342
1343 // time
1344         dig = cl.completed_time/60;
1345         Sbar_DrawNum (160, 64, dig, 3, 0);
1346         num = cl.completed_time - dig*60;
1347         if (gamemode != GAME_NEXUIZ)
1348                 Sbar_DrawPic (234,64,sb_colon);
1349         Sbar_DrawPic (246,64,sb_nums[0][num/10]);
1350         Sbar_DrawPic (266,64,sb_nums[0][num%10]);
1351
1352         Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1353         if (gamemode != GAME_NEXUIZ)
1354                 Sbar_DrawPic (232, 104, sb_slash);
1355         Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1356
1357         Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1358         if (gamemode != GAME_NEXUIZ)
1359                 Sbar_DrawPic (232, 144, sb_slash);
1360         Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1361
1362 }
1363
1364
1365 /*
1366 ==================
1367 Sbar_FinaleOverlay
1368
1369 ==================
1370 */
1371 void Sbar_FinaleOverlay (void)
1372 {
1373         cachepic_t      *pic;
1374
1375         pic = Draw_CachePic ("gfx/finale", true);
1376         DrawQ_Pic((vid_conwidth.integer - pic->width)/2, 16, "gfx/finale", 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0);
1377 }
1378