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