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