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