rewrote RecursiveHullCheck, no longer gets stuck on angle changes, and is generally...
[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 (gamemode == GAME_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         else if (gamemode == GAME_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, y + (vid.conheight-SBAR_HEIGHT), pic);
250         else
251                 Draw_Pic (x + ((vid.conwidth - 320)>>1), y + (vid.conheight-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, y + (vid.conheight-SBAR_HEIGHT), pic, alpha);
259         else
260                 Draw_AlphaPic (x + ((vid.conwidth - 320)>>1), y + (vid.conheight-SBAR_HEIGHT), pic, alpha);
261 }
262
263 /*
264 ================
265 Sbar_DrawCharacter
266
267 Draws one solid graphics character
268 ================
269 */
270 void Sbar_DrawCharacter (int x, int y, int num)
271 {
272         if (cl.gametype == GAME_DEATHMATCH)
273                 Draw_Character ( x + 4 , y + vid.conheight-SBAR_HEIGHT, num);
274         else
275                 Draw_Character ( x + ((vid.conwidth - 320)>>1) + 4 , y + vid.conheight-SBAR_HEIGHT, num);
276 }
277
278 /*
279 ================
280 Sbar_DrawString
281 ================
282 */
283 void Sbar_DrawString (int x, int y, char *str)
284 {
285         if (cl.gametype == GAME_DEATHMATCH)
286                 Draw_String (x, y+ vid.conheight-SBAR_HEIGHT, str, 0);
287         else
288                 Draw_String (x + ((vid.conwidth - 320)>>1), y+ vid.conheight-SBAR_HEIGHT, str, 0);
289 }
290
291 /*
292 =============
293 Sbar_itoa
294 =============
295 */
296 int Sbar_itoa (int num, char *buf)
297 {
298         char    *str;
299         int             pow10;
300         int             dig;
301
302         str = buf;
303
304         if (num < 0)
305         {
306                 *str++ = '-';
307                 num = -num;
308         }
309
310         for (pow10 = 10 ; num >= pow10 ; pow10 *= 10)
311         ;
312
313         do
314         {
315                 pow10 /= 10;
316                 dig = num/pow10;
317                 *str++ = '0'+dig;
318                 num -= dig*pow10;
319         } while (pow10 != 1);
320
321         *str = 0;
322
323         return str-buf;
324 }
325
326
327 /*
328 =============
329 Sbar_DrawNum
330 =============
331 */
332 void Sbar_DrawNum (int x, int y, int num, int digits, int color)
333 {
334         char                    str[12];
335         char                    *ptr;
336         int                             l, frame;
337
338         l = Sbar_itoa (num, str);
339         ptr = str;
340         if (l > digits)
341                 ptr += (l-digits);
342         if (l < digits)
343                 x += (digits-l)*24;
344
345         while (*ptr)
346         {
347                 if (*ptr == '-')
348                         frame = STAT_MINUS;
349                 else
350                         frame = *ptr -'0';
351
352                 Sbar_DrawPic (x,y,sb_nums[color][frame]);
353                 x += 24;
354                 ptr++;
355         }
356 }
357
358 //=============================================================================
359
360 int             fragsort[MAX_SCOREBOARD];
361
362 char    scoreboardtext[MAX_SCOREBOARD][20];
363 int             scoreboardtop[MAX_SCOREBOARD];
364 int             scoreboardbottom[MAX_SCOREBOARD];
365 int             scoreboardcount[MAX_SCOREBOARD];
366 int             scoreboardlines;
367
368 /*
369 ===============
370 Sbar_SortFrags
371 ===============
372 */
373 void Sbar_SortFrags (void)
374 {
375         int             i, j, k;
376
377 // sort by frags
378         scoreboardlines = 0;
379         for (i=0 ; i<cl.maxclients ; i++)
380         {
381                 if (cl.scores[i].name[0])
382                 {
383                         fragsort[scoreboardlines] = i;
384                         scoreboardlines++;
385                 }
386         }
387
388         for (i=0 ; i<scoreboardlines ; i++)
389                 for (j=0 ; j<scoreboardlines-1-i ; j++)
390                         if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
391                         {
392                                 k = fragsort[j];
393                                 fragsort[j] = fragsort[j+1];
394                                 fragsort[j+1] = k;
395                         }
396 }
397
398 /*
399 ===============
400 Sbar_UpdateScoreboard
401 ===============
402 */
403 void Sbar_UpdateScoreboard (void)
404 {
405         int             i, k;
406         int             top, bottom;
407         scoreboard_t    *s;
408
409         Sbar_SortFrags ();
410
411 // draw the text
412         memset (scoreboardtext, 0, sizeof(scoreboardtext));
413
414         for (i=0 ; i<scoreboardlines; i++)
415         {
416                 k = fragsort[i];
417                 s = &cl.scores[k];
418                 sprintf (&scoreboardtext[i][1], "%3i %s", s->frags, s->name);
419
420                 top = s->colors & 0xf0;
421                 bottom = (s->colors & 15) <<4;
422                 scoreboardtop[i] = top + 8;
423                 scoreboardbottom[i] = bottom + 8;
424         }
425 }
426
427
428
429 /*
430 ===============
431 Sbar_SoloScoreboard
432 ===============
433 */
434 void Sbar_SoloScoreboard (void)
435 {
436         char    str[80];
437         int             minutes, seconds, tens, units;
438         int             l;
439
440         sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
441         Sbar_DrawString (8, 4, str);
442
443         sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
444         Sbar_DrawString (8, 12, str);
445
446 // time
447         minutes = cl.time / 60;
448         seconds = cl.time - 60*minutes;
449         tens = seconds / 10;
450         units = seconds - 10*tens;
451         sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
452         Sbar_DrawString (184, 4, str);
453
454 // draw level name
455         l = strlen (cl.levelname);
456         Sbar_DrawString (232 - l*4, 12, cl.levelname);
457 }
458
459 /*
460 ===============
461 Sbar_DrawScoreboard
462 ===============
463 */
464 void Sbar_DrawScoreboard (void)
465 {
466         Sbar_SoloScoreboard ();
467         if (cl.gametype == GAME_DEATHMATCH)
468                 Sbar_DeathmatchOverlay ();
469 }
470
471 //=============================================================================
472
473 /*
474 ===============
475 Sbar_DrawInventory
476 ===============
477 */
478 void Sbar_DrawInventory (void)
479 {
480         int             i;
481         char    num[6];
482         float   time;
483         int             flashon;
484
485         if (gamemode == GAME_ROGUE)
486         {
487                 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
488                         Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], 0.4);
489                 else
490                         Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], 0.4);
491         }
492         else
493                 Sbar_DrawAlphaPic (0, -24, sb_ibar, 0.4);
494
495         // weapons
496         for (i=0 ; i<7 ; i++)
497         {
498                 if (cl.items & (IT_SHOTGUN<<i) )
499                 {
500                         time = cl.item_gettime[i];
501                         flashon = (int)((cl.time - time)*10);
502                         if (flashon >= 10)
503                         {
504                                 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i)  )
505                                         flashon = 1;
506                                 else
507                                         flashon = 0;
508                         }
509                         else
510                                 flashon = (flashon%5) + 2;
511
512                         Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], 0.4);
513                 }
514         }
515
516         // MED 01/04/97
517         // hipnotic weapons
518         if (gamemode == GAME_HIPNOTIC)
519         {
520                 int grenadeflashing=0;
521                 for (i=0 ; i<4 ; i++)
522                 {
523                         if (cl.items & (1<<hipweapons[i]) )
524                         {
525                                 time = cl.item_gettime[hipweapons[i]];
526                                 flashon = (int)((cl.time - time)*10);
527                                 if (flashon >= 10)
528                                 {
529                                         if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i])  )
530                                                 flashon = 1;
531                                         else
532                                                 flashon = 0;
533                                 }
534                                 else
535                                         flashon = (flashon%5) + 2;
536
537                                 // check grenade launcher
538                                 if (i==2)
539                                 {
540                                         if (cl.items & HIT_PROXIMITY_GUN)
541                                         {
542                                                 if (flashon)
543                                                 {
544                                                         grenadeflashing = 1;
545                                                         Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
546                                                 }
547                                         }
548                                 }
549                                 else if (i==3)
550                                 {
551                                         if (cl.items & (IT_SHOTGUN<<4))
552                                         {
553                                                 if (!grenadeflashing)
554                                                         Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
555                                         }
556                                         else
557                                                 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
558                                 }
559                                 else
560                                         Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
561                         }
562                 }
563         }
564
565         if (gamemode == GAME_ROGUE)
566         {
567                 // check for powered up weapon.
568                 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
569                         for (i=0;i<5;i++)
570                                 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
571                                         Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
572         }
573
574         // ammo counts
575         for (i=0 ; i<4 ; i++)
576         {
577                 sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] );
578                 if (num[0] != ' ')
579                         Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
580                 if (num[1] != ' ')
581                         Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
582                 if (num[2] != ' ')
583                         Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
584         }
585
586         // items
587         for (i=0 ; i<6 ; i++)
588                 if (cl.items & (1<<(17+i)))
589                 {
590                         //MED 01/04/97 changed keys
591                         if (gamemode != GAME_HIPNOTIC || (i>1))
592                                 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
593                 }
594
595         //MED 01/04/97 added hipnotic items
596         // hipnotic items
597         if (gamemode == GAME_HIPNOTIC)
598         {
599                 for (i=0 ; i<2 ; i++)
600                         if (cl.items & (1<<(24+i)))
601                                 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
602         }
603
604         if (gamemode == GAME_ROGUE)
605         {
606                 // new rogue items
607                 for (i=0 ; i<2 ; i++)
608                         if (cl.items & (1<<(29+i)))
609                                 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
610         }
611         else
612         {
613                 // sigils
614                 for (i=0 ; i<4 ; i++)
615                         if (cl.items & (1<<(28+i)))
616                                 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
617         }
618 }
619
620 //=============================================================================
621
622 /*
623 ===============
624 Sbar_DrawFrags
625 ===============
626 */
627 void Sbar_DrawFrags (void)
628 {
629         int                             i, k, l;
630         int                             top, bottom;
631         int                             x, y, f;
632         int                             xofs;
633         char                    num[12];
634         scoreboard_t    *s;
635
636         Sbar_SortFrags ();
637
638 // draw the text
639         l = scoreboardlines <= 4 ? scoreboardlines : 4;
640
641         x = 23;
642         if (cl.gametype == GAME_DEATHMATCH)
643                 xofs = 0;
644         else
645                 xofs = (vid.conwidth - 320)>>1;
646         y = vid.conheight - SBAR_HEIGHT - 23;
647
648         for (i=0 ; i<l ; i++)
649         {
650                 k = fragsort[i];
651                 s = &cl.scores[k];
652                 if (!s->name[0])
653                         continue;
654
655         // draw background
656                 top = (s->colors & 0xf0) + 8;
657                 bottom = ((s->colors & 15)<<4) + 8;
658
659                 Draw_Fill (xofs + x*8 + 10, y, 28, 4, top);
660                 Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom);
661
662         // draw number
663                 f = s->frags;
664                 sprintf (num, "%3i",f);
665
666                 Sbar_DrawCharacter ( (x+1)*8 , -24, num[0]);
667                 Sbar_DrawCharacter ( (x+2)*8 , -24, num[1]);
668                 Sbar_DrawCharacter ( (x+3)*8 , -24, num[2]);
669
670                 if (k == cl.viewentity - 1)
671                 {
672                         Sbar_DrawCharacter (x*8+2, -24, 16);
673                         Sbar_DrawCharacter ( (x+4)*8-4, -24, 17);
674                 }
675                 x+=4;
676         }
677 }
678
679 //=============================================================================
680
681
682 /*
683 ===============
684 Sbar_DrawFace
685 ===============
686 */
687 void Sbar_DrawFace (void)
688 {
689         int f;
690
691 // PGM 01/19/97 - team color drawing
692 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
693         if (gamemode == GAME_ROGUE && (cl.maxclients != 1) && (teamplay.value > 3) && (teamplay.value < 7))
694         {
695                 int                             top, bottom;
696                 int                             xofs;
697                 char                    num[12];
698                 scoreboard_t    *s;
699
700                 s = &cl.scores[cl.viewentity - 1];
701                 // draw background
702                 top = (s->colors & 0xf0) + 8;
703                 bottom = ((s->colors & 15)<<4) + 8;
704
705                 if (cl.gametype == GAME_DEATHMATCH)
706                         xofs = 113;
707                 else
708                         xofs = ((vid.conwidth - 320)>>1) + 113;
709
710                 Sbar_DrawPic (112, 0, rsb_teambord);
711                 Draw_Fill (xofs, vid.conheight-SBAR_HEIGHT+3, 22, 9, top);
712                 Draw_Fill (xofs, vid.conheight-SBAR_HEIGHT+12, 22, 9, bottom);
713
714                 // draw number
715                 f = s->frags;
716                 sprintf (num, "%3i",f);
717
718                 if (top==8)
719                 {
720                         if (num[0] != ' ')
721                                 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
722                         if (num[1] != ' ')
723                                 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
724                         if (num[2] != ' ')
725                                 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
726                 }
727                 else
728                 {
729                         Sbar_DrawCharacter ( 109, 3, num[0]);
730                         Sbar_DrawCharacter ( 116, 3, num[1]);
731                         Sbar_DrawCharacter ( 123, 3, num[2]);
732                 }
733
734                 return;
735         }
736 // PGM 01/19/97 - team color drawing
737
738         if ( (cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) )
739                 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
740         else if (cl.items & IT_QUAD)
741                 Sbar_DrawPic (112, 0, sb_face_quad );
742         else if (cl.items & IT_INVISIBILITY)
743                 Sbar_DrawPic (112, 0, sb_face_invis );
744         else if (cl.items & IT_INVULNERABILITY)
745                 Sbar_DrawPic (112, 0, sb_face_invuln);
746         else
747         {
748                 f = cl.stats[STAT_HEALTH] / 20;
749                 f = bound(0, f, 4);
750                 Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]);
751         }
752 }
753
754 /*
755 ===============
756 Sbar_Draw
757 ===============
758 */
759 void Sbar_Draw (void)
760 {
761         if (scr_con_current == vid.conheight)
762                 return;         // console is full screen
763
764         if (sb_lines > 24)
765         {
766                 Sbar_DrawInventory ();
767                 if (cl.maxclients != 1)
768                         Sbar_DrawFrags ();
769         }
770
771         if (sb_showscores || cl.stats[STAT_HEALTH] <= 0)
772         {
773                 Sbar_DrawAlphaPic (0, 0, sb_scorebar, 0.4);
774                 Sbar_DrawScoreboard ();
775         }
776         else if (sb_lines)
777         {
778                 Sbar_DrawAlphaPic (0, 0, sb_sbar, 0.4);
779
780 // keys (hipnotic only)
781                 //MED 01/04/97 moved keys here so they would not be overwritten
782                 if (gamemode == GAME_HIPNOTIC)
783                 {
784                         if (cl.items & IT_KEY1)
785                                 Sbar_DrawPic (209, 3, sb_items[0]);
786                         if (cl.items & IT_KEY2)
787                                 Sbar_DrawPic (209, 12, sb_items[1]);
788                 }
789 // armor
790                 if (cl.items & IT_INVULNERABILITY)
791                 {
792                         Sbar_DrawNum (24, 0, 666, 3, 1);
793                         Sbar_DrawPic (0, 0, draw_disc);
794                 }
795                 else
796                 {
797                         if (gamemode == GAME_ROGUE)
798                         {
799                                 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
800                                 if (cl.items & RIT_ARMOR3)
801                                         Sbar_DrawPic (0, 0, sb_armor[2]);
802                                 else if (cl.items & RIT_ARMOR2)
803                                         Sbar_DrawPic (0, 0, sb_armor[1]);
804                                 else if (cl.items & RIT_ARMOR1)
805                                         Sbar_DrawPic (0, 0, sb_armor[0]);
806                         }
807                         else
808                         {
809                                 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25);
810                                 if (cl.items & IT_ARMOR3)
811                                         Sbar_DrawPic (0, 0, sb_armor[2]);
812                                 else if (cl.items & IT_ARMOR2)
813                                         Sbar_DrawPic (0, 0, sb_armor[1]);
814                                 else if (cl.items & IT_ARMOR1)
815                                         Sbar_DrawPic (0, 0, sb_armor[0]);
816                         }
817                 }
818
819         // face
820                 Sbar_DrawFace ();
821
822         // health
823                 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25);
824
825         // ammo icon
826                 if (gamemode == GAME_ROGUE)
827                 {
828                         if (cl.items & RIT_SHELLS)
829                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
830                         else if (cl.items & RIT_NAILS)
831                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
832                         else if (cl.items & RIT_ROCKETS)
833                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
834                         else if (cl.items & RIT_CELLS)
835                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
836                         else if (cl.items & RIT_LAVA_NAILS)
837                                 Sbar_DrawPic (224, 0, rsb_ammo[0]);
838                         else if (cl.items & RIT_PLASMA_AMMO)
839                                 Sbar_DrawPic (224, 0, rsb_ammo[1]);
840                         else if (cl.items & RIT_MULTI_ROCKETS)
841                                 Sbar_DrawPic (224, 0, rsb_ammo[2]);
842                 }
843                 else
844                 {
845                         if (cl.items & IT_SHELLS)
846                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
847                         else if (cl.items & IT_NAILS)
848                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
849                         else if (cl.items & IT_ROCKETS)
850                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
851                         else if (cl.items & IT_CELLS)
852                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
853                 }
854
855                 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
856         }
857
858         if (vid.conwidth > 320 && cl.gametype == GAME_DEATHMATCH)
859                 Sbar_MiniDeathmatchOverlay ();
860 }
861
862 //=============================================================================
863
864 /*
865 ==================
866 Sbar_IntermissionNumber
867
868 ==================
869 */
870 void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)
871 {
872         char                    str[12];
873         char                    *ptr;
874         int                             l, frame;
875
876         l = Sbar_itoa (num, str);
877         ptr = str;
878         if (l > digits)
879                 ptr += (l-digits);
880         if (l < digits)
881                 x += (digits-l)*24;
882
883         while (*ptr)
884         {
885                 if (*ptr == '-')
886                         frame = STAT_MINUS;
887                 else
888                         frame = *ptr -'0';
889
890                 Draw_Pic (x,y,sb_nums[color][frame]);
891                 x += 24;
892                 ptr++;
893         }
894 }
895
896 /*
897 ==================
898 Sbar_DeathmatchOverlay
899
900 ==================
901 */
902 void Sbar_DeathmatchOverlay (void)
903 {
904         qpic_t                  *pic;
905         int                             i, k, l, top, bottom, x, y, total, n, minutes, tens, units, fph;
906         char                    num[128];
907         scoreboard_t    *s;
908
909         pic = Draw_CachePic ("gfx/ranking.lmp");
910         M_DrawPic ((320-pic->width)/2, 8, pic);
911
912 // scores
913         Sbar_SortFrags ();
914
915 // draw the text
916         l = scoreboardlines;
917
918         x = ((vid.conwidth - 320)>>1) - 140;
919         y = 40;
920         for (i = 0;i < l;i++)
921         {
922                 k = fragsort[i];
923                 s = &cl.scores[k];
924                 if (!s->name[0])
925                         continue;
926
927         // draw background
928                 top = (s->colors & 0xf0) + 8;
929                 bottom = ((s->colors & 15)<<4) + 8;
930
931                 Draw_Fill ( x, y+1, 88, 3, top);
932                 Draw_Fill ( x, y+4, 88, 3, bottom);
933
934                 total = cl.time - s->entertime;
935                 minutes = (int)total/60;
936                 n = total - minutes*60;
937                 tens = n/10;
938                 units = n%10;
939
940                 fph = total ? (int) ((float) s->frags * 3600.0 / total) : 0;
941                 if (fph < -999) fph = -999;
942                 if (fph > 9999) fph = 9999;
943
944                 // put it together
945                 sprintf (num, "%c %4i:%4i  %3i:%i%i %s", k == cl.viewentity - 1 ? 12 : ' ', (int) s->frags, fph, minutes, tens, units, s->name);
946                 Draw_String(x - 8, y, num, 0);
947
948                 y += 8;
949         }
950 }
951
952 /*
953 ==================
954 Sbar_DeathmatchOverlay
955
956 ==================
957 */
958 void Sbar_MiniDeathmatchOverlay (void)
959 {
960         int                             i, l, k, top, bottom, x, y, fph, numlines;
961         char                    num[128];
962         scoreboard_t    *s;
963
964         if (vid.conwidth < 512 || !sb_lines)
965                 return;
966
967 // scores
968         Sbar_SortFrags ();
969
970 // draw the text
971         l = scoreboardlines;
972         y = vid.conheight - sb_lines;
973         numlines = sb_lines/8;
974         if (numlines < 3)
975                 return;
976
977         //find us
978         for (i = 0; i < scoreboardlines; i++)
979                 if (fragsort[i] == cl.viewentity - 1)
980                         break;
981
982     if (i == scoreboardlines) // we're not there
983             i = 0;
984     else // figure out start
985             i = i - numlines/2;
986
987     if (i > scoreboardlines - numlines)
988             i = scoreboardlines - numlines;
989     if (i < 0)
990             i = 0;
991
992         x = 324;
993         for (;i < scoreboardlines && y < vid.conheight - 8;i++)
994         {
995                 k = fragsort[i];
996                 s = &cl.scores[k];
997                 if (!s->name[0])
998                         continue;
999
1000         // draw background
1001                 top = (s->colors & 0xf0) + 8;
1002                 bottom = ((s->colors & 15)<<4) + 8;
1003
1004                 Draw_Fill ( x, y+1, 72, 3, top);
1005                 Draw_Fill ( x, y+4, 72, 3, bottom);
1006
1007                 fph = (cl.time - s->entertime) ? (int) ((float) s->frags * 3600.0 / (cl.time - s->entertime)) : 0;
1008                 if (fph < -999) fph = -999;
1009                 if (fph > 9999) fph = 9999;
1010                 
1011                 // put it together
1012                 sprintf (num, "%c%4i:%4i%c %s", k == cl.viewentity - 1 ? 16 : ' ', (int) s->frags, fph, k == cl.viewentity - 1 ? 17 : ' ', s->name);
1013                 Draw_String(x - 8, y, num, 0);
1014
1015                 y += 8;
1016         }
1017 }
1018
1019 /*
1020 ==================
1021 Sbar_IntermissionOverlay
1022
1023 ==================
1024 */
1025 void Sbar_IntermissionOverlay (void)
1026 {
1027         qpic_t  *pic;
1028         int             dig;
1029         int             num;
1030
1031         if (cl.gametype == GAME_DEATHMATCH)
1032         {
1033                 Sbar_DeathmatchOverlay ();
1034                 return;
1035         }
1036
1037         pic = Draw_CachePic ("gfx/complete.lmp");
1038         Draw_Pic (64, 24, pic);
1039
1040         pic = Draw_CachePic ("gfx/inter.lmp");
1041         Draw_Pic (0, 56, pic);
1042
1043 // time
1044         dig = cl.completed_time/60;
1045         Sbar_IntermissionNumber (160, 64, dig, 3, 0);
1046         num = cl.completed_time - dig*60;
1047         Draw_Pic (234,64,sb_colon);
1048         Draw_Pic (246,64,sb_nums[0][num/10]);
1049         Draw_Pic (266,64,sb_nums[0][num%10]);
1050
1051         Sbar_IntermissionNumber (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1052         Draw_Pic (232,104,sb_slash);
1053         Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1054
1055         Sbar_IntermissionNumber (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1056         Draw_Pic (232,144,sb_slash);
1057         Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1058
1059 }
1060
1061
1062 /*
1063 ==================
1064 Sbar_FinaleOverlay
1065
1066 ==================
1067 */
1068 void Sbar_FinaleOverlay (void)
1069 {
1070         qpic_t  *pic;
1071
1072         pic = Draw_CachePic ("gfx/finale.lmp");
1073         Draw_Pic ( (vid.conwidth-pic->width)/2, 16, pic);
1074 }