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