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