a big change with a little description...
[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_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 /*+ ((vid.width - 320)>>1) */ + 4 , y + vid.height-SBAR_HEIGHT, num);
274         else
275                 Draw_Character ( x + ((vid.width - 320)>>1) + 4 , y + vid.height-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 /*+ ((vid.width - 320)>>1)*/, y+ vid.height-SBAR_HEIGHT, str, 0);
287         else
288                 Draw_String (x + ((vid.width - 320)>>1), y+ vid.height-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 (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 (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 (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         flashon = 0;
587         // items
588         for (i=0 ; i<6 ; i++)
589                 if (cl.items & (1<<(17+i)))
590                 {
591                         time = cl.item_gettime[17+i];
592                         if (time && time > cl.time - 2 && flashon )
593                         {  // flash frame
594                         }
595                         else
596                         //MED 01/04/97 changed keys
597                                 if (!hipnotic || (i>1))
598                                         Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
599                 }
600         //MED 01/04/97 added hipnotic items
601         // hipnotic items
602         if (hipnotic)
603         {
604                 for (i=0 ; i<2 ; i++)
605                         if (cl.items & (1<<(24+i)))
606                         {
607                                 time = cl.item_gettime[24+i];
608                                 if (!time || time <= cl.time - 2 || !flashon)
609                                         Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
610                         }
611         }
612
613         if (rogue)
614         {
615                 // new rogue items
616                 for (i=0 ; i<2 ; i++)
617                         if (cl.items & (1<<(29+i)))
618                         {
619                                 time = cl.item_gettime[29+i];
620                                 if (!time || time <= cl.time - 2 || !flashon)
621                                         Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
622                         }
623         }
624         else
625         {
626                 // sigils
627                 for (i=0 ; i<4 ; i++)
628                 {
629                         if (cl.items & (1<<(28+i)))
630                         {
631                                 time = cl.item_gettime[28+i];
632                                 if (!time || time <= cl.time - 2 || !flashon)
633                                         Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
634                         }
635                 }
636         }
637 }
638
639 //=============================================================================
640
641 /*
642 ===============
643 Sbar_DrawFrags
644 ===============
645 */
646 void Sbar_DrawFrags (void)
647 {
648         int                             i, k, l;
649         int                             top, bottom;
650         int                             x, y, f;
651         int                             xofs;
652         char                    num[12];
653         scoreboard_t    *s;
654
655         Sbar_SortFrags ();
656
657 // draw the text
658         l = scoreboardlines <= 4 ? scoreboardlines : 4;
659
660         x = 23;
661         if (cl.gametype == GAME_DEATHMATCH)
662                 xofs = 0;
663         else
664                 xofs = (vid.width - 320)>>1;
665         y = vid.height - SBAR_HEIGHT - 23;
666
667         for (i=0 ; i<l ; i++)
668         {
669                 k = fragsort[i];
670                 s = &cl.scores[k];
671                 if (!s->name[0])
672                         continue;
673
674         // draw background
675                 top = (s->colors & 0xf0) + 8;
676                 bottom = ((s->colors & 15)<<4) + 8;
677
678                 Draw_Fill (xofs + x*8 + 10, y, 28, 4, top);
679                 Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom);
680
681         // draw number
682                 f = s->frags;
683                 sprintf (num, "%3i",f);
684
685                 Sbar_DrawCharacter ( (x+1)*8 , -24, num[0]);
686                 Sbar_DrawCharacter ( (x+2)*8 , -24, num[1]);
687                 Sbar_DrawCharacter ( (x+3)*8 , -24, num[2]);
688
689                 if (k == cl.viewentity - 1)
690                 {
691                         Sbar_DrawCharacter (x*8+2, -24, 16);
692                         Sbar_DrawCharacter ( (x+4)*8-4, -24, 17);
693                 }
694                 x+=4;
695         }
696 }
697
698 //=============================================================================
699
700
701 /*
702 ===============
703 Sbar_DrawFace
704 ===============
705 */
706 void Sbar_DrawFace (void)
707 {
708         int             f, anim;
709
710 // PGM 01/19/97 - team color drawing
711 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
712         if (rogue &&
713         (cl.maxclients != 1) &&
714         (teamplay.value>3) &&
715         (teamplay.value<7))
716         {
717                 int                             top, bottom;
718                 int                             xofs;
719                 char                    num[12];
720                 scoreboard_t    *s;
721                 
722                 s = &cl.scores[cl.viewentity - 1];
723                 // draw background
724                 top = (s->colors & 0xf0) + 8;
725                 bottom = ((s->colors & 15)<<4) + 8;
726
727                 if (cl.gametype == GAME_DEATHMATCH)
728                         xofs = 113;
729                 else
730                         xofs = ((vid.width - 320)>>1) + 113;
731
732                 Sbar_DrawPic (112, 0, rsb_teambord);
733                 Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, top);
734                 Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, bottom);
735
736                 // draw number
737                 f = s->frags;
738                 sprintf (num, "%3i",f);
739
740                 if (top==8)
741                 {
742                         if (num[0] != ' ')
743                                 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
744                         if (num[1] != ' ')
745                                 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
746                         if (num[2] != ' ')
747                                 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
748                 }
749                 else
750                 {
751                         Sbar_DrawCharacter ( 109, 3, num[0]);
752                         Sbar_DrawCharacter ( 116, 3, num[1]);
753                         Sbar_DrawCharacter ( 123, 3, num[2]);
754                 }
755                 
756                 return;
757         }
758 // PGM 01/19/97 - team color drawing
759
760         if ( (cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY) )
761         == (IT_INVISIBILITY | IT_INVULNERABILITY) )
762         {
763                 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
764                 return;
765         }
766         if (cl.items & IT_QUAD)
767         {
768                 Sbar_DrawPic (112, 0, sb_face_quad );
769                 return;
770         }
771         if (cl.items & IT_INVISIBILITY)
772         {
773                 Sbar_DrawPic (112, 0, sb_face_invis );
774                 return;
775         }
776         if (cl.items & IT_INVULNERABILITY)
777         {
778                 Sbar_DrawPic (112, 0, sb_face_invuln);
779                 return;
780         }
781
782         if (cl.stats[STAT_HEALTH] >= 100)
783                 f = 4;
784         else
785                 f = cl.stats[STAT_HEALTH] / 20;
786         // LordHavoc: I don't even know how the game didn't crash without this
787         if (f < 0)
788                 f = 0;
789
790         if (cl.time <= cl.faceanimtime)
791         {
792                 anim = 1;
793 //              sb_updates = 0;         // make sure the anim gets drawn over
794         }
795         else
796                 anim = 0;
797         Sbar_DrawPic (112, 0, sb_faces[f][anim]);
798 }
799
800 /*
801 ===============
802 Sbar_Draw
803 ===============
804 */
805 void Sbar_Draw (void)
806 {
807         if (scr_con_current == vid.height)
808                 return;         // console is full screen
809
810         scr_copyeverything = 1;
811
812 //      sb_updates++;
813
814         if (sb_lines > 24)
815         {
816                 Sbar_DrawInventory ();
817                 if (cl.maxclients != 1)
818                         Sbar_DrawFrags ();
819         }
820
821         if (sb_showscores || cl.stats[STAT_HEALTH] <= 0)
822         {
823                 Sbar_DrawAlphaPic (0, 0, sb_scorebar, 0.4);
824                 Sbar_DrawScoreboard ();
825 //              sb_updates = 0;
826         }
827         else if (sb_lines)
828         {
829                 Sbar_DrawAlphaPic (0, 0, sb_sbar, 0.4);
830
831    // keys (hipnotic only)
832       //MED 01/04/97 moved keys here so they would not be overwritten
833       if (hipnotic)
834       {
835          if (cl.items & IT_KEY1)
836             Sbar_DrawPic (209, 3, sb_items[0]);
837          if (cl.items & IT_KEY2)
838             Sbar_DrawPic (209, 12, sb_items[1]);
839       }
840    // armor
841                 if (cl.items & IT_INVULNERABILITY)
842                 {
843                         Sbar_DrawNum (24, 0, 666, 3, 1);
844                         Sbar_DrawPic (0, 0, draw_disc);
845                 }
846                 else
847                 {
848                         if (rogue)
849                         {
850                                 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3,
851                                                                 cl.stats[STAT_ARMOR] <= 25);
852                                 if (cl.items & RIT_ARMOR3)
853                                         Sbar_DrawPic (0, 0, sb_armor[2]);
854                                 else if (cl.items & RIT_ARMOR2)
855                                         Sbar_DrawPic (0, 0, sb_armor[1]);
856                                 else if (cl.items & RIT_ARMOR1)
857                                         Sbar_DrawPic (0, 0, sb_armor[0]);
858                         }
859                         else
860                         {
861                                 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3
862                                 , cl.stats[STAT_ARMOR] <= 25);
863                                 if (cl.items & IT_ARMOR3)
864                                         Sbar_DrawPic (0, 0, sb_armor[2]);
865                                 else if (cl.items & IT_ARMOR2)
866                                         Sbar_DrawPic (0, 0, sb_armor[1]);
867                                 else if (cl.items & IT_ARMOR1)
868                                         Sbar_DrawPic (0, 0, sb_armor[0]);
869                         }
870                 }
871
872         // face
873                 Sbar_DrawFace ();
874
875         // health
876                 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3
877                 , cl.stats[STAT_HEALTH] <= 25);
878
879         // ammo icon
880                 if (rogue)
881                 {
882                         if (cl.items & RIT_SHELLS)
883                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
884                         else if (cl.items & RIT_NAILS)
885                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
886                         else if (cl.items & RIT_ROCKETS)
887                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
888                         else if (cl.items & RIT_CELLS)
889                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
890                         else if (cl.items & RIT_LAVA_NAILS)
891                                 Sbar_DrawPic (224, 0, rsb_ammo[0]);
892                         else if (cl.items & RIT_PLASMA_AMMO)
893                                 Sbar_DrawPic (224, 0, rsb_ammo[1]);
894                         else if (cl.items & RIT_MULTI_ROCKETS)
895                                 Sbar_DrawPic (224, 0, rsb_ammo[2]);
896                 }
897                 else
898                 {
899                         if (cl.items & IT_SHELLS)
900                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
901                         else if (cl.items & IT_NAILS)
902                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
903                         else if (cl.items & IT_ROCKETS)
904                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
905                         else if (cl.items & IT_CELLS)
906                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
907                 }
908
909                 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3,
910                                           cl.stats[STAT_AMMO] <= 10);
911         }
912
913         if (vid.width > 320) {
914                 if (cl.gametype == GAME_DEATHMATCH)
915                         Sbar_MiniDeathmatchOverlay ();
916         }
917 }
918
919 //=============================================================================
920
921 /*
922 ==================
923 Sbar_IntermissionNumber
924
925 ==================
926 */
927 void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)
928 {
929         char                    str[12];
930         char                    *ptr;
931         int                             l, frame;
932
933         l = Sbar_itoa (num, str);
934         ptr = str;
935         if (l > digits)
936                 ptr += (l-digits);
937         if (l < digits)
938                 x += (digits-l)*24;
939
940         while (*ptr)
941         {
942                 if (*ptr == '-')
943                         frame = STAT_MINUS;
944                 else
945                         frame = *ptr -'0';
946
947                 Draw_Pic (x,y,sb_nums[color][frame]);
948                 x += 24;
949                 ptr++;
950         }
951 }
952
953 /*
954 ==================
955 Sbar_DeathmatchOverlay
956
957 ==================
958 */
959 void Sbar_DeathmatchOverlay (void)
960 {
961         qpic_t                  *pic;
962         int                             i, k, l, top, bottom, x, y, total, n, minutes, tens, units, fph;
963         char                    num[128];
964         scoreboard_t    *s;
965
966         scr_copyeverything = 1;
967         scr_fullupdate = 0;
968
969         pic = Draw_CachePic ("gfx/ranking.lmp");
970         M_DrawPic ((320-pic->width)/2, 8, pic);
971
972 // scores
973         Sbar_SortFrags ();
974
975 // draw the text
976         l = scoreboardlines;
977
978         x = ((vid.width - 320)>>1) - 140;
979         y = 40;
980         for (i = 0;i < l;i++)
981         {
982                 k = fragsort[i];
983                 s = &cl.scores[k];
984                 if (!s->name[0])
985                         continue;
986
987         // draw background
988                 top = (s->colors & 0xf0) + 8;
989                 bottom = ((s->colors & 15)<<4) + 8;
990
991                 Draw_Fill ( x, y+1, 88, 3, top);
992                 Draw_Fill ( x, y+4, 88, 3, bottom);
993
994                 total = cl.time - s->entertime;
995                 minutes = (int)total/60;
996                 n = total - minutes*60;
997                 tens = n/10;
998                 units = n%10;
999
1000                 fph = total ? (int) ((float) s->frags * 3600.0 / total) : 0;
1001                 if (fph < -999) fph = -999;
1002                 if (fph > 9999) fph = 9999;
1003
1004                 // put it together
1005                 sprintf (num, "%c %4i:%4i  %3i:%i%i %s", k == cl.viewentity - 1 ? 12 : ' ', (int) s->frags, fph, minutes, tens, units, s->name);
1006                 Draw_String(x - 8, y, num, 0);
1007
1008                 y += 8;
1009         }
1010 }
1011
1012 /*
1013 ==================
1014 Sbar_DeathmatchOverlay
1015
1016 ==================
1017 */
1018 void Sbar_MiniDeathmatchOverlay (void)
1019 {
1020         int                             i, l, k, top, bottom, x, y, fph, numlines;
1021         char                    num[128];
1022         scoreboard_t    *s;
1023
1024         if (vid.width < 512 || !sb_lines)
1025                 return;
1026
1027         scr_copyeverything = 1;
1028         scr_fullupdate = 0;
1029
1030 // scores
1031         Sbar_SortFrags ();
1032
1033 // draw the text
1034         l = scoreboardlines;
1035         y = vid.height - sb_lines;
1036         numlines = sb_lines/8;
1037         if (numlines < 3)
1038                 return;
1039
1040         //find us
1041         for (i = 0; i < scoreboardlines; i++)
1042                 if (fragsort[i] == cl.viewentity - 1)
1043                         break;
1044
1045     if (i == scoreboardlines) // we're not there
1046             i = 0;
1047     else // figure out start
1048             i = i - numlines/2;
1049
1050     if (i > scoreboardlines - numlines)
1051             i = scoreboardlines - numlines;
1052     if (i < 0)
1053             i = 0;
1054
1055         x = 324;
1056         for (;i < scoreboardlines && y < vid.height - 8;i++)
1057         {
1058                 k = fragsort[i];
1059                 s = &cl.scores[k];
1060                 if (!s->name[0])
1061                         continue;
1062
1063         // draw background
1064                 top = (s->colors & 0xf0) + 8;
1065                 bottom = ((s->colors & 15)<<4) + 8;
1066
1067                 Draw_Fill ( x, y+1, 72, 3, top);
1068                 Draw_Fill ( x, y+4, 72, 3, bottom);
1069
1070                 fph = (cl.time - s->entertime) ? (int) ((float) s->frags * 3600.0 / (cl.time - s->entertime)) : 0;
1071                 if (fph < -999) fph = -999;
1072                 if (fph > 9999) fph = 9999;
1073                 
1074                 // put it together
1075                 sprintf (num, "%c%4i:%4i%c %s", k == cl.viewentity - 1 ? 16 : ' ', (int) s->frags, fph, k == cl.viewentity - 1 ? 17 : ' ', s->name);
1076                 Draw_String(x - 8, y, num, 0);
1077
1078                 y += 8;
1079         }
1080 }
1081
1082 /*
1083 ==================
1084 Sbar_IntermissionOverlay
1085
1086 ==================
1087 */
1088 void Sbar_IntermissionOverlay (void)
1089 {
1090         qpic_t  *pic;
1091         int             dig;
1092         int             num;
1093
1094         scr_copyeverything = 1;
1095         scr_fullupdate = 0;
1096
1097         if (cl.gametype == GAME_DEATHMATCH)
1098         {
1099                 Sbar_DeathmatchOverlay ();
1100                 return;
1101         }
1102
1103         pic = Draw_CachePic ("gfx/complete.lmp");
1104         Draw_Pic (64, 24, pic);
1105
1106         pic = Draw_CachePic ("gfx/inter.lmp");
1107         Draw_Pic (0, 56, pic);
1108
1109 // time
1110         dig = cl.completed_time/60;
1111         Sbar_IntermissionNumber (160, 64, dig, 3, 0);
1112         num = cl.completed_time - dig*60;
1113         Draw_Pic (234,64,sb_colon);
1114         Draw_Pic (246,64,sb_nums[0][num/10]);
1115         Draw_Pic (266,64,sb_nums[0][num%10]);
1116
1117         Sbar_IntermissionNumber (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1118         Draw_Pic (232,104,sb_slash);
1119         Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1120
1121         Sbar_IntermissionNumber (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1122         Draw_Pic (232,144,sb_slash);
1123         Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1124
1125 }
1126
1127
1128 /*
1129 ==================
1130 Sbar_FinaleOverlay
1131
1132 ==================
1133 */
1134 void Sbar_FinaleOverlay (void)
1135 {
1136         qpic_t  *pic;
1137
1138         scr_copyeverything = 1;
1139
1140         pic = Draw_CachePic ("gfx/finale.lmp");
1141         Draw_Pic ( (vid.width-pic->width)/2, 16, pic);
1142 }