]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - sbar.c
got rid of Hunk_Alloc, all allocations now have a proper name (perhaps a bit too...
[xonotic/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
787         if (cl.time <= cl.faceanimtime)
788         {
789                 anim = 1;
790 //              sb_updates = 0;         // make sure the anim gets drawn over
791         }
792         else
793                 anim = 0;
794         Sbar_DrawPic (112, 0, sb_faces[f][anim]);
795 }
796
797 /*
798 ===============
799 Sbar_Draw
800 ===============
801 */
802 void Sbar_Draw (void)
803 {
804         if (scr_con_current == vid.height)
805                 return;         // console is full screen
806
807         scr_copyeverything = 1;
808
809 //      sb_updates++;
810
811         if (sb_lines > 24)
812         {
813                 Sbar_DrawInventory ();
814                 if (cl.maxclients != 1)
815                         Sbar_DrawFrags ();
816         }
817
818         if (sb_showscores || cl.stats[STAT_HEALTH] <= 0)
819         {
820                 Sbar_DrawAlphaPic (0, 0, sb_scorebar, 0.4);
821                 Sbar_DrawScoreboard ();
822 //              sb_updates = 0;
823         }
824         else if (sb_lines)
825         {
826                 Sbar_DrawAlphaPic (0, 0, sb_sbar, 0.4);
827
828    // keys (hipnotic only)
829       //MED 01/04/97 moved keys here so they would not be overwritten
830       if (hipnotic)
831       {
832          if (cl.items & IT_KEY1)
833             Sbar_DrawPic (209, 3, sb_items[0]);
834          if (cl.items & IT_KEY2)
835             Sbar_DrawPic (209, 12, sb_items[1]);
836       }
837    // armor
838                 if (cl.items & IT_INVULNERABILITY)
839                 {
840                         Sbar_DrawNum (24, 0, 666, 3, 1);
841                         Sbar_DrawPic (0, 0, draw_disc);
842                 }
843                 else
844                 {
845                         if (rogue)
846                         {
847                                 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3,
848                                                                 cl.stats[STAT_ARMOR] <= 25);
849                                 if (cl.items & RIT_ARMOR3)
850                                         Sbar_DrawPic (0, 0, sb_armor[2]);
851                                 else if (cl.items & RIT_ARMOR2)
852                                         Sbar_DrawPic (0, 0, sb_armor[1]);
853                                 else if (cl.items & RIT_ARMOR1)
854                                         Sbar_DrawPic (0, 0, sb_armor[0]);
855                         }
856                         else
857                         {
858                                 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3
859                                 , cl.stats[STAT_ARMOR] <= 25);
860                                 if (cl.items & IT_ARMOR3)
861                                         Sbar_DrawPic (0, 0, sb_armor[2]);
862                                 else if (cl.items & IT_ARMOR2)
863                                         Sbar_DrawPic (0, 0, sb_armor[1]);
864                                 else if (cl.items & IT_ARMOR1)
865                                         Sbar_DrawPic (0, 0, sb_armor[0]);
866                         }
867                 }
868
869         // face
870                 Sbar_DrawFace ();
871
872         // health
873                 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3
874                 , cl.stats[STAT_HEALTH] <= 25);
875
876         // ammo icon
877                 if (rogue)
878                 {
879                         if (cl.items & RIT_SHELLS)
880                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
881                         else if (cl.items & RIT_NAILS)
882                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
883                         else if (cl.items & RIT_ROCKETS)
884                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
885                         else if (cl.items & RIT_CELLS)
886                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
887                         else if (cl.items & RIT_LAVA_NAILS)
888                                 Sbar_DrawPic (224, 0, rsb_ammo[0]);
889                         else if (cl.items & RIT_PLASMA_AMMO)
890                                 Sbar_DrawPic (224, 0, rsb_ammo[1]);
891                         else if (cl.items & RIT_MULTI_ROCKETS)
892                                 Sbar_DrawPic (224, 0, rsb_ammo[2]);
893                 }
894                 else
895                 {
896                         if (cl.items & IT_SHELLS)
897                                 Sbar_DrawPic (224, 0, sb_ammo[0]);
898                         else if (cl.items & IT_NAILS)
899                                 Sbar_DrawPic (224, 0, sb_ammo[1]);
900                         else if (cl.items & IT_ROCKETS)
901                                 Sbar_DrawPic (224, 0, sb_ammo[2]);
902                         else if (cl.items & IT_CELLS)
903                                 Sbar_DrawPic (224, 0, sb_ammo[3]);
904                 }
905
906                 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3,
907                                           cl.stats[STAT_AMMO] <= 10);
908         }
909
910         if (vid.width > 320) {
911                 if (cl.gametype == GAME_DEATHMATCH)
912                         Sbar_MiniDeathmatchOverlay ();
913         }
914 }
915
916 //=============================================================================
917
918 /*
919 ==================
920 Sbar_IntermissionNumber
921
922 ==================
923 */
924 void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)
925 {
926         char                    str[12];
927         char                    *ptr;
928         int                             l, frame;
929
930         l = Sbar_itoa (num, str);
931         ptr = str;
932         if (l > digits)
933                 ptr += (l-digits);
934         if (l < digits)
935                 x += (digits-l)*24;
936
937         while (*ptr)
938         {
939                 if (*ptr == '-')
940                         frame = STAT_MINUS;
941                 else
942                         frame = *ptr -'0';
943
944                 Draw_Pic (x,y,sb_nums[color][frame]);
945                 x += 24;
946                 ptr++;
947         }
948 }
949
950 /*
951 ==================
952 Sbar_DeathmatchOverlay
953
954 ==================
955 */
956 void Sbar_DeathmatchOverlay (void)
957 {
958         qpic_t                  *pic;
959         int                             i, k, l, top, bottom, x, y, total, n, minutes, tens, units, fph;
960         char                    num[128];
961         scoreboard_t    *s;
962
963         scr_copyeverything = 1;
964         scr_fullupdate = 0;
965
966         pic = Draw_CachePic ("gfx/ranking.lmp");
967         M_DrawPic ((320-pic->width)/2, 8, pic);
968
969 // scores
970         Sbar_SortFrags ();
971
972 // draw the text
973         l = scoreboardlines;
974
975         x = ((vid.width - 320)>>1) - 140;
976         y = 40;
977         for (i = 0;i < l;i++)
978         {
979                 k = fragsort[i];
980                 s = &cl.scores[k];
981                 if (!s->name[0])
982                         continue;
983
984         // draw background
985                 top = (s->colors & 0xf0) + 8;
986                 bottom = ((s->colors & 15)<<4) + 8;
987
988                 Draw_Fill ( x, y+1, 88, 3, top);
989                 Draw_Fill ( x, y+4, 88, 3, bottom);
990
991                 total = cl.time - s->entertime;
992                 minutes = (int)total/60;
993                 n = total - minutes*60;
994                 tens = n/10;
995                 units = n%10;
996
997                 fph = total ? (int) ((float) s->frags * 3600.0 / total) : 0;
998                 if (fph < -999) fph = -999;
999                 if (fph > 9999) fph = 9999;
1000
1001                 // put it together
1002                 sprintf (num, "%c %4i:%4i  %3i:%i%i %s", k == cl.viewentity - 1 ? 12 : ' ', (int) s->frags, fph, minutes, tens, units, s->name);
1003                 Draw_String(x - 8, y, num, 0);
1004
1005                 y += 8;
1006         }
1007 }
1008
1009 /*
1010 ==================
1011 Sbar_DeathmatchOverlay
1012
1013 ==================
1014 */
1015 void Sbar_MiniDeathmatchOverlay (void)
1016 {
1017         int                             i, l, k, top, bottom, x, y, fph, numlines;
1018         char                    num[128];
1019         scoreboard_t    *s;
1020
1021         if (vid.width < 512 || !sb_lines)
1022                 return;
1023
1024         scr_copyeverything = 1;
1025         scr_fullupdate = 0;
1026
1027 // scores
1028         Sbar_SortFrags ();
1029
1030 // draw the text
1031         l = scoreboardlines;
1032         y = vid.height - sb_lines;
1033         numlines = sb_lines/8;
1034         if (numlines < 3)
1035                 return;
1036
1037         //find us
1038         for (i = 0; i < scoreboardlines; i++)
1039                 if (fragsort[i] == cl.viewentity - 1)
1040                         break;
1041
1042     if (i == scoreboardlines) // we're not there
1043             i = 0;
1044     else // figure out start
1045             i = i - numlines/2;
1046
1047     if (i > scoreboardlines - numlines)
1048             i = scoreboardlines - numlines;
1049     if (i < 0)
1050             i = 0;
1051
1052         x = 324;
1053         for (;i < scoreboardlines && y < vid.height - 8;i++)
1054         {
1055                 k = fragsort[i];
1056                 s = &cl.scores[k];
1057                 if (!s->name[0])
1058                         continue;
1059
1060         // draw background
1061                 top = (s->colors & 0xf0) + 8;
1062                 bottom = ((s->colors & 15)<<4) + 8;
1063
1064                 Draw_Fill ( x, y+1, 72, 3, top);
1065                 Draw_Fill ( x, y+4, 72, 3, bottom);
1066
1067                 fph = (cl.time - s->entertime) ? (int) ((float) s->frags * 3600.0 / (cl.time - s->entertime)) : 0;
1068                 if (fph < -999) fph = -999;
1069                 if (fph > 9999) fph = 9999;
1070                 
1071                 // put it together
1072                 sprintf (num, "%c%4i:%4i%c %s", k == cl.viewentity - 1 ? 16 : ' ', (int) s->frags, fph, k == cl.viewentity - 1 ? 17 : ' ', s->name);
1073                 Draw_String(x - 8, y, num, 0);
1074
1075                 y += 8;
1076         }
1077 }
1078
1079 /*
1080 ==================
1081 Sbar_IntermissionOverlay
1082
1083 ==================
1084 */
1085 void Sbar_IntermissionOverlay (void)
1086 {
1087         qpic_t  *pic;
1088         int             dig;
1089         int             num;
1090
1091         scr_copyeverything = 1;
1092         scr_fullupdate = 0;
1093
1094         if (cl.gametype == GAME_DEATHMATCH)
1095         {
1096                 Sbar_DeathmatchOverlay ();
1097                 return;
1098         }
1099
1100         pic = Draw_CachePic ("gfx/complete.lmp");
1101         Draw_Pic (64, 24, pic);
1102
1103         pic = Draw_CachePic ("gfx/inter.lmp");
1104         Draw_Pic (0, 56, pic);
1105
1106 // time
1107         dig = cl.completed_time/60;
1108         Sbar_IntermissionNumber (160, 64, dig, 3, 0);
1109         num = cl.completed_time - dig*60;
1110         Draw_Pic (234,64,sb_colon);
1111         Draw_Pic (246,64,sb_nums[0][num/10]);
1112         Draw_Pic (266,64,sb_nums[0][num%10]);
1113
1114         Sbar_IntermissionNumber (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1115         Draw_Pic (232,104,sb_slash);
1116         Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1117
1118         Sbar_IntermissionNumber (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1119         Draw_Pic (232,144,sb_slash);
1120         Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1121
1122 }
1123
1124
1125 /*
1126 ==================
1127 Sbar_FinaleOverlay
1128
1129 ==================
1130 */
1131 void Sbar_FinaleOverlay (void)
1132 {
1133         qpic_t  *pic;
1134
1135         scr_copyeverything = 1;
1136
1137         pic = Draw_CachePic ("gfx/finale.lmp");
1138         Draw_Pic ( (vid.width-pic->width)/2, 16, pic);
1139 }