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