Home | History | Annotate | Line # | Download | only in larn
main.c revision 1.16
      1 /*	$NetBSD: main.c,v 1.16 2001/02/05 00:57:33 christos Exp $	*/
      2 
      3 /* main.c		 */
      4 #include <sys/cdefs.h>
      5 #ifndef lint
      6 __RCSID("$NetBSD: main.c,v 1.16 2001/02/05 00:57:33 christos Exp $");
      7 #endif				/* not lint */
      8 
      9 #include <sys/types.h>
     10 #include <stdio.h>
     11 #include <pwd.h>
     12 #include <unistd.h>
     13 #include <stdlib.h>
     14 #include <string.h>
     15 #include "header.h"
     16 #include "extern.h"
     17 
     18 static char     copyright[] = "\nLarn is copyrighted 1986 by Noah Morgan.\n";
     19 int             srcount = 0;	/* line counter for showstr()	 */
     20 int             dropflag = 0;	/* if 1 then don't lookforobject() next round */
     21 int             rmst = 80;	/* random monster creation counter		 */
     22 int             userid;		/* the players login user id number */
     23 uid_t           uid, euid;	/* used for security */
     24 u_char          nowelcome = 0, nomove = 0;	/* if (nomove) then don't
     25 						 * count next iteration as a
     26 						 * move */
     27 static char     viewflag = 0;
     28 /*
     29  * if viewflag then we have done a 99 stay here and don't showcell in the
     30  * main loop
     31  */
     32 u_char          restorflag = 0;	/* 1 means restore has been done	 */
     33 static char     cmdhelp[] = "\
     34 Cmd line format: larn [-slicnh] [-o<optsfile>] [-##] [++]\n\
     35   -s   show the scoreboard\n\
     36   -l   show the logfile (wizard id only)\n\
     37   -i   show scoreboard with inventories of dead characters\n\
     38   -c   create new scoreboard (wizard id only)\n\
     39   -n   suppress welcome message on starting game\n\
     40   -##  specify level of difficulty (example: -5)\n\
     41   -h   print this help text\n\
     42   ++   restore game from checkpoint file\n\
     43   -o<optsfile>   specify .larnopts filename to be used instead of \"~/.larnopts\"\n\
     44 ";
     45 #ifdef VT100
     46 static char    *termtypes[] = {"vt100", "vt101", "vt102", "vt103", "vt125",
     47 	"vt131", "vt140", "vt180", "vt220", "vt240", "vt241", "vt320", "vt340",
     48 "vt341"};
     49 #endif	/* VT100 */
     50 /*
     51 	************
     52 	MAIN PROGRAM
     53 	************
     54  */
     55 int
     56 main(argc, argv)
     57 	int             argc;
     58 	char          **argv;
     59 {
     60 	int    i;
     61 	int             hard;
     62 	const char     *ptr = 0;
     63 	struct passwd  *pwe;
     64 
     65 	i = 0;
     66 	euid = geteuid();
     67 	uid = getuid();
     68 	seteuid(uid);		/* give up "games" if we have it */
     69 	/*
     70 	 *	first task is to identify the player
     71 	 */
     72 #ifndef VT100
     73 	init_term();		/* setup the terminal (find out what type)
     74 				 * for termcap */
     75 #endif	/* VT100 */
     76 	/* try to get login name */
     77 	if (((ptr = getlogin()) == 0) || (*ptr == 0)) {
     78 		/* can we get it from /etc/passwd? */
     79 		if ((pwe = getpwuid(getuid())) != NULL)
     80 			ptr = pwe->pw_name;
     81 		else if ((ptr = getenv("USER")) == 0)
     82 			if ((ptr = getenv("LOGNAME")) == 0) {
     83 		noone:		write(2, "Can't find your logname.  Who Are You?\n", 39);
     84 				exit(1);
     85 			}
     86 	}
     87 	if (ptr == 0)
     88 		goto noone;
     89 	if (strlen(ptr) == 0)
     90 		goto noone;
     91 	/*
     92 	 *	second task is to prepare the pathnames the player will need
     93 	 */
     94 	strcpy(loginname, ptr);	/* save loginname of the user for logging
     95 				 * purposes */
     96 	strcpy(logname, ptr);	/* this will be overwritten with the players
     97 				 * name */
     98 	if ((ptr = getenv("HOME")) == NULL)
     99 		ptr = ".";
    100 	strcpy(savefilename, ptr);
    101 	strcat(savefilename, "/Larn.sav");	/* save file name in home
    102 						 * directory */
    103 	snprintf(optsfile, sizeof(optsfile), "%s/.larnopts", ptr);
    104 	/* the .larnopts filename */
    105 
    106 	/*
    107 	 *	now malloc the memory for the dungeon
    108 	 */
    109 	cell = (struct cel *) malloc(sizeof(struct cel) * (MAXLEVEL + MAXVLEVEL) * MAXX * MAXY);
    110 	if (cell == 0)
    111 		died(-285);	/* malloc failure */
    112 	lpbuf = malloc((5 * BUFBIG) >> 2);	/* output buffer */
    113 	inbuffer = malloc((5 * MAXIBUF) >> 2);	/* output buffer */
    114 	if ((lpbuf == 0) || (inbuffer == 0))
    115 		died(-285);	/* malloc() failure */
    116 
    117 	lcreat((char *) 0);
    118 	newgame();		/* set the initial clock  */
    119 	hard = -1;
    120 
    121 #ifdef VT100
    122 	/*
    123 	 *	check terminal type to avoid users who have not vt100 type terminals
    124 	 */
    125 	ttype = getenv("TERM");
    126 	for (j = 1, i = 0; i < sizeof(termtypes) / sizeof(char *); i++)
    127 		if (strcmp(ttype, termtypes[i]) == 0) {
    128 			j = 0;
    129 			break;
    130 		}
    131 	if (j) {
    132 		lprcat("Sorry, Larn needs a VT100 family terminal for all it's features.\n");
    133 		lflush();
    134 		exit(1);
    135 	}
    136 #endif	/* VT100 */
    137 
    138 	/*
    139 	 *	now make scoreboard if it is not there (don't clear)
    140 	 */
    141 	if (access(scorefile, 0) == -1)	/* not there */
    142 		makeboard();
    143 
    144 	/*
    145 	 *	now process the command line arguments
    146 	 */
    147 	for (i = 1; i < argc; i++) {
    148 		if (argv[i][0] == '-')
    149 			switch (argv[i][1]) {
    150 			case 's':
    151 				showscores();
    152 				exit(0);	/* show scoreboard   */
    153 
    154 			case 'l':	/* show log file     */
    155 				diedlog();
    156 				exit(0);
    157 
    158 			case 'i':
    159 				showallscores();
    160 				exit(0);	/* show all scoreboard */
    161 
    162 			case 'c':	/* anyone with password can create
    163 					 * scoreboard */
    164 				lprcat("Preparing to initialize the scoreboard.\n");
    165 				if (getpassword() != 0) {	/* make new scoreboard */
    166 					makeboard();
    167 					lprc('\n');
    168 					showscores();
    169 				}
    170 				exit(0);
    171 
    172 			case 'n':	/* no welcome msg	 */
    173 				nowelcome = 1;
    174 				argv[i][0] = 0;
    175 				break;
    176 
    177 			case '0':
    178 			case '1':
    179 			case '2':
    180 			case '3':
    181 			case '4':
    182 			case '5':
    183 			case '6':
    184 			case '7':
    185 			case '8':
    186 			case '9':	/* for hardness */
    187 				sscanf(&argv[i][1], "%d", &hard);
    188 				break;
    189 
    190 			case 'h':	/* print out command line arguments */
    191 				write(1, cmdhelp, sizeof(cmdhelp));
    192 				exit(0);
    193 
    194 			case 'o':	/* specify a .larnopts filename */
    195 				strncpy(optsfile, argv[i] + 2, 127);
    196 				break;
    197 
    198 			default:
    199 				printf("Unknown option <%s>\n", argv[i]);
    200 				exit(1);
    201 			};
    202 
    203 		if (argv[i][0] == '+') {
    204 			clear();
    205 			restorflag = 1;
    206 			if (argv[i][1] == '+') {
    207 				hitflag = 1;
    208 				restoregame(ckpfile);	/* restore checkpointed
    209 							 * game */
    210 			}
    211 			i = argc;
    212 		}
    213 	}
    214 
    215 	readopts();		/* read the options file if there is one */
    216 
    217 
    218 #ifdef UIDSCORE
    219 	userid = geteuid();	/* obtain the user's effective id number */
    220 #else	/* UIDSCORE */
    221 	userid = getplid(logname);	/* obtain the players id number */
    222 #endif	/* UIDSCORE */
    223 	if (userid < 0) {
    224 		write(2, "Can't obtain playerid\n", 22);
    225 		exit(1);
    226 	}
    227 #ifdef HIDEBYLINK
    228 	/*
    229 	 *	this section of code causes the program to look like something else to ps
    230 	 */
    231 	if (strcmp(psname, argv[0])) {	/* if a different process name only */
    232 		if ((i = access(psname, 1)) < 0) {	/* link not there */
    233 			if (link(argv[0], psname) >= 0) {
    234 				argv[0] = psname;
    235 				execv(psname, argv);
    236 			}
    237 		} else
    238 			unlink(psname);
    239 	}
    240 	for (i = 1; i < argc; i++) {
    241 		szero(argv[i]);	/* zero the argument to avoid ps snooping */
    242 	}
    243 #endif	/* HIDEBYLINK */
    244 
    245 	if (access(savefilename, 0) == 0) {	/* restore game if need to */
    246 		clear();
    247 		restorflag = 1;
    248 		hitflag = 1;
    249 		restoregame(savefilename);	/* restore last game	 */
    250 	}
    251 	sigsetup();		/* trap all needed signals	 */
    252 	sethard(hard);		/* set up the desired difficulty				 */
    253 	setupvt100();		/* setup the terminal special mode				 */
    254 	if (c[HP] == 0) {	/* create new game */
    255 		makeplayer();	/* make the character that will play			 */
    256 		newcavelevel(0);/* make the dungeon						 	 */
    257 		predostuff = 1;	/* tell signals that we are in the welcome
    258 				 * screen */
    259 		if (nowelcome == 0)
    260 			welcome();	/* welcome the player to the game */
    261 	}
    262 	drawscreen();		/* show the initial dungeon					 */
    263 	predostuff = 2;		/* tell the trap functions that they must do
    264 				 * a showplayer() from here on */
    265 #if 0
    266 	nice(1);		/* games should be run niced */
    267 #endif
    268 	yrepcount = hit2flag = 0;
    269 	while (1) {
    270 		if (dropflag == 0)
    271 			lookforobject();	/* see if there is an object
    272 						 * here	 */
    273 		else
    274 			dropflag = 0;	/* don't show it just dropped an item */
    275 		if (hitflag == 0) {
    276 			if (c[HASTEMONST])
    277 				movemonst();
    278 			movemonst();
    279 		}		/* move the monsters		 */
    280 		if (viewflag == 0)
    281 			showcell(playerx, playery);
    282 		else
    283 			viewflag = 0;	/* show stuff around player	 */
    284 		if (hit3flag)
    285 			flushall();
    286 		hitflag = hit3flag = 0;
    287 		nomove = 1;
    288 		bot_linex();	/* update bottom line */
    289 		while (nomove) {
    290 			if (hit3flag)
    291 				flushall();
    292 			nomove = 0;
    293 			parse();
    294 		}		/* get commands and make moves	 */
    295 		regen();	/* regenerate hp and spells			 */
    296 		if (c[TIMESTOP] == 0)
    297 			if (--rmst <= 0) {
    298 				rmst = 120 - (level << 2);
    299 				fillmonst(makemonst(level));
    300 			}
    301 	}
    302 }
    303 
    304 
    305 /*
    306 	showstr()
    307 
    308 	show character's inventory
    309  */
    310 void
    311 showstr()
    312 {
    313 	int    i, number;
    314 	for (number = 3, i = 0; i < 26; i++)
    315 		if (iven[i])
    316 			number++;	/* count items in inventory */
    317 	t_setup(number);
    318 	qshowstr();
    319 	t_endup(number);
    320 }
    321 
    322 void
    323 qshowstr()
    324 {
    325 	int    i, j, k, sigsav;
    326 	srcount = 0;
    327 	sigsav = nosignal;
    328 	nosignal = 1;		/* don't allow ^c etc */
    329 	if (c[GOLD]) {
    330 		lprintf(".)   %d gold pieces", (long) c[GOLD]);
    331 		srcount++;
    332 	}
    333 	for (k = 26; k >= 0; k--)
    334 		if (iven[k]) {
    335 			for (i = 22; i < 84; i++)
    336 				for (j = 0; j <= k; j++)
    337 					if (i == iven[j])
    338 						show3(j);
    339 			k = 0;
    340 		}
    341 	lprintf("\nElapsed time is %d.  You have %d mobuls left", (long) ((gltime + 99) / 100 + 1), (long) ((TIMELIMIT - gltime) / 100));
    342 	more();
    343 	nosignal = sigsav;
    344 }
    345 
    346 /*
    347  *	subroutine to clear screen depending on # lines to display
    348  */
    349 void
    350 t_setup(count)
    351 	int    count;
    352 {
    353 	if (count < 20) {	/* how do we clear the screen? */
    354 		cl_up(79, count);
    355 		cursor(1, 1);
    356 	} else {
    357 		resetscroll();
    358 		clear();
    359 	}
    360 }
    361 
    362 /*
    363  *	subroutine to restore normal display screen depending on t_setup()
    364  */
    365 void
    366 t_endup(count)
    367 	int    count;
    368 {
    369 	if (count < 18)		/* how did we clear the screen? */
    370 		draws(0, MAXX, 0, (count > MAXY) ? MAXY : count);
    371 	else {
    372 		drawscreen();
    373 		setscroll();
    374 	}
    375 }
    376 
    377 /*
    378 	function to show the things player is wearing only
    379  */
    380 void
    381 showwear()
    382 {
    383 	int    i, j, sigsav, count;
    384 	sigsav = nosignal;
    385 	nosignal = 1;		/* don't allow ^c etc */
    386 	srcount = 0;
    387 
    388 	for (count = 2, j = 0; j <= 26; j++)	/* count number of items we
    389 						 * will display */
    390 		if ((i = iven[j]) != 0)
    391 			switch (i) {
    392 			case OLEATHER:
    393 			case OPLATE:
    394 			case OCHAIN:
    395 			case ORING:
    396 			case OSTUDLEATHER:
    397 			case OSPLINT:
    398 			case OPLATEARMOR:
    399 			case OSSPLATE:
    400 			case OSHIELD:
    401 				count++;
    402 			};
    403 
    404 	t_setup(count);
    405 
    406 	for (i = 22; i < 84; i++)
    407 		for (j = 0; j <= 26; j++)
    408 			if (i == iven[j])
    409 				switch (i) {
    410 				case OLEATHER:
    411 				case OPLATE:
    412 				case OCHAIN:
    413 				case ORING:
    414 				case OSTUDLEATHER:
    415 				case OSPLINT:
    416 				case OPLATEARMOR:
    417 				case OSSPLATE:
    418 				case OSHIELD:
    419 					show3(j);
    420 				};
    421 	more();
    422 	nosignal = sigsav;
    423 	t_endup(count);
    424 }
    425 
    426 /*
    427 	function to show the things player can wield only
    428  */
    429 void
    430 showwield()
    431 {
    432 	int    i, j, sigsav, count;
    433 	sigsav = nosignal;
    434 	nosignal = 1;		/* don't allow ^c etc */
    435 	srcount = 0;
    436 
    437 	for (count = 2, j = 0; j <= 26; j++)	/* count how many items */
    438 		if ((i = iven[j]) != 0)
    439 			switch (i) {
    440 			case ODIAMOND:
    441 			case ORUBY:
    442 			case OEMERALD:
    443 			case OSAPPHIRE:
    444 			case OBOOK:
    445 			case OCHEST:
    446 			case OLARNEYE:
    447 			case ONOTHEFT:
    448 			case OSPIRITSCARAB:
    449 			case OCUBEofUNDEAD:
    450 			case OPOTION:
    451 			case OSCROLL:
    452 				break;
    453 			default:
    454 				count++;
    455 			};
    456 
    457 	t_setup(count);
    458 
    459 	for (i = 22; i < 84; i++)
    460 		for (j = 0; j <= 26; j++)
    461 			if (i == iven[j])
    462 				switch (i) {
    463 				case ODIAMOND:
    464 				case ORUBY:
    465 				case OEMERALD:
    466 				case OSAPPHIRE:
    467 				case OBOOK:
    468 				case OCHEST:
    469 				case OLARNEYE:
    470 				case ONOTHEFT:
    471 				case OSPIRITSCARAB:
    472 				case OCUBEofUNDEAD:
    473 				case OPOTION:
    474 				case OSCROLL:
    475 					break;
    476 				default:
    477 					show3(j);
    478 				};
    479 	more();
    480 	nosignal = sigsav;
    481 	t_endup(count);
    482 }
    483 
    484 /*
    485  *	function to show the things player can read only
    486  */
    487 void
    488 showread()
    489 {
    490 	int    i, j, sigsav, count;
    491 	sigsav = nosignal;
    492 	nosignal = 1;		/* don't allow ^c etc */
    493 	srcount = 0;
    494 
    495 	for (count = 2, j = 0; j <= 26; j++)
    496 		switch (iven[j]) {
    497 		case OBOOK:
    498 		case OSCROLL:
    499 			count++;
    500 		};
    501 	t_setup(count);
    502 
    503 	for (i = 22; i < 84; i++)
    504 		for (j = 0; j <= 26; j++)
    505 			if (i == iven[j])
    506 				switch (i) {
    507 				case OBOOK:
    508 				case OSCROLL:
    509 					show3(j);
    510 				};
    511 	more();
    512 	nosignal = sigsav;
    513 	t_endup(count);
    514 }
    515 
    516 /*
    517  *	function to show the things player can eat only
    518  */
    519 void
    520 showeat()
    521 {
    522 	int    i, j, sigsav, count;
    523 	sigsav = nosignal;
    524 	nosignal = 1;		/* don't allow ^c etc */
    525 	srcount = 0;
    526 
    527 	for (count = 2, j = 0; j <= 26; j++)
    528 		switch (iven[j]) {
    529 		case OCOOKIE:
    530 			count++;
    531 		};
    532 	t_setup(count);
    533 
    534 	for (i = 22; i < 84; i++)
    535 		for (j = 0; j <= 26; j++)
    536 			if (i == iven[j])
    537 				switch (i) {
    538 				case OCOOKIE:
    539 					show3(j);
    540 				};
    541 	more();
    542 	nosignal = sigsav;
    543 	t_endup(count);
    544 }
    545 
    546 /*
    547 	function to show the things player can quaff only
    548  */
    549 void
    550 showquaff()
    551 {
    552 	int    i, j, sigsav, count;
    553 	sigsav = nosignal;
    554 	nosignal = 1;		/* don't allow ^c etc */
    555 	srcount = 0;
    556 
    557 	for (count = 2, j = 0; j <= 26; j++)
    558 		switch (iven[j]) {
    559 		case OPOTION:
    560 			count++;
    561 		};
    562 	t_setup(count);
    563 
    564 	for (i = 22; i < 84; i++)
    565 		for (j = 0; j <= 26; j++)
    566 			if (i == iven[j])
    567 				switch (i) {
    568 				case OPOTION:
    569 					show3(j);
    570 				};
    571 	more();
    572 	nosignal = sigsav;
    573 	t_endup(count);
    574 }
    575 
    576 void
    577 show1(idx, str2)
    578 	int    idx;
    579 	char  *str2[];
    580 {
    581 	lprintf("\n%c)   %s", idx + 'a', objectname[iven[idx]]);
    582 	if (str2 != 0 && str2[ivenarg[idx]][0] != 0)
    583 		lprintf(" of%s", str2[ivenarg[idx]]);
    584 }
    585 
    586 void
    587 show3(index)
    588 	int    index;
    589 {
    590 	switch (iven[index]) {
    591 	case OPOTION:
    592 		show1(index, potionname);
    593 		break;
    594 	case OSCROLL:
    595 		show1(index, scrollname);
    596 		break;
    597 
    598 	case OLARNEYE:
    599 	case OBOOK:
    600 	case OSPIRITSCARAB:
    601 	case ODIAMOND:
    602 	case ORUBY:
    603 	case OCUBEofUNDEAD:
    604 	case OEMERALD:
    605 	case OCHEST:
    606 	case OCOOKIE:
    607 	case OSAPPHIRE:
    608 	case ONOTHEFT:
    609 		show1(index, (char **) 0);
    610 		break;
    611 
    612 	default:
    613 		lprintf("\n%c)   %s", index + 'a', objectname[iven[index]]);
    614 		if (ivenarg[index] > 0)
    615 			lprintf(" + %d", (long) ivenarg[index]);
    616 		else if (ivenarg[index] < 0)
    617 			lprintf(" %d", (long) ivenarg[index]);
    618 		break;
    619 	}
    620 	if (c[WIELD] == index)
    621 		lprcat(" (weapon in hand)");
    622 	if ((c[WEAR] == index) || (c[SHIELD] == index))
    623 		lprcat(" (being worn)");
    624 	if (++srcount >= 22) {
    625 		srcount = 0;
    626 		more();
    627 		clear();
    628 	}
    629 }
    630 
    631 /*
    632 	subroutine to randomly create monsters if needed
    633  */
    634 void
    635 randmonst()
    636 {
    637 	if (c[TIMESTOP])
    638 		return;		/* don't make monsters if time is stopped	 */
    639 	if (--rmst <= 0) {
    640 		rmst = 120 - (level << 2);
    641 		fillmonst(makemonst(level));
    642 	}
    643 }
    644 
    645 
    646 
    647 /*
    648 	parse()
    649 
    650 	get and execute a command
    651  */
    652 void
    653 parse()
    654 {
    655 	int    i, j, k, flag;
    656 	while (1) {
    657 		k = yylex();
    658 		switch (k) {	/* get the token from the input and switch on
    659 				 * it	 */
    660 		case 'h':
    661 			moveplayer(4);
    662 			return;	/* west		 */
    663 		case 'H':
    664 			run(4);
    665 			return;	/* west		 */
    666 		case 'l':
    667 			moveplayer(2);
    668 			return;	/* east		 */
    669 		case 'L':
    670 			run(2);
    671 			return;	/* east		 */
    672 		case 'j':
    673 			moveplayer(1);
    674 			return;	/* south		 */
    675 		case 'J':
    676 			run(1);
    677 			return;	/* south		 */
    678 		case 'k':
    679 			moveplayer(3);
    680 			return;	/* north		 */
    681 		case 'K':
    682 			run(3);
    683 			return;	/* north		 */
    684 		case 'u':
    685 			moveplayer(5);
    686 			return;	/* northeast	 */
    687 		case 'U':
    688 			run(5);
    689 			return;	/* northeast	 */
    690 		case 'y':
    691 			moveplayer(6);
    692 			return;	/* northwest	 */
    693 		case 'Y':
    694 			run(6);
    695 			return;	/* northwest	 */
    696 		case 'n':
    697 			moveplayer(7);
    698 			return;	/* southeast	 */
    699 		case 'N':
    700 			run(7);
    701 			return;	/* southeast	 */
    702 		case 'b':
    703 			moveplayer(8);
    704 			return;	/* southwest	 */
    705 		case 'B':
    706 			run(8);
    707 			return;	/* southwest	 */
    708 
    709 		case '.':
    710 			if (yrepcount)
    711 				viewflag = 1;
    712 			return;	/* stay here		 */
    713 
    714 		case 'w':
    715 			yrepcount = 0;
    716 			wield();
    717 			return;	/* wield a weapon */
    718 
    719 		case 'W':
    720 			yrepcount = 0;
    721 			wear();
    722 			return;	/* wear armor	 */
    723 
    724 		case 'r':
    725 			yrepcount = 0;
    726 			if (c[BLINDCOUNT]) {
    727 				cursors();
    728 				lprcat("\nYou can't read anything when you're blind!");
    729 			} else if (c[TIMESTOP] == 0)
    730 				readscr();
    731 			return;	/* to read a scroll	 */
    732 
    733 		case 'q':
    734 			yrepcount = 0;
    735 			if (c[TIMESTOP] == 0)
    736 				quaff();
    737 			return;	/* quaff a potion		 */
    738 
    739 		case 'd':
    740 			yrepcount = 0;
    741 			if (c[TIMESTOP] == 0)
    742 				dropobj();
    743 			return;	/* to drop an object	 */
    744 
    745 		case 'c':
    746 			yrepcount = 0;
    747 			cast();
    748 			return;	/* cast a spell	 */
    749 
    750 		case 'i':
    751 			yrepcount = 0;
    752 			nomove = 1;
    753 			showstr();
    754 			return;	/* status		 */
    755 
    756 		case 'e':
    757 			yrepcount = 0;
    758 			if (c[TIMESTOP] == 0)
    759 				eatcookie();
    760 			return;	/* to eat a fortune cookie */
    761 
    762 		case 'D':
    763 			yrepcount = 0;
    764 			seemagic(0);
    765 			nomove = 1;
    766 			return;	/* list spells and scrolls */
    767 
    768 		case '?':
    769 			yrepcount = 0;
    770 			help();
    771 			nomove = 1;
    772 			return;	/* give the help screen */
    773 
    774 		case 'S':
    775 			clear();
    776 			lprcat("Saving . . .");
    777 			lflush();
    778 			savegame(savefilename);
    779 			wizard = 1;
    780 			died(-257);	/* save the game - doesn't return	 */
    781 
    782 		case 'Z':
    783 			yrepcount = 0;
    784 			if (c[LEVEL] > 9) {
    785 				oteleport(1);
    786 				return;
    787 			}
    788 			cursors();
    789 			lprcat("\nAs yet, you don't have enough experience to use teleportation");
    790 			return;	/* teleport yourself	 */
    791 
    792 		case '^':	/* identify traps */
    793 			flag = yrepcount = 0;
    794 			cursors();
    795 			lprc('\n');
    796 			for (j = playery - 1; j < playery + 2; j++) {
    797 				if (j < 0)
    798 					j = 0;
    799 				if (j >= MAXY)
    800 					break;
    801 				for (i = playerx - 1; i < playerx + 2; i++) {
    802 					if (i < 0)
    803 						i = 0;
    804 					if (i >= MAXX)
    805 						break;
    806 					switch (item[i][j]) {
    807 					case OTRAPDOOR:
    808 					case ODARTRAP:
    809 					case OTRAPARROW:
    810 					case OTELEPORTER:
    811 						lprcat("\nIts ");
    812 						lprcat(objectname[item[i][j]]);
    813 						flag++;
    814 					};
    815 				}
    816 			}
    817 			if (flag == 0)
    818 				lprcat("\nNo traps are visible");
    819 			return;
    820 
    821 #if WIZID
    822 		case '_':	/* this is the fudge player password for
    823 				 * wizard mode */
    824 			yrepcount = 0;
    825 			cursors();
    826 			nomove = 1;
    827 			if (userid != wisid) {
    828 				lprcat("Sorry, you are not empowered to be a wizard.\n");
    829 				scbr();	/* system("stty -echo cbreak"); */
    830 				lflush();
    831 				return;
    832 			}
    833 			if (getpassword() == 0) {
    834 				scbr();	/* system("stty -echo cbreak"); */
    835 				return;
    836 			}
    837 			wizard = 1;
    838 			scbr();	/* system("stty -echo cbreak"); */
    839 			for (i = 0; i < 6; i++)
    840 				c[i] = 70;
    841 			iven[0] = iven[1] = 0;
    842 			take(OPROTRING, 50);
    843 			take(OLANCE, 25);
    844 			c[WIELD] = 1;
    845 			c[LANCEDEATH] = 1;
    846 			c[WEAR] = c[SHIELD] = -1;
    847 			raiseexperience(6000000L);
    848 			c[AWARENESS] += 25000;
    849 			{
    850 				int    i, j;
    851 				for (i = 0; i < MAXY; i++)
    852 					for (j = 0; j < MAXX; j++)
    853 						know[j][i] = 1;
    854 				for (i = 0; i < SPNUM; i++)
    855 					spelknow[i] = 1;
    856 				for (i = 0; i < MAXSCROLL; i++)
    857 					scrollname[i] = scrollhide[i];
    858 				for (i = 0; i < MAXPOTION; i++)
    859 					potionname[i] = potionhide[i];
    860 			}
    861 			for (i = 0; i < MAXSCROLL; i++)
    862 				if (strlen(scrollname[i]) > 2) {	/* no null items */
    863 					item[i][0] = OSCROLL;
    864 					iarg[i][0] = i;
    865 				}
    866 			for (i = MAXX - 1; i > MAXX - 1 - MAXPOTION; i--)
    867 				if (strlen(potionname[i - MAXX + MAXPOTION]) > 2) {	/* no null items */
    868 					item[i][0] = OPOTION;
    869 					iarg[i][0] = i - MAXX + MAXPOTION;
    870 				}
    871 			for (i = 1; i < MAXY; i++) {
    872 				item[0][i] = i;
    873 				iarg[0][i] = 0;
    874 			}
    875 			for (i = MAXY; i < MAXY + MAXX; i++) {
    876 				item[i - MAXY][MAXY - 1] = i;
    877 				iarg[i - MAXY][MAXY - 1] = 0;
    878 			}
    879 			for (i = MAXX + MAXY; i < MAXX + MAXY + MAXY; i++) {
    880 				item[MAXX - 1][i - MAXX - MAXY] = i;
    881 				iarg[MAXX - 1][i - MAXX - MAXY] = 0;
    882 			}
    883 			c[GOLD] += 25000;
    884 			drawscreen();
    885 			return;
    886 #endif
    887 
    888 		case 'T':
    889 			yrepcount = 0;
    890 			cursors();
    891 			if (c[SHIELD] != -1) {
    892 				c[SHIELD] = -1;
    893 				lprcat("\nYour shield is off");
    894 				bottomline();
    895 			} else if (c[WEAR] != -1) {
    896 				c[WEAR] = -1;
    897 				lprcat("\nYour armor is off");
    898 				bottomline();
    899 			} else
    900 				lprcat("\nYou aren't wearing anything");
    901 			return;
    902 
    903 		case 'g':
    904 			cursors();
    905 			lprintf("\nThe stuff you are carrying presently weighs %d pounds", (long) packweight());
    906 		case ' ':
    907 			yrepcount = 0;
    908 			nomove = 1;
    909 			return;
    910 
    911 		case 'v':
    912 			yrepcount = 0;
    913 			cursors();
    914 			lprintf("\nCaverns of Larn, Version %d.%d, Diff=%d", (long) VERSION, (long) SUBVERSION, (long) c[HARDGAME]);
    915 			if (wizard)
    916 				lprcat(" Wizard");
    917 			nomove = 1;
    918 			if (cheat)
    919 				lprcat(" Cheater");
    920 			lprcat(copyright);
    921 			return;
    922 
    923 		case 'Q':
    924 			yrepcount = 0;
    925 			quit();
    926 			nomove = 1;
    927 			return;	/* quit		 */
    928 
    929 		case 'L' - 64:
    930 			yrepcount = 0;
    931 			drawscreen();
    932 			nomove = 1;
    933 			return;	/* look		 */
    934 
    935 #if WIZID
    936 #ifdef EXTRA
    937 		case 'A':
    938 			yrepcount = 0;
    939 			nomove = 1;
    940 			if (wizard) {
    941 				diag();
    942 				return;
    943 			}	/* create diagnostic file */
    944 			return;
    945 #endif
    946 #endif
    947 		case 'P':
    948 			cursors();
    949 			if (outstanding_taxes > 0)
    950 				lprintf("\nYou presently owe %d gp in taxes.", (long) outstanding_taxes);
    951 			else
    952 				lprcat("\nYou do not owe any taxes.");
    953 			return;
    954 		};
    955 	}
    956 }
    957 
    958 void
    959 parse2()
    960 {
    961 	if (c[HASTEMONST])
    962 		movemonst();
    963 	movemonst();		/* move the monsters		 */
    964 	randmonst();
    965 	regen();
    966 }
    967 
    968 void
    969 run(dir)
    970 	int             dir;
    971 {
    972 	int    i;
    973 	i = 1;
    974 	while (i) {
    975 		i = moveplayer(dir);
    976 		if (i > 0) {
    977 			if (c[HASTEMONST])
    978 				movemonst();
    979 			movemonst();
    980 			randmonst();
    981 			regen();
    982 		}
    983 		if (hitflag)
    984 			i = 0;
    985 		if (i != 0)
    986 			showcell(playerx, playery);
    987 	}
    988 }
    989 
    990 /*
    991 	function to wield a weapon
    992  */
    993 void
    994 wield()
    995 {
    996 	int    i;
    997 	while (1) {
    998 		if ((i = whatitem("wield")) == '\33')
    999 			return;
   1000 		if (i != '.') {
   1001 			if (i == '*')
   1002 				showwield();
   1003 			else if (iven[i - 'a'] == 0) {
   1004 				ydhi(i);
   1005 				return;
   1006 			} else if (iven[i - 'a'] == OPOTION) {
   1007 				ycwi(i);
   1008 				return;
   1009 			} else if (iven[i - 'a'] == OSCROLL) {
   1010 				ycwi(i);
   1011 				return;
   1012 			} else if ((c[SHIELD] != -1) && (iven[i - 'a'] == O2SWORD)) {
   1013 				lprcat("\nBut one arm is busy with your shield!");
   1014 				return;
   1015 			} else {
   1016 				c[WIELD] = i - 'a';
   1017 				if (iven[i - 'a'] == OLANCE)
   1018 					c[LANCEDEATH] = 1;
   1019 				else
   1020 					c[LANCEDEATH] = 0;
   1021 				bottomline();
   1022 				return;
   1023 			}
   1024 		}
   1025 	}
   1026 }
   1027 
   1028 /*
   1029 	common routine to say you don't have an item
   1030  */
   1031 void
   1032 ydhi(x)
   1033 	int             x;
   1034 {
   1035 	cursors();
   1036 	lprintf("\nYou don't have item %c!", x);
   1037 }
   1038 void
   1039 ycwi(x)
   1040 	int             x;
   1041 {
   1042 	cursors();
   1043 	lprintf("\nYou can't wield item %c!", x);
   1044 }
   1045 
   1046 /*
   1047 	function to wear armor
   1048  */
   1049 void
   1050 wear()
   1051 {
   1052 	int    i;
   1053 	while (1) {
   1054 		if ((i = whatitem("wear")) == '\33')
   1055 			return;
   1056 		if (i != '.') {
   1057 			if (i == '*')
   1058 				showwear();
   1059 			else
   1060 				switch (iven[i - 'a']) {
   1061 				case 0:
   1062 					ydhi(i);
   1063 					return;
   1064 				case OLEATHER:
   1065 				case OCHAIN:
   1066 				case OPLATE:
   1067 				case OSTUDLEATHER:
   1068 				case ORING:
   1069 				case OSPLINT:
   1070 				case OPLATEARMOR:
   1071 				case OSSPLATE:
   1072 					if (c[WEAR] != -1) {
   1073 						lprcat("\nYou're already wearing some armor");
   1074 						return;
   1075 					}
   1076 					c[WEAR] = i - 'a';
   1077 					bottomline();
   1078 					return;
   1079 				case OSHIELD:
   1080 					if (c[SHIELD] != -1) {
   1081 						lprcat("\nYou are already wearing a shield");
   1082 						return;
   1083 					}
   1084 					if (iven[c[WIELD]] == O2SWORD) {
   1085 						lprcat("\nYour hands are busy with the two handed sword!");
   1086 						return;
   1087 					}
   1088 					c[SHIELD] = i - 'a';
   1089 					bottomline();
   1090 					return;
   1091 				default:
   1092 					lprcat("\nYou can't wear that!");
   1093 				};
   1094 		}
   1095 	}
   1096 }
   1097 
   1098 /*
   1099 	function to drop an object
   1100  */
   1101 void
   1102 dropobj()
   1103 {
   1104 	int    i;
   1105 	char  *p;
   1106 	long            amt;
   1107 	p = &item[playerx][playery];
   1108 	while (1) {
   1109 		if ((i = whatitem("drop")) == '\33')
   1110 			return;
   1111 		if (i == '*')
   1112 			showstr();
   1113 		else {
   1114 			if (i == '.') {	/* drop some gold */
   1115 				if (*p) {
   1116 					lprcat("\nThere's something here already!");
   1117 					return;
   1118 				}
   1119 				lprcat("\n\n");
   1120 				cl_dn(1, 23);
   1121 				lprcat("How much gold do you drop? ");
   1122 				if ((amt = readnum((long) c[GOLD])) == 0)
   1123 					return;
   1124 				if (amt > c[GOLD]) {
   1125 					lprcat("\nYou don't have that much!");
   1126 					return;
   1127 				}
   1128 				if (amt <= 32767) {
   1129 					*p = OGOLDPILE;
   1130 					i = amt;
   1131 				} else if (amt <= 327670L) {
   1132 					*p = ODGOLD;
   1133 					i = amt / 10;
   1134 					amt = 10 * i;
   1135 				} else if (amt <= 3276700L) {
   1136 					*p = OMAXGOLD;
   1137 					i = amt / 100;
   1138 					amt = 100 * i;
   1139 				} else if (amt <= 32767000L) {
   1140 					*p = OKGOLD;
   1141 					i = amt / 1000;
   1142 					amt = 1000 * i;
   1143 				} else {
   1144 					*p = OKGOLD;
   1145 					i = 32767;
   1146 					amt = 32767000L;
   1147 				}
   1148 				c[GOLD] -= amt;
   1149 				lprintf("You drop %d gold pieces", (long) amt);
   1150 				iarg[playerx][playery] = i;
   1151 				bottomgold();
   1152 				know[playerx][playery] = 0;
   1153 				dropflag = 1;
   1154 				return;
   1155 			}
   1156 			drop_object(i - 'a');
   1157 			return;
   1158 		}
   1159 	}
   1160 }
   1161 
   1162 /*
   1163  *	readscr()		Subroutine to read a scroll one is carrying
   1164  */
   1165 void
   1166 readscr()
   1167 {
   1168 	int    i;
   1169 	while (1) {
   1170 		if ((i = whatitem("read")) == '\33')
   1171 			return;
   1172 		if (i != '.') {
   1173 			if (i == '*')
   1174 				showread();
   1175 			else {
   1176 				if (iven[i - 'a'] == OSCROLL) {
   1177 					read_scroll(ivenarg[i - 'a']);
   1178 					iven[i - 'a'] = 0;
   1179 					return;
   1180 				}
   1181 				if (iven[i - 'a'] == OBOOK) {
   1182 					readbook(ivenarg[i - 'a']);
   1183 					iven[i - 'a'] = 0;
   1184 					return;
   1185 				}
   1186 				if (iven[i - 'a'] == 0) {
   1187 					ydhi(i);
   1188 					return;
   1189 				}
   1190 				lprcat("\nThere's nothing on it to read");
   1191 				return;
   1192 			}
   1193 		}
   1194 	}
   1195 }
   1196 
   1197 /*
   1198  *	subroutine to eat a cookie one is carrying
   1199  */
   1200 void
   1201 eatcookie()
   1202 {
   1203 	int    i;
   1204 	char           *p;
   1205 	while (1) {
   1206 		if ((i = whatitem("eat")) == '\33')
   1207 			return;
   1208 		if (i != '.') {
   1209 			if (i == '*')
   1210 				showeat();
   1211 			else {
   1212 				if (iven[i - 'a'] == OCOOKIE) {
   1213 					lprcat("\nThe cookie was delicious.");
   1214 					iven[i - 'a'] = 0;
   1215 					if (!c[BLINDCOUNT]) {
   1216 						if ((p = fortune()) != NULL) {
   1217 							lprcat("  Inside you find a scrap of paper that says:\n");
   1218 							lprcat(p);
   1219 						}
   1220 					}
   1221 					return;
   1222 				}
   1223 				if (iven[i - 'a'] == 0) {
   1224 					ydhi(i);
   1225 					return;
   1226 				}
   1227 				lprcat("\nYou can't eat that!");
   1228 				return;
   1229 			}
   1230 		}
   1231 	}
   1232 }
   1233 
   1234 /*
   1235  *	subroutine to quaff a potion one is carrying
   1236  */
   1237 void
   1238 quaff()
   1239 {
   1240 	int    i;
   1241 	while (1) {
   1242 		if ((i = whatitem("quaff")) == '\33')
   1243 			return;
   1244 		if (i != '.') {
   1245 			if (i == '*')
   1246 				showquaff();
   1247 			else {
   1248 				if (iven[i - 'a'] == OPOTION) {
   1249 					quaffpotion(ivenarg[i - 'a']);
   1250 					iven[i - 'a'] = 0;
   1251 					return;
   1252 				}
   1253 				if (iven[i - 'a'] == 0) {
   1254 					ydhi(i);
   1255 					return;
   1256 				}
   1257 				lprcat("\nYou wouldn't want to quaff that, would you? ");
   1258 				return;
   1259 			}
   1260 		}
   1261 	}
   1262 }
   1263 
   1264 /*
   1265 	function to ask what player wants to do
   1266  */
   1267 int
   1268 whatitem(str)
   1269 	char           *str;
   1270 {
   1271 	int             i;
   1272 	cursors();
   1273 	lprintf("\nWhat do you want to %s [* for all] ? ", str);
   1274 	i = 0;
   1275 	while (i > 'z' || (i < 'a' && i != '*' && i != '\33' && i != '.'))
   1276 		i = lgetchar();
   1277 	if (i == '\33')
   1278 		lprcat(" aborted");
   1279 	return (i);
   1280 }
   1281 
   1282 /*
   1283 	subroutine to get a number from the player
   1284 	and allow * to mean return amt, else return the number entered
   1285  */
   1286 unsigned long
   1287 readnum(mx)
   1288 	long            mx;
   1289 {
   1290 	int    i;
   1291 	unsigned long amt = 0;
   1292 	sncbr();
   1293 	if ((i = lgetchar()) == '*')
   1294 		amt = mx;	/* allow him to say * for all gold */
   1295 	else
   1296 		while (i != '\n') {
   1297 			if (i == '\033') {
   1298 				scbr();
   1299 				lprcat(" aborted");
   1300 				return (0);
   1301 			}
   1302 			if ((i <= '9') && (i >= '0') && (amt < 99999999))
   1303 				amt = amt * 10 + i - '0';
   1304 			i = lgetchar();
   1305 		}
   1306 	scbr();
   1307 	return (amt);
   1308 }
   1309 
   1310 #ifdef HIDEBYLINK
   1311 /*
   1312  *	routine to zero every byte in a string
   1313  */
   1314 void
   1315 szero(str)
   1316 	char  *str;
   1317 {
   1318 	while (*str)
   1319 		*str++ = 0;
   1320 }
   1321 #endif	/* HIDEBYLINK */
   1322