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