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