xref: /netbsd-src/games/larn/main.c (revision 1182a44c59cae4d586117d55eca24b4b8b173211)
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
main(int argc,char ** argv)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
showstr(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
qshowstr(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
t_setup(int count)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
t_endup(int count)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
showwear(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
showwield(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
showread(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
showeat(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
showquaff(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
show1(int idx,const char * str2[])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
show3(int indx)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
randmonst(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
parse(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
parse2(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
run(int dir)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
wield(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
ydhi(int x)1051 ydhi(int x)
1052 {
1053 	cursors();
1054 	lprintf("\nYou don't have item %c!", x);
1055 }
1056 static void
ycwi(int x)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
wear(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
dropobj(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
readscr(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
eatcookie(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
quaff(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
whatitem(const char * str)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
readnum(long mx)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
szero(str)1331 szero(str)
1332 	char  *str;
1333 {
1334 	while (*str)
1335 		*str++ = 0;
1336 }
1337 #endif	/* HIDEBYLINK */
1338