1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 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
25int			sb_updates;		// if >= vid.numpages, no update needed
26
27#define STAT_MINUS		10	// num frame for '-' stats digit
28qpic_t		*sb_nums[2][11];
29qpic_t		*sb_colon, *sb_slash;
30qpic_t		*sb_ibar;
31qpic_t		*sb_sbar;
32qpic_t		*sb_scorebar;
33
34qpic_t      *sb_weapons[7][8];   // 0 is active, 1 is owned, 2-5 are flashes
35qpic_t      *sb_ammo[4];
36qpic_t		*sb_sigil[4];
37qpic_t		*sb_armor[3];
38qpic_t		*sb_items[32];
39
40qpic_t	*sb_faces[7][2];		// 0 is gibbed, 1 is dead, 2-6 are alive
41							// 0 is static, 1 is temporary animation
42qpic_t	*sb_face_invis;
43qpic_t	*sb_face_quad;
44qpic_t	*sb_face_invuln;
45qpic_t	*sb_face_invis_invuln;
46
47qboolean	sb_showscores;
48
49int			sb_lines;			// scan lines to draw
50
51qpic_t      *rsb_invbar[2];
52qpic_t      *rsb_weapons[5];
53qpic_t      *rsb_items[2];
54qpic_t      *rsb_ammo[3];
55qpic_t      *rsb_teambord;		// PGM 01/19/97 - team color border
56
57//MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
58qpic_t      *hsb_weapons[7][5];   // 0 is active, 1 is owned, 2-5 are flashes
59//MED 01/04/97 added array to simplify weapon parsing
60int         hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
61//MED 01/04/97 added hipnotic items array
62qpic_t      *hsb_items[2];
63
64void Sbar_MiniDeathmatchOverlay (void);
65void Sbar_DeathmatchOverlay (void);
66void M_DrawPic (int x, int y, qpic_t *pic);
67
68/*
69===============
70Sbar_ShowScores
71
72Tab key down
73===============
74*/
75void Sbar_ShowScores (void)
76{
77	if (sb_showscores)
78		return;
79	sb_showscores = true;
80	sb_updates = 0;
81}
82
83/*
84===============
85Sbar_DontShowScores
86
87Tab key up
88===============
89*/
90void Sbar_DontShowScores (void)
91{
92	sb_showscores = false;
93	sb_updates = 0;
94}
95
96/*
97===============
98Sbar_Changed
99===============
100*/
101void Sbar_Changed (void)
102{
103	sb_updates = 0;	// update next frame
104}
105
106/*
107===============
108Sbar_Init
109===============
110*/
111void Sbar_Init (void)
112{
113	int		i;
114
115	for (i=0 ; i<10 ; i++)
116	{
117		sb_nums[0][i] = Draw_PicFromWad (va("num_%i",i));
118		sb_nums[1][i] = Draw_PicFromWad (va("anum_%i",i));
119	}
120
121	sb_nums[0][10] = Draw_PicFromWad ("num_minus");
122	sb_nums[1][10] = Draw_PicFromWad ("anum_minus");
123
124	sb_colon = Draw_PicFromWad ("num_colon");
125	sb_slash = Draw_PicFromWad ("num_slash");
126
127	sb_weapons[0][0] = Draw_PicFromWad ("inv_shotgun");
128	sb_weapons[0][1] = Draw_PicFromWad ("inv_sshotgun");
129	sb_weapons[0][2] = Draw_PicFromWad ("inv_nailgun");
130	sb_weapons[0][3] = Draw_PicFromWad ("inv_snailgun");
131	sb_weapons[0][4] = Draw_PicFromWad ("inv_rlaunch");
132	sb_weapons[0][5] = Draw_PicFromWad ("inv_srlaunch");
133	sb_weapons[0][6] = Draw_PicFromWad ("inv_lightng");
134
135	sb_weapons[1][0] = Draw_PicFromWad ("inv2_shotgun");
136	sb_weapons[1][1] = Draw_PicFromWad ("inv2_sshotgun");
137	sb_weapons[1][2] = Draw_PicFromWad ("inv2_nailgun");
138	sb_weapons[1][3] = Draw_PicFromWad ("inv2_snailgun");
139	sb_weapons[1][4] = Draw_PicFromWad ("inv2_rlaunch");
140	sb_weapons[1][5] = Draw_PicFromWad ("inv2_srlaunch");
141	sb_weapons[1][6] = Draw_PicFromWad ("inv2_lightng");
142
143	for (i=0 ; i<5 ; i++)
144	{
145		sb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_shotgun",i+1));
146		sb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_sshotgun",i+1));
147		sb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_nailgun",i+1));
148		sb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_snailgun",i+1));
149		sb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_rlaunch",i+1));
150		sb_weapons[2+i][5] = Draw_PicFromWad (va("inva%i_srlaunch",i+1));
151		sb_weapons[2+i][6] = Draw_PicFromWad (va("inva%i_lightng",i+1));
152	}
153
154	sb_ammo[0] = Draw_PicFromWad ("sb_shells");
155	sb_ammo[1] = Draw_PicFromWad ("sb_nails");
156	sb_ammo[2] = Draw_PicFromWad ("sb_rocket");
157	sb_ammo[3] = Draw_PicFromWad ("sb_cells");
158
159	sb_armor[0] = Draw_PicFromWad ("sb_armor1");
160	sb_armor[1] = Draw_PicFromWad ("sb_armor2");
161	sb_armor[2] = Draw_PicFromWad ("sb_armor3");
162
163	sb_items[0] = Draw_PicFromWad ("sb_key1");
164	sb_items[1] = Draw_PicFromWad ("sb_key2");
165	sb_items[2] = Draw_PicFromWad ("sb_invis");
166	sb_items[3] = Draw_PicFromWad ("sb_invuln");
167	sb_items[4] = Draw_PicFromWad ("sb_suit");
168	sb_items[5] = Draw_PicFromWad ("sb_quad");
169
170	sb_sigil[0] = Draw_PicFromWad ("sb_sigil1");
171	sb_sigil[1] = Draw_PicFromWad ("sb_sigil2");
172	sb_sigil[2] = Draw_PicFromWad ("sb_sigil3");
173	sb_sigil[3] = Draw_PicFromWad ("sb_sigil4");
174
175	sb_faces[4][0] = Draw_PicFromWad ("face1");
176	sb_faces[4][1] = Draw_PicFromWad ("face_p1");
177	sb_faces[3][0] = Draw_PicFromWad ("face2");
178	sb_faces[3][1] = Draw_PicFromWad ("face_p2");
179	sb_faces[2][0] = Draw_PicFromWad ("face3");
180	sb_faces[2][1] = Draw_PicFromWad ("face_p3");
181	sb_faces[1][0] = Draw_PicFromWad ("face4");
182	sb_faces[1][1] = Draw_PicFromWad ("face_p4");
183	sb_faces[0][0] = Draw_PicFromWad ("face5");
184	sb_faces[0][1] = Draw_PicFromWad ("face_p5");
185
186	sb_face_invis = Draw_PicFromWad ("face_invis");
187	sb_face_invuln = Draw_PicFromWad ("face_invul2");
188	sb_face_invis_invuln = Draw_PicFromWad ("face_inv2");
189	sb_face_quad = Draw_PicFromWad ("face_quad");
190
191	Cmd_AddCommand ("+showscores", Sbar_ShowScores);
192	Cmd_AddCommand ("-showscores", Sbar_DontShowScores);
193
194	sb_sbar = Draw_PicFromWad ("sbar");
195	sb_ibar = Draw_PicFromWad ("ibar");
196	sb_scorebar = Draw_PicFromWad ("scorebar");
197
198//MED 01/04/97 added new hipnotic weapons
199	if (hipnotic)
200	{
201	  hsb_weapons[0][0] = Draw_PicFromWad ("inv_laser");
202	  hsb_weapons[0][1] = Draw_PicFromWad ("inv_mjolnir");
203	  hsb_weapons[0][2] = Draw_PicFromWad ("inv_gren_prox");
204	  hsb_weapons[0][3] = Draw_PicFromWad ("inv_prox_gren");
205	  hsb_weapons[0][4] = Draw_PicFromWad ("inv_prox");
206
207	  hsb_weapons[1][0] = Draw_PicFromWad ("inv2_laser");
208	  hsb_weapons[1][1] = Draw_PicFromWad ("inv2_mjolnir");
209	  hsb_weapons[1][2] = Draw_PicFromWad ("inv2_gren_prox");
210	  hsb_weapons[1][3] = Draw_PicFromWad ("inv2_prox_gren");
211	  hsb_weapons[1][4] = Draw_PicFromWad ("inv2_prox");
212
213	  for (i=0 ; i<5 ; i++)
214	  {
215		 hsb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_laser",i+1));
216		 hsb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_mjolnir",i+1));
217		 hsb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_gren_prox",i+1));
218		 hsb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_prox_gren",i+1));
219		 hsb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_prox",i+1));
220	  }
221
222	  hsb_items[0] = Draw_PicFromWad ("sb_wsuit");
223	  hsb_items[1] = Draw_PicFromWad ("sb_eshld");
224	}
225
226	if (rogue)
227	{
228		rsb_invbar[0] = Draw_PicFromWad ("r_invbar1");
229		rsb_invbar[1] = Draw_PicFromWad ("r_invbar2");
230
231		rsb_weapons[0] = Draw_PicFromWad ("r_lava");
232		rsb_weapons[1] = Draw_PicFromWad ("r_superlava");
233		rsb_weapons[2] = Draw_PicFromWad ("r_gren");
234		rsb_weapons[3] = Draw_PicFromWad ("r_multirock");
235		rsb_weapons[4] = Draw_PicFromWad ("r_plasma");
236
237		rsb_items[0] = Draw_PicFromWad ("r_shield1");
238        rsb_items[1] = Draw_PicFromWad ("r_agrav1");
239
240// PGM 01/19/97 - team color border
241        rsb_teambord = Draw_PicFromWad ("r_teambord");
242// PGM 01/19/97 - team color border
243
244		rsb_ammo[0] = Draw_PicFromWad ("r_ammolava");
245		rsb_ammo[1] = Draw_PicFromWad ("r_ammomulti");
246		rsb_ammo[2] = Draw_PicFromWad ("r_ammoplasma");
247	}
248}
249
250
251//=============================================================================
252
253// drawing routines are relative to the status bar location
254
255/*
256=============
257Sbar_DrawPic
258=============
259*/
260void Sbar_DrawPic (int x, int y, qpic_t *pic)
261{
262	if (cl.gametype == GAME_DEATHMATCH)
263		Draw_Pic (x /* + ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic);
264	else
265		Draw_Pic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic);
266}
267
268/*
269=============
270Sbar_DrawTransPic
271=============
272*/
273void Sbar_DrawTransPic (int x, int y, qpic_t *pic)
274{
275	if (cl.gametype == GAME_DEATHMATCH)
276		Draw_TransPic (x /*+ ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic);
277	else
278		Draw_TransPic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic);
279}
280
281/*
282================
283Sbar_DrawCharacter
284
285Draws one solid graphics character
286================
287*/
288void Sbar_DrawCharacter (int x, int y, int num)
289{
290	if (cl.gametype == GAME_DEATHMATCH)
291		Draw_Character ( x /*+ ((vid.width - 320)>>1) */ + 4 , y + vid.height-SBAR_HEIGHT, num);
292	else
293		Draw_Character ( x + ((vid.width - 320)>>1) + 4 , y + vid.height-SBAR_HEIGHT, num);
294}
295
296/*
297================
298Sbar_DrawString
299================
300*/
301void Sbar_DrawString (int x, int y, char *str)
302{
303	if (cl.gametype == GAME_DEATHMATCH)
304		Draw_String (x /*+ ((vid.width - 320)>>1)*/, y+ vid.height-SBAR_HEIGHT, str);
305	else
306		Draw_String (x + ((vid.width - 320)>>1), y+ vid.height-SBAR_HEIGHT, str);
307}
308
309/*
310=============
311Sbar_itoa
312=============
313*/
314int Sbar_itoa (int num, char *buf)
315{
316	char	*str;
317	int		pow10;
318	int		dig;
319
320	str = buf;
321
322	if (num < 0)
323	{
324		*str++ = '-';
325		num = -num;
326	}
327
328	for (pow10 = 10 ; num >= pow10 ; pow10 *= 10)
329	;
330
331	do
332	{
333		pow10 /= 10;
334		dig = num/pow10;
335		*str++ = '0'+dig;
336		num -= dig*pow10;
337	} while (pow10 != 1);
338
339	*str = 0;
340
341	return str-buf;
342}
343
344
345/*
346=============
347Sbar_DrawNum
348=============
349*/
350void Sbar_DrawNum (int x, int y, int num, int digits, int color)
351{
352	char			str[12];
353	char			*ptr;
354	int				l, frame;
355
356	l = Sbar_itoa (num, str);
357	ptr = str;
358	if (l > digits)
359		ptr += (l-digits);
360	if (l < digits)
361		x += (digits-l)*24;
362
363	while (*ptr)
364	{
365		if (*ptr == '-')
366			frame = STAT_MINUS;
367		else
368			frame = *ptr -'0';
369
370		Sbar_DrawTransPic (x,y,sb_nums[color][frame]);
371		x += 24;
372		ptr++;
373	}
374}
375
376//=============================================================================
377
378int		fragsort[MAX_SCOREBOARD];
379
380char	scoreboardtext[MAX_SCOREBOARD][20];
381int		scoreboardtop[MAX_SCOREBOARD];
382int		scoreboardbottom[MAX_SCOREBOARD];
383int		scoreboardcount[MAX_SCOREBOARD];
384int		scoreboardlines;
385
386/*
387===============
388Sbar_SortFrags
389===============
390*/
391void Sbar_SortFrags (void)
392{
393	int		i, j, k;
394
395// sort by frags
396	scoreboardlines = 0;
397	for (i=0 ; i<cl.maxclients ; i++)
398	{
399		if (cl.scores[i].name[0])
400		{
401			fragsort[scoreboardlines] = i;
402			scoreboardlines++;
403		}
404	}
405
406	for (i=0 ; i<scoreboardlines ; i++)
407		for (j=0 ; j<scoreboardlines-1-i ; j++)
408			if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
409			{
410				k = fragsort[j];
411				fragsort[j] = fragsort[j+1];
412				fragsort[j+1] = k;
413			}
414}
415
416int	Sbar_ColorForMap (int m)
417{
418	return m < 128 ? m + 8 : m + 8;
419}
420
421/*
422===============
423Sbar_UpdateScoreboard
424===============
425*/
426void Sbar_UpdateScoreboard (void)
427{
428	int		i, k;
429	int		top, bottom;
430	scoreboard_t	*s;
431
432	Sbar_SortFrags ();
433
434// draw the text
435	memset (scoreboardtext, 0, sizeof(scoreboardtext));
436
437	for (i=0 ; i<scoreboardlines; i++)
438	{
439		k = fragsort[i];
440		s = &cl.scores[k];
441		sprintf (&scoreboardtext[i][1], "%3i %s", s->frags, s->name);
442
443		top = s->colors & 0xf0;
444		bottom = (s->colors & 15) <<4;
445		scoreboardtop[i] = Sbar_ColorForMap (top);
446		scoreboardbottom[i] = Sbar_ColorForMap (bottom);
447	}
448}
449
450
451
452/*
453===============
454Sbar_SoloScoreboard
455===============
456*/
457void Sbar_SoloScoreboard (void)
458{
459	char	str[80];
460	int		minutes, seconds, tens, units;
461	int		l;
462
463	sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
464	Sbar_DrawString (8, 4, str);
465
466	sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
467	Sbar_DrawString (8, 12, str);
468
469// time
470	minutes = (int)(cl.time / 60);
471	seconds = (int)(cl.time - 60*minutes);
472	tens = seconds / 10;
473	units = seconds - 10*tens;
474	sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
475	Sbar_DrawString (184, 4, str);
476
477// draw level name
478	l = strlen (cl.levelname);
479	Sbar_DrawString (232 - l*4, 12, cl.levelname);
480}
481
482/*
483===============
484Sbar_DrawScoreboard
485===============
486*/
487void Sbar_DrawScoreboard (void)
488{
489	Sbar_SoloScoreboard ();
490	if (cl.gametype == GAME_DEATHMATCH)
491		Sbar_DeathmatchOverlay ();
492#if 0
493	int		i, j, c;
494	int		x, y;
495	int		l;
496	int		top, bottom;
497	scoreboard_t	*s;
498
499	if (cl.gametype != GAME_DEATHMATCH)
500	{
501		Sbar_SoloScoreboard ();
502		return;
503	}
504
505	Sbar_UpdateScoreboard ();
506
507	l = scoreboardlines <= 6 ? scoreboardlines : 6;
508
509	for (i=0 ; i<l ; i++)
510	{
511		x = 20*(i&1);
512		y = i/2 * 8;
513
514		s = &cl.scores[fragsort[i]];
515		if (!s->name[0])
516			continue;
517
518	// draw background
519		top = s->colors & 0xf0;
520		bottom = (s->colors & 15)<<4;
521		top = Sbar_ColorForMap (top);
522		bottom = Sbar_ColorForMap (bottom);
523
524		Draw_Fill ( x*8+10 + ((vid.width - 320)>>1), y + vid.height - SBAR_HEIGHT, 28, 4, top);
525		Draw_Fill ( x*8+10 + ((vid.width - 320)>>1), y+4 + vid.height - SBAR_HEIGHT, 28, 4, bottom);
526
527	// draw text
528		for (j=0 ; j<20 ; j++)
529		{
530			c = scoreboardtext[i][j];
531			if (c == 0 || c == ' ')
532				continue;
533			Sbar_DrawCharacter ( (x+j)*8, y, c);
534		}
535	}
536#endif
537}
538
539//=============================================================================
540
541/*
542===============
543Sbar_DrawInventory
544===============
545*/
546void Sbar_DrawInventory (void)
547{
548	int		i;
549	char	num[6];
550	float	time;
551	int		flashon;
552
553	if (rogue)
554	{
555		if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
556			Sbar_DrawPic (0, -24, rsb_invbar[0]);
557		else
558			Sbar_DrawPic (0, -24, rsb_invbar[1]);
559	}
560	else
561	{
562		Sbar_DrawPic (0, -24, sb_ibar);
563	}
564
565// weapons
566	for (i=0 ; i<7 ; i++)
567	{
568		if (cl.items & (IT_SHOTGUN<<i) )
569		{
570			time = cl.item_gettime[i];
571			flashon = (int)((cl.time - time)*10);
572			if (flashon >= 10)
573			{
574				if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i)  )
575					flashon = 1;
576				else
577					flashon = 0;
578			}
579			else
580				flashon = (flashon%5) + 2;
581
582         Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
583
584			if (flashon > 1)
585				sb_updates = 0;		// force update to remove flash
586		}
587	}
588
589// MED 01/04/97
590// hipnotic weapons
591    if (hipnotic)
592    {
593      int grenadeflashing=0;
594      for (i=0 ; i<4 ; i++)
595      {
596         if (cl.items & (1<<hipweapons[i]) )
597         {
598            time = cl.item_gettime[hipweapons[i]];
599            flashon = (int)((cl.time - time)*10);
600            if (flashon >= 10)
601            {
602               if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i])  )
603                  flashon = 1;
604               else
605                  flashon = 0;
606            }
607            else
608               flashon = (flashon%5) + 2;
609
610            // check grenade launcher
611            if (i==2)
612            {
613               if (cl.items & HIT_PROXIMITY_GUN)
614               {
615                  if (flashon)
616                  {
617                     grenadeflashing = 1;
618                     Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
619                  }
620               }
621            }
622            else if (i==3)
623            {
624               if (cl.items & (IT_SHOTGUN<<4))
625               {
626                  if (flashon && !grenadeflashing)
627                  {
628                     Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
629                  }
630                  else if (!grenadeflashing)
631                  {
632                     Sbar_DrawPic (96, -16, hsb_weapons[0][3]);
633                  }
634               }
635               else
636                  Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
637            }
638            else
639               Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
640            if (flashon > 1)
641               sb_updates = 0;      // force update to remove flash
642         }
643      }
644    }
645
646	if (rogue)
647	{
648    // check for powered up weapon.
649		if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
650		{
651			for (i=0;i<5;i++)
652			{
653				if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
654				{
655					Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
656				}
657			}
658		}
659	}
660
661// ammo counts
662	for (i=0 ; i<4 ; i++)
663	{
664		sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] );
665		if (num[0] != ' ')
666			Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
667		if (num[1] != ' ')
668			Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
669		if (num[2] != ' ')
670			Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
671	}
672
673	flashon = 0;
674   // items
675   for (i=0 ; i<6 ; i++)
676      if (cl.items & (1<<(17+i)))
677      {
678         time = cl.item_gettime[17+i];
679         if (time && time > cl.time - 2 && flashon )
680         {  // flash frame
681            sb_updates = 0;
682         }
683         else
684         {
685         //MED 01/04/97 changed keys
686            if (!hipnotic || (i>1))
687            {
688               Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
689            }
690         }
691         if (time && time > cl.time - 2)
692            sb_updates = 0;
693      }
694   //MED 01/04/97 added hipnotic items
695   // hipnotic items
696   if (hipnotic)
697   {
698      for (i=0 ; i<2 ; i++)
699         if (cl.items & (1<<(24+i)))
700         {
701            time = cl.item_gettime[24+i];
702            if (time && time > cl.time - 2 && flashon )
703            {  // flash frame
704               sb_updates = 0;
705            }
706            else
707            {
708               Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
709            }
710            if (time && time > cl.time - 2)
711               sb_updates = 0;
712         }
713   }
714
715	if (rogue)
716	{
717	// new rogue items
718		for (i=0 ; i<2 ; i++)
719		{
720			if (cl.items & (1<<(29+i)))
721			{
722				time = cl.item_gettime[29+i];
723
724				if (time &&	time > cl.time - 2 && flashon )
725				{	// flash frame
726					sb_updates = 0;
727				}
728				else
729				{
730					Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
731				}
732
733				if (time &&	time > cl.time - 2)
734					sb_updates = 0;
735			}
736		}
737	}
738	else
739	{
740	// sigils
741		for (i=0 ; i<4 ; i++)
742		{
743			if (cl.items & (1<<(28+i)))
744			{
745				time = cl.item_gettime[28+i];
746				if (time &&	time > cl.time - 2 && flashon )
747				{	// flash frame
748					sb_updates = 0;
749				}
750				else
751					Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
752				if (time &&	time > cl.time - 2)
753					sb_updates = 0;
754			}
755		}
756	}
757}
758
759//=============================================================================
760
761/*
762===============
763Sbar_DrawFrags
764===============
765*/
766void Sbar_DrawFrags (void)
767{
768	int				i, k, l;
769	int				top, bottom;
770	int				x, y, f;
771	int				xofs;
772	char			num[12];
773	scoreboard_t	*s;
774
775	Sbar_SortFrags ();
776
777// draw the text
778	l = scoreboardlines <= 4 ? scoreboardlines : 4;
779
780	x = 23;
781	if (cl.gametype == GAME_DEATHMATCH)
782		xofs = 0;
783	else
784		xofs = (vid.width - 320)>>1;
785	y = vid.height - SBAR_HEIGHT - 23;
786
787	for (i=0 ; i<l ; i++)
788	{
789		k = fragsort[i];
790		s = &cl.scores[k];
791		if (!s->name[0])
792			continue;
793
794	// draw background
795		top = s->colors & 0xf0;
796		bottom = (s->colors & 15)<<4;
797		top = Sbar_ColorForMap (top);
798		bottom = Sbar_ColorForMap (bottom);
799
800		Draw_Fill (xofs + x*8 + 10, y, 28, 4, top);
801		Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom);
802
803	// draw number
804		f = s->frags;
805		sprintf (num, "%3i",f);
806
807		Sbar_DrawCharacter ( (x+1)*8 , -24, num[0]);
808		Sbar_DrawCharacter ( (x+2)*8 , -24, num[1]);
809		Sbar_DrawCharacter ( (x+3)*8 , -24, num[2]);
810
811		if (k == cl.viewentity - 1)
812		{
813			Sbar_DrawCharacter (x*8+2, -24, 16);
814			Sbar_DrawCharacter ( (x+4)*8-4, -24, 17);
815		}
816		x+=4;
817	}
818}
819
820//=============================================================================
821
822
823/*
824===============
825Sbar_DrawFace
826===============
827*/
828void Sbar_DrawFace (void)
829{
830	int		f, anim;
831
832// PGM 01/19/97 - team color drawing
833// PGM 03/02/97 - fixed so color swatch only appears in CTF modes
834	if (rogue &&
835        (cl.maxclients != 1) &&
836        (teamplay.value>3) &&
837        (teamplay.value<7))
838	{
839		int				top, bottom;
840		int				xofs;
841		char			num[12];
842		scoreboard_t	*s;
843
844		s = &cl.scores[cl.viewentity - 1];
845		// draw background
846		top = s->colors & 0xf0;
847		bottom = (s->colors & 15)<<4;
848		top = Sbar_ColorForMap (top);
849		bottom = Sbar_ColorForMap (bottom);
850
851		if (cl.gametype == GAME_DEATHMATCH)
852			xofs = 113;
853		else
854			xofs = ((vid.width - 320)>>1) + 113;
855
856		Sbar_DrawPic (112, 0, rsb_teambord);
857		Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, top);
858		Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, bottom);
859
860		// draw number
861		f = s->frags;
862		sprintf (num, "%3i",f);
863
864		if (top==8)
865		{
866			if (num[0] != ' ')
867				Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
868			if (num[1] != ' ')
869				Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
870			if (num[2] != ' ')
871				Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
872		}
873		else
874		{
875			Sbar_DrawCharacter ( 109, 3, num[0]);
876			Sbar_DrawCharacter ( 116, 3, num[1]);
877			Sbar_DrawCharacter ( 123, 3, num[2]);
878		}
879
880		return;
881	}
882// PGM 01/19/97 - team color drawing
883
884	if ( (cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY) )
885	== (IT_INVISIBILITY | IT_INVULNERABILITY) )
886	{
887		Sbar_DrawPic (112, 0, sb_face_invis_invuln);
888		return;
889	}
890	if (cl.items & IT_QUAD)
891	{
892		Sbar_DrawPic (112, 0, sb_face_quad );
893		return;
894	}
895	if (cl.items & IT_INVISIBILITY)
896	{
897		Sbar_DrawPic (112, 0, sb_face_invis );
898		return;
899	}
900	if (cl.items & IT_INVULNERABILITY)
901	{
902		Sbar_DrawPic (112, 0, sb_face_invuln);
903		return;
904	}
905
906	if (cl.stats[STAT_HEALTH] >= 100)
907		f = 4;
908	else
909		f = cl.stats[STAT_HEALTH] / 20;
910
911	if (cl.time <= cl.faceanimtime)
912	{
913		anim = 1;
914		sb_updates = 0;		// make sure the anim gets drawn over
915	}
916	else
917		anim = 0;
918	Sbar_DrawPic (112, 0, sb_faces[f][anim]);
919}
920
921/*
922===============
923Sbar_Draw
924===============
925*/
926void Sbar_Draw (void)
927{
928	if (scr_con_current == vid.height)
929		return;		// console is full screen
930
931#if 0
932	if (sb_updates >= vid.numpages)
933		return;
934#else
935	// Always draw status bar, to handle hardware that always destroys
936	// the frame buffer. (essentially an infinite number of vid pages.)
937#endif
938	scr_copyeverything = 1;
939
940	sb_updates++;
941
942	if (sb_lines && vid.width > 320)
943		Draw_TileClear (0, vid.height - sb_lines, vid.width, sb_lines);
944
945	if (sb_lines > 24)
946	{
947		Sbar_DrawInventory ();
948		if (cl.maxclients != 1)
949			Sbar_DrawFrags ();
950	}
951
952	if (sb_showscores || cl.stats[STAT_HEALTH] <= 0)
953	{
954		Sbar_DrawPic (0, 0, sb_scorebar);
955		Sbar_DrawScoreboard ();
956		sb_updates = 0;
957	}
958	else if (sb_lines)
959	{
960		Sbar_DrawPic (0, 0, sb_sbar);
961
962   // keys (hipnotic only)
963      //MED 01/04/97 moved keys here so they would not be overwritten
964      if (hipnotic)
965      {
966         if (cl.items & IT_KEY1)
967            Sbar_DrawPic (209, 3, sb_items[0]);
968         if (cl.items & IT_KEY2)
969            Sbar_DrawPic (209, 12, sb_items[1]);
970      }
971   // armor
972		if (cl.items & IT_INVULNERABILITY)
973		{
974			Sbar_DrawNum (24, 0, 666, 3, 1);
975			Sbar_DrawPic (0, 0, draw_disc);
976		}
977		else
978		{
979			if (rogue)
980			{
981				Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3,
982								cl.stats[STAT_ARMOR] <= 25);
983				if (cl.items & RIT_ARMOR3)
984					Sbar_DrawPic (0, 0, sb_armor[2]);
985				else if (cl.items & RIT_ARMOR2)
986					Sbar_DrawPic (0, 0, sb_armor[1]);
987				else if (cl.items & RIT_ARMOR1)
988					Sbar_DrawPic (0, 0, sb_armor[0]);
989			}
990			else
991			{
992				Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3
993				, cl.stats[STAT_ARMOR] <= 25);
994				if (cl.items & IT_ARMOR3)
995					Sbar_DrawPic (0, 0, sb_armor[2]);
996				else if (cl.items & IT_ARMOR2)
997					Sbar_DrawPic (0, 0, sb_armor[1]);
998				else if (cl.items & IT_ARMOR1)
999					Sbar_DrawPic (0, 0, sb_armor[0]);
1000			}
1001		}
1002
1003	// face
1004		Sbar_DrawFace ();
1005
1006	// health
1007		Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3
1008		, cl.stats[STAT_HEALTH] <= 25);
1009
1010	// ammo icon
1011		if (rogue)
1012		{
1013			if (cl.items & RIT_SHELLS)
1014				Sbar_DrawPic (224, 0, sb_ammo[0]);
1015			else if (cl.items & RIT_NAILS)
1016				Sbar_DrawPic (224, 0, sb_ammo[1]);
1017			else if (cl.items & RIT_ROCKETS)
1018				Sbar_DrawPic (224, 0, sb_ammo[2]);
1019			else if (cl.items & RIT_CELLS)
1020				Sbar_DrawPic (224, 0, sb_ammo[3]);
1021			else if (cl.items & RIT_LAVA_NAILS)
1022				Sbar_DrawPic (224, 0, rsb_ammo[0]);
1023			else if (cl.items & RIT_PLASMA_AMMO)
1024				Sbar_DrawPic (224, 0, rsb_ammo[1]);
1025			else if (cl.items & RIT_MULTI_ROCKETS)
1026				Sbar_DrawPic (224, 0, rsb_ammo[2]);
1027		}
1028		else
1029		{
1030			if (cl.items & IT_SHELLS)
1031				Sbar_DrawPic (224, 0, sb_ammo[0]);
1032			else if (cl.items & IT_NAILS)
1033				Sbar_DrawPic (224, 0, sb_ammo[1]);
1034			else if (cl.items & IT_ROCKETS)
1035				Sbar_DrawPic (224, 0, sb_ammo[2]);
1036			else if (cl.items & IT_CELLS)
1037				Sbar_DrawPic (224, 0, sb_ammo[3]);
1038		}
1039
1040		Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3,
1041					  cl.stats[STAT_AMMO] <= 10);
1042	}
1043
1044	if (vid.width > 320) {
1045		if (cl.gametype == GAME_DEATHMATCH)
1046			Sbar_MiniDeathmatchOverlay ();
1047	}
1048}
1049
1050//=============================================================================
1051
1052/*
1053==================
1054Sbar_IntermissionNumber
1055
1056==================
1057*/
1058void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)
1059{
1060	char			str[12];
1061	char			*ptr;
1062	int				l, frame;
1063
1064	l = Sbar_itoa (num, str);
1065	ptr = str;
1066	if (l > digits)
1067		ptr += (l-digits);
1068	if (l < digits)
1069		x += (digits-l)*24;
1070
1071	while (*ptr)
1072	{
1073		if (*ptr == '-')
1074			frame = STAT_MINUS;
1075		else
1076			frame = *ptr -'0';
1077
1078		Draw_TransPic (x,y,sb_nums[color][frame]);
1079		x += 24;
1080		ptr++;
1081	}
1082}
1083
1084/*
1085==================
1086Sbar_DeathmatchOverlay
1087
1088==================
1089*/
1090void Sbar_DeathmatchOverlay (void)
1091{
1092	qpic_t			*pic;
1093	int				i, k, l;
1094	int				top, bottom;
1095	int				x, y, f;
1096	char			num[12];
1097	scoreboard_t	*s;
1098
1099	scr_copyeverything = 1;
1100	scr_fullupdate = 0;
1101
1102	pic = Draw_CachePic ("gfx/ranking.lmp");
1103	M_DrawPic ((320-pic->width)/2, 8, pic);
1104
1105// scores
1106	Sbar_SortFrags ();
1107
1108// draw the text
1109	l = scoreboardlines;
1110
1111	x = 80 + ((vid.width - 320)>>1);
1112	y = 40;
1113	for (i=0 ; i<l ; i++)
1114	{
1115		k = fragsort[i];
1116		s = &cl.scores[k];
1117		if (!s->name[0])
1118			continue;
1119
1120	// draw background
1121		top = s->colors & 0xf0;
1122		bottom = (s->colors & 15)<<4;
1123		top = Sbar_ColorForMap (top);
1124		bottom = Sbar_ColorForMap (bottom);
1125
1126		Draw_Fill ( x, y, 40, 4, top);
1127		Draw_Fill ( x, y+4, 40, 4, bottom);
1128
1129	// draw number
1130		f = s->frags;
1131		sprintf (num, "%3i",f);
1132
1133		Draw_Character ( x+8 , y, num[0]);
1134		Draw_Character ( x+16 , y, num[1]);
1135		Draw_Character ( x+24 , y, num[2]);
1136
1137		if (k == cl.viewentity - 1)
1138			Draw_Character ( x - 8, y, 12);
1139
1140#if 0
1141{
1142	int				total;
1143	int				n, minutes, tens, units;
1144
1145	// draw time
1146		total = cl.completed_time - s->entertime;
1147		minutes = (int)total/60;
1148		n = total - minutes*60;
1149		tens = n/10;
1150		units = n%10;
1151
1152		sprintf (num, "%3i:%i%i", minutes, tens, units);
1153
1154		Draw_String ( x+48 , y, num);
1155}
1156#endif
1157
1158	// draw name
1159		Draw_String (x+64, y, s->name);
1160
1161		y += 10;
1162	}
1163}
1164
1165/*
1166==================
1167Sbar_DeathmatchOverlay
1168
1169==================
1170*/
1171void Sbar_MiniDeathmatchOverlay (void)
1172{
1173	qpic_t			*pic;
1174	int				i, k, l;
1175	int				top, bottom;
1176	int				x, y, f;
1177	char			num[12];
1178	scoreboard_t	*s;
1179	int				numlines;
1180
1181	if (vid.width < 512 || !sb_lines)
1182		return;
1183
1184	scr_copyeverything = 1;
1185	scr_fullupdate = 0;
1186
1187// scores
1188	Sbar_SortFrags ();
1189
1190// draw the text
1191	l = scoreboardlines;
1192	y = vid.height - sb_lines;
1193	numlines = sb_lines/8;
1194	if (numlines < 3)
1195		return;
1196
1197	//find us
1198	for (i = 0; i < scoreboardlines; i++)
1199		if (fragsort[i] == cl.viewentity - 1)
1200			break;
1201
1202    if (i == scoreboardlines) // we're not there
1203            i = 0;
1204    else // figure out start
1205            i = i - numlines/2;
1206
1207    if (i > scoreboardlines - numlines)
1208            i = scoreboardlines - numlines;
1209    if (i < 0)
1210            i = 0;
1211
1212	x = 324;
1213	for (/* */; i < scoreboardlines && y < (int) (vid.height - 8) ; i++)
1214	{
1215		k = fragsort[i];
1216		s = &cl.scores[k];
1217		if (!s->name[0])
1218			continue;
1219
1220	// draw background
1221		top = s->colors & 0xf0;
1222		bottom = (s->colors & 15)<<4;
1223		top = Sbar_ColorForMap (top);
1224		bottom = Sbar_ColorForMap (bottom);
1225
1226		Draw_Fill ( x, y+1, 40, 3, top);
1227		Draw_Fill ( x, y+4, 40, 4, bottom);
1228
1229	// draw number
1230		f = s->frags;
1231		sprintf (num, "%3i",f);
1232
1233		Draw_Character ( x+8 , y, num[0]);
1234		Draw_Character ( x+16 , y, num[1]);
1235		Draw_Character ( x+24 , y, num[2]);
1236
1237		if (k == cl.viewentity - 1) {
1238			Draw_Character ( x, y, 16);
1239			Draw_Character ( x + 32, y, 17);
1240		}
1241
1242#if 0
1243{
1244	int				total;
1245	int				n, minutes, tens, units;
1246
1247	// draw time
1248		total = cl.completed_time - s->entertime;
1249		minutes = (int)total/60;
1250		n = total - minutes*60;
1251		tens = n/10;
1252		units = n%10;
1253
1254		sprintf (num, "%3i:%i%i", minutes, tens, units);
1255
1256		Draw_String ( x+48 , y, num);
1257}
1258#endif
1259
1260	// draw name
1261		Draw_String (x+48, y, s->name);
1262
1263		y += 8;
1264	}
1265}
1266
1267/*
1268==================
1269Sbar_IntermissionOverlay
1270
1271==================
1272*/
1273void Sbar_IntermissionOverlay (void)
1274{
1275	qpic_t	*pic;
1276	int		dig;
1277	int		num;
1278
1279	scr_copyeverything = 1;
1280	scr_fullupdate = 0;
1281
1282	if (cl.gametype == GAME_DEATHMATCH)
1283	{
1284		Sbar_DeathmatchOverlay ();
1285		return;
1286	}
1287
1288	pic = Draw_CachePic ("gfx/complete.lmp");
1289	Draw_Pic (64, 24, pic);
1290
1291	pic = Draw_CachePic ("gfx/inter.lmp");
1292	Draw_TransPic (0, 56, pic);
1293
1294// time
1295	dig = cl.completed_time/60;
1296	Sbar_IntermissionNumber (160, 64, dig, 3, 0);
1297	num = cl.completed_time - dig*60;
1298	Draw_TransPic (234,64,sb_colon);
1299	Draw_TransPic (246,64,sb_nums[0][num/10]);
1300	Draw_TransPic (266,64,sb_nums[0][num%10]);
1301
1302	Sbar_IntermissionNumber (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1303	Draw_TransPic (232,104,sb_slash);
1304	Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1305
1306	Sbar_IntermissionNumber (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1307	Draw_TransPic (232,144,sb_slash);
1308	Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1309
1310}
1311
1312
1313/*
1314==================
1315Sbar_FinaleOverlay
1316
1317==================
1318*/
1319void Sbar_FinaleOverlay (void)
1320{
1321	qpic_t	*pic;
1322
1323	scr_copyeverything = 1;
1324
1325	pic = Draw_CachePic ("gfx/finale.lmp");
1326	Draw_TransPic ( (vid.width-pic->width)/2, 16, pic);
1327}
1328