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