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 
25 int			sb_updates;		// if >= vid.numpages, no update needed
26 
27 #define STAT_MINUS		10	// num frame for '-' stats digit
28 qpic_t		*sb_nums[2][11];
29 qpic_t		*sb_colon, *sb_slash;
30 qpic_t		*sb_ibar;
31 qpic_t		*sb_sbar;
32 qpic_t		*sb_scorebar;
33 
34 qpic_t      *sb_weapons[7][8];   // 0 is active, 1 is owned, 2-5 are flashes
35 qpic_t      *sb_ammo[4];
36 qpic_t		*sb_sigil[4];
37 qpic_t		*sb_armor[3];
38 qpic_t		*sb_items[32];
39 
40 qpic_t	*sb_faces[7][2];		// 0 is gibbed, 1 is dead, 2-6 are alive
41 							// 0 is static, 1 is temporary animation
42 qpic_t	*sb_face_invis;
43 qpic_t	*sb_face_quad;
44 qpic_t	*sb_face_invuln;
45 qpic_t	*sb_face_invis_invuln;
46 
47 qboolean	sb_showscores;
48 
49 int			sb_lines;			// scan lines to draw
50 
51 qpic_t      *rsb_invbar[2];
52 qpic_t      *rsb_weapons[5];
53 qpic_t      *rsb_items[2];
54 qpic_t      *rsb_ammo[3];
55 qpic_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
58 qpic_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
60 int         hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
61 //MED 01/04/97 added hipnotic items array
62 qpic_t      *hsb_items[2];
63 
64 void Sbar_MiniDeathmatchOverlay (void);
65 void Sbar_DeathmatchOverlay (void);
66 void M_DrawPic (int x, int y, qpic_t *pic);
67 
68 /*
69 ===============
70 Sbar_ShowScores
71 
72 Tab key down
73 ===============
74 */
Sbar_ShowScores(void)75 void Sbar_ShowScores (void)
76 {
77 	if (sb_showscores)
78 		return;
79 	sb_showscores = true;
80 	sb_updates = 0;
81 }
82 
83 /*
84 ===============
85 Sbar_DontShowScores
86 
87 Tab key up
88 ===============
89 */
Sbar_DontShowScores(void)90 void Sbar_DontShowScores (void)
91 {
92 	sb_showscores = false;
93 	sb_updates = 0;
94 }
95 
96 /*
97 ===============
98 Sbar_Changed
99 ===============
100 */
Sbar_Changed(void)101 void Sbar_Changed (void)
102 {
103 	sb_updates = 0;	// update next frame
104 }
105 
106 /*
107 ===============
108 Sbar_Init
109 ===============
110 */
Sbar_Init(void)111 void 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 =============
257 Sbar_DrawPic
258 =============
259 */
Sbar_DrawPic(int x,int y,qpic_t * pic)260 void 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 =============
270 Sbar_DrawTransPic
271 =============
272 */
Sbar_DrawTransPic(int x,int y,qpic_t * pic)273 void 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 ================
283 Sbar_DrawCharacter
284 
285 Draws one solid graphics character
286 ================
287 */
Sbar_DrawCharacter(int x,int y,int num)288 void 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 ================
298 Sbar_DrawString
299 ================
300 */
Sbar_DrawString(int x,int y,char * str)301 void 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 =============
311 Sbar_itoa
312 =============
313 */
Sbar_itoa(int num,char * buf)314 int 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 =============
347 Sbar_DrawNum
348 =============
349 */
Sbar_DrawNum(int x,int y,int num,int digits,int color)350 void 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 
378 int		fragsort[MAX_SCOREBOARD];
379 
380 char	scoreboardtext[MAX_SCOREBOARD][20];
381 int		scoreboardtop[MAX_SCOREBOARD];
382 int		scoreboardbottom[MAX_SCOREBOARD];
383 int		scoreboardcount[MAX_SCOREBOARD];
384 int		scoreboardlines;
385 
386 /*
387 ===============
388 Sbar_SortFrags
389 ===============
390 */
Sbar_SortFrags(void)391 void 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 
Sbar_ColorForMap(int m)416 int	Sbar_ColorForMap (int m)
417 {
418 	return m < 128 ? m + 8 : m + 8;
419 }
420 
421 /*
422 ===============
423 Sbar_UpdateScoreboard
424 ===============
425 */
Sbar_UpdateScoreboard(void)426 void 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 ===============
454 Sbar_SoloScoreboard
455 ===============
456 */
Sbar_SoloScoreboard(void)457 void Sbar_SoloScoreboard (void)
458 {
459 	char	str[80];
460 	int		minutes, seconds, tens, units;
461 	int	l, SecretEnd, TStart;
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 	SecretEnd = 1 + strlen (str);
470 
471 // time
472 	minutes = cl.time / 60;
473 	seconds = cl.time - 60*minutes;
474 	tens = seconds / 10;
475 	units = seconds - 10*tens;
476 	sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
477 	Sbar_DrawString (184, 4, str);
478 
479 // draw level name
480 	strncpy (str, cl.levelname, sizeof(str) - 1);
481 	str[sizeof(str) - 1] = '\0';
482 	l = strlen (str);
483 
484 	// X position is 8 pixels wide
485 	TStart = 232 / 8 - l / 2;
486 
487 	if (TStart < SecretEnd + 1)
488 	{
489 		// Don't cover # secrets info
490 		TStart = SecretEnd + 1;
491 
492 /*		l = (232 / 8 - TStart) * 2;
493 
494 		// Paranoid
495 		if (l < 0)
496 			l = 0;
497 		else if (l >= sizeof(str))
498 			l = sizeof(str) - 1;
499 
500 		str[l] = '\0';*/
501 	}
502 
503 	Sbar_DrawString (TStart * 8, 12, str);
504 }
505 
506 /*
507 ===============
508 Sbar_DrawScoreboard
509 ===============
510 */
Sbar_DrawScoreboard(void)511 void Sbar_DrawScoreboard (void)
512 {
513 	Sbar_SoloScoreboard ();
514 	if (cl.gametype == GAME_DEATHMATCH)
515 		Sbar_DeathmatchOverlay ();
516 #if 0
517 	int		i, j, c;
518 	int		x, y;
519 	int		l;
520 	int		top, bottom;
521 	scoreboard_t	*s;
522 
523 	if (cl.gametype != GAME_DEATHMATCH)
524 	{
525 		Sbar_SoloScoreboard ();
526 		return;
527 	}
528 
529 	Sbar_UpdateScoreboard ();
530 
531 	l = scoreboardlines <= 6 ? scoreboardlines : 6;
532 
533 	for (i=0 ; i<l ; i++)
534 	{
535 		x = 20*(i&1);
536 		y = i/2 * 8;
537 
538 		s = &cl.scores[fragsort[i]];
539 		if (!s->name[0])
540 			continue;
541 
542 	// draw background
543 		top = s->colors & 0xf0;
544 		bottom = (s->colors & 15)<<4;
545 		top = Sbar_ColorForMap (top);
546 		bottom = Sbar_ColorForMap (bottom);
547 
548 		Draw_Fill ( x*8+10 + ((vid.width - 320)>>1), y + vid.height - SBAR_HEIGHT, 28, 4, top);
549 		Draw_Fill ( x*8+10 + ((vid.width - 320)>>1), y+4 + vid.height - SBAR_HEIGHT, 28, 4, bottom);
550 
551 	// draw text
552 		for (j=0 ; j<20 ; j++)
553 		{
554 			c = scoreboardtext[i][j];
555 			if (c == 0 || c == ' ')
556 				continue;
557 			Sbar_DrawCharacter ( (x+j)*8, y, c);
558 		}
559 	}
560 #endif
561 }
562 
563 //=============================================================================
564 
565 /*
566 ===============
567 Sbar_DrawInventory
568 ===============
569 */
Sbar_DrawInventory(void)570 void Sbar_DrawInventory (void)
571 {
572 	int		i;
573 	char	num[6];
574 	float	time;
575 	int		flashon;
576 
577 	if (rogue)
578 	{
579 		if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
580 			Sbar_DrawPic (0, -24, rsb_invbar[0]);
581 		else
582 			Sbar_DrawPic (0, -24, rsb_invbar[1]);
583 	}
584 	else
585 	{
586 		Sbar_DrawPic (0, -24, sb_ibar);
587 	}
588 
589 // weapons
590 	for (i=0 ; i<7 ; i++)
591 	{
592 		if (cl.items & (IT_SHOTGUN<<i) )
593 		{
594 			time = cl.item_gettime[i];
595 			flashon = (int)((cl.time - time)*10);
596 			if (flashon >= 10)
597 			{
598 				if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i)  )
599 					flashon = 1;
600 				else
601 					flashon = 0;
602 			}
603 			else
604 				flashon = (flashon%5) + 2;
605 
606          Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
607 
608 			if (flashon > 1)
609 				sb_updates = 0;		// force update to remove flash
610 		}
611 	}
612 
613 // MED 01/04/97
614 // hipnotic weapons
615     if (hipnotic)
616     {
617       int grenadeflashing=0;
618       for (i=0 ; i<4 ; i++)
619       {
620          if (cl.items & (1<<hipweapons[i]) )
621          {
622             time = cl.item_gettime[hipweapons[i]];
623             flashon = (int)((cl.time - time)*10);
624             if (flashon >= 10)
625             {
626                if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i])  )
627                   flashon = 1;
628                else
629                   flashon = 0;
630             }
631             else
632                flashon = (flashon%5) + 2;
633 
634             // check grenade launcher
635             if (i==2)
636             {
637                if (cl.items & HIT_PROXIMITY_GUN)
638                {
639                   if (flashon)
640                   {
641                      grenadeflashing = 1;
642                      Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
643                   }
644                }
645             }
646             else if (i==3)
647             {
648                if (cl.items & (IT_SHOTGUN<<4))
649                {
650                   if (flashon && !grenadeflashing)
651                   {
652                      Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
653                   }
654                   else if (!grenadeflashing)
655                   {
656                      Sbar_DrawPic (96, -16, hsb_weapons[0][3]);
657                   }
658                }
659                else
660                   Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
661             }
662             else
663                Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
664             if (flashon > 1)
665                sb_updates = 0;      // force update to remove flash
666          }
667       }
668     }
669 
670 	if (rogue)
671 	{
672     // check for powered up weapon.
673 		if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
674 		{
675 			for (i=0;i<5;i++)
676 			{
677 				if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
678 				{
679 					Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
680 				}
681 			}
682 		}
683 	}
684 
685 // ammo counts
686 	for (i=0 ; i<4 ; i++)
687 	{
688 		sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] );
689 		if (num[0] != ' ')
690 			Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
691 		if (num[1] != ' ')
692 			Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
693 		if (num[2] != ' ')
694 			Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
695 	}
696 
697 	flashon = 0;
698    // items
699    for (i=0 ; i<6 ; i++)
700       if (cl.items & (1<<(17+i)))
701       {
702          time = cl.item_gettime[17+i];
703          if (time && time > cl.time - 2 && flashon )
704          {  // flash frame
705             sb_updates = 0;
706          }
707          else
708          {
709          //MED 01/04/97 changed keys
710             if (!hipnotic || (i>1))
711             {
712                Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
713             }
714          }
715          if (time && time > cl.time - 2)
716             sb_updates = 0;
717       }
718    //MED 01/04/97 added hipnotic items
719    // hipnotic items
720    if (hipnotic)
721    {
722       for (i=0 ; i<2 ; i++)
723          if (cl.items & (1<<(24+i)))
724          {
725             time = cl.item_gettime[24+i];
726             if (time && time > cl.time - 2 && flashon )
727             {  // flash frame
728                sb_updates = 0;
729             }
730             else
731             {
732                Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
733             }
734             if (time && time > cl.time - 2)
735                sb_updates = 0;
736          }
737    }
738 
739 	if (rogue)
740 	{
741 	// new rogue items
742 		for (i=0 ; i<2 ; i++)
743 		{
744 			if (cl.items & (1<<(29+i)))
745 			{
746 				time = cl.item_gettime[29+i];
747 
748 				if (time &&	time > cl.time - 2 && flashon )
749 				{	// flash frame
750 					sb_updates = 0;
751 				}
752 				else
753 				{
754 					Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
755 				}
756 
757 				if (time &&	time > cl.time - 2)
758 					sb_updates = 0;
759 			}
760 		}
761 	}
762 	else
763 	{
764 	// sigils
765 		for (i=0 ; i<4 ; i++)
766 		{
767 			if (cl.items & (1<<(28+i)))
768 			{
769 				time = cl.item_gettime[28+i];
770 				if (time &&	time > cl.time - 2 && flashon )
771 				{	// flash frame
772 					sb_updates = 0;
773 				}
774 				else
775 					Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
776 				if (time &&	time > cl.time - 2)
777 					sb_updates = 0;
778 			}
779 		}
780 	}
781 }
782 
783 //=============================================================================
784 
785 /*
786 ===============
787 Sbar_DrawFrags
788 ===============
789 */
Sbar_DrawFrags(void)790 void Sbar_DrawFrags (void)
791 {
792 	int				i, k, l;
793 	int				top, bottom;
794 	int				x, y, f;
795 	int				xofs;
796 	char			num[12];
797 	scoreboard_t	*s;
798 
799 	Sbar_SortFrags ();
800 
801 // draw the text
802 	l = scoreboardlines <= 4 ? scoreboardlines : 4;
803 
804 	x = 23;
805 	if (cl.gametype == GAME_DEATHMATCH)
806 		xofs = 0;
807 	else
808 		xofs = (vid.width - 320)>>1;
809 	y = vid.height - SBAR_HEIGHT - 23;
810 
811 	for (i=0 ; i<l ; i++)
812 	{
813 		k = fragsort[i];
814 		s = &cl.scores[k];
815 		if (!s->name[0])
816 			continue;
817 
818 	// draw background
819 		top = s->colors & 0xf0;
820 		bottom = (s->colors & 15)<<4;
821 		top = Sbar_ColorForMap (top);
822 		bottom = Sbar_ColorForMap (bottom);
823 
824 		Draw_Fill (xofs + x*8 + 10, y, 28, 4, top);
825 		Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom);
826 
827 	// draw number
828 		f = s->frags;
829 		sprintf (num, "%3i",f);
830 
831 		Sbar_DrawCharacter ( (x+1)*8 , -24, num[0]);
832 		Sbar_DrawCharacter ( (x+2)*8 , -24, num[1]);
833 		Sbar_DrawCharacter ( (x+3)*8 , -24, num[2]);
834 
835 		if (k == cl.viewentity - 1)
836 		{
837 			Sbar_DrawCharacter (x*8+2, -24, 16);
838 			Sbar_DrawCharacter ( (x+4)*8-4, -24, 17);
839 		}
840 		x+=4;
841 	}
842 }
843 
844 //=============================================================================
845 
846 
847 /*
848 ===============
849 Sbar_DrawFace
850 ===============
851 */
Sbar_DrawFace(void)852 void Sbar_DrawFace (void)
853 {
854 	int		f, anim;
855 
856 // PGM 01/19/97 - team color drawing
857 // PGM 03/02/97 - fixed so color swatch only appears in CTF modes
858 	if (rogue &&
859         (cl.maxclients != 1) &&
860         (teamplay.value>3) &&
861         (teamplay.value<7))
862 	{
863 		int				top, bottom;
864 		int				xofs;
865 		char			num[12];
866 		scoreboard_t	*s;
867 
868 		s = &cl.scores[cl.viewentity - 1];
869 		// draw background
870 		top = s->colors & 0xf0;
871 		bottom = (s->colors & 15)<<4;
872 		top = Sbar_ColorForMap (top);
873 		bottom = Sbar_ColorForMap (bottom);
874 
875 		if (cl.gametype == GAME_DEATHMATCH)
876 			xofs = 113;
877 		else
878 			xofs = ((vid.width - 320)>>1) + 113;
879 
880 		Sbar_DrawPic (112, 0, rsb_teambord);
881 		Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, top);
882 		Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, bottom);
883 
884 		// draw number
885 		f = s->frags;
886 		sprintf (num, "%3i",f);
887 
888 		if (top==8)
889 		{
890 			if (num[0] != ' ')
891 				Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
892 			if (num[1] != ' ')
893 				Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
894 			if (num[2] != ' ')
895 				Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
896 		}
897 		else
898 		{
899 			Sbar_DrawCharacter ( 109, 3, num[0]);
900 			Sbar_DrawCharacter ( 116, 3, num[1]);
901 			Sbar_DrawCharacter ( 123, 3, num[2]);
902 		}
903 
904 		return;
905 	}
906 // PGM 01/19/97 - team color drawing
907 
908 	if ( (cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY) )
909 	== (IT_INVISIBILITY | IT_INVULNERABILITY) )
910 	{
911 		Sbar_DrawPic (112, 0, sb_face_invis_invuln);
912 		return;
913 	}
914 	if (cl.items & IT_QUAD)
915 	{
916 		Sbar_DrawPic (112, 0, sb_face_quad );
917 		return;
918 	}
919 	if (cl.items & IT_INVISIBILITY)
920 	{
921 		Sbar_DrawPic (112, 0, sb_face_invis );
922 		return;
923 	}
924 	if (cl.items & IT_INVULNERABILITY)
925 	{
926 		Sbar_DrawPic (112, 0, sb_face_invuln);
927 		return;
928 	}
929 
930 	if (cl.stats[STAT_HEALTH] >= 100)
931 		f = 4;
932 	else
933 		f = cl.stats[STAT_HEALTH] / 20;
934 
935 	if (cl.time <= cl.faceanimtime)
936 	{
937 		anim = 1;
938 		sb_updates = 0;		// make sure the anim gets drawn over
939 	}
940 	else
941 		anim = 0;
942 	Sbar_DrawPic (112, 0, sb_faces[f][anim]);
943 }
944 
945 /*
946 ===============
947 Sbar_Draw
948 ===============
949 */
Sbar_Draw(void)950 void Sbar_Draw (void)
951 {
952 	if (scr_con_current == vid.height)
953 		return;		// console is full screen
954 
955 	if (sb_updates >= vid.numpages && !gl_clear.value && !scr_showedicts.value)
956 		return;
957 
958 	scr_copyeverything = 1;
959 
960 	sb_updates++;
961 
962 	if (sb_lines && vid.width > 320)
963 		Draw_TileClear (0, vid.height - sb_lines, vid.width, sb_lines);
964 
965 	if (sb_lines > 24)
966 	{
967 		Sbar_DrawInventory ();
968 		if (cl.maxclients != 1)
969 			Sbar_DrawFrags ();
970 	}
971 
972 	if (sb_showscores || cl.stats[STAT_HEALTH] <= 0)
973 	{
974 		Sbar_DrawPic (0, 0, sb_scorebar);
975 		Sbar_DrawScoreboard ();
976 		sb_updates = 0;
977 	}
978 	else if (sb_lines)
979 	{
980 		Sbar_DrawPic (0, 0, sb_sbar);
981 
982    // keys (hipnotic only)
983       //MED 01/04/97 moved keys here so they would not be overwritten
984       if (hipnotic)
985       {
986          if (cl.items & IT_KEY1)
987             Sbar_DrawPic (209, 3, sb_items[0]);
988          if (cl.items & IT_KEY2)
989             Sbar_DrawPic (209, 12, sb_items[1]);
990       }
991    // armor
992 		if (cl.items & IT_INVULNERABILITY)
993 		{
994 			Sbar_DrawNum (24, 0, 666, 3, 1);
995 			Sbar_DrawPic (0, 0, draw_disc);
996 		}
997 		else
998 		{
999 			if (rogue)
1000 			{
1001 				Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3,
1002 								cl.stats[STAT_ARMOR] <= 25);
1003 				if (cl.items & RIT_ARMOR3)
1004 					Sbar_DrawPic (0, 0, sb_armor[2]);
1005 				else if (cl.items & RIT_ARMOR2)
1006 					Sbar_DrawPic (0, 0, sb_armor[1]);
1007 				else if (cl.items & RIT_ARMOR1)
1008 					Sbar_DrawPic (0, 0, sb_armor[0]);
1009 			}
1010 			else
1011 			{
1012 				Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3
1013 				, cl.stats[STAT_ARMOR] <= 25);
1014 				if (cl.items & IT_ARMOR3)
1015 					Sbar_DrawPic (0, 0, sb_armor[2]);
1016 				else if (cl.items & IT_ARMOR2)
1017 					Sbar_DrawPic (0, 0, sb_armor[1]);
1018 				else if (cl.items & IT_ARMOR1)
1019 					Sbar_DrawPic (0, 0, sb_armor[0]);
1020 			}
1021 		}
1022 
1023 	// face
1024 		Sbar_DrawFace ();
1025 
1026 	// health
1027 		Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3
1028 		, cl.stats[STAT_HEALTH] <= 25);
1029 
1030 	// ammo icon
1031 		if (rogue)
1032 		{
1033 			if (cl.items & RIT_SHELLS)
1034 				Sbar_DrawPic (224, 0, sb_ammo[0]);
1035 			else if (cl.items & RIT_NAILS)
1036 				Sbar_DrawPic (224, 0, sb_ammo[1]);
1037 			else if (cl.items & RIT_ROCKETS)
1038 				Sbar_DrawPic (224, 0, sb_ammo[2]);
1039 			else if (cl.items & RIT_CELLS)
1040 				Sbar_DrawPic (224, 0, sb_ammo[3]);
1041 			else if (cl.items & RIT_LAVA_NAILS)
1042 				Sbar_DrawPic (224, 0, rsb_ammo[0]);
1043 			else if (cl.items & RIT_PLASMA_AMMO)
1044 				Sbar_DrawPic (224, 0, rsb_ammo[1]);
1045 			else if (cl.items & RIT_MULTI_ROCKETS)
1046 				Sbar_DrawPic (224, 0, rsb_ammo[2]);
1047 		}
1048 		else
1049 		{
1050 			if (cl.items & IT_SHELLS)
1051 				Sbar_DrawPic (224, 0, sb_ammo[0]);
1052 			else if (cl.items & IT_NAILS)
1053 				Sbar_DrawPic (224, 0, sb_ammo[1]);
1054 			else if (cl.items & IT_ROCKETS)
1055 				Sbar_DrawPic (224, 0, sb_ammo[2]);
1056 			else if (cl.items & IT_CELLS)
1057 				Sbar_DrawPic (224, 0, sb_ammo[3]);
1058 		}
1059 
1060 		Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3,
1061 					  cl.stats[STAT_AMMO] <= 10);
1062 	}
1063 
1064 	if (vid.width > 320) {
1065 		if (cl.gametype == GAME_DEATHMATCH)
1066 			Sbar_MiniDeathmatchOverlay ();
1067 	}
1068 }
1069 
1070 //=============================================================================
1071 
1072 /*
1073 ==================
1074 Sbar_IntermissionNumber
1075 
1076 ==================
1077 */
Sbar_IntermissionNumber(int x,int y,int num,int digits,int color)1078 void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)
1079 {
1080 	char			str[12];
1081 	char			*ptr;
1082 	int				l, frame;
1083 
1084 	l = Sbar_itoa (num, str);
1085 	ptr = str;
1086 	if (l > digits)
1087 		ptr += (l-digits);
1088 	if (l < digits)
1089 		x += (digits-l)*24;
1090 
1091 	while (*ptr)
1092 	{
1093 		if (*ptr == '-')
1094 			frame = STAT_MINUS;
1095 		else
1096 			frame = *ptr -'0';
1097 
1098 		Draw_TransPic (x,y,sb_nums[color][frame]);
1099 		x += 24;
1100 		ptr++;
1101 	}
1102 }
1103 
1104 /*
1105 ==================
1106 Sbar_DeathmatchOverlay
1107 
1108 ==================
1109 */
Sbar_DeathmatchOverlay(void)1110 void Sbar_DeathmatchOverlay (void)
1111 {
1112 	qpic_t			*pic;
1113 	int				i, k, l;
1114 	int				top, bottom;
1115 	int				x, y, f;
1116 	char			num[12];
1117 	scoreboard_t	*s;
1118 
1119 	scr_copyeverything = 1;
1120 	scr_fullupdate = 0;
1121 
1122 	pic = Draw_CachePic ("gfx/ranking.lmp");
1123 	M_DrawPic ((320-pic->width)/2, 8, pic);
1124 
1125 // scores
1126 	Sbar_SortFrags ();
1127 
1128 // draw the text
1129 	l = scoreboardlines;
1130 
1131 	x = 80 + ((vid.width - 320)>>1);
1132 	y = 40;
1133 	for (i=0 ; i<l ; i++)
1134 	{
1135 		k = fragsort[i];
1136 		s = &cl.scores[k];
1137 		if (!s->name[0])
1138 			continue;
1139 
1140 	// draw background
1141 		top = s->colors & 0xf0;
1142 		bottom = (s->colors & 15)<<4;
1143 		top = Sbar_ColorForMap (top);
1144 		bottom = Sbar_ColorForMap (bottom);
1145 
1146 		Draw_Fill ( x, y, 40, 4, top);
1147 		Draw_Fill ( x, y+4, 40, 4, bottom);
1148 
1149 	// draw number
1150 		f = s->frags;
1151 		sprintf (num, "%3i",f);
1152 
1153 		Draw_Character ( x+8 , y, num[0]);
1154 		Draw_Character ( x+16 , y, num[1]);
1155 		Draw_Character ( x+24 , y, num[2]);
1156 
1157 		if (k == cl.viewentity - 1)
1158 			Draw_Character ( x - 8, y, 12);
1159 
1160 #if 0
1161 {
1162 	int				total;
1163 	int				n, minutes, tens, units;
1164 
1165 	// draw time
1166 		total = cl.completed_time - s->entertime;
1167 		minutes = (int)total/60;
1168 		n = total - minutes*60;
1169 		tens = n/10;
1170 		units = n%10;
1171 
1172 		sprintf (num, "%3i:%i%i", minutes, tens, units);
1173 
1174 		Draw_String ( x+48 , y, num);
1175 }
1176 #endif
1177 
1178 	// draw name
1179 		Draw_String (x+64, y, s->name);
1180 
1181 		y += 10;
1182 	}
1183 }
1184 
1185 /*
1186 ==================
1187 Sbar_DeathmatchOverlay
1188 
1189 ==================
1190 */
Sbar_MiniDeathmatchOverlay(void)1191 void Sbar_MiniDeathmatchOverlay (void)
1192 {
1193 	qpic_t			*pic;
1194 	int				i, k, l;
1195 	int				top, bottom;
1196 	int				x, y, f;
1197 	char			num[12];
1198 	scoreboard_t	*s;
1199 	int				numlines;
1200 
1201 	if (vid.width < 512 || !sb_lines)
1202 		return;
1203 
1204 	scr_copyeverything = 1;
1205 	scr_fullupdate = 0;
1206 
1207 // scores
1208 	Sbar_SortFrags ();
1209 
1210 // draw the text
1211 	l = scoreboardlines;
1212 	y = vid.height - sb_lines;
1213 	numlines = sb_lines/8;
1214 	if (numlines < 3)
1215 		return;
1216 
1217 	//find us
1218 	for (i = 0; i < scoreboardlines; i++)
1219 		if (fragsort[i] == cl.viewentity - 1)
1220 			break;
1221 
1222     if (i == scoreboardlines) // we're not there
1223             i = 0;
1224     else // figure out start
1225             i = i - numlines/2;
1226 
1227     if (i > scoreboardlines - numlines)
1228             i = scoreboardlines - numlines;
1229     if (i < 0)
1230             i = 0;
1231 
1232 	x = 324;
1233 	for (/* */; i < scoreboardlines && y < vid.height - 8 ; i++)
1234 	{
1235 		k = fragsort[i];
1236 		s = &cl.scores[k];
1237 		if (!s->name[0])
1238 			continue;
1239 
1240 	// draw background
1241 		top = s->colors & 0xf0;
1242 		bottom = (s->colors & 15)<<4;
1243 		top = Sbar_ColorForMap (top);
1244 		bottom = Sbar_ColorForMap (bottom);
1245 
1246 		Draw_Fill ( x, y+1, 40, 3, top);
1247 		Draw_Fill ( x, y+4, 40, 4, bottom);
1248 
1249 	// draw number
1250 		f = s->frags;
1251 		sprintf (num, "%3i",f);
1252 
1253 		Draw_Character ( x+8 , y, num[0]);
1254 		Draw_Character ( x+16 , y, num[1]);
1255 		Draw_Character ( x+24 , y, num[2]);
1256 
1257 		if (k == cl.viewentity - 1) {
1258 			Draw_Character ( x, y, 16);
1259 			Draw_Character ( x + 32, y, 17);
1260 		}
1261 
1262 #if 0
1263 {
1264 	int				total;
1265 	int				n, minutes, tens, units;
1266 
1267 	// draw time
1268 		total = cl.completed_time - s->entertime;
1269 		minutes = (int)total/60;
1270 		n = total - minutes*60;
1271 		tens = n/10;
1272 		units = n%10;
1273 
1274 		sprintf (num, "%3i:%i%i", minutes, tens, units);
1275 
1276 		Draw_String ( x+48 , y, num);
1277 }
1278 #endif
1279 
1280 	// draw name
1281 		Draw_String (x+48, y, s->name);
1282 
1283 		y += 8;
1284 	}
1285 }
1286 
1287 /*
1288 ==================
1289 Sbar_IntermissionOverlay
1290 
1291 ==================
1292 */
Sbar_IntermissionOverlay(void)1293 void Sbar_IntermissionOverlay (void)
1294 {
1295 	qpic_t	*pic;
1296 	int	dig, Digits, Offset;
1297 	int	num;
1298 
1299 	scr_copyeverything = 1;
1300 	scr_fullupdate = 0;
1301 
1302 	if (cl.gametype == GAME_DEATHMATCH)
1303 	{
1304 		Sbar_DeathmatchOverlay ();
1305 		return;
1306 	}
1307 
1308 	pic = Draw_CachePic ("gfx/complete.lmp");
1309 	Draw_Pic (64, 24, pic);
1310 
1311 	pic = Draw_CachePic ("gfx/inter.lmp");
1312 	Draw_TransPic (0, 56, pic);
1313 
1314 // time
1315 	dig = cl.completed_time/60;
1316 	Sbar_IntermissionNumber (160, 64, dig, 3, 0);
1317 	num = cl.completed_time - dig*60;
1318 	Draw_TransPic (234,64,sb_colon);
1319 	Draw_TransPic (246,64,sb_nums[0][num/10]);
1320 	Draw_TransPic (266,64,sb_nums[0][num%10]);
1321 
1322 	Sbar_IntermissionNumber (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1323 	Draw_TransPic (232,104,sb_slash);
1324 	Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1325 
1326 	Digits = cl.stats[STAT_TOTALMONSTERS] > 999 ? 4 : 3; // Handle 4-digit monsters ...
1327 	Offset = (Digits - 3) * 24;
1328 
1329 	Sbar_IntermissionNumber (160 - Offset * 2, 144, cl.stats[STAT_MONSTERS], Digits, 0);
1330 	Draw_TransPic (232 - Offset, 144, sb_slash);
1331 	Sbar_IntermissionNumber (240 - Offset, 144, cl.stats[STAT_TOTALMONSTERS], Digits, 0);
1332 
1333 }
1334 
1335 
1336 /*
1337 ==================
1338 Sbar_FinaleOverlay
1339 
1340 ==================
1341 */
Sbar_FinaleOverlay(void)1342 void Sbar_FinaleOverlay (void)
1343 {
1344 	qpic_t	*pic;
1345 
1346 	scr_copyeverything = 1;
1347 
1348 	pic = Draw_CachePic ("gfx/finale.lmp");
1349 	Draw_TransPic ( (vid.width-pic->width)/2, 16, pic);
1350 }
1351