Home | History | Annotate | Line # | Download | only in larn
display.c revision 1.8
      1 /*	$NetBSD: display.c,v 1.8 2008/02/03 19:20:41 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.8 2008/02/03 19:20:41 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 char            always = 0;
     23 /*
     24 	bottomline()
     25 
     26 	now for the bottom line of the display
     27  */
     28 void
     29 bottomline()
     30 {
     31 	recalc();
     32 	bot1f = 1;
     33 }
     34 
     35 void
     36 bottomhp()
     37 {
     38 	bot2f = 1;
     39 }
     40 
     41 void
     42 bottomspell()
     43 {
     44 	bot3f = 1;
     45 }
     46 
     47 void
     48 bottomdo()
     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
     66 bot_linex()
     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
    145 bottomgold()
    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
    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
    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
    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
    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 int             d_xmin = 0, d_xmax = MAXX, d_ymin = 0, d_ymax = MAXY;
    245 
    246 void
    247 draws(xmin, xmax, ymin, ymax)
    248 	int             xmin, xmax, ymin, ymax;
    249 {
    250 	int    i, idx;
    251 	if (xmin == 0 && xmax == MAXX) {	/* clear section of screen as
    252 						 * needed */
    253 		if (ymin == 0)
    254 			cl_up(79, ymax);
    255 		else
    256 			for (i = ymin; i < ymin; i++)
    257 				cl_line(1, i + 1);
    258 		xmin = -1;
    259 	}
    260 	d_xmin = xmin;
    261 	d_xmax = xmax;
    262 	d_ymin = ymin;
    263 	d_ymax = ymax;		/* for limited screen drawing */
    264 	drawscreen();
    265 	if (xmin <= 0 && xmax == MAXX) {	/* draw stuff on right side
    266 						 * of screen as needed */
    267 		for (i = ymin; i < ymax; i++) {
    268 			idx = bot_data[i].typ;
    269 			if (c[idx]) {
    270 				cursor(70, i + 1);
    271 				lprcat(bot_data[i].string);
    272 			}
    273 			cbak[idx] = c[idx];
    274 		}
    275 	}
    276 }
    277 
    278 /*
    279 	drawscreen()
    280 
    281 	subroutine to redraw the whole screen as the player knows it
    282  */
    283 u_char            screen[MAXX][MAXY], d_flag;	/* template for the screen */
    284 void
    285 drawscreen()
    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
    378 showcell(x, y)
    379 	int             x, y;
    380 {
    381 	int    i, j, kk, mm;
    382 	if (c[BLINDCOUNT])
    383 		return;		/* see nothing if blind		 */
    384 	if (c[AWARENESS]) {
    385 		minx = x - 3;
    386 		maxx = x + 3;
    387 		miny = y - 3;
    388 		maxy = y + 3;
    389 	} else {
    390 		minx = x - 1;
    391 		maxx = x + 1;
    392 		miny = y - 1;
    393 		maxy = y + 1;
    394 	}
    395 
    396 	if (minx < 0)
    397 		minx = 0;
    398 	if (maxx > MAXX - 1)
    399 		maxx = MAXX - 1;
    400 	if (miny < 0)
    401 		miny = 0;
    402 	if (maxy > MAXY - 1)
    403 		maxy = MAXY - 1;
    404 
    405 	for (j = miny; j <= maxy; j++)
    406 		for (mm = minx; mm <= maxx; mm++)
    407 			if (know[mm][j] == 0) {
    408 				cursor(mm + 1, j + 1);
    409 				x = maxx;
    410 				while (know[x][j])
    411 					--x;
    412 				for (i = mm; i <= x; i++) {
    413 					if ((kk = mitem[i][j]) != 0)
    414 						lprc(monstnamelist[kk]);
    415 					else
    416 						switch (kk = item[i][j]) {
    417 						case OWALL:
    418 						case 0:
    419 						case OIVTELETRAP:
    420 						case OTRAPARROWIV:
    421 						case OIVDARTRAP:
    422 						case OIVTRAPDOOR:
    423 							lprc(objnamelist[kk]);
    424 							break;
    425 
    426 						default:
    427 							setbold();
    428 							lprc(objnamelist[kk]);
    429 							resetbold();
    430 						};
    431 					know[i][j] = 1;
    432 				}
    433 				mm = maxx;
    434 			}
    435 }
    436 
    437 /*
    438 	this routine shows only the spot that is given it.  the spaces around
    439 	these coordinated are not shown
    440 	used in godirect() in monster.c for missile weapons display
    441  */
    442 void
    443 show1cell(x, y)
    444 	int             x, y;
    445 {
    446 	if (c[BLINDCOUNT])
    447 		return;		/* see nothing if blind		 */
    448 	cursor(x + 1, y + 1);
    449 	if ((k = mitem[x][y]) != 0)
    450 		lprc(monstnamelist[k]);
    451 	else
    452 		switch (k = item[x][y]) {
    453 		case OWALL:
    454 		case 0:
    455 		case OIVTELETRAP:
    456 		case OTRAPARROWIV:
    457 		case OIVDARTRAP:
    458 		case OIVTRAPDOOR:
    459 			lprc(objnamelist[k]);
    460 			break;
    461 
    462 		default:
    463 			setbold();
    464 			lprc(objnamelist[k]);
    465 			resetbold();
    466 		};
    467 	know[x][y] |= 1;	/* we end up knowing about it */
    468 }
    469 
    470 /*
    471 	showplayer()
    472 
    473 	subroutine to show where the player is on the screen
    474 	cursor values start from 1 up
    475  */
    476 void
    477 showplayer()
    478 {
    479 	cursor(playerx + 1, playery + 1);
    480 	oldx = playerx;
    481 	oldy = playery;
    482 }
    483 
    484 /*
    485 	moveplayer(dir)
    486 
    487 	subroutine to move the player from one room to another
    488 	returns 0 if can't move in that direction or hit a monster or on an object
    489 	else returns 1
    490 	nomove is set to 1 to stop the next move (inadvertent monsters hitting
    491 	players when walking into walls) if player walks off screen or into wall
    492  */
    493 short           diroffx[] = {0, 0, 1, 0, -1, 1, -1, 1, -1};
    494 short           diroffy[] = {0, 1, 0, -1, 0, -1, -1, 1, 1};
    495 int
    496 moveplayer(dir)
    497 	int             dir;	/* from = present room #  direction =
    498 				 * [1-north] [2-east] [3-south] [4-west]
    499 				 * [5-northeast] [6-northwest] [7-southeast]
    500 				 * [8-southwest] if direction=0, don't
    501 				 * move--just show where he is */
    502 {
    503 	int    kk, mm, i, j;
    504 	if (c[CONFUSE])
    505 		if (c[LEVEL] < rnd(30))
    506 			dir = rund(9);	/* if confused any dir */
    507 	kk = playerx + diroffx[dir];
    508 	mm = playery + diroffy[dir];
    509 	if (kk < 0 || kk >= MAXX || mm < 0 || mm >= MAXY) {
    510 		nomove = 1;
    511 		return (yrepcount = 0);
    512 	}
    513 	i = item[kk][mm];
    514 	j = mitem[kk][mm];
    515 	if (i == OWALL && c[WTW] == 0) {
    516 		nomove = 1;
    517 		return (yrepcount = 0);
    518 	}			/* hit a wall	 */
    519 	if (kk == 33 && mm == MAXY - 1 && level == 1) {
    520 		newcavelevel(0);
    521 		for (kk = 0; kk < MAXX; kk++)
    522 			for (mm = 0; mm < MAXY; mm++)
    523 				if (item[kk][mm] == OENTRANCE) {
    524 					playerx = kk;
    525 					playery = mm;
    526 					positionplayer();
    527 					drawscreen();
    528 					return (0);
    529 				}
    530 	}
    531 	if (j > 0) {
    532 		hitmonster(kk, mm);
    533 		return (yrepcount = 0);
    534 	}			/* hit a monster */
    535 	lastpx = playerx;
    536 	lastpy = playery;
    537 	playerx = kk;
    538 	playery = mm;
    539 	if (i && i != OTRAPARROWIV && i != OIVTELETRAP && i != OIVDARTRAP && i != OIVTRAPDOOR)
    540 		return (yrepcount = 0);
    541 	else
    542 		return (1);
    543 }
    544 
    545 
    546 /*
    547  *	function to show what magic items have been discovered thus far
    548  *	enter with -1 for just spells, anything else will give scrolls & potions
    549  */
    550 static int      lincount, count;
    551 void
    552 seemagic(arg)
    553 	int             arg;
    554 {
    555 	int    i, number = 0;
    556 	count = lincount = 0;
    557 	nosignal = 1;
    558 
    559 	if (arg == -1) {	/* if display spells while casting one */
    560 		for (number = i = 0; i < SPNUM; i++)
    561 			if (spelknow[i])
    562 				number++;
    563 		number = (number + 2) / 3 + 4;	/* # lines needed to display */
    564 		cl_up(79, number);
    565 		cursor(1, 1);
    566 	} else {
    567 		resetscroll();
    568 		clear();
    569 	}
    570 
    571 	lprcat("The magic spells you have discovered thus far:\n\n");
    572 	for (i = 0; i < SPNUM; i++)
    573 		if (spelknow[i]) {
    574 			lprintf("%s %-20s ", spelcode[i], spelname[i]);
    575 			seepage();
    576 		}
    577 	if (arg == -1) {
    578 		seepage();
    579 		more();
    580 		nosignal = 0;
    581 		draws(0, MAXX, 0, number);
    582 		return;
    583 	}
    584 	lincount += 3;
    585 	if (count != 0) {
    586 		count = 2;
    587 		seepage();
    588 	}
    589 	lprcat("\nThe magic scrolls you have found to date are:\n\n");
    590 	count = 0;
    591 	for (i = 0; i < MAXSCROLL; i++)
    592 		if (scrollname[i][0])
    593 			if (scrollname[i][1] != ' ') {
    594 				lprintf("%-26s", &scrollname[i][1]);
    595 				seepage();
    596 			}
    597 	lincount += 3;
    598 	if (count != 0) {
    599 		count = 2;
    600 		seepage();
    601 	}
    602 	lprcat("\nThe magic potions you have found to date are:\n\n");
    603 	count = 0;
    604 	for (i = 0; i < MAXPOTION; i++)
    605 		if (potionname[i][0])
    606 			if (potionname[i][1] != ' ') {
    607 				lprintf("%-26s", &potionname[i][1]);
    608 				seepage();
    609 			}
    610 	if (lincount != 0)
    611 		more();
    612 	nosignal = 0;
    613 	setscroll();
    614 	drawscreen();
    615 }
    616 
    617 /*
    618  *	subroutine to paginate the seemagic function
    619  */
    620 static void
    621 seepage(void)
    622 {
    623 	if (++count == 3) {
    624 		lincount++;
    625 		count = 0;
    626 		lprc('\n');
    627 		if (lincount > 17) {
    628 			lincount = 0;
    629 			more();
    630 			clear();
    631 		}
    632 	}
    633 }
    634