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