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