1 /*
2 	sbar.c
3 
4 	Status bar
5 
6 	Copyright (C) 1996-1997  Id Software, Inc.
7 
8 	This program is free software; you can redistribute it and/or
9 	modify it under the terms of the GNU General Public License
10 	as published by the Free Software Foundation; either version 2
11 	of the License, or (at your option) any later version.
12 
13 	This program is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 	See the GNU General Public License for more details.
18 
19 	You should have received a copy of the GNU General Public License
20 	along with this program; if not, write to:
21 
22 		Free Software Foundation, Inc.
23 		59 Temple Place - Suite 330
24 		Boston, MA  02111-1307, USA
25 
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #endif
34 #ifdef HAVE_STRINGS_H
35 # include <strings.h>
36 #endif
37 
38 #include <time.h>
39 
40 #include "QF/cmd.h"
41 #include "QF/console.h"
42 #include "QF/cvar.h"
43 #include "QF/draw.h"
44 #include "QF/dstring.h"
45 #include "QF/gib.h"
46 #include "QF/screen.h"
47 #include "QF/sys.h"
48 #include "QF/va.h"
49 #include "QF/vid.h"
50 #include "QF/view.h"
51 #include "QF/wad.h"
52 
53 #include "QF/plugin/console.h"
54 #include "QF/plugin/vid_render.h"
55 
56 #include "client.h"
57 #include "compat.h"
58 #include "game.h"
59 #include "sbar.h"
60 #include "server.h"
61 
62 int         sb_updates;				// if >= vid.numpages, no update needed
63 
64 #define STAT_MINUS		10			// num frame for '-' stats digit
65 
66 qpic_t     *sb_nums[2][11];
67 qpic_t     *sb_colon, *sb_slash;
68 qpic_t     *sb_ibar;
69 qpic_t     *sb_sbar;
70 qpic_t     *sb_scorebar;
71 
72 qpic_t     *sb_weapons[7][8];		// 0 is active, 1 is owned, 2-5 are flashes
73 qpic_t     *sb_ammo[4];
74 qpic_t     *sb_sigil[4];
75 qpic_t     *sb_armor[3];
76 qpic_t     *sb_items[32];
77 
78 qpic_t     *sb_faces[7][2];			// 0 is gibbed, 1 is dead, 2-6 are alive
79 									// 0 is static, 1 is temporary animation
80 qpic_t     *sb_face_invis;
81 qpic_t     *sb_face_quad;
82 qpic_t     *sb_face_invuln;
83 qpic_t     *sb_face_invis_invuln;
84 
85 qboolean    sb_showscores;
86 
87 int         sb_lines;				// scan lines to draw
88 qboolean	hudswap;
89 
90 qpic_t     *rsb_invbar[2];
91 qpic_t     *rsb_weapons[5];
92 qpic_t     *rsb_items[2];
93 qpic_t     *rsb_ammo[3];
94 qpic_t     *rsb_teambord;			// PGM 01/19/97 - team color border
95 
96 								// MED 01/04/97 added two more weapons + 3
97 								// alternates for grenade launcher
98 qpic_t     *hsb_weapons[7][5];	// 0 is active, 1 is owned, 2-5 are flashes
99 
100 								// MED 01/04/97 added array to simplify
101 								// weapon parsing
102 int         hipweapons[4] =
103 	{ HIT_LASER_CANNON_BIT, HIT_MJOLNIR_BIT, 4, HIT_PROXIMITY_GUN_BIT };
104 qpic_t     *hsb_items[2];			// MED 01/04/97 added hipnotic items array
105 
106 cvar_t     *hud_sbar;
107 cvar_t     *hud_swap;
108 cvar_t     *hud_scoreboard_gravity;
109 cvar_t     *scr_centertime;
110 cvar_t     *scr_printspeed;
111 
112 static view_t *sbar_view;
113 static view_t *sbar_inventory_view;
114 static view_t *sbar_frags_view;
115 
116 static view_t *hud_view;
117 static view_t *hud_inventory_view;
118 static view_t *hud_armament_view;
119 static view_t *hud_frags_view;
120 
121 static view_t *overlay_view;
122 static view_t *stuff_view;
123 static view_t *main_view;
124 
125 static void
hud_swap_f(cvar_t * var)126 hud_swap_f (cvar_t *var)
127 {
128 	hudswap = var->int_val;
129 	if (var->int_val) {
130 		hud_armament_view->gravity = grav_southwest;
131 		hud_armament_view->children[0]->gravity = grav_northwest;
132 		hud_armament_view->children[1]->gravity = grav_southeast;
133 		stuff_view->gravity = grav_southeast;
134 	} else {
135 		hud_armament_view->gravity = grav_southeast;
136 		hud_armament_view->children[0]->gravity = grav_northeast;
137 		hud_armament_view->children[1]->gravity = grav_southwest;
138 		stuff_view->gravity = grav_southwest;
139 	}
140 	view_move (hud_armament_view, hud_armament_view->xpos,
141 			   hud_armament_view->ypos);
142 	view_move (stuff_view, stuff_view->xpos, stuff_view->ypos);
143 }
144 
145 static void
hud_scoreboard_gravity_f(cvar_t * var)146 hud_scoreboard_gravity_f (cvar_t *var)
147 {
148 	grav_t      grav;
149 
150 	if (strequal (var->string, "center"))
151 		grav = grav_center;
152 	else if (strequal (var->string, "northwest"))
153 		grav = grav_northwest;
154 	else if (strequal (var->string, "north"))
155 		grav = grav_north;
156 	else if (strequal (var->string, "northeast"))
157 		grav = grav_northeast;
158 	else if (strequal (var->string, "west"))
159 		grav = grav_west;
160 	else if (strequal (var->string, "east"))
161 		grav = grav_east;
162 	else if (strequal (var->string, "southwest"))
163 		grav = grav_southwest;
164 	else if (strequal (var->string, "south"))
165 		grav = grav_south;
166 	else if (strequal (var->string, "southeast"))
167 		grav = grav_southeast;
168 	else
169 		grav = grav_center;
170 	overlay_view->gravity = grav;
171 	view_move (overlay_view, overlay_view->xpos, overlay_view->ypos);
172 }
173 
174 static void
calc_sb_lines(cvar_t * var)175 calc_sb_lines (cvar_t *var)
176 {
177 	int        stuff_y;
178 
179 	if (var->int_val >= 120) {
180 		sb_lines = 0;
181 		stuff_y = 0;
182 	} else if (var->int_val >= 110) {
183 		sb_lines = 24;
184 		sbar_inventory_view->visible = 0;
185 		hud_inventory_view->visible = 0;
186 		hud_armament_view->visible = 0;
187 		stuff_y = 32;
188 	} else {
189 		sb_lines = 48;
190 		sbar_inventory_view->visible = 1;
191 		hud_inventory_view->visible = 1;
192 		hud_armament_view->visible = 1;
193 		stuff_y = 48;
194 	}
195 	if (sb_lines) {
196 		sbar_view->visible = 1;
197 		hud_view->visible = 1;
198 		view_resize (sbar_view, sbar_view->xlen, sb_lines);
199 		view_resize (hud_view, hud_view->xlen, sb_lines);
200 	} else {
201 		sbar_view->visible = 0;
202 		hud_view->visible = 0;
203 	}
204 	view_move (stuff_view, stuff_view->xpos, stuff_y);
205 }
206 
207 static void
hud_sbar_f(cvar_t * var)208 hud_sbar_f (cvar_t *var)
209 {
210 	r_data->vid->recalc_refdef = true;
211 	if (r_data->scr_viewsize)
212 		calc_sb_lines (r_data->scr_viewsize);
213 	r_data->lineadj = var->int_val ? sb_lines : 0;
214 	if (var->int_val) {
215 		view_remove (main_view, main_view->children[0]);
216 		view_insert (main_view, sbar_view, 0);
217 	} else {
218 		view_remove (main_view, main_view->children[0]);
219 		view_insert (main_view, hud_view, 0);
220 	}
221 }
222 
223 static void
viewsize_f(cvar_t * var)224 viewsize_f (cvar_t *var)
225 {
226 	calc_sb_lines (var);
227 	if (hud_sbar)
228 		r_data->lineadj = hud_sbar->int_val ? sb_lines : 0;
229 }
230 
231 
232 static int
Sbar_ColorForMap(int m)233 Sbar_ColorForMap (int m)
234 {
235 	return (bound (0, m, 13) * 16) + 8;
236 }
237 
238 static void
Sbar_ShowScores(void)239 Sbar_ShowScores (void)
240 {
241 	if (sb_showscores)
242 		return;
243 
244 	sb_showscores = true;
245 	sb_updates = 0;
246 }
247 
248 static void
Sbar_DontShowScores(void)249 Sbar_DontShowScores (void)
250 {
251 	sb_showscores = false;
252 	sb_updates = 0;
253 }
254 
255 void
Sbar_Changed(void)256 Sbar_Changed (void)
257 {
258 	sb_updates = 0;						// update next frame
259 }
260 
261 static void
draw_pic(view_t * view,int x,int y,qpic_t * pic)262 draw_pic (view_t *view, int x, int y, qpic_t *pic)
263 {
264 	r_funcs->Draw_Pic (view->xabs + x, view->yabs + y, pic);
265 }
266 
267 static inline void
draw_cachepic(view_t * view,int x,int y,const char * name,int cent)268 draw_cachepic (view_t *view, int x, int y, const char *name, int cent)
269 {
270 	qpic_t *pic = r_funcs->Draw_CachePic (name, true);
271 	if (cent)
272 		x += (view->xlen - pic->width) / 2;
273 	r_funcs->Draw_Pic (view->xabs + x, view->yabs + y, pic);
274 }
275 
276 static inline void
draw_subpic(view_t * view,int x,int y,qpic_t * pic,int srcx,int srcy,int width,int height)277 draw_subpic (view_t *view, int x, int y, qpic_t *pic,
278 		     int srcx, int srcy, int width, int height)
279 {
280 	r_funcs->Draw_SubPic (view->xabs + x, view->yabs + y, pic,
281 				 srcx, srcy, width, height);
282 }
283 
284 static inline void
draw_transpic(view_t * view,int x,int y,qpic_t * pic)285 draw_transpic (view_t *view, int x, int y, qpic_t *pic)
286 {
287 	r_funcs->Draw_Pic (view->xabs + x, view->yabs + y, pic);
288 }
289 
290 
291 // drawing routines are reletive to the status bar location
292 
293 static inline void
draw_character(view_t * view,int x,int y,int c)294 draw_character (view_t *view, int x, int y, int c)
295 {
296 	r_funcs->Draw_Character (view->xabs + x, view->yabs + y, c);
297 }
298 
299 static inline void
draw_string(view_t * view,int x,int y,const char * str)300 draw_string (view_t *view, int x, int y, const char *str)
301 {
302 	r_funcs->Draw_String (view->xabs + x, view->yabs + y, str);
303 }
304 
305 static inline void
draw_altstring(view_t * view,int x,int y,const char * str)306 draw_altstring (view_t *view, int x, int y, const char *str)
307 {
308 	r_funcs->Draw_AltString (view->xabs + x, view->yabs + y, str);
309 }
310 
311 static inline void
draw_nstring(view_t * view,int x,int y,const char * str,int n)312 draw_nstring (view_t *view, int x, int y, const char *str, int n)
313 {
314 	r_funcs->Draw_nString (view->xabs + x, view->yabs + y, str, n);
315 }
316 
317 static inline void
draw_fill(view_t * view,int x,int y,int w,int h,int col)318 draw_fill (view_t *view, int x, int y, int w, int h, int col)
319 {
320 	r_funcs->Draw_Fill (view->xabs + x, view->yabs + y, w, h, col);
321 }
322 
323 static void
draw_num(view_t * view,int x,int y,int num,int digits,int color)324 draw_num (view_t *view, int x, int y, int num, int digits, int color)
325 {
326 	char        str[12];
327 	char       *ptr;
328 	int         l, frame;
329 
330 	if (num > 999999999)
331 		num = 999999999;
332 
333 	l = snprintf (str, sizeof (str), "%d", num);
334 	ptr = str;
335 	if (l > digits)
336 		ptr += (l - digits);
337 	if (l < digits)
338 		x += (digits - l) * 24;
339 
340 	while (*ptr) {
341 		if (*ptr == '-')
342 			frame = STAT_MINUS;
343 		else
344 			frame = *ptr - '0';
345 
346 		draw_transpic (view, x, y, sb_nums[color][frame]);
347 		x += 24;
348 		ptr++;
349 	}
350 }
351 
352 static inline void
draw_smallnum(view_t * view,int x,int y,int n,int packed,int colored)353 draw_smallnum (view_t *view, int x, int y, int n, int packed, int colored)
354 {
355 	char        num[4];
356 
357 	packed = packed != 0;				// ensure 0 or 1
358 
359 	if (n > 999)
360 		n = 999;
361 
362 	snprintf (num, sizeof (num), "%3d", n);
363 	if (colored) {
364 		if (num[0] != ' ')
365 			num[0] = 18 + num[0] - '0';
366 		if (num[1] != ' ')
367 			num[1] = 18 + num[1] - '0';
368 		if (num[2] != ' ')
369 			num[2] = 18 + num[2] - '0';
370 	}
371 	draw_character (view, x + packed, y, num[0]);
372 	draw_character (view, x + 8, y, num[1]);
373 	draw_character (view, x + 16 - packed, y, num[2]);
374 }
375 
376 static void
draw_tile(view_t * view)377 draw_tile (view_t *view)
378 {
379 	r_funcs->Draw_TileClear (view->xabs, view->yabs, view->xlen, view->ylen);
380 }
381 
382 static void
draw_ammo_sbar(view_t * view)383 draw_ammo_sbar (view_t *view)
384 {
385 	int         i, count;
386 
387 	// ammo counts
388 	for (i = 0; i < 4; i++) {
389 		count = cl.stats[STAT_SHELLS + i];
390 		draw_smallnum (view, (6 * i + 1) * 8 + 2, 0, count, 0, 1);
391 	}
392 }
393 
394 static void
draw_ammo_hud(view_t * view)395 draw_ammo_hud (view_t *view)
396 {
397 	int         i, count;
398 
399 	// ammo counts
400 	for (i = 0; i < 4; i++) {
401 		count = cl.stats[STAT_SHELLS + i];
402 		draw_subpic (view, 0, i * 11, sb_ibar, 3 + (i * 48), 0, 42, 11);
403 		draw_smallnum (view, 7, i * 11, count, 0, 1);
404 	}
405 }
406 
407 static int
calc_flashon(float time,int mask)408 calc_flashon (float time, int mask)
409 {
410 	int         flashon;
411 
412 	flashon = (int) ((cl.time - time) * 10);
413 	if (flashon < 0)
414 		flashon = 0;
415 	if (flashon >= 10) {
416 		if (cl.stats[STAT_ACTIVEWEAPON] == mask)
417 			flashon = 1;
418 		else
419 			flashon = 0;
420 	} else
421 		flashon = (flashon % 5) + 2;
422 	return flashon;
423 }
424 
425 static void
draw_weapons_sbar(view_t * view)426 draw_weapons_sbar (view_t *view)
427 {
428 	int         flashon, i;
429 
430 	for (i = 0; i < 7; i++) {
431 		if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN << i)) {
432 			flashon = calc_flashon (cl.item_gettime[i], IT_SHOTGUN << i);
433 			draw_pic (view, i * 24, 0, sb_weapons[flashon][i]);
434 			if (flashon > 1)
435 				sb_updates = 0;			// force update to remove flash
436 		}
437 	}
438 }
439 
440 static void
draw_weapons_hud(view_t * view)441 draw_weapons_hud (view_t *view)
442 {
443 	int         flashon, i, x = 0;
444 
445 	if (view->parent->gravity == grav_southeast)
446 		x = view->xlen - 24;
447 
448 	for (i = r_data->vid->conheight < 204; i < 7; i++) {
449 		if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN << i)) {
450 			flashon = calc_flashon (cl.item_gettime[i], IT_SHOTGUN << i);
451 			draw_subpic (view, x, i * 16, sb_weapons[flashon][i], 0, 0, 24, 16);
452 			if (flashon > 1)
453 				sb_updates = 0;			// force update to remove flash
454 		}
455 	}
456 }
457 
458 static void
draw_items(view_t * view)459 draw_items (view_t *view)
460 {
461 	float       time;
462 	int         flashon = 0, i;
463 
464 	for (i = 0; i < 6; i++) {
465 		if (cl.stats[STAT_ITEMS] & (1 << (17 + i))) {
466 			time = cl.item_gettime[17 + i];
467 			if (time && time > cl.time - 2 && flashon) {	// Flash frame
468 				sb_updates = 0;
469 			} else {
470 				draw_pic (view, i * 16, 0, sb_items[i]);
471 			}
472 			if (time && time > cl.time - 2)
473 				sb_updates = 0;
474 		}
475 	}
476 }
477 
478 static void
draw_sigils(view_t * view)479 draw_sigils (view_t *view)
480 {
481 	float       time;
482 	int         flashon = 0, i;
483 
484 	for (i = 0; i < 4; i++) {
485 		if (cl.stats[STAT_ITEMS] & (1 << (28 + i))) {
486 			time = cl.item_gettime[28 + i];
487 			if (time && time > cl.time - 2 && flashon) {	// flash frame
488 				sb_updates = 0;
489 			} else {
490 				draw_pic (view, i * 8, 0, sb_sigil[i]);
491 			}
492 			if (time && time > cl.time - 2)
493 				sb_updates = 0;
494 		}
495 	}
496 }
497 
498 static void
draw_inventory_sbar(view_t * view)499 draw_inventory_sbar (view_t *view)
500 {
501 	draw_pic (view, 0, 0, sb_ibar);
502 	view_draw (view);
503 }
504 
505 
506 int         fragsort[MAX_SCOREBOARD];
507 char        scoreboardtext[MAX_SCOREBOARD][20];
508 int         scoreboardtop[MAX_SCOREBOARD];
509 int         scoreboardbottom[MAX_SCOREBOARD];
510 int         scoreboardcount[MAX_SCOREBOARD];
511 int         scoreboardlines;
512 
513 
514 static void
Sbar_SortFrags(void)515 Sbar_SortFrags (void)
516 {
517 	int         i, j, k;
518 
519 	// sort by frags
520 	scoreboardlines = 0;
521 	for (i = 0; i < cl.maxclients; i++) {
522 		if (cl.scores[i].name->value[0]) {
523 			fragsort[scoreboardlines] = i;
524 			scoreboardlines++;
525 		}
526 	}
527 
528 	for (i = 0; i < scoreboardlines; i++) {
529 		for (j = 0; j < (scoreboardlines - 1 - i); j++) {
530 			if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j + 1]].frags) {
531 				k = fragsort[j];
532 				fragsort[j] = fragsort[j + 1];
533 				fragsort[j + 1] = k;
534 			}
535 		}
536 	}
537 }
538 
539 
540 static void
draw_solo(view_t * view)541 draw_solo (view_t *view)
542 {
543 	char        str[80];
544 	int         minutes, seconds, tens, units;
545 	int         l;
546 
547 	draw_pic (view, 0, 0, sb_scorebar);
548 
549 	snprintf (str, sizeof (str), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS],
550 			  cl.stats[STAT_TOTALMONSTERS]);
551 	draw_string (view, 8, 4, str);
552 
553 	snprintf (str, sizeof (str), "Secrets :%3i /%3i", cl.stats[STAT_SECRETS],
554 			  cl.stats[STAT_TOTALSECRETS]);
555 	draw_string (view, 8, 12, str);
556 
557 	// time
558 	minutes = cl.time / 60;
559 	seconds = cl.time - (60 * minutes);
560 	tens = seconds / 10;
561 	units = seconds - (10 * tens);
562 	snprintf (str, sizeof (str), "Time :%3i:%i%i", minutes, tens, units);
563 	draw_string (view, 184, 4, str);
564 
565 	// draw level name
566 	l = strlen (cl.levelname);
567 	l = 232 - l * 4;
568 	draw_string (view, max (l, 152), 12, cl.levelname);
569 }
570 
571 static void
draw_frags(view_t * view)572 draw_frags (view_t *view)
573 {
574 	int         i, k, l, p = -1;
575 	int         top, bottom;
576 	int         x;
577 	scoreboard_t *s;
578 
579 	if (cl.maxclients == 1)
580 		return;
581 
582 	Sbar_SortFrags ();
583 
584 	// draw the text
585 	l = scoreboardlines <= 4 ? scoreboardlines : 4;
586 
587 	x = 0;
588 
589 	for (i = 0; i < l; i++) {
590 		k = fragsort[i];
591 		s = &cl.scores[k];
592 		if (!s->name->value[0])
593 			continue;
594 
595 		// draw background
596 		top = Sbar_ColorForMap (s->topcolor);
597 		bottom = Sbar_ColorForMap (s->bottomcolor);
598 
599 		draw_fill (view, x + 4, 1, 28, 4, top);
600 		draw_fill (view, x + 4, 5, 28, 3, bottom);
601 
602 		draw_smallnum (view, x + 6, 0, s->frags, 0, 0);
603 
604 		if (k == cl.viewentity - 1)
605 			p = i;
606 
607 		x += 32;
608 	}
609 	if (p != -1) {
610 		draw_character (view, p * 32, 0, 16);
611 		draw_character (view, p * 32 + 26, 0, 17);
612 	}
613 }
614 
615 static void
draw_face(view_t * view)616 draw_face (view_t *view)
617 {
618 	int         f, anim;
619 
620 	if ((cl.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY))
621 		== (IT_INVISIBILITY | IT_INVULNERABILITY)) {
622 		draw_pic (view, 112, 0, sb_face_invis_invuln);
623 		return;
624 	}
625 	if (cl.stats[STAT_ITEMS] & IT_QUAD) {
626 		draw_pic (view, 112, 0, sb_face_quad);
627 		return;
628 	}
629 	if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) {
630 		draw_pic (view, 112, 0, sb_face_invis);
631 		return;
632 	}
633 	if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) {
634 		draw_pic (view, 112, 0, sb_face_invuln);
635 		return;
636 	}
637 
638 	if (cl.stats[STAT_HEALTH] >= 100)
639 		f = 4;
640 	else
641 		f = cl.stats[STAT_HEALTH] / 20;
642 
643 	if (cl.time <= cl.faceanimtime) {
644 		anim = 1;
645 		sb_updates = 0;					// make sure the anim gets drawn over
646 	} else
647 		anim = 0;
648 	draw_pic (view, 112, 0, sb_faces[f][anim]);
649 }
650 
651 static void
draw_status_bar(view_t * view)652 draw_status_bar (view_t *view)
653 {
654 	draw_pic (view, 0, 0, sb_sbar);
655 }
656 
657 static inline void
draw_armor(view_t * view)658 draw_armor (view_t *view)
659 {
660 	if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) {
661 		draw_num (view, 24, 0, 666, 3, 1);
662 	} else {
663 		draw_num (view, 24, 0, cl.stats[STAT_ARMOR], 3,
664 				  cl.stats[STAT_ARMOR] <= 25);
665 		if (cl.stats[STAT_ITEMS] & IT_ARMOR3)
666 			draw_pic (view, 0, 0, sb_armor[2]);
667 		else if (cl.stats[STAT_ITEMS] & IT_ARMOR2)
668 			draw_pic (view, 0, 0, sb_armor[1]);
669 		else if (cl.stats[STAT_ITEMS] & IT_ARMOR1)
670 			draw_pic (view, 0, 0, sb_armor[0]);
671 	}
672 }
673 
674 static inline void
draw_health(view_t * view)675 draw_health (view_t *view)
676 {
677 	draw_num (view, 136, 0, cl.stats[STAT_HEALTH], 3,
678 			  cl.stats[STAT_HEALTH] <= 25);
679 }
680 
681 static inline void
draw_ammo(view_t * view)682 draw_ammo (view_t *view)
683 {
684 	if (cl.stats[STAT_ITEMS] & IT_SHELLS)
685 		draw_pic (view, 224, 0, sb_ammo[0]);
686 	else if (cl.stats[STAT_ITEMS] & IT_NAILS)
687 		draw_pic (view, 224, 0, sb_ammo[1]);
688 	else if (cl.stats[STAT_ITEMS] & IT_ROCKETS)
689 		draw_pic (view, 224, 0, sb_ammo[2]);
690 	else if (cl.stats[STAT_ITEMS] & IT_CELLS)
691 		draw_pic (view, 224, 0, sb_ammo[3]);
692 
693 	draw_num (view, 248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
694 }
695 
696 static void
draw_status(view_t * view)697 draw_status (view_t *view)
698 {
699 	if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) {
700 		draw_solo (view);
701 		return;
702 	}
703 
704 	draw_armor (view);
705 	draw_face (view);
706 	draw_health (view);
707 	draw_ammo (view);
708 }
709 
710 static void
draw_rogue_weapons_sbar(view_t * view)711 draw_rogue_weapons_sbar (view_t *view)
712 {
713 	int         i;
714 
715 	draw_weapons_sbar (view);
716 
717 	// check for powered up weapon.
718 	if (cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN) {
719 		for (i = 0; i < 5; i++) {
720 			if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i)) {
721 				draw_pic (view, (i + 2) * 24, 0, rsb_weapons[i]);
722 			}
723 		}
724 	}
725 }
726 
727 static void
draw_rogue_weapons_hud(view_t * view)728 draw_rogue_weapons_hud (view_t *view)
729 {
730 	int         flashon, i, j;
731 	qpic_t     *pic;
732 
733 	for (i = r_data->vid->conheight < 204; i < 7; i++) {
734 		if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN << i)) {
735 			flashon = calc_flashon (cl.item_gettime[i], IT_SHOTGUN << i);
736 			if (i >= 2) {
737 				j = i - 2;
738 				if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << j))
739 					pic = rsb_weapons[j];
740 				else
741 					pic = sb_weapons[flashon][i];
742 			} else {
743 				pic = sb_weapons[flashon][i];
744 			}
745 			draw_subpic (view, 0, i * 16, pic, 0, 0, 24, 16);
746 			if (flashon > 1)
747 				sb_updates = 0;			// force update to remove flash
748 		}
749 	}
750 }
751 
752 static void
draw_rogue_ammo_hud(view_t * view)753 draw_rogue_ammo_hud (view_t *view)
754 {
755 	int         i, count;
756 	qpic_t     *pic;
757 
758 	if (cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN)
759 		pic = rsb_invbar[0];
760 	else
761 		pic = rsb_invbar[1];
762 
763 	for (i = 0; i < 4; i++) {
764 		count = cl.stats[STAT_SHELLS + i];
765 		draw_subpic (view, 0, i * 11, pic, 3 + (i * 48), 0, 42, 11);
766 		draw_smallnum (view, 7, i * 11, count, 0, 1);
767 	}
768 }
769 
770 static void
draw_rogue_items(view_t * view)771 draw_rogue_items (view_t *view)
772 {
773 	int         i;
774 	float       time;
775 
776 	draw_items (view);
777 
778 	for (i = 0; i < 2; i++) {
779 		if (cl.stats[STAT_ITEMS] & (1 << (29 + i))) {
780 			time = cl.item_gettime[29 + i];
781 			draw_pic (view, 96 + i * 16, 0, rsb_items[i]);
782 			if (time && time > (cl.time - 2))
783 				sb_updates = 0;
784 		}
785 	}
786 }
787 
788 static void
draw_rogue_inventory_sbar(view_t * view)789 draw_rogue_inventory_sbar (view_t *view)
790 {
791 	if (cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN)
792 		draw_pic (view, 0, 0, rsb_invbar[0]);
793 	else
794 		draw_pic (view, 0, 0, rsb_invbar[1]);
795 
796 	view_draw (view);
797 }
798 
799 static void
draw_rogue_face(view_t * view)800 draw_rogue_face (view_t *view)
801 {
802 	int         top, bottom;
803 	scoreboard_t *s;
804 
805 	// PGM 01/19/97 - team color drawing
806 
807 	s = &cl.scores[cl.viewentity - 1];
808 
809 	top = Sbar_ColorForMap (s->topcolor);
810 	bottom = Sbar_ColorForMap (s->bottomcolor);
811 
812 	draw_pic (view, 112, 0, rsb_teambord);
813 	draw_fill (view, 113, 3, 22, 9, top);
814 	draw_fill (view, 113, 12, 22, 9, bottom);
815 
816 	draw_smallnum (view, 108, 3, s->frags, 1, top == 8);
817 }
818 
819 static void
draw_rogue_status(view_t * view)820 draw_rogue_status (view_t *view)
821 {
822 	if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) {
823 		draw_solo (view);
824 		return;
825 	}
826 
827 	draw_num (view, 24, 0, cl.stats[STAT_ARMOR], 3,
828 			  cl.stats[STAT_ARMOR] <= 25);
829 	if (cl.stats[STAT_ITEMS] & RIT_ARMOR3)
830 		draw_pic (view, 0, 0, sb_armor[2]);
831 	else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2)
832 		draw_pic (view, 0, 0, sb_armor[1]);
833 	else if (cl.stats[STAT_ITEMS] & RIT_ARMOR1)
834 		draw_pic (view, 0, 0, sb_armor[0]);
835 
836 	// PGM 03/02/97 - fixed so color swatch appears in only CTF modes
837 	if (cl.maxclients != 1 && teamplay->int_val > 3 && teamplay->int_val < 7)
838 		draw_rogue_face (view);
839 	else
840 		draw_face (view);
841 
842 	draw_health (view);
843 
844 	if (cl.stats[STAT_ITEMS] & RIT_SHELLS)
845 		draw_pic (view, 224, 0, sb_ammo[0]);
846 	else if (cl.stats[STAT_ITEMS] & RIT_NAILS)
847 		draw_pic (view, 224, 0, sb_ammo[1]);
848 	else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS)
849 		draw_pic (view, 224, 0, sb_ammo[2]);
850 	else if (cl.stats[STAT_ITEMS] & RIT_CELLS)
851 		draw_pic (view, 224, 0, sb_ammo[3]);
852 	else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS)
853 		draw_pic (view, 224, 0, rsb_ammo[0]);
854 	else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO)
855 		draw_pic (view, 224, 0, rsb_ammo[1]);
856 	else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS)
857 		draw_pic (view, 224, 0, rsb_ammo[2]);
858 	draw_num (view, 248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10);
859 }
860 
861 static void
draw_hipnotic_weapons_sbar(view_t * view)862 draw_hipnotic_weapons_sbar (view_t *view)
863 {
864 	static int  x[] = {0, 24, 48, 72, 96, 120, 144, 176, 200, 96};
865 	static int  h[] = {0, 1, 3};
866 	int         flashon, i;
867 	qpic_t     *pic;
868 	int         mask;
869 	float       time;
870 
871 	for (i = 0; i < 10; i++) {
872 		if (i < 7) {
873 			mask = IT_SHOTGUN << i;
874 			time = cl.item_gettime[i];
875 		} else {
876 			mask = 1 << hipweapons[h[i - 7]];
877 			time = cl.item_gettime[hipweapons[h[i - 7]]];
878 		}
879 		if (cl.stats[STAT_ITEMS] & mask) {
880 			flashon = calc_flashon (time, mask);
881 
882 			if (i == 4 && cl.stats[STAT_ACTIVEWEAPON] == (1 << hipweapons[3]))
883 				continue;
884 			if (i == 9 && cl.stats[STAT_ACTIVEWEAPON] != (1 << hipweapons[3]))
885 				continue;
886 			if (i < 7) {
887 				pic = sb_weapons[flashon][i];
888 			} else {
889 				pic = hsb_weapons[flashon][h[i - 7]];
890 			}
891 
892 			draw_subpic (view, x[i], 0, pic, 0, 0, 24, 16);
893 
894 			if (flashon > 1)
895 				sb_updates = 0;		// force update to remove flash
896 		}
897 	}
898 }
899 
900 static void
draw_hipnotic_weapons_hud(view_t * view)901 draw_hipnotic_weapons_hud (view_t *view)
902 {
903 	int         flashon, i;
904 	static int  y[] = {0, 16, 32, 48, 64, 96, 112, 128, 144, 80};
905 	static int  h[] = {0, 1, 3};
906 	qpic_t     *pic;
907 	int         mask;
908 	float       time;
909 
910 	for (i = 0; i < 10; i++) {
911 		if (i < 7) {
912 			mask = IT_SHOTGUN << i;
913 			time = cl.item_gettime[i];
914 		} else {
915 			mask = 1 << hipweapons[h[i - 7]];
916 			time = cl.item_gettime[hipweapons[h[i - 7]]];
917 		}
918 		if (cl.stats[STAT_ITEMS] & mask) {
919 			flashon = calc_flashon (time, mask);
920 
921 			if (i < 7) {
922 				pic = sb_weapons[flashon][i];
923 			} else {
924 				pic = hsb_weapons[flashon][h[i - 7]];
925 			}
926 
927 			draw_subpic (view, 0, y[i], pic, 0, 0, 24, 16);
928 
929 			if (flashon > 1)
930 				sb_updates = 0;		// force update to remove flash
931 		}
932 	}
933 }
934 
935 static void
draw_hipnotic_items(view_t * view)936 draw_hipnotic_items (view_t *view)
937 {
938 	int         i;
939 	float       time;
940 
941 	// items
942 	for (i = 2; i < 6; i++) {
943 		if (cl.stats[STAT_ITEMS] & (1 << (17 + i))) {
944 			time = cl.item_gettime[17 + i];
945 			draw_pic (view, 192 + i * 16, 0, sb_items[i]);
946 			if (time && time > cl.time - 2)
947 				sb_updates = 0;
948 		}
949 	}
950 
951 	// hipnotic items
952 	for (i = 0; i < 2; i++) {
953 		if (cl.stats[STAT_ITEMS] & (1 << (24 + i))) {
954 			time = cl.item_gettime[24 + i];
955 			draw_pic (view, 288 + i * 16, 0, hsb_items[i]);
956 			if (time && time > (cl.time - 2))
957 				sb_updates = 0;
958 		}
959 	}
960 }
961 
962 static void
draw_hipnotic_inventory_sbar(view_t * view)963 draw_hipnotic_inventory_sbar (view_t *view)
964 {
965 	draw_pic (view, 0, 0, sb_ibar);
966 	view_draw (view);
967 }
968 
969 static void
draw_hipnotic_status(view_t * view)970 draw_hipnotic_status (view_t *view)
971 {
972 	if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) {
973 		draw_solo (view);
974 		return;
975 	}
976 
977 	draw_armor (view);
978 	draw_face (view);
979 	draw_health (view);
980 	draw_ammo (view);
981 
982 	if (cl.stats[STAT_ITEMS] & IT_KEY1)
983 		draw_pic (view, 209, 3, sb_items[0]);
984 	if (cl.stats[STAT_ITEMS] & IT_KEY2)
985 		draw_pic (view, 209, 12, sb_items[1]);
986 }
987 
988 static void
sbar_update_vis(void)989 sbar_update_vis (void)
990 {
991 	qboolean    headsup;
992 
993 	if (r_data->scr_copyeverything)
994 		Sbar_Changed ();
995 
996 	sbar_view->visible = 0;
997 
998 	headsup = !(hud_sbar->int_val || r_data->scr_viewsize->int_val < 100);
999 
1000 	if ((sb_updates >= r_data->vid->numpages) && !headsup)
1001 		return;
1002 
1003 	if (con_module &&
1004 		con_module->data->console->lines == r_data->vid->conheight)
1005 		return;							// console is full screen
1006 
1007 	if (cls.state == ca_active
1008 		&& ((cl.stats[STAT_HEALTH] <= 0) || sb_showscores))
1009 		overlay_view->visible = 1;
1010 	else
1011 		overlay_view->visible = 0;
1012 
1013 	if (!sb_lines)
1014 		return;
1015 
1016 	sbar_view->visible = 1;
1017 
1018 	r_data->scr_copyeverything = 1;
1019 	sb_updates++;
1020 }
1021 
1022 void
Sbar_Draw(void)1023 Sbar_Draw (void)
1024 {
1025 	sbar_update_vis ();
1026 	main_view->draw (main_view);
1027 }
1028 
1029 static void
Sbar_DeathmatchOverlay(view_t * view)1030 Sbar_DeathmatchOverlay (view_t *view)
1031 {
1032 	int         i, k, l;
1033 	int         top, bottom;
1034 	int         x, y;
1035 	scoreboard_t *s;
1036 
1037 	r_data->scr_copyeverything = 1;
1038 	r_data->scr_fullupdate = 0;
1039 
1040 	draw_cachepic (view, 0, 0, "gfx/ranking.lmp", 1);
1041 
1042 	// scores
1043 	Sbar_SortFrags ();
1044 
1045 	// draw the text
1046 	l = scoreboardlines;
1047 
1048 	x = 80;
1049 	y = 40;
1050 	for (i = 0; i < l; i++) {
1051 		k = fragsort[i];
1052 		s = &cl.scores[k];
1053 		if (!s->name->value[0])
1054 			continue;
1055 
1056 		// draw background
1057 		top = Sbar_ColorForMap (s->topcolor);
1058 		bottom = Sbar_ColorForMap (s->bottomcolor);
1059 
1060 		draw_fill (view, x, y, 40, 4, top);
1061 		draw_fill (view, x, y + 4, 40, 4, bottom);
1062 
1063 		draw_smallnum (view, x + 12, y, s->frags, 0, 0);
1064 
1065 		if (k == cl.viewentity - 1)
1066 			draw_character (view, x - 4, y, 12);
1067 
1068 		// draw name
1069 		draw_string (view, x + 64, y, s->name->value);
1070 
1071 		y += 10;
1072 	}
1073 }
1074 
1075 static void
Sbar_DrawScoreboard(void)1076 Sbar_DrawScoreboard (void)
1077 {
1078 	//Sbar_SoloScoreboard ();
1079 	if (cl.gametype == GAME_DEATHMATCH)
1080 		Sbar_DeathmatchOverlay (overlay_view);
1081 }
1082 
1083 static void
draw_overlay(view_t * view)1084 draw_overlay (view_t *view)
1085 {
1086 	if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) {
1087 		Sbar_DrawScoreboard ();
1088 	}
1089 }
1090 
1091 static void
draw_time(view_t * view)1092 draw_time (view_t *view)
1093 {
1094 	struct tm  *local = NULL;
1095 	time_t      utc = 0;
1096 	const char *timefmt = NULL;
1097 	char        st[80];		//FIXME: overflow
1098 
1099 	// Get local time
1100 	utc = time (NULL);
1101 	local = localtime (&utc);
1102 
1103 	if (hud_time->int_val == 1) {  // Use international format
1104 		timefmt = "%k:%M";
1105 	} else if (hud_time->int_val >= 2) {   // US AM/PM display
1106 		timefmt = "%l:%M %P";
1107 	}
1108 
1109 	strftime (st, sizeof (st), timefmt, local);
1110 	draw_string (view, 8, 0, st);
1111 }
1112 
1113 static void
draw_fps(view_t * view)1114 draw_fps (view_t *view)
1115 {
1116 	static char   st[80];
1117 	double        t;
1118 	static double lastframetime;
1119 	static double lastfps;
1120 
1121 	t = Sys_DoubleTime ();
1122 	if ((t - lastframetime) >= 0.2) {
1123 		lastfps = fps_count / (t - lastframetime);
1124 		fps_count = 0;
1125 		lastframetime = t;
1126 		snprintf (st, sizeof (st), "%5.1f FPS", lastfps);
1127 	}
1128 	draw_string (view, 80, 8, st);
1129 }
1130 
1131 static void
draw_stuff(view_t * view)1132 draw_stuff (view_t *view)
1133 {
1134 	if (hud_time->int_val > 0)
1135 		draw_time (view);
1136 	if (hud_fps->int_val > 0)
1137 		draw_fps (view);
1138 }
1139 
1140 static void
draw_intermission(view_t * view)1141 draw_intermission (view_t *view)
1142 {
1143 	int         dig;
1144 	int         num;
1145 
1146 	r_data->scr_copyeverything = 1;
1147 	r_data->scr_fullupdate = 0;
1148 
1149 	draw_cachepic (view, 64, 24, "gfx/complete.lmp", 0);
1150 
1151 	draw_cachepic (view, 0, 56, "gfx/inter.lmp", 0);
1152 
1153 	// time
1154 	dig = cl.completed_time / 60;
1155 	draw_num (view, 160, 64, dig, 3, 0);
1156 	num = cl.completed_time - dig * 60;
1157 	draw_pic (view, 234, 64, sb_colon);
1158 	draw_pic (view, 246, 64, sb_nums[0][num / 10]);
1159 	draw_pic (view, 266, 64, sb_nums[0][num % 10]);
1160 
1161 	draw_num (view, 160, 104, cl.stats[STAT_SECRETS], 3, 0);
1162 	draw_pic (view, 232, 104, sb_slash);
1163 	draw_num (view, 240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1164 
1165 	draw_num (view, 160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1166 	draw_pic (view, 232, 144, sb_slash);
1167 	draw_num (view, 240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1168 }
1169 
1170 void
Sbar_IntermissionOverlay(void)1171 Sbar_IntermissionOverlay (void)
1172 {
1173 	r_data->scr_copyeverything = 1;
1174 	r_data->scr_fullupdate = 0;
1175 
1176 	if (cl.gametype == GAME_DEATHMATCH) {
1177 		Sbar_DeathmatchOverlay (overlay_view);
1178 		return;
1179 	}
1180 	draw_intermission (overlay_view);
1181 }
1182 
1183 /* CENTER PRINTING */
1184 static dstring_t center_string = {&dstring_default_mem};
1185 static float centertime_start;				// for slow victory printing
1186 static float centertime_off;
1187 static int   center_lines;
1188 
1189 /*
1190 	Called for important messages that should stay in the center of the screen
1191 	for a few moments
1192 */
1193 void
Sbar_CenterPrint(const char * str)1194 Sbar_CenterPrint (const char *str)
1195 {
1196 	if (!str) {
1197 		centertime_off = 0;
1198 		dstring_clearstr (&center_string);
1199 		return;
1200 	}
1201 
1202 	dstring_copystr (&center_string, str);
1203 
1204 	centertime_off = scr_centertime->value;
1205 	centertime_start = realtime;
1206 
1207 	// count the number of lines for centering
1208 	center_lines = 1;
1209 	while (*str) {
1210 		if (*str == '\n')
1211 			center_lines++;
1212 		str++;
1213 	}
1214 }
1215 
1216 static void
Sbar_DrawCenterString(view_t * view,int remaining)1217 Sbar_DrawCenterString (view_t *view, int remaining)
1218 {
1219 	const char *start;
1220 	int         j, l, x, y;
1221 
1222 	start = center_string.str;
1223 
1224 	if (center_lines <= 4)
1225 		y = view->yabs + view->ylen * 0.35;
1226 	else
1227 		y = view->yabs + 48;
1228 
1229 	do {
1230 		// scan the width of the line
1231 		for (l = 0; l < 40; l++)
1232 			if (start[l] == '\n' || !start[l])
1233 				break;
1234 		x = view->xabs + (view->xlen - l * 8) / 2;
1235 		for (j = 0; j < l; j++, x += 8) {
1236 			r_funcs->Draw_Character (x, y, start[j]);
1237 			if (!remaining--)
1238 				return;
1239 		}
1240 
1241 		y += 8;
1242 
1243 		while (*start && *start != '\n')
1244 			start++;
1245 		if (!*start)
1246 			break;
1247 		start++;						// skip the \n
1248 	} while (1);
1249 }
1250 
1251 void
Sbar_FinaleOverlay(void)1252 Sbar_FinaleOverlay (void)
1253 {
1254 	int         remaining;
1255 
1256 	r_data->scr_copyeverything = 1;
1257 
1258 	draw_cachepic (overlay_view, 0, 16, "gfx/finale.lmp", 1);
1259 	// the finale prints the characters one at a time
1260 	remaining = scr_printspeed->value * (realtime - centertime_start);
1261 	Sbar_DrawCenterString (overlay_view, remaining);
1262 }
1263 
1264 void
Sbar_DrawCenterPrint(void)1265 Sbar_DrawCenterPrint (void)
1266 {
1267 	r_data->scr_copytop = 1;
1268 
1269 	centertime_off -= r_data->frametime;
1270 	if (centertime_off <= 0)
1271 		return;
1272 
1273 	Sbar_DrawCenterString (overlay_view, -1);
1274 }
1275 
1276 static void
init_sbar_views(void)1277 init_sbar_views (void)
1278 {
1279 	view_t     *view;
1280 
1281 	sbar_view = view_new (0, 0, 320, 48, grav_south);
1282 
1283 	sbar_frags_view = view_new (0, 0, 130, 8, grav_northeast);
1284 	sbar_frags_view->draw = draw_frags;
1285 
1286 	sbar_inventory_view = view_new (0, 0, 320, 24, grav_northwest);
1287 	sbar_inventory_view->draw = draw_inventory_sbar;
1288 
1289 	view = view_new (0, 0, 32, 16, grav_southwest);
1290 	view->draw = draw_weapons_sbar;
1291 	view_add (sbar_inventory_view, view);
1292 
1293 	view = view_new (0, 0, 32, 8, grav_northwest);
1294 	view->draw = draw_ammo_sbar;
1295 	view_add (sbar_inventory_view, view);
1296 
1297 	view = view_new (32, 0, 96, 16, grav_southeast);
1298 	view->draw = draw_items;
1299 	view_add (sbar_inventory_view, view);
1300 
1301 	view = view_new (0, 0, 32, 16, grav_southeast);
1302 	view->draw = draw_sigils;
1303 	view_add (sbar_inventory_view, view);
1304 
1305 	if (sbar_frags_view)
1306 		view_add (sbar_inventory_view, sbar_frags_view);
1307 
1308 	view_add (sbar_view, sbar_inventory_view);
1309 
1310 	view = view_new (0, 0, 320, 24, grav_southwest);
1311 	view->draw = draw_status_bar;
1312 	view_add (sbar_view, view);
1313 
1314 	view = view_new (0, 0, 320, 24, grav_southwest);
1315 	view->draw = draw_status;
1316 	view_add (sbar_view, view);
1317 
1318 	if (r_data->vid->conwidth > 320) {
1319 		int         l = (r_data->vid->conwidth - 320) / 2;
1320 
1321 		view = view_new (-l, 0, l, 48, grav_southwest);
1322 		view->draw = draw_tile;
1323 		view->resize_y = 1;
1324 		view_add (sbar_view, view);
1325 
1326 		view = view_new (-l, 0, l, 48, grav_southeast);
1327 		view->draw = draw_tile;
1328 		view->resize_y = 1;
1329 		view_add (sbar_view, view);
1330 	}
1331 }
1332 
1333 static void
init_hud_views(void)1334 init_hud_views (void)
1335 {
1336 	view_t     *view;
1337 
1338 	hud_view = view_new (0, 0, 320, 48, grav_south);
1339 	hud_frags_view = view_new (0, 0, 130, 8, grav_northeast);
1340 	hud_frags_view->draw = draw_frags;
1341 
1342 	hud_view->resize_y = 1;
1343 
1344 	hud_armament_view = view_new (0, 48, 42, 156, grav_southeast);
1345 
1346 	view = view_new (0, 0, 24, 112, grav_northeast);
1347 	view->draw = draw_weapons_hud;
1348 	view_add (hud_armament_view, view);
1349 
1350 	view = view_new (0, 0, 42, 44, grav_southeast);
1351 	view->draw = draw_ammo_hud;
1352 	view_add (hud_armament_view, view);
1353 
1354 	hud_inventory_view = view_new (0, 0, 320, 24, grav_northwest);
1355 	view_add (hud_view, hud_inventory_view);
1356 
1357 	view = view_new (0, 0, 320, 24, grav_southwest);
1358 	view->draw = draw_status;
1359 	view_add (hud_view, view);
1360 
1361 	view = view_new (32, 0, 96, 16, grav_southeast);
1362 	view->draw = draw_items;
1363 	view_add (hud_inventory_view, view);
1364 
1365 	view = view_new (0, 0, 32, 16, grav_southeast);
1366 	view->draw = draw_sigils;
1367 	view_add (hud_inventory_view, view);
1368 
1369 	if (hud_frags_view)
1370 		view_add (hud_inventory_view, hud_frags_view);
1371 
1372 	view = view_new (0, 0, r_data->vid->conwidth, 48, grav_south);
1373 	view_add (view, hud_view);
1374 	hud_view = view;
1375 
1376 	view_add (hud_view, hud_armament_view);
1377 
1378 	view_insert (main_view, hud_view, 0);
1379 }
1380 
1381 static void
init_hipnotic_sbar_views(void)1382 init_hipnotic_sbar_views (void)
1383 {
1384 	view_t     *view;
1385 
1386 	sbar_view = view_new (0, 0, 320, 48, grav_south);
1387 
1388 	sbar_frags_view = view_new (0, 0, 130, 8, grav_northeast);
1389 	sbar_frags_view->draw = draw_frags;
1390 
1391 	sbar_inventory_view = view_new (0, 0, 320, 24, grav_northwest);
1392 	sbar_inventory_view->draw = draw_hipnotic_inventory_sbar;
1393 
1394 	view = view_new (0, 0, 224, 16, grav_southwest);
1395 	view->draw = draw_hipnotic_weapons_sbar;
1396 	view_add (sbar_inventory_view, view);
1397 
1398 	view = view_new (0, 0, 32, 8, grav_northwest);
1399 	view->draw = draw_ammo_sbar;
1400 	view_add (sbar_inventory_view, view);
1401 
1402 	view = view_new (0, 0, 96, 16, grav_southeast);
1403 	view->draw = draw_hipnotic_items;
1404 	view_add (sbar_inventory_view, view);
1405 
1406 	view = view_new (0, 0, 32, 16, grav_southeast);
1407 	view->draw = draw_sigils;
1408 	view_add (sbar_inventory_view, view);
1409 
1410 	if (sbar_frags_view)
1411 		view_add (sbar_inventory_view, sbar_frags_view);
1412 
1413 	view_add (sbar_view, sbar_inventory_view);
1414 
1415 	view = view_new (0, 0, 320, 24, grav_southwest);
1416 	view->draw = draw_status_bar;
1417 	view_add (sbar_view, view);
1418 
1419 	view = view_new (0, 0, 320, 24, grav_southwest);
1420 	view->draw = draw_hipnotic_status;
1421 	view_add (sbar_view, view);
1422 
1423 	if (r_data->vid->conwidth > 320) {
1424 		int         l = (r_data->vid->conwidth - 320) / 2;
1425 
1426 		view = view_new (-l, 0, l, 48, grav_southwest);
1427 		view->draw = draw_tile;
1428 		view->resize_y = 1;
1429 		view_add (sbar_view, view);
1430 
1431 		view = view_new (-l, 0, l, 48, grav_southeast);
1432 		view->draw = draw_tile;
1433 		view->resize_y = 1;
1434 		view_add (sbar_view, view);
1435 	}
1436 }
1437 
1438 static void
init_hipnotic_hud_views(void)1439 init_hipnotic_hud_views (void)
1440 {
1441 	view_t     *view;
1442 
1443 	hud_view = view_new (0, 0, 320, 48, grav_south);
1444 	hud_frags_view = view_new (0, 0, 130, 8, grav_northeast);
1445 	hud_frags_view->draw = draw_frags;
1446 
1447 	hud_view->resize_y = 1;
1448 
1449 	if (r_data->vid->conheight < 252) {
1450 		hud_armament_view = view_new (0,
1451 									  min (r_data->vid->conheight - 160, 48),
1452 									  66, 160, grav_southeast);
1453 	} else {
1454 		hud_armament_view = view_new (0, 48, 42, 204, grav_southeast);
1455 	}
1456 
1457 	view = view_new (0, 0, 24, 160, grav_northeast);
1458 	view->draw = draw_hipnotic_weapons_hud;
1459 	view_add (hud_armament_view, view);
1460 
1461 	view = view_new (0, 0, 42, 44, grav_southeast);
1462 	view->draw = draw_ammo_hud;
1463 	view_add (hud_armament_view, view);
1464 
1465 	hud_inventory_view = view_new (0, 0, 320, 24, grav_northwest);
1466 	view_add (hud_view, hud_inventory_view);
1467 
1468 	view = view_new (0, 0, 320, 24, grav_southwest);
1469 	view->draw = draw_hipnotic_status;
1470 	view_add (hud_view, view);
1471 
1472 	view = view_new (0, 0, 96, 16, grav_southeast);
1473 	view->draw = draw_hipnotic_items;
1474 	view_add (hud_inventory_view, view);
1475 
1476 	view = view_new (0, 0, 32, 16, grav_southeast);
1477 	view->draw = draw_sigils;
1478 	view_add (hud_inventory_view, view);
1479 
1480 	if (hud_frags_view)
1481 		view_add (hud_inventory_view, hud_frags_view);
1482 
1483 	view = view_new (0, 0, r_data->vid->conwidth, 48, grav_south);
1484 	view_add (view, hud_view);
1485 	hud_view = view;
1486 
1487 	view_add (hud_view, hud_armament_view);
1488 
1489 	view_insert (main_view, hud_view, 0);
1490 }
1491 
1492 static void
init_rogue_sbar_views(void)1493 init_rogue_sbar_views (void)
1494 {
1495 	view_t     *view;
1496 
1497 	sbar_view = view_new (0, 0, 320, 48, grav_south);
1498 
1499 	sbar_frags_view = view_new (0, 0, 130, 8, grav_northeast);
1500 	sbar_frags_view->draw = draw_frags;
1501 
1502 	sbar_inventory_view = view_new (0, 0, 320, 24, grav_northwest);
1503 	sbar_inventory_view->draw = draw_rogue_inventory_sbar;
1504 
1505 	view = view_new (0, 0, 224, 16, grav_southwest);
1506 	view->draw = draw_rogue_weapons_sbar;
1507 	view_add (sbar_inventory_view, view);
1508 
1509 	view = view_new (0, 0, 32, 8, grav_northwest);
1510 	view->draw = draw_ammo_sbar;
1511 	view_add (sbar_inventory_view, view);
1512 
1513 	view = view_new (0, 0, 128, 16, grav_southeast);
1514 	view->draw = draw_rogue_items;
1515 	view_add (sbar_inventory_view, view);
1516 
1517 	if (sbar_frags_view)
1518 		view_add (sbar_inventory_view, sbar_frags_view);
1519 
1520 	view_add (sbar_view, sbar_inventory_view);
1521 
1522 	view = view_new (0, 0, 320, 24, grav_southwest);
1523 	view->draw = draw_status_bar;
1524 	view_add (sbar_view, view);
1525 
1526 	view = view_new (0, 0, 320, 24, grav_southwest);
1527 	view->draw = draw_rogue_status;
1528 	view_add (sbar_view, view);
1529 
1530 	if (r_data->vid->conwidth > 320) {
1531 		int         l = (r_data->vid->conwidth - 320) / 2;
1532 
1533 		view = view_new (-l, 0, l, 48, grav_southwest);
1534 		view->draw = draw_tile;
1535 		view->resize_y = 1;
1536 		view_add (sbar_view, view);
1537 
1538 		view = view_new (-l, 0, l, 48, grav_southeast);
1539 		view->draw = draw_tile;
1540 		view->resize_y = 1;
1541 		view_add (sbar_view, view);
1542 	}
1543 }
1544 
1545 static void
init_rogue_hud_views(void)1546 init_rogue_hud_views (void)
1547 {
1548 	view_t     *view;
1549 
1550 	hud_view = view_new (0, 0, 320, 48, grav_south);
1551 	hud_frags_view = view_new (0, 0, 130, 8, grav_northeast);
1552 	hud_frags_view->draw = draw_frags;
1553 
1554 	hud_view->resize_y = 1;
1555 
1556 	hud_armament_view = view_new (0, 48, 42, 156, grav_southeast);
1557 
1558 	view = view_new (0, 0, 24, 112, grav_northeast);
1559 	view->draw = draw_rogue_weapons_hud;
1560 	view_add (hud_armament_view, view);
1561 
1562 	view = view_new (0, 0, 42, 44, grav_southeast);
1563 	view->draw = draw_rogue_ammo_hud;
1564 	view_add (hud_armament_view, view);
1565 
1566 	hud_inventory_view = view_new (0, 0, 320, 24, grav_northwest);
1567 	view_add (hud_view, hud_inventory_view);
1568 
1569 	view = view_new (0, 0, 320, 24, grav_southwest);
1570 	view->draw = draw_rogue_status;
1571 	view_add (hud_view, view);
1572 
1573 	view = view_new (0, 0, 128, 16, grav_southeast);
1574 	view->draw = draw_rogue_items;
1575 	view_add (hud_inventory_view, view);
1576 
1577 	if (hud_frags_view)
1578 		view_add (hud_inventory_view, hud_frags_view);
1579 
1580 	view = view_new (0, 0, r_data->vid->conwidth, 48, grav_south);
1581 	view_add (view, hud_view);
1582 	hud_view = view;
1583 
1584 	view_add (hud_view, hud_armament_view);
1585 
1586 	view_insert (main_view, hud_view, 0);
1587 }
1588 
1589 static void
init_views(void)1590 init_views (void)
1591 {
1592 	main_view = view_new (0, 0, r_data->vid->conwidth, r_data->vid->conheight,
1593 						  grav_northwest);
1594 	if (con_module)
1595 		view_insert (con_module->data->console->view, main_view, 0);
1596 	main_view->resize_x = 1;	// get resized if the 2d view resizes
1597 	main_view->resize_y = 1;
1598 	main_view->visible = 0;		// but don't let the console draw our stuff
1599 	if (r_data->vid->conheight > 300)
1600 		overlay_view = view_new (0, 0, 320, 300, grav_center);
1601 	else
1602 		overlay_view = view_new (0, 0, 320, r_data->vid->conheight,
1603 								 grav_center);
1604 	overlay_view->draw = draw_overlay;
1605 	overlay_view->visible = 0;
1606 
1607 	stuff_view = view_new (0, 48, 152, 16, grav_southwest);
1608 	stuff_view->draw = draw_stuff;
1609 
1610 	view_insert (main_view, overlay_view, 0);
1611 	view_insert (main_view, stuff_view, 0);
1612 
1613 	if (!strcmp (qfs_gamedir->hudtype, "hipnotic")) {
1614 		init_hipnotic_sbar_views ();
1615 		init_hipnotic_hud_views ();
1616 	} else if (!strcmp (qfs_gamedir->hudtype, "rogue")) {
1617 		init_rogue_sbar_views ();
1618 		init_rogue_hud_views ();
1619 	} else {
1620 		init_sbar_views ();
1621 		init_hud_views ();
1622 	}
1623 }
1624 
1625 static void
Sbar_GIB_Print_Center_f(void)1626 Sbar_GIB_Print_Center_f (void)
1627 {
1628 	if (GIB_Argc () != 2) {
1629 		GIB_USAGE ("text");
1630 	} else
1631 		Sbar_CenterPrint (GIB_Argv(1));
1632 }
1633 
1634 static void
sbar_keydest_callback(keydest_t kd)1635 sbar_keydest_callback (keydest_t kd)
1636 {
1637 	overlay_view->visible = kd == key_game;
1638 }
1639 
1640 void
Sbar_Init(void)1641 Sbar_Init (void)
1642 {
1643 	int         i;
1644 
1645 	init_views ();
1646 
1647 	Key_KeydestCallback (sbar_keydest_callback);
1648 
1649 	for (i = 0; i < 10; i++) {
1650 		sb_nums[0][i] = r_funcs->Draw_PicFromWad (va ("num_%i", i));
1651 		sb_nums[1][i] = r_funcs->Draw_PicFromWad (va ("anum_%i", i));
1652 	}
1653 
1654 	sb_nums[0][10] = r_funcs->Draw_PicFromWad ("num_minus");
1655 	sb_nums[1][10] = r_funcs->Draw_PicFromWad ("anum_minus");
1656 
1657 	sb_colon = r_funcs->Draw_PicFromWad ("num_colon");
1658 	sb_slash = r_funcs->Draw_PicFromWad ("num_slash");
1659 
1660 	sb_weapons[0][0] = r_funcs->Draw_PicFromWad ("inv_shotgun");
1661 	sb_weapons[0][1] = r_funcs->Draw_PicFromWad ("inv_sshotgun");
1662 	sb_weapons[0][2] = r_funcs->Draw_PicFromWad ("inv_nailgun");
1663 	sb_weapons[0][3] = r_funcs->Draw_PicFromWad ("inv_snailgun");
1664 	sb_weapons[0][4] = r_funcs->Draw_PicFromWad ("inv_rlaunch");
1665 	sb_weapons[0][5] = r_funcs->Draw_PicFromWad ("inv_srlaunch");
1666 	sb_weapons[0][6] = r_funcs->Draw_PicFromWad ("inv_lightng");
1667 
1668 	sb_weapons[1][0] = r_funcs->Draw_PicFromWad ("inv2_shotgun");
1669 	sb_weapons[1][1] = r_funcs->Draw_PicFromWad ("inv2_sshotgun");
1670 	sb_weapons[1][2] = r_funcs->Draw_PicFromWad ("inv2_nailgun");
1671 	sb_weapons[1][3] = r_funcs->Draw_PicFromWad ("inv2_snailgun");
1672 	sb_weapons[1][4] = r_funcs->Draw_PicFromWad ("inv2_rlaunch");
1673 	sb_weapons[1][5] = r_funcs->Draw_PicFromWad ("inv2_srlaunch");
1674 	sb_weapons[1][6] = r_funcs->Draw_PicFromWad ("inv2_lightng");
1675 
1676 	for (i = 0; i < 5; i++) {
1677 		sb_weapons[2 + i][0] =
1678 			r_funcs->Draw_PicFromWad (va ("inva%i_shotgun", i + 1));
1679 		sb_weapons[2 + i][1] =
1680 			r_funcs->Draw_PicFromWad (va ("inva%i_sshotgun", i + 1));
1681 		sb_weapons[2 + i][2] =
1682 			r_funcs->Draw_PicFromWad (va ("inva%i_nailgun", i + 1));
1683 		sb_weapons[2 + i][3] =
1684 			r_funcs->Draw_PicFromWad (va ("inva%i_snailgun", i + 1));
1685 		sb_weapons[2 + i][4] =
1686 			r_funcs->Draw_PicFromWad (va ("inva%i_rlaunch", i + 1));
1687 		sb_weapons[2 + i][5] =
1688 			r_funcs->Draw_PicFromWad (va ("inva%i_srlaunch", i + 1));
1689 		sb_weapons[2 + i][6] =
1690 			r_funcs->Draw_PicFromWad (va ("inva%i_lightng", i + 1));
1691 	}
1692 
1693 	sb_ammo[0] = r_funcs->Draw_PicFromWad ("sb_shells");
1694 	sb_ammo[1] = r_funcs->Draw_PicFromWad ("sb_nails");
1695 	sb_ammo[2] = r_funcs->Draw_PicFromWad ("sb_rocket");
1696 	sb_ammo[3] = r_funcs->Draw_PicFromWad ("sb_cells");
1697 
1698 	sb_armor[0] = r_funcs->Draw_PicFromWad ("sb_armor1");
1699 	sb_armor[1] = r_funcs->Draw_PicFromWad ("sb_armor2");
1700 	sb_armor[2] = r_funcs->Draw_PicFromWad ("sb_armor3");
1701 
1702 	sb_items[0] = r_funcs->Draw_PicFromWad ("sb_key1");
1703 	sb_items[1] = r_funcs->Draw_PicFromWad ("sb_key2");
1704 	sb_items[2] = r_funcs->Draw_PicFromWad ("sb_invis");
1705 	sb_items[3] = r_funcs->Draw_PicFromWad ("sb_invuln");
1706 	sb_items[4] = r_funcs->Draw_PicFromWad ("sb_suit");
1707 	sb_items[5] = r_funcs->Draw_PicFromWad ("sb_quad");
1708 
1709 	sb_sigil[0] = r_funcs->Draw_PicFromWad ("sb_sigil1");
1710 	sb_sigil[1] = r_funcs->Draw_PicFromWad ("sb_sigil2");
1711 	sb_sigil[2] = r_funcs->Draw_PicFromWad ("sb_sigil3");
1712 	sb_sigil[3] = r_funcs->Draw_PicFromWad ("sb_sigil4");
1713 
1714 	sb_faces[4][0] = r_funcs->Draw_PicFromWad ("face1");
1715 	sb_faces[4][1] = r_funcs->Draw_PicFromWad ("face_p1");
1716 	sb_faces[3][0] = r_funcs->Draw_PicFromWad ("face2");
1717 	sb_faces[3][1] = r_funcs->Draw_PicFromWad ("face_p2");
1718 	sb_faces[2][0] = r_funcs->Draw_PicFromWad ("face3");
1719 	sb_faces[2][1] = r_funcs->Draw_PicFromWad ("face_p3");
1720 	sb_faces[1][0] = r_funcs->Draw_PicFromWad ("face4");
1721 	sb_faces[1][1] = r_funcs->Draw_PicFromWad ("face_p4");
1722 	sb_faces[0][0] = r_funcs->Draw_PicFromWad ("face5");
1723 	sb_faces[0][1] = r_funcs->Draw_PicFromWad ("face_p5");
1724 
1725 	sb_face_invis = r_funcs->Draw_PicFromWad ("face_invis");
1726 	sb_face_invuln = r_funcs->Draw_PicFromWad ("face_invul2");
1727 	sb_face_invis_invuln = r_funcs->Draw_PicFromWad ("face_inv2");
1728 	sb_face_quad = r_funcs->Draw_PicFromWad ("face_quad");
1729 
1730 	Cmd_AddCommand ("+showscores", Sbar_ShowScores,
1731 					"Display information on everyone playing");
1732 	Cmd_AddCommand ("-showscores", Sbar_DontShowScores,
1733 					"Stop displaying information on everyone playing");
1734 
1735 	sb_sbar = r_funcs->Draw_PicFromWad ("sbar");
1736 	sb_ibar = r_funcs->Draw_PicFromWad ("ibar");
1737 	sb_scorebar = r_funcs->Draw_PicFromWad ("scorebar");
1738 
1739 	// MED 01/04/97 added new hipnotic weapons
1740 	if (!strcmp (qfs_gamedir->hudtype, "hipnotic")) {
1741 		hsb_weapons[0][0] = r_funcs->Draw_PicFromWad ("inv_laser");
1742 		hsb_weapons[0][1] = r_funcs->Draw_PicFromWad ("inv_mjolnir");
1743 		hsb_weapons[0][2] = r_funcs->Draw_PicFromWad ("inv_gren_prox");
1744 		hsb_weapons[0][3] = r_funcs->Draw_PicFromWad ("inv_prox_gren");
1745 		hsb_weapons[0][4] = r_funcs->Draw_PicFromWad ("inv_prox");
1746 
1747 		hsb_weapons[1][0] = r_funcs->Draw_PicFromWad ("inv2_laser");
1748 		hsb_weapons[1][1] = r_funcs->Draw_PicFromWad ("inv2_mjolnir");
1749 		hsb_weapons[1][2] = r_funcs->Draw_PicFromWad ("inv2_gren_prox");
1750 		hsb_weapons[1][3] = r_funcs->Draw_PicFromWad ("inv2_prox_gren");
1751 		hsb_weapons[1][4] = r_funcs->Draw_PicFromWad ("inv2_prox");
1752 
1753 		for (i = 0; i < 5; i++) {
1754 			hsb_weapons[2 + i][0] =
1755 				r_funcs->Draw_PicFromWad (va ("inva%i_laser", i + 1));
1756 			hsb_weapons[2 + i][1] =
1757 				r_funcs->Draw_PicFromWad (va ("inva%i_mjolnir", i + 1));
1758 			hsb_weapons[2 + i][2] =
1759 				r_funcs->Draw_PicFromWad (va ("inva%i_gren_prox", i + 1));
1760 			hsb_weapons[2 + i][3] =
1761 				r_funcs->Draw_PicFromWad (va ("inva%i_prox_gren", i + 1));
1762 			hsb_weapons[2 + i][4] =
1763 				r_funcs->Draw_PicFromWad (va ("inva%i_prox", i + 1));
1764 		}
1765 
1766 		hsb_items[0] = r_funcs->Draw_PicFromWad ("sb_wsuit");
1767 		hsb_items[1] = r_funcs->Draw_PicFromWad ("sb_eshld");
1768 	}
1769 
1770 	// FIXME: MISSIONHUD
1771 	if (!strcmp (qfs_gamedir->hudtype, "rogue")) {
1772 		rsb_invbar[0] = r_funcs->Draw_PicFromWad ("r_invbar1");
1773 		rsb_invbar[1] = r_funcs->Draw_PicFromWad ("r_invbar2");
1774 
1775 		rsb_weapons[0] = r_funcs->Draw_PicFromWad ("r_lava");
1776 		rsb_weapons[1] = r_funcs->Draw_PicFromWad ("r_superlava");
1777 		rsb_weapons[2] = r_funcs->Draw_PicFromWad ("r_gren");
1778 		rsb_weapons[3] = r_funcs->Draw_PicFromWad ("r_multirock");
1779 		rsb_weapons[4] = r_funcs->Draw_PicFromWad ("r_plasma");
1780 
1781 		rsb_items[0] = r_funcs->Draw_PicFromWad ("r_shield1");
1782 		rsb_items[1] = r_funcs->Draw_PicFromWad ("r_agrav1");
1783 
1784 		// PGM 01/19/97 - team color border
1785 		rsb_teambord = r_funcs->Draw_PicFromWad ("r_teambord");
1786 		// PGM 01/19/97 - team color border
1787 
1788 		rsb_ammo[0] = r_funcs->Draw_PicFromWad ("r_ammolava");
1789 		rsb_ammo[1] = r_funcs->Draw_PicFromWad ("r_ammomulti");
1790 		rsb_ammo[2] = r_funcs->Draw_PicFromWad ("r_ammoplasma");
1791 	}
1792 
1793 	r_data->viewsize_callback = viewsize_f;
1794 	hud_sbar = Cvar_Get ("hud_sbar", "0", CVAR_ARCHIVE, hud_sbar_f,
1795 						 "status bar mode: 0 = hud, 1 = oldstyle");
1796 	hud_swap = Cvar_Get ("hud_swap", "0", CVAR_ARCHIVE, hud_swap_f,
1797 						 "new HUD on left side?");
1798 	hud_scoreboard_gravity = Cvar_Get ("hud_scoreboard_gravity", "center",
1799 									   CVAR_ARCHIVE, hud_scoreboard_gravity_f,
1800 									   "control placement of scoreboard "
1801 									   "overlay: center, northwest, north, "
1802 									   "northeast, west, east, southwest, "
1803 									   "south, southeast");
1804 	scr_centertime = Cvar_Get ("scr_centertime", "2", CVAR_NONE, NULL, "How "
1805 							   "long in seconds screen hints are displayed");
1806 	scr_printspeed = Cvar_Get ("scr_printspeed", "8", CVAR_NONE, NULL,
1807 							   "How fast the text is displayed at the end of "
1808 							   "the single player episodes");
1809 
1810 	// register GIB builtins
1811 	GIB_Builtin_Add ("print::center", Sbar_GIB_Print_Center_f);
1812 }
1813