xref: /netbsd/games/larn/display.c (revision bf9ec67e)
1 /*	$NetBSD: display.c,v 1.4 1997/10/18 20:03:15 christos Exp $	*/
2 
3 /* display.c		Larn is copyrighted 1986 by Noah Morgan. */
4 #include <sys/cdefs.h>
5 #ifndef lint
6 __RCSID("$NetBSD: display.c,v 1.4 1997/10/18 20:03:15 christos Exp $");
7 #endif /* not lint */
8 
9 #include "header.h"
10 #include "extern.h"
11 #define makecode(_a,_b,_c) (((_a)<<16) + ((_b)<<8) + (_c))
12 
13 static void botsub __P((int, char *));
14 
15 static int      minx, maxx, miny, maxy, k, m;
16 static char     bot1f = 0, bot2f = 0, bot3f = 0;
17 char            always = 0;
18 /*
19 	bottomline()
20 
21 	now for the bottom line of the display
22  */
23 void
24 bottomline()
25 {
26 	recalc();
27 	bot1f = 1;
28 }
29 
30 void
31 bottomhp()
32 {
33 	bot2f = 1;
34 }
35 
36 void
37 bottomspell()
38 {
39 	bot3f = 1;
40 }
41 
42 void
43 bottomdo()
44 {
45 	if (bot1f) {
46 		bot3f = bot1f = bot2f = 0;
47 		bot_linex();
48 		return;
49 	}
50 	if (bot2f) {
51 		bot2f = 0;
52 		bot_hpx();
53 	}
54 	if (bot3f) {
55 		bot3f = 0;
56 		bot_spellx();
57 	}
58 }
59 
60 void
61 bot_linex()
62 {
63 	int    i;
64 	if (cbak[SPELLS] <= -50 || (always)) {
65 		cursor(1, 18);
66 		if (c[SPELLMAX] > 99)
67 			lprintf("Spells:%3d(%3d)", (long) c[SPELLS], (long) c[SPELLMAX]);
68 		else
69 			lprintf("Spells:%3d(%2d) ", (long) c[SPELLS], (long) c[SPELLMAX]);
70 		lprintf(" AC: %-3d  WC: %-3d  Level", (long) c[AC], (long) c[WCLASS]);
71 		if (c[LEVEL] > 99)
72 			lprintf("%3d", (long) c[LEVEL]);
73 		else
74 			lprintf(" %-2d", (long) c[LEVEL]);
75 		lprintf(" Exp: %-9d %s\n", (long) c[EXPERIENCE], class[c[LEVEL] - 1]);
76 		lprintf("HP: %3d(%3d) STR=%-2d INT=%-2d ",
77 			(long) c[HP], (long) c[HPMAX], (long) (c[STRENGTH] + c[STREXTRA]), (long) c[INTELLIGENCE]);
78 		lprintf("WIS=%-2d CON=%-2d DEX=%-2d CHA=%-2d LV:",
79 			(long) c[WISDOM], (long) c[CONSTITUTION], (long) c[DEXTERITY], (long) c[CHARISMA]);
80 
81 		if ((level == 0) || (wizard))
82 			c[TELEFLAG] = 0;
83 		if (c[TELEFLAG])
84 			lprcat(" ?");
85 		else
86 			lprcat(levelname[level]);
87 		lprintf("  Gold: %-6d", (long) c[GOLD]);
88 		always = 1;
89 		botside();
90 		c[TMP] = c[STRENGTH] + c[STREXTRA];
91 		for (i = 0; i < 100; i++)
92 			cbak[i] = c[i];
93 		return;
94 	}
95 	botsub(makecode(SPELLS, 8, 18), "%3d");
96 	if (c[SPELLMAX] > 99)
97 		botsub(makecode(SPELLMAX, 12, 18), "%3d)");
98 	else
99 		botsub(makecode(SPELLMAX, 12, 18), "%2d) ");
100 	botsub(makecode(HP, 5, 19), "%3d");
101 	botsub(makecode(HPMAX, 9, 19), "%3d");
102 	botsub(makecode(AC, 21, 18), "%-3d");
103 	botsub(makecode(WCLASS, 30, 18), "%-3d");
104 	botsub(makecode(EXPERIENCE, 49, 18), "%-9d");
105 	if (c[LEVEL] != cbak[LEVEL]) {
106 		cursor(59, 18);
107 		lprcat(class[c[LEVEL] - 1]);
108 	}
109 	if (c[LEVEL] > 99)
110 		botsub(makecode(LEVEL, 40, 18), "%3d");
111 	else
112 		botsub(makecode(LEVEL, 40, 18), " %-2d");
113 	c[TMP] = c[STRENGTH] + c[STREXTRA];
114 	botsub(makecode(TMP, 18, 19), "%-2d");
115 	botsub(makecode(INTELLIGENCE, 25, 19), "%-2d");
116 	botsub(makecode(WISDOM, 32, 19), "%-2d");
117 	botsub(makecode(CONSTITUTION, 39, 19), "%-2d");
118 	botsub(makecode(DEXTERITY, 46, 19), "%-2d");
119 	botsub(makecode(CHARISMA, 53, 19), "%-2d");
120 	if ((level != cbak[CAVELEVEL]) || (c[TELEFLAG] != cbak[TELEFLAG])) {
121 		if ((level == 0) || (wizard))
122 			c[TELEFLAG] = 0;
123 		cbak[TELEFLAG] = c[TELEFLAG];
124 		cbak[CAVELEVEL] = level;
125 		cursor(59, 19);
126 		if (c[TELEFLAG])
127 			lprcat(" ?");
128 		else
129 			lprcat(levelname[level]);
130 	}
131 	botsub(makecode(GOLD, 69, 19), "%-6d");
132 	botside();
133 }
134 
135 /*
136 	special subroutine to update only the gold number on the bottomlines
137 	called from ogold()
138  */
139 void
140 bottomgold()
141 {
142 	botsub(makecode(GOLD, 69, 19), "%-6d");
143 	/* botsub(GOLD,"%-6d",69,19); */
144 }
145 
146 /*
147 	special routine to update hp and level fields on bottom lines
148 	called in monster.c hitplayer() and spattack()
149  */
150 void
151 bot_hpx()
152 {
153 	if (c[EXPERIENCE] != cbak[EXPERIENCE]) {
154 		recalc();
155 		bot_linex();
156 	} else
157 		botsub(makecode(HP, 5, 19), "%3d");
158 }
159 
160 /*
161 	special routine to update number of spells called from regen()
162  */
163 void
164 bot_spellx()
165 {
166 	botsub(makecode(SPELLS, 9, 18), "%2d");
167 }
168 
169 /*
170 	common subroutine for a more economical bottomline()
171  */
172 static struct bot_side_def {
173 	int             typ;
174 	char           *string;
175 }
176                 bot_data[] =
177 {
178 	{ STEALTH, "stealth"},
179 	{ UNDEADPRO, "undead pro" },
180 	{ SPIRITPRO, "spirit pro" },
181 	{ CHARMCOUNT, "Charm"},
182 	{ TIMESTOP, "Time Stop" },
183 	{ HOLDMONST, "Hold Monst" },
184 	{ GIANTSTR, "Giant Str"},
185 	{ FIRERESISTANCE, "Fire Resit" },
186 	{ DEXCOUNT, "Dexterity" },
187 	{ STRCOUNT, "Strength"},
188 	{ SCAREMONST, "Scare" },
189 	{ HASTESELF, "Haste Self" },
190 	{ CANCELLATION, "Cancel"},
191 	{ INVISIBILITY, "Invisible" },
192 	{ ALTPRO, "Protect 3" },
193 	{ PROTECTIONTIME, "Protect 2"},
194 	{ WTW, "Wall-Walk" }
195 };
196 
197 void
198 botside()
199 {
200 	int    i, idx;
201 	for (i = 0; i < 17; i++) {
202 		idx = bot_data[i].typ;
203 		if ((always) || (c[idx] != cbak[idx])) {
204 			if ((always) || (cbak[idx] == 0)) {
205 				if (c[idx]) {
206 					cursor(70, i + 1);
207 					lprcat(bot_data[i].string);
208 				}
209 			} else if (c[idx] == 0) {
210 				cursor(70, i + 1);
211 				lprcat("          ");
212 			}
213 			cbak[idx] = c[idx];
214 		}
215 	}
216 	always = 0;
217 }
218 
219 static void
220 botsub(idx, str)
221 	int    idx;
222 	char           *str;
223 {
224 	int    x, y;
225 	y = idx & 0xff;
226 	x = (idx >> 8) & 0xff;
227 	idx >>= 16;
228 	if (c[idx] != cbak[idx]) {
229 		cbak[idx] = c[idx];
230 		cursor(x, y);
231 		lprintf(str, (long) c[idx]);
232 	}
233 }
234 
235 /*
236  *	subroutine to draw only a section of the screen
237  *	only the top section of the screen is updated.
238  *	If entire lines are being drawn, then they will be cleared first.
239  */
240 /* for limited screen drawing */
241 int             d_xmin = 0, d_xmax = MAXX, d_ymin = 0, d_ymax = MAXY;
242 
243 void
244 draws(xmin, xmax, ymin, ymax)
245 	int             xmin, xmax, ymin, ymax;
246 {
247 	int    i, idx;
248 	if (xmin == 0 && xmax == MAXX) {	/* clear section of screen as
249 						 * needed */
250 		if (ymin == 0)
251 			cl_up(79, ymax);
252 		else
253 			for (i = ymin; i < ymin; i++)
254 				cl_line(1, i + 1);
255 		xmin = -1;
256 	}
257 	d_xmin = xmin;
258 	d_xmax = xmax;
259 	d_ymin = ymin;
260 	d_ymax = ymax;		/* for limited screen drawing */
261 	drawscreen();
262 	if (xmin <= 0 && xmax == MAXX) {	/* draw stuff on right side
263 						 * of screen as needed */
264 		for (i = ymin; i < ymax; i++) {
265 			idx = bot_data[i].typ;
266 			if (c[idx]) {
267 				cursor(70, i + 1);
268 				lprcat(bot_data[i].string);
269 			}
270 			cbak[idx] = c[idx];
271 		}
272 	}
273 }
274 
275 /*
276 	drawscreen()
277 
278 	subroutine to redraw the whole screen as the player knows it
279  */
280 u_char            screen[MAXX][MAXY], d_flag;	/* template for the screen */
281 void
282 drawscreen()
283 {
284 	int    i, j, k;
285 	int             lastx, lasty;	/* variables used to optimize the
286 					 * object printing */
287 	if (d_xmin == 0 && d_xmax == MAXX && d_ymin == 0 && d_ymax == MAXY) {
288 		d_flag = 1;
289 		clear();	/* clear the screen */
290 	} else {
291 		d_flag = 0;
292 		cursor(1, 1);
293 	}
294 	if (d_xmin < 0)
295 		d_xmin = 0;	/* d_xmin=-1 means display all without
296 				 * bottomline */
297 
298 	for (i = d_ymin; i < d_ymax; i++)
299 		for (j = d_xmin; j < d_xmax; j++)
300 			if (know[j][i] == 0)
301 				screen[j][i] = ' ';
302 			else if ((k = mitem[j][i]) != 0)
303 				screen[j][i] = monstnamelist[k];
304 			else if ((k = item[j][i]) == OWALL)
305 				screen[j][i] = '#';
306 			else
307 				screen[j][i] = ' ';
308 
309 	for (i = d_ymin; i < d_ymax; i++) {
310 		j = d_xmin;
311 		while ((screen[j][i] == ' ') && (j < d_xmax))
312 			j++;
313 		/* was m=0 */
314 		if (j >= d_xmax)
315 			m = d_xmin;	/* don't search backwards if blank
316 					 * line */
317 		else {		/* search backwards for end of line */
318 			m = d_xmax - 1;
319 			while ((screen[m][i] == ' ') && (m > d_xmin))
320 				--m;
321 			if (j <= m)
322 				cursor(j + 1, i + 1);
323 			else
324 				continue;
325 		}
326 		while (j <= m) {
327 			if (j <= m - 3) {
328 				for (k = j; k <= j + 3; k++)
329 					if (screen[k][i] != ' ')
330 						k = 1000;
331 				if (k < 1000) {
332 					while (screen[j][i] == ' ' && j <= m)
333 						j++;
334 					cursor(j + 1, i + 1);
335 				}
336 			}
337 			lprc(screen[j++][i]);
338 		}
339 	}
340 	setbold();		/* print out only bold objects now */
341 
342 	for (lastx = lasty = 127, i = d_ymin; i < d_ymax; i++)
343 		for (j = d_xmin; j < d_xmax; j++) {
344 			if ((k = item[j][i]) != 0)
345 				if (k != OWALL)
346 					if ((know[j][i]) && (mitem[j][i] == 0))
347 						if (objnamelist[k] != ' ') {
348 							if (lasty != i + 1 || lastx != j)
349 								cursor(lastx = j + 1, lasty = i + 1);
350 							else
351 								lastx++;
352 							lprc(objnamelist[k]);
353 						}
354 		}
355 
356 	resetbold();
357 	if (d_flag) {
358 		always = 1;
359 		botside();
360 		always = 1;
361 		bot_linex();
362 	}
363 	oldx = 99;
364 	d_xmin = 0, d_xmax = MAXX, d_ymin = 0, d_ymax = MAXY;	/* for limited screen
365 								 * drawing */
366 }
367 
368 
369 /*
370 	showcell(x,y)
371 
372 	subroutine to display a cell location on the screen
373  */
374 void
375 showcell(x, y)
376 	int             x, y;
377 {
378 	int    i, j, k, m;
379 	if (c[BLINDCOUNT])
380 		return;		/* see nothing if blind		 */
381 	if (c[AWARENESS]) {
382 		minx = x - 3;
383 		maxx = x + 3;
384 		miny = y - 3;
385 		maxy = y + 3;
386 	} else {
387 		minx = x - 1;
388 		maxx = x + 1;
389 		miny = y - 1;
390 		maxy = y + 1;
391 	}
392 
393 	if (minx < 0)
394 		minx = 0;
395 	if (maxx > MAXX - 1)
396 		maxx = MAXX - 1;
397 	if (miny < 0)
398 		miny = 0;
399 	if (maxy > MAXY - 1)
400 		maxy = MAXY - 1;
401 
402 	for (j = miny; j <= maxy; j++)
403 		for (m = minx; m <= maxx; m++)
404 			if (know[m][j] == 0) {
405 				cursor(m + 1, j + 1);
406 				x = maxx;
407 				while (know[x][j])
408 					--x;
409 				for (i = m; i <= x; i++) {
410 					if ((k = mitem[i][j]) != 0)
411 						lprc(monstnamelist[k]);
412 					else
413 						switch (k = item[i][j]) {
414 						case OWALL:
415 						case 0:
416 						case OIVTELETRAP:
417 						case OTRAPARROWIV:
418 						case OIVDARTRAP:
419 						case OIVTRAPDOOR:
420 							lprc(objnamelist[k]);
421 							break;
422 
423 						default:
424 							setbold();
425 							lprc(objnamelist[k]);
426 							resetbold();
427 						};
428 					know[i][j] = 1;
429 				}
430 				m = maxx;
431 			}
432 }
433 
434 /*
435 	this routine shows only the spot that is given it.  the spaces around
436 	these coordinated are not shown
437 	used in godirect() in monster.c for missile weapons display
438  */
439 void
440 show1cell(x, y)
441 	int             x, y;
442 {
443 	if (c[BLINDCOUNT])
444 		return;		/* see nothing if blind		 */
445 	cursor(x + 1, y + 1);
446 	if ((k = mitem[x][y]) != 0)
447 		lprc(monstnamelist[k]);
448 	else
449 		switch (k = item[x][y]) {
450 		case OWALL:
451 		case 0:
452 		case OIVTELETRAP:
453 		case OTRAPARROWIV:
454 		case OIVDARTRAP:
455 		case OIVTRAPDOOR:
456 			lprc(objnamelist[k]);
457 			break;
458 
459 		default:
460 			setbold();
461 			lprc(objnamelist[k]);
462 			resetbold();
463 		};
464 	know[x][y] |= 1;	/* we end up knowing about it */
465 }
466 
467 /*
468 	showplayer()
469 
470 	subroutine to show where the player is on the screen
471 	cursor values start from 1 up
472  */
473 void
474 showplayer()
475 {
476 	cursor(playerx + 1, playery + 1);
477 	oldx = playerx;
478 	oldy = playery;
479 }
480 
481 /*
482 	moveplayer(dir)
483 
484 	subroutine to move the player from one room to another
485 	returns 0 if can't move in that direction or hit a monster or on an object
486 	else returns 1
487 	nomove is set to 1 to stop the next move (inadvertent monsters hitting
488 	players when walking into walls) if player walks off screen or into wall
489  */
490 short           diroffx[] = {0, 0, 1, 0, -1, 1, -1, 1, -1};
491 short           diroffy[] = {0, 1, 0, -1, 0, -1, -1, 1, 1};
492 int
493 moveplayer(dir)
494 	int             dir;	/* from = present room #  direction =
495 				 * [1-north] [2-east] [3-south] [4-west]
496 				 * [5-northeast] [6-northwest] [7-southeast]
497 				 * [8-southwest] if direction=0, don't
498 				 * move--just show where he is */
499 {
500 	int    k, m, i, j;
501 	if (c[CONFUSE])
502 		if (c[LEVEL] < rnd(30))
503 			dir = rund(9);	/* if confused any dir */
504 	k = playerx + diroffx[dir];
505 	m = playery + diroffy[dir];
506 	if (k < 0 || k >= MAXX || m < 0 || m >= MAXY) {
507 		nomove = 1;
508 		return (yrepcount = 0);
509 	}
510 	i = item[k][m];
511 	j = mitem[k][m];
512 	if (i == OWALL && c[WTW] == 0) {
513 		nomove = 1;
514 		return (yrepcount = 0);
515 	}			/* hit a wall	 */
516 	if (k == 33 && m == MAXY - 1 && level == 1) {
517 		newcavelevel(0);
518 		for (k = 0; k < MAXX; k++)
519 			for (m = 0; m < MAXY; m++)
520 				if (item[k][m] == OENTRANCE) {
521 					playerx = k;
522 					playery = m;
523 					positionplayer();
524 					drawscreen();
525 					return (0);
526 				}
527 	}
528 	if (j > 0) {
529 		hitmonster(k, m);
530 		return (yrepcount = 0);
531 	}			/* hit a monster */
532 	lastpx = playerx;
533 	lastpy = playery;
534 	playerx = k;
535 	playery = m;
536 	if (i && i != OTRAPARROWIV && i != OIVTELETRAP && i != OIVDARTRAP && i != OIVTRAPDOOR)
537 		return (yrepcount = 0);
538 	else
539 		return (1);
540 }
541 
542 
543 /*
544  *	function to show what magic items have been discovered thus far
545  *	enter with -1 for just spells, anything else will give scrolls & potions
546  */
547 static int      lincount, count;
548 void
549 seemagic(arg)
550 	int             arg;
551 {
552 	int    i, number = 0;
553 	count = lincount = 0;
554 	nosignal = 1;
555 
556 	if (arg == -1) {	/* if display spells while casting one */
557 		for (number = i = 0; i < SPNUM; i++)
558 			if (spelknow[i])
559 				number++;
560 		number = (number + 2) / 3 + 4;	/* # lines needed to display */
561 		cl_up(79, number);
562 		cursor(1, 1);
563 	} else {
564 		resetscroll();
565 		clear();
566 	}
567 
568 	lprcat("The magic spells you have discovered thus far:\n\n");
569 	for (i = 0; i < SPNUM; i++)
570 		if (spelknow[i]) {
571 			lprintf("%s %-20s ", spelcode[i], spelname[i]);
572 			seepage();
573 		}
574 	if (arg == -1) {
575 		seepage();
576 		more();
577 		nosignal = 0;
578 		draws(0, MAXX, 0, number);
579 		return;
580 	}
581 	lincount += 3;
582 	if (count != 0) {
583 		count = 2;
584 		seepage();
585 	}
586 	lprcat("\nThe magic scrolls you have found to date are:\n\n");
587 	count = 0;
588 	for (i = 0; i < MAXSCROLL; i++)
589 		if (scrollname[i][0])
590 			if (scrollname[i][1] != ' ') {
591 				lprintf("%-26s", &scrollname[i][1]);
592 				seepage();
593 			}
594 	lincount += 3;
595 	if (count != 0) {
596 		count = 2;
597 		seepage();
598 	}
599 	lprcat("\nThe magic potions you have found to date are:\n\n");
600 	count = 0;
601 	for (i = 0; i < MAXPOTION; i++)
602 		if (potionname[i][0])
603 			if (potionname[i][1] != ' ') {
604 				lprintf("%-26s", &potionname[i][1]);
605 				seepage();
606 			}
607 	if (lincount != 0)
608 		more();
609 	nosignal = 0;
610 	setscroll();
611 	drawscreen();
612 }
613 
614 /*
615  *	subroutine to paginate the seemagic function
616  */
617 void
618 seepage()
619 {
620 	if (++count == 3) {
621 		lincount++;
622 		count = 0;
623 		lprc('\n');
624 		if (lincount > 17) {
625 			lincount = 0;
626 			more();
627 			clear();
628 		}
629 	}
630 }
631