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