Gigantic commit - dlight system rewritten
[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
25 #define STAT_MINUS              10      // num frame for '-' stats digit
26 qpic_t          *sb_nums[2][11];
27 qpic_t          *sb_colon, *sb_slash;
28 qpic_t          *sb_ibar;
29 qpic_t          *sb_sbar;
30 qpic_t          *sb_scorebar;
31
32 qpic_t      *sb_weapons[7][8];   // 0 is active, 1 is owned, 2-5 are flashes
33 qpic_t      *sb_ammo[4];
34 qpic_t          *sb_sigil[4];
35 qpic_t          *sb_armor[3];
36 qpic_t          *sb_items[32];
37
38 qpic_t  *sb_faces[7][2];                // 0 is gibbed, 1 is dead, 2-6 are alive
39                                                         // 0 is static, 1 is temporary animation
40 qpic_t  *sb_face_invis;
41 qpic_t  *sb_face_quad;
42 qpic_t  *sb_face_invuln;
43 qpic_t  *sb_face_invis_invuln;
44
45 qboolean        sb_showscores;
46
47 int                     sb_lines;                       // scan lines to draw
48
49 qpic_t      *rsb_invbar[2];
50 qpic_t      *rsb_weapons[5];
51 qpic_t      *rsb_items[2];
52 qpic_t      *rsb_ammo[3];
53 qpic_t      *rsb_teambord;              // PGM 01/19/97 - team color border
54
55 //MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
56 qpic_t      *hsb_weapons[7][5];   // 0 is active, 1 is owned, 2-5 are flashes
57 //MED 01/04/97 added array to simplify weapon parsing
58 int         hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
59 //MED 01/04/97 added hipnotic items array
60 qpic_t      *hsb_items[2];
61
62 void Sbar_MiniDeathmatchOverlay (void);
63 void Sbar_DeathmatchOverlay (void);
64 void M_DrawPic (int x, int y, qpic_t *pic);
65
66 /*
67 ===============
68 Sbar_ShowScores
69
70 Tab key down
71 ===============
72 */
73 void Sbar_ShowScores (void)
74 {
75         if (sb_showscores)
76                 return;
77         sb_showscores = true;
78 }
79
80 /*
81 ===============
82 Sbar_DontShowScores
83
84 Tab key up
85 ===============
86 */
87 void Sbar_DontShowScores (void)
88 {
89         sb_showscores = false;
90 }
91
92 /*
93 ===============
94 Sbar_Init
95 ===============
96 */
97 void Sbar_Init (void)
98 {
99         int             i;
100
101         for (i=0 ; i<10 ; i++)
102         {
103                 sb_nums[0][i] = Draw_PicFromWad (va("num_%i",i));
104                 sb_nums[1][i] = Draw_PicFromWad (va("anum_%i",i));
105         }
106
107         sb_nums[0][10] = Draw_PicFromWad ("num_minus");
108         sb_nums[1][10] = Draw_PicFromWad ("anum_minus");
109
110         sb_colon = Draw_PicFromWad ("num_colon");
111         sb_slash = Draw_PicFromWad ("num_slash");
112
113         sb_weapons[0][0] = Draw_PicFromWad ("inv_shotgun");
114         sb_weapons[0][1] = Draw_PicFromWad ("inv_sshotgun");
115         sb_weapons[0][2] = Draw_PicFromWad ("inv_nailgun");
116         sb_weapons[0][3] = Draw_PicFromWad ("inv_snailgun");
117         sb_weapons[0][4] = Draw_PicFromWad ("inv_rlaunch");
118         sb_weapons[0][5] = Draw_PicFromWad ("inv_srlaunch");
119         sb_weapons[0][6] = Draw_PicFromWad ("inv_lightng");
120
121         sb_weapons[1][0] = Draw_PicFromWad ("inv2_shotgun");
122         sb_weapons[1][1] = Draw_PicFromWad ("inv2_sshotgun");
123         sb_weapons[1][2] = Draw_PicFromWad ("inv2_nailgun");
124         sb_weapons[1][3] = Draw_PicFromWad ("inv2_snailgun");
125         sb_weapons[1][4] = Draw_PicFromWad ("inv2_rlaunch");
126         sb_weapons[1][5] = Draw_PicFromWad ("inv2_srlaunch");
127         sb_weapons[1][6] = Draw_PicFromWad ("inv2_lightng");
128
129         for (i=0 ; i<5 ; i++)
130         {
131                 sb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_shotgun",i+1));
132                 sb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_sshotgun",i+1));
133                 sb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_nailgun",i+1));
134                 sb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_snailgun",i+1));
135                 sb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_rlaunch",i+1));
136                 sb_weapons[2+i][5] = Draw_PicFromWad (va("inva%i_srlaunch",i+1));
137                 sb_weapons[2+i][6] = Draw_PicFromWad (va("inva%i_lightng",i+1));
138         }
139
140         sb_ammo[0] = Draw_PicFromWad ("sb_shells");
141         sb_ammo[1] = Draw_PicFromWad ("sb_nails");
142         sb_ammo[2] = Draw_PicFromWad ("sb_rocket");
143         sb_ammo[3] = Draw_PicFromWad ("sb_cells");
144
145         sb_armor[0] = Draw_PicFromWad ("sb_armor1");
146         sb_armor[1] = Draw_PicFromWad ("sb_armor2");
147         sb_armor[2] = Draw_PicFromWad ("sb_armor3");
148
149         sb_items[0] = Draw_PicFromWad ("sb_key1");
150         sb_items[1] = Draw_PicFromWad ("sb_key2");
151         sb_items[2] = Draw_PicFromWad ("sb_invis");
152         sb_items[3] = Draw_PicFromWad ("sb_invuln");
153         sb_items[4] = Draw_PicFromWad ("sb_suit");
154         sb_items[5] = Draw_PicFromWad ("sb_quad");
155
156         sb_sigil[0] = Draw_PicFromWad ("sb_sigil1");
157         sb_sigil[1] = Draw_PicFromWad ("sb_sigil2");
158         sb_sigil[2] = Draw_PicFromWad ("sb_sigil3");
159         sb_sigil[3] = Draw_PicFromWad ("sb_sigil4");
160
161         sb_faces[4][0] = Draw_PicFromWad ("face1");
162         sb_faces[4][1] = Draw_PicFromWad ("face_p1");
163         sb_faces[3][0] = Draw_PicFromWad ("face2");
164         sb_faces[3][1] = Draw_PicFromWad ("face_p2");
165         sb_faces[2][0] = Draw_PicFromWad ("face3");
166         sb_faces[2][1] = Draw_PicFromWad ("face_p3");
167         sb_faces[1][0] = Draw_PicFromWad ("face4");
168         sb_faces[1][1] = Draw_PicFromWad ("face_p4");
169         sb_faces[0][0] = Draw_PicFromWad ("face5");
170         sb_faces[0][1] = Draw_PicFromWad ("face_p5");
171
172         sb_face_invis = Draw_PicFromWad ("face_invis");
173         sb_face_invuln = Draw_PicFromWad ("face_invul2");
174         sb_face_invis_invuln = Draw_PicFromWad ("face_inv2");
175         sb_face_quad = Draw_PicFromWad ("face_quad");
176
177         Cmd_AddCommand ("+showscores", Sbar_ShowScores);
178         Cmd_AddCommand ("-showscores", Sbar_DontShowScores);
179
180         sb_sbar = Draw_PicFromWad ("sbar");
181         sb_ibar = Draw_PicFromWad ("ibar");
182         sb_scorebar = Draw_PicFromWad ("scorebar");
183
184 //MED 01/04/97 added new hipnotic weapons
185         if (hipnotic)
186         {
187           hsb_weapons[0][0] = Draw_PicFromWad ("inv_laser");
188           hsb_weapons[0][1] = Draw_PicFromWad ("inv_mjolnir");
189           hsb_weapons[0][2] = Draw_PicFromWad ("inv_gren_prox");
190           hsb_weapons[0][3] = Draw_PicFromWad ("inv_prox_gren");
191           hsb_weapons[0][4] = Draw_PicFromWad ("inv_prox");
192
193           hsb_weapons[1][0] = Draw_PicFromWad ("inv2_laser");
194           hsb_weapons[1][1] = Draw_PicFromWad ("inv2_mjolnir");
195           hsb_weapons[1][2] = Draw_PicFromWad ("inv2_gren_prox");
196           hsb_weapons[1][3] = Draw_PicFromWad ("inv2_prox_gren");
197           hsb_weapons[1][4] = Draw_PicFromWad ("inv2_prox");
198
199           for (i=0 ; i<5 ; i++)
200           {
201                  hsb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_laser",i+1));
202                  hsb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_mjolnir",i+1));
203                  hsb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_gren_prox",i+1));
204                  hsb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_prox_gren",i+1));
205                  hsb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_prox",i+1));
206           }
207
208           hsb_items[0] = Draw_PicFromWad ("sb_wsuit");
209           hsb_items[1] = Draw_PicFromWad ("sb_eshld");
210         }
211
212         if (rogue)
213         {
214                 rsb_invbar[0] = Draw_PicFromWad ("r_invbar1");
215                 rsb_invbar[1] = Draw_PicFromWad ("r_invbar2");
216
217                 rsb_weapons[0] = Draw_PicFromWad ("r_lava");
218                 rsb_weapons[1] = Draw_PicFromWad ("r_superlava");
219                 rsb_weapons[2] = Draw_PicFromWad ("r_gren");
220                 rsb_weapons[3] = Draw_PicFromWad ("r_multirock");
221                 rsb_weapons[4] = Draw_PicFromWad ("r_plasma");
222
223                 rsb_items[0] = Draw_PicFromWad ("r_shield1");
224         rsb_items[1] = Draw_PicFromWad ("r_agrav1");
225
226 // PGM 01/19/97 - team color border
227         rsb_teambord = Draw_PicFromWad ("r_teambord");
228 // PGM 01/19/97 - team color border
229
230                 rsb_ammo[0] = Draw_PicFromWad ("r_ammolava");
231                 rsb_ammo[1] = Draw_PicFromWad ("r_ammomulti");
232                 rsb_ammo[2] = Draw_PicFromWad ("r_ammoplasma");
233         }
234 }
235
236
237 //=============================================================================
238
239 // drawing routines are relative to the status bar location
240
241 /*
242 =============
243 Sbar_DrawPic
244 =============
245 */
246 void Sbar_DrawPic (int x, int y, qpic_t *pic)
247 {
248         if (cl.gametype == GAME_DEATHMATCH)
249                 Draw_Pic (x /* + ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic);
250         else
251                 Draw_Pic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic);
252 }
253
254 void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha);
255 void Sbar_DrawAlphaPic (int x, int y, qpic_t *pic, float alpha)
256 {
257         if (cl.gametype == GAME_DEATHMATCH)
258                 Draw_AlphaPic (x /* + ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic, alpha);
259         else
260                 Draw_AlphaPic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic, alpha);
261 }
262
263 /*
264 =============
265 Sbar_DrawTransPic
266 =============
267 */
268 void Sbar_DrawTransPic (int x, int y, qpic_t *pic)
269 {
270         if (cl.gametype == GAME_DEATHMATCH)
271                 Draw_TransPic (x /*+ ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic);
272         else
273                 Draw_TransPic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic);
274 }
275
276 /*
277 ================
278 Sbar_DrawCharacter
279
280 Draws one solid graphics character
281 ================
282 */
283 void Sbar_DrawCharacter (int x, int y, int num)
284 {
285         if (cl.gametype == GAME_DEATHMATCH)
286                 Draw_Character ( x /*+ ((vid.width - 320)>>1) */ + 4 , y + vid.height-SBAR_HEIGHT, num);
287         else
288                 Draw_Character ( x + ((vid.width - 320)>>1) + 4 , y + vid.height-SBAR_HEIGHT, num);
289 }
290
291 /*
292 ================
293 Sbar_DrawString
294 ================
295 */
296 void Sbar_DrawString (int x, int y, char *str)
297 {
298         if (cl.gametype == GAME_DEATHMATCH)
299                 Draw_String (x /*+ ((vid.width - 320)>>1)*/, y+ vid.height-SBAR_HEIGHT, str, 0);
300         else
301                 Draw_String (x + ((vid.width - 320)>>1), y+ vid.height-SBAR_HEIGHT, str, 0);
302 }
303
304 /*
305 =============
306 Sbar_itoa
307 =============
308 */
309 int Sbar_itoa (int num, char *buf)
310 {
311         char    *str;
312         int             pow10;
313         int             dig;
314
315         str = buf;
316
317         if (num < 0)
318         {
319                 *str++ = '-';
320                 num = -num;
321         }
322
323         for (pow10 = 10 ; num >= pow10 ; pow10 *= 10)
324         ;
325
326         do
327         {
328                 pow10 /= 10;
329                 dig = num/pow10;
330                 *str++ = '0'+dig;
331                 num -= dig*pow10;
332         } while (pow10 != 1);
333
334         *str = 0;
335
336         return str-buf;
337 }
338
339
340 /*
341 =============
342 Sbar_DrawNum
343 =============
344 */
345 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
346 {
347         char                    str[12];
348         char                    *ptr;
349         int                             l, frame;
350
351         l = Sbar_itoa (num, str);
352         ptr = str;
353         if (l > digits)
354                 ptr += (l-digits);
355         if (l < digits)
356                 x += (digits-l)*24;
357
358         while (*ptr)
359         {
360                 if (*ptr == '-')
361                         frame = STAT_MINUS;
362                 else
363                         frame = *ptr -'0';
364
365                 Sbar_DrawTransPic (x,y,sb_nums[color][frame]);
366                 x += 24;
367                 ptr++;
368         }
369 }
370
371 //=============================================================================
372
373 int             fragsort[MAX_SCOREBOARD];
374
375 char    scoreboardtext[MAX_SCOREBOARD][20];
376 int             scoreboardtop[MAX_SCOREBOARD];
377 int             scoreboardbottom[MAX_SCOREBOARD];
378 int             scoreboardcount[MAX_SCOREBOARD];
379 int             scoreboardlines;
380
381 /*
382 ===============
383 Sbar_SortFrags
384 ===============
385 */
386 void Sbar_SortFrags (void)
387 {
388         int             i, j, k;
389
390 // sort by frags
391         scoreboardlines = 0;
392         for (i=0 ; i<cl.maxclients ; i++)
393         {
394                 if (cl.scores[i].name[0])
395                 {
396                         fragsort[scoreboardlines] = i;
397                         scoreboardlines++;
398                 }
399         }
400
401         for (i=0 ; i<scoreboardlines ; i++)
402                 for (j=0 ; j<scoreboardlines-1-i ; j++)
403                         if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
404                         {
405                                 k = fragsort[j];
406                                 fragsort[j] = fragsort[j+1];
407                                 fragsort[j+1] = k;
408                         }
409 }
410
411 /*
412 ===============
413 Sbar_UpdateScoreboard
414 ===============
415 */
416 void Sbar_UpdateScoreboard (void)
417 {
418         int             i, k;
419         int             top, bottom;
420         scoreboard_t    *s;
421
422         Sbar_SortFrags ();
423
424 // draw the text
425         memset (scoreboardtext, 0, sizeof(scoreboardtext));
426
427         for (i=0 ; i<scoreboardlines; i++)
428         {
429                 k = fragsort[i];
430                 s = &cl.scores[k];
431                 sprintf (&scoreboardtext[i][1], "%3i %s", s->frags, s->name);
432
433                 top = s->colors & 0xf0;
434                 bottom = (s->colors & 15) <<4;
435                 scoreboardtop[i] = top + 8;
436                 scoreboardbottom[i] = bottom + 8;
437         }
438 }
439
440
441
442 /*
443 ===============
444 Sbar_SoloScoreboard
445 ===============
446 */
447 void Sbar_SoloScoreboard (void)
448 {
449         char    str[80];
450         int             minutes, seconds, tens, units;
451         int             l;
452
453         sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
454         Sbar_DrawString (8, 4, str);
455
456         sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
457         Sbar_DrawString (8, 12, str);
458
459 // time
460         minutes = cl.time / 60;
461         seconds = cl.time - 60*minutes;
462         tens = seconds / 10;
463         units = seconds - 10*tens;
464         sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
465         Sbar_DrawString (184, 4, str);
466
467 // draw level name
468         l = strlen (cl.levelname);
469         Sbar_DrawString (232 - l*4, 12, cl.levelname);
470 }
471
472 /*
473 ===============
474 Sbar_DrawScoreboard
475 ===============
476 */
477 void Sbar_DrawScoreboard (void)
478 {
479         Sbar_SoloScoreboard ();
480         if (cl.gametype == GAME_DEATHMATCH)
481                 Sbar_DeathmatchOverlay ();
482 }
483
484 //=============================================================================
485
486 /*
487 ===============
488 Sbar_DrawInventory
489 ===============
490 */
491 void Sbar_DrawInventory (void)
492 {
493         int             i;
494         char    num[6];
495         float   time;
496         int             flashon;
497
498         if (rogue)
499         {
500                 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
501                         Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], 0.4);
502                 else
503                         Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], 0.4);
504         }
505         else
506                 Sbar_DrawAlphaPic (0, -24, sb_ibar, 0.4);
507
508         // weapons
509         for (i=0 ; i<7 ; i++)
510         {
511                 if (cl.items & (IT_SHOTGUN<<i) )
512                 {
513                         time = cl.item_gettime[i];
514                         flashon = (int)((cl.time - time)*10);
515                         if (flashon >= 10)
516                         {
517                                 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i)  )
518                                         flashon = 1;
519                                 else
520                                         flashon = 0;
521                         }
522                         else
523                                 flashon = (flashon%5) + 2;
524
525                         Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], 0.4);
526                 }
527         }
528
529         // MED 01/04/97
530         // hipnotic weapons
531         if (hipnotic)
532         {
533                 int grenadeflashing=0;
534                 for (i=0 ; i<4 ; i++)
535                 {
536                         if (cl.items & (1<<hipweapons[i]) )
537                         {
538                                 time = cl.item_gettime[hipweapons[i]];
539                                 flashon = (int)((cl.time - time)*10);
540                                 if (flashon >= 10)
541                                 {
542                                         if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i])  )
543                                                 flashon = 1;
544                                         else
545                                                 flashon = 0;
546                                 }
547                                 else
548                                         flashon = (flashon%5) + 2;
549
550                                 // check grenade launcher
551                                 if (i==2)
552                                 {
553                                         if (cl.items & HIT_PROXIMITY_GUN)
554                                         {
555                                                 if (flashon)
556                                                 {
557                                                         grenadeflashing = 1;
558                                                         Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
559                                                 }
560                                         }
561                                 }
562                                 else if (i==3)
563                                 {
564                                         if (cl.items & (IT_SHOTGUN<<4))
565                                         {
566                                                 if (!grenadeflashing)
567                                                         Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
568                                         }
569                                         else
570                                                 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
571                                 }
572                                 else
573                                         Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
574                         }
575                 }
576         }
577
578         if (rogue)
579         {
580                 // check for powered up weapon.
581                 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
582                         for (i=0;i<5;i++)
583                                 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
584                                         Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
585         }
586
587         // ammo counts
588         for (i=0 ; i<4 ; i++)
589         {
590                 sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] );
591                 if (num[0] != ' ')
592                         Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
593                 if (num[1] != ' ')
594                         Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
595                 if (num[2] != ' ')
596                         Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
597         }
598
599         flashon = 0;
600         // items
601         for (i=0 ; i<6 ; i++)
602                 if (cl.items & (1<<(17+i)))
603                 {
604                         time = cl.item_gettime[17+i];
605                         if (time && time > cl.time - 2 && flashon )
606                         {  // flash frame
607                         }
608                         else
609                         //MED 01/04/97 changed keys
610                                 if (!hipnotic || (i>1))
611                                         Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
612                 }
613         //MED 01/04/97 added hipnotic items
614         // hipnotic items
615         if (hipnotic)
616         {
617                 for (i=0 ; i<2 ; i++)
618                         if (cl.items & (1<<(24+i)))
619                         {
620                                 time = cl.item_gettime[24+i];
621                                 if (!time || time <= cl.time - 2 || !flashon)
622                                         Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
623                         }
624         }
625
626         if (rogue)
627         {
628                 // new rogue items
629                 for (i=0 ; i<2 ; i++)
630                         if (cl.items & (1<<(29+i)))
631                         {
632                                 time = cl.item_gettime[29+i];
633                                 if (!time || time <= cl.time - 2 || !flashon)
634                                         Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
635                         }
636         }
637         else
638         {
639                 // sigils
640                 for (i=0 ; i<4 ; i++)
641                 {
642                         if (cl.items & (1<<(28+i)))
643                         {
644                                 time = cl.item_gettime[28+i];
645                                 if (!time || time <= cl.time - 2 || !flashon)
646                                         Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
647                         }
648                 }
649         }
650 }
651
652 //=============================================================================
653
654 /*
655 ===============
656 Sbar_DrawFrags
657 ===============
658 */
659 void Sbar_DrawFrags (void)
660 {
661         int                             i, k, l;
662         int                             top, bottom;
663         int                             x, y, f;
664         int                             xofs;
665         char                    num[12];
666         scoreboard_t    *s;
667
668         Sbar_SortFrags ();
669
670 // draw the text
671         l = scoreboardlines <= 4 ? scoreboardlines : 4;
672
673         x = 23;
674         if (cl.gametype == GAME_DEATHMATCH)
675                 xofs = 0;
676         else
677                 xofs = (vid.width - 320)>>1;
678         y = vid.height - SBAR_HEIGHT - 23;
679
680         for (i=0 ; i<l ; i++)
681         {
682                 k = fragsort[i];
683                 s = &cl.scores[k];
684                 if (!s->name[0])
685                         continue;
686
687         // draw background
688                 top = (s->colors & 0xf0) + 8;
689                 bottom = ((s->colors & 15)<<4) + 8;
690
691                 Draw_Fill (xofs + x*8 + 10, y, 28, 4, top);
692                 Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom);
693
694         // draw number
695                 f = s->frags;
696                 sprintf (num, "%3i",f);
697
698                 Sbar_DrawCharacter ( (x+1)*8 , -24, num[0]);
699                 Sbar_DrawCharacter ( (x+2)*8 , -24, num[1]);
700                 Sbar_DrawCharacter ( (x+3)*8 , -24, num[2]);
701
702                 if (k == cl.viewentity - 1)
703                 {
704                         Sbar_DrawCharacter (x*8+2, -24, 16);
705                         Sbar_DrawCharacter ( (x+4)*8-4, -24, 17);
706                 }
707                 x+=4;
708         }
709 }
710
711 //=============================================================================
712
713
714 /*
715 ===============
716 Sbar_DrawFace
717 ===============
718 */
719 void Sbar_DrawFace (void)
720 {
721         int             f, anim;
722
723 // PGM 01/19/97 - team color drawing
724 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
725         if (rogue &&
726         (cl.maxclients != 1) &&
727         (teamplay.value>3) &&
728         (teamplay.value<7))
729         {
730                 int                             top, bottom;
731                 int                             xofs;
732                 char                    num[12];
733                 scoreboard_t    *s;
734                 
735                 s = &cl.scores[cl.viewentity - 1];
736                 // draw background
737                 top = (s->colors & 0xf0) + 8;
738                 bottom = ((s->colors & 15)<<4) + 8;
739
740                 if (cl.gametype == GAME_DEATHMATCH)
741                         xofs = 113;
742                 else
743                         xofs = ((vid.width - 320)>>1) + 113;
744
745                 Sbar_DrawPic (112, 0, rsb_teambord);
746                 Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, top);
747                 Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, bottom);
748
749                 // draw number
750                 f = s->frags;
751                 sprintf (num, "%3i",f);
752
753                 if (top==8)
754                 {
755                         if (num[0] != ' ')
756                                 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
757                         if (num[1] != ' ')
758                                 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
759                         if (num[2] != ' ')
760                                 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
761                 }
762                 else
763                 {
764                         Sbar_DrawCharacter ( 109, 3, num[0]);
765                         Sbar_DrawCharacter ( 116, 3, num[1]);
766                         Sbar_DrawCharacter ( 123, 3, num[2]);
767                 }
768                 
769                 return;
770         }
771 // PGM 01/19/97 - team color drawing
772
773         if ( (cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY) )
774         == (IT_INVISIBILITY | IT_INVULNERABILITY) )
775         {
776                 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
777                 return;
778         }
779         if (cl.items & IT_QUAD)
780         {
781                 Sbar_DrawPic (112, 0, sb_face_quad );
782                 return;
783         }
784         if (cl.items & IT_INVISIBILITY)
785         {
786                 Sbar_DrawPic (112, 0, sb_face_invis );
787                 return;
788         }
789         if (cl.items & IT_INVULNERABILITY)
790         {
791                 Sbar_DrawPic (112, 0, sb_face_invuln);
792                 return;
793         }
794
795         if (cl.stats[STAT_HEALTH] >= 100)
796                 f = 4;
797         else
798                 f = cl.stats[STAT_HEALTH] / 20;
799
800         if (cl.time <= cl.faceanimtime)
801         {
802                 anim = 1;
803 //              sb_updates = 0;         // make sure the anim gets drawn over
804         }
805         else
806                 anim = 0;
807         Sbar_DrawPic (112, 0, sb_faces[f][anim]);
808 }
809
810 /*
811 ===============
812 Sbar_Draw
813 ===============
814 */
815 void Sbar_Draw (void)
816 {
817         if (scr_con_current == vid.height)
818                 return;         // console is full screen
819
820         scr_copyeverything = 1;
821
822 //      sb_updates++;
823
824         if (sb_lines > 24)
825         {
826                 Sbar_DrawInventory ();
827                 if (cl.maxclients != 1)
828                         Sbar_DrawFrags ();
829         }
830
831         if (sb_showscores || cl.stats[STAT_HEALTH] <= 0)
832         {
833                 Sbar_DrawAlphaPic (0, 0, sb_scorebar, 0.4);
834                 Sbar_DrawScoreboard ();
835 //              sb_updates = 0;
836         }
837         else if (sb_lines)
838         {
839                 Sbar_DrawAlphaPic (0, 0, sb_sbar, 0.4);
840
841    // keys (hipnotic only)
842       //MED 01/04/97 moved keys here so they would not be overwritten
843       if (hipnotic)
844       {
845          if (cl.items & IT_KEY1)
846             Sbar_DrawPic (209, 3, sb_items[0]);
847          if (cl.items & IT_KEY2)
848             Sbar_DrawPic (209, 12, sb_items[1]);
849       }
850    // armor
851                 if (cl.items & IT_INVULNERABILITY)
852                 {
853                         Sbar_DrawNum (24, 0, 666, 3, 1);
854                         Sbar_DrawPic (0, 0, draw_disc);
855                 }
856                 else
857                 {
858                         if (rogue)
859                         {
860                                 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3,
861                                                                 cl.stats[STAT_ARMOR] <= 25);
862                                 if (cl.items & RIT_ARMOR3)
863                                         Sbar_DrawPic (0, 0, sb_armor[2]);
864                                 else if (cl.items & RIT_ARMOR2)
865                                         Sbar_DrawPic (0, 0, sb_armor[1]);
866                                 else if (cl.items & RIT_ARMOR1)
867                                         Sbar_DrawPic (0, 0, sb_armor[0]);
868                         }
869                         else
870                         {
871                                 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3
872                                 , cl.stats[STAT_ARMOR] <= 25);
873                                 if (cl.items & IT_ARMOR3)
874                                         Sbar_DrawPic (0, 0, sb_armor[2]);
875                                 else if (cl.items & IT_ARMOR2)
876                                         Sbar_DrawPic (0, 0, sb_armor[1]);
877                                 else if (cl.items & IT_ARMOR1)
878                                         Sbar_DrawPic (0, 0, sb_armor[0]);
879                         }
880                 }
881
882         // face
883                 Sbar_DrawFace ();
884
885         // health
886                 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3
887                 , cl.stats[STAT_HEALTH] <= 25);
888
889         // ammo icon
890                 if (rogue)
891                 {
892                         if (cl.items & RIT_SHELLS)
893                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
894                         else if (cl.items & RIT_NAILS)
895                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
896                         else if (cl.items & RIT_ROCKETS)
897                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
898                         else if (cl.items & RIT_CELLS)
899                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
900                         else if (cl.items & RIT_LAVA_NAILS)
901                                 Sbar_DrawPic (224, 0, rsb_ammo[0]);
902                         else if (cl.items & RIT_PLASMA_AMMO)
903                                 Sbar_DrawPic (224, 0, rsb_ammo[1]);
904                         else if (cl.items & RIT_MULTI_ROCKETS)
905                                 Sbar_DrawPic (224, 0, rsb_ammo[2]);
906                 }
907                 else
908                 {
909                         if (cl.items & IT_SHELLS)
910                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
911                         else if (cl.items & IT_NAILS)
912                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
913                         else if (cl.items & IT_ROCKETS)
914                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
915                         else if (cl.items & IT_CELLS)
916                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
917                 }
918
919                 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3,
920                                           cl.stats[STAT_AMMO] <= 10);
921         }
922
923         if (vid.width > 320) {
924                 if (cl.gametype == GAME_DEATHMATCH)
925                         Sbar_MiniDeathmatchOverlay ();
926         }
927 }
928
929 //=============================================================================
930
931 /*
932 ==================
933 Sbar_IntermissionNumber
934
935 ==================
936 */
937 void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)
938 {
939         char                    str[12];
940         char                    *ptr;
941         int                             l, frame;
942
943         l = Sbar_itoa (num, str);
944         ptr = str;
945         if (l > digits)
946                 ptr += (l-digits);
947         if (l < digits)
948                 x += (digits-l)*24;
949
950         while (*ptr)
951         {
952                 if (*ptr == '-')
953                         frame = STAT_MINUS;
954                 else
955                         frame = *ptr -'0';
956
957                 Draw_TransPic (x,y,sb_nums[color][frame]);
958                 x += 24;
959                 ptr++;
960         }
961 }
962
963 /*
964 ==================
965 Sbar_DeathmatchOverlay
966
967 ==================
968 */
969 void Sbar_DeathmatchOverlay (void)
970 {
971         qpic_t                  *pic;
972         int                             i, k, l, top, bottom, x, y, total, n, minutes, tens, units, fph;
973         char                    num[128];
974         scoreboard_t    *s;
975
976         scr_copyeverything = 1;
977         scr_fullupdate = 0;
978
979         pic = Draw_CachePic ("gfx/ranking.lmp");
980         M_DrawPic ((320-pic->width)/2, 8, pic);
981
982 // scores
983         Sbar_SortFrags ();
984
985 // draw the text
986         l = scoreboardlines;
987
988         x = ((vid.width - 320)>>1) - 140;
989         y = 40;
990         for (i = 0;i < l;i++)
991         {
992                 k = fragsort[i];
993                 s = &cl.scores[k];
994                 if (!s->name[0])
995                         continue;
996
997         // draw background
998                 top = (s->colors & 0xf0) + 8;
999                 bottom = ((s->colors & 15)<<4) + 8;
1000
1001                 Draw_Fill ( x, y+1, 88, 3, top);
1002                 Draw_Fill ( x, y+4, 88, 3, bottom);
1003
1004                 total = cl.time - s->entertime;
1005                 minutes = (int)total/60;
1006                 n = total - minutes*60;
1007                 tens = n/10;
1008                 units = n%10;
1009
1010                 fph = total ? (int) ((float) s->frags * 3600.0 / total) : 0;
1011                 if (fph < -999) fph = -999;
1012                 if (fph > 9999) fph = 9999;
1013
1014                 // put it together
1015                 sprintf (num, "%c %4i:%4i  %3i:%i%i %s", k == cl.viewentity - 1 ? 12 : ' ', (int) s->frags, fph, minutes, tens, units, s->name);
1016                 Draw_String(x - 8, y, num, 0);
1017
1018                 y += 8;
1019         }
1020 }
1021
1022 /*
1023 ==================
1024 Sbar_DeathmatchOverlay
1025
1026 ==================
1027 */
1028 void Sbar_MiniDeathmatchOverlay (void)
1029 {
1030         int                             i, l, k, top, bottom, x, y, fph, numlines;
1031         char                    num[128];
1032         scoreboard_t    *s;
1033
1034         if (vid.width < 512 || !sb_lines)
1035                 return;
1036
1037         scr_copyeverything = 1;
1038         scr_fullupdate = 0;
1039
1040 // scores
1041         Sbar_SortFrags ();
1042
1043 // draw the text
1044         l = scoreboardlines;
1045         y = vid.height - sb_lines;
1046         numlines = sb_lines/8;
1047         if (numlines < 3)
1048                 return;
1049
1050         //find us
1051         for (i = 0; i < scoreboardlines; i++)
1052                 if (fragsort[i] == cl.viewentity - 1)
1053                         break;
1054
1055     if (i == scoreboardlines) // we're not there
1056             i = 0;
1057     else // figure out start
1058             i = i - numlines/2;
1059
1060     if (i > scoreboardlines - numlines)
1061             i = scoreboardlines - numlines;
1062     if (i < 0)
1063             i = 0;
1064
1065         x = 324;
1066         for (;i < scoreboardlines && y < vid.height - 8;i++)
1067         {
1068                 k = fragsort[i];
1069                 s = &cl.scores[k];
1070                 if (!s->name[0])
1071                         continue;
1072
1073         // draw background
1074                 top = (s->colors & 0xf0) + 8;
1075                 bottom = ((s->colors & 15)<<4) + 8;
1076
1077                 Draw_Fill ( x, y+1, 72, 3, top);
1078                 Draw_Fill ( x, y+4, 72, 3, bottom);
1079
1080                 fph = (cl.time - s->entertime) ? (int) ((float) s->frags * 3600.0 / (cl.time - s->entertime)) : 0;
1081                 if (fph < -999) fph = -999;
1082                 if (fph > 9999) fph = 9999;
1083                 
1084                 // put it together
1085                 sprintf (num, "%c%4i:%4i%c %s", k == cl.viewentity - 1 ? 16 : ' ', (int) s->frags, fph, k == cl.viewentity - 1 ? 17 : ' ', s->name);
1086                 Draw_String(x - 8, y, num, 0);
1087
1088                 y += 8;
1089         }
1090 }
1091
1092 /*
1093 ==================
1094 Sbar_IntermissionOverlay
1095
1096 ==================
1097 */
1098 void Sbar_IntermissionOverlay (void)
1099 {
1100         qpic_t  *pic;
1101         int             dig;
1102         int             num;
1103
1104         scr_copyeverything = 1;
1105         scr_fullupdate = 0;
1106
1107         if (cl.gametype == GAME_DEATHMATCH)
1108         {
1109                 Sbar_DeathmatchOverlay ();
1110                 return;
1111         }
1112
1113         pic = Draw_CachePic ("gfx/complete.lmp");
1114         Draw_Pic (64, 24, pic);
1115
1116         pic = Draw_CachePic ("gfx/inter.lmp");
1117         Draw_TransPic (0, 56, pic);
1118
1119 // time
1120         dig = cl.completed_time/60;
1121         Sbar_IntermissionNumber (160, 64, dig, 3, 0);
1122         num = cl.completed_time - dig*60;
1123         Draw_TransPic (234,64,sb_colon);
1124         Draw_TransPic (246,64,sb_nums[0][num/10]);
1125         Draw_TransPic (266,64,sb_nums[0][num%10]);
1126
1127         Sbar_IntermissionNumber (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1128         Draw_TransPic (232,104,sb_slash);
1129         Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1130
1131         Sbar_IntermissionNumber (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1132         Draw_TransPic (232,144,sb_slash);
1133         Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1134
1135 }
1136
1137
1138 /*
1139 ==================
1140 Sbar_FinaleOverlay
1141
1142 ==================
1143 */
1144 void Sbar_FinaleOverlay (void)
1145 {
1146         qpic_t  *pic;
1147
1148         scr_copyeverything = 1;
1149
1150         pic = Draw_CachePic ("gfx/finale.lmp");
1151         Draw_TransPic ( (vid.width-pic->width)/2, 16, pic);
1152 }