xref: /original-bsd/games/larn/main.c (revision f91c1509)
1 /*	main.c		*/
2 #include <sys/types.h>
3 #include "header.h"
4 #include <pwd.h>
5 static char copyright[]="\nLarn is copyrighted 1986 by Noah Morgan.\n";
6 int srcount=0;	/* line counter for showstr()	*/
7 int dropflag=0; /* if 1 then don't lookforobject() next round */
8 int rmst=80;	/*	random monster creation counter		*/
9 int userid;		/* the players login user id number */
10 char nowelcome=0,nomove=0; /* if (nomove) then don't count next iteration as a move */
11 static char viewflag=0;
12 	/*	if viewflag then we have done a 99 stay here and don't showcell in the main loop */
13 char restorflag=0;	/* 1 means restore has been done	*/
14 static char cmdhelp[] = "\
15 Cmd line format: larn [-slicnh] [-o<optsifle>] [-##] [++]\n\
16   -s   show the scoreboard\n\
17   -l   show the logfile (wizard id only)\n\
18   -i   show scoreboard with inventories of dead characters\n\
19   -c   create new scoreboard (wizard id only)\n\
20   -n   suppress welcome message on starting game\n\
21   -##  specify level of difficulty (example: -5)\n\
22   -h   print this help text\n\
23   ++   restore game from checkpoint file\n\
24   -o<optsfile>   specify .larnopts filename to be used instead of \"~/.larnopts\"\n\
25 ";
26 #ifdef VT100
27 static char *termtypes[] = { "vt100", "vt101", "vt102", "vt103", "vt125",
28 	"vt131", "vt140", "vt180", "vt220", "vt240", "vt241", "vt320", "vt340",
29 	"vt341"  };
30 #endif VT100
31 /*
32 	************
33 	MAIN PROGRAM
34 	************
35  */
36 main(argc,argv)
37 	int argc;
38 	char **argv;
39 	{
40 	register int i,j;
41 	int hard;
42 	char *ptr=0,*ttype;
43 	struct passwd *pwe;
44 
45 /*
46  *	first task is to identify the player
47  */
48 #ifndef VT100
49 	init_term();	/* setup the terminal (find out what type) for termcap */
50 #endif VT100
51 	if (((ptr = getlogin()) == 0) || (*ptr==0))	/* try to get login name */
52 	  if (pwe=getpwuid(getuid())) /* can we get it from /etc/passwd? */
53 		ptr = pwe->pw_name;
54 	  else
55 	  if ((ptr = getenv("USER")) == 0)
56 		if ((ptr = getenv("LOGNAME")) == 0)
57 		  {
58 		  noone: write(2, "Can't find your logname.  Who Are You?\n",39);
59 		 		 exit();
60 		  }
61 	if (ptr==0) goto noone;
62 	if (strlen(ptr)==0) goto noone;
63 /*
64  *	second task is to prepare the pathnames the player will need
65  */
66 	strcpy(loginname,ptr); /* save loginname of the user for logging purposes */
67 	strcpy(logname,ptr);	/* this will be overwritten with the players name */
68 	if ((ptr = getenv("HOME")) == 0) ptr = ".";
69 	strcpy(savefilename, ptr);
70 	strcat(savefilename, "/Larn.sav");	/* save file name in home directory */
71 	sprintf(optsfile, "%s/.larnopts",ptr);	/* the .larnopts filename */
72 
73 /*
74  *	now malloc the memory for the dungeon
75  */
76 	cell = (struct cel *)malloc(sizeof(struct cel)*(MAXLEVEL+MAXVLEVEL)*MAXX*MAXY);
77 	if (cell == 0) died(-285);	/* malloc failure */
78 	lpbuf    = malloc((5* BUFBIG)>>2);	/* output buffer */
79 	inbuffer = malloc((5*MAXIBUF)>>2);	/* output buffer */
80 	if ((lpbuf==0) || (inbuffer==0)) died(-285); /* malloc() failure */
81 
82 	lcreat((char*)0);	newgame();		/*	set the initial clock  */ hard= -1;
83 
84 #ifdef VT100
85 /*
86  *	check terminal type to avoid users who have not vt100 type terminals
87  */
88 	ttype = getenv("TERM");
89 	for (j=1, i=0; i<sizeof(termtypes)/sizeof(char *); i++)
90 		if (strcmp(ttype,termtypes[i]) == 0) { j=0;  break; }
91 	if (j)
92 		{
93 		lprcat("Sorry, Larn needs a VT100 family terminal for all it's features.\n"); lflush();
94 		exit();
95 		}
96 #endif VT100
97 
98 /*
99  *	now make scoreboard if it is not there (don't clear)
100  */
101 	if (access(scorefile,0) == -1) /* not there */
102 		makeboard();
103 
104 /*
105  *	now process the command line arguments
106  */
107 	for (i=1; i<argc; i++)
108 		{
109 		if (argv[i][0] == '-')
110 		  switch(argv[i][1])
111 			{
112 			case 's': showscores();  exit();  /* show scoreboard   */
113 
114 			case 'l': /* show log file     */
115 						diedlog();		exit();
116 
117 			case 'i': showallscores();  exit();  /* show all scoreboard */
118 
119 			case 'c': 		 /* anyone with password can create scoreboard */
120 					  lprcat("Preparing to initialize the scoreboard.\n");
121 					  if (getpassword() != 0)  /*make new scoreboard*/
122 							{
123 							makeboard(); lprc('\n'); showscores();
124 							}
125 					  exit();
126 
127 			case 'n':	/* no welcome msg	*/ nowelcome=1; argv[i][0]=0; break;
128 
129 			case '0': case '1': case '2': case '3': case '4': case '5':
130 			case '6': case '7': case '8': case '9':	/* for hardness */
131 						sscanf(&argv[i][1],"%d",&hard);
132 						break;
133 
134 			case 'h':	/* print out command line arguments */
135 						write(1,cmdhelp,sizeof(cmdhelp));  exit();
136 
137 			case 'o':	/* specify a .larnopts filename */
138 						strncpy(optsfile,argv[i]+2,127);  break;
139 
140 			default:	printf("Unknown option <%s>\n",argv[i]);  exit();
141 			};
142 
143 		if (argv[i][0] == '+')
144 			{
145 			clear();	restorflag = 1;
146 			if (argv[i][1] == '+')
147 				{
148 				hitflag=1; restoregame(ckpfile); /* restore checkpointed game */
149 				}
150 			i = argc;
151 			}
152 		}
153 
154 	readopts();		/* read the options file if there is one */
155 
156 
157 #ifdef UIDSCORE
158 	userid = geteuid();	/* obtain the user's effective id number */
159 #else UIDSCORE
160 	userid = getplid(logname);	/* obtain the players id number */
161 #endif UIDSCORE
162 	if (userid < 0) { write(2,"Can't obtain playerid\n",22); exit(); }
163 
164 #ifdef HIDEBYLINK
165 /*
166  *	this section of code causes the program to look like something else to ps
167  */
168 	if (strcmp(psname,argv[0])) /* if a different process name only */
169 		{
170 		if ((i=access(psname,1)) < 0)
171 			{		/* link not there */
172 			if (link(argv[0],psname)>=0)
173 				{
174 				argv[0] = psname;   execv(psname,argv);
175 				}
176 			}
177 		else
178 			unlink(psname);
179 		}
180 
181 	for (i=1; i<argc; i++)
182 		{
183 		szero(argv[i]);	/* zero the argument to avoid ps snooping */
184 		}
185 #endif HIDEBYLINK
186 
187 	if (access(savefilename,0)==0)	/* restore game if need to */
188 		{
189 		clear();	restorflag = 1;
190 		hitflag=1;	restoregame(savefilename);  /* restore last game	*/
191 		}
192 	sigsetup();		/* trap all needed signals	*/
193 	sethard(hard);	/* set up the desired difficulty				*/
194 	setupvt100();	/*	setup the terminal special mode				*/
195 	if (c[HP]==0)	/* create new game */
196 		{
197 		makeplayer();	/*	make the character that will play			*/
198 		newcavelevel(0);/*	make the dungeon						 	*/
199 		predostuff = 1;	/* tell signals that we are in the welcome screen */
200 		if (nowelcome==0) welcome();	 /* welcome the player to the game */
201 		}
202 	drawscreen();	/*	show the initial dungeon					*/
203 	predostuff = 2;	/* tell the trap functions that they must do a showplayer()
204 						from here on */
205 	/* nice(1);	/* games should be run niced */
206 	yrepcount = hit2flag = 0;
207 	while (1)
208 		{
209 		if (dropflag==0) lookforobject(); /* see if there is an object here	*/
210 			else dropflag=0; /* don't show it just dropped an item */
211 		if (hitflag==0) { if (c[HASTEMONST]) movemonst(); movemonst(); }	/*	move the monsters		*/
212 		if (viewflag==0) showcell(playerx,playery); else viewflag=0;	/*	show stuff around player	*/
213 		if (hit3flag) flushall();
214 		hitflag=hit3flag=0;	nomove=1;
215 		bot_linex();	/* update bottom line */
216 		while (nomove)
217 			{
218 			if (hit3flag) flushall();
219 			nomove=0; parse();
220 			}	/*	get commands and make moves	*/
221 		regen();			/*	regenerate hp and spells			*/
222 		if (c[TIMESTOP]==0)
223 			if (--rmst <= 0)
224 				{ rmst = 120-(level<<2); fillmonst(makemonst(level)); }
225 		}
226 	}
227 
228 /*
229 	showstr()
230 
231 	show character's inventory
232  */
233 showstr()
234 	{
235 	register int i,number;
236 	for (number=3, i=0; i<26; i++)
237 		if (iven[i]) number++;	/* count items in inventory */
238 	t_setup(number);	qshowstr();	  t_endup(number);
239 	}
240 
241 qshowstr()
242 	{
243 	register int i,j,k,sigsav;
244 	srcount=0;  sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
245 	if (c[GOLD]) { lprintf(".)   %d gold pieces",(long)c[GOLD]); srcount++; }
246 	for (k=26; k>=0; k--)
247 	  if (iven[k])
248 		{  for (i=22; i<84; i++)
249 			 for (j=0; j<=k; j++)  if (i==iven[j])  show3(j); k=0; }
250 
251 	lprintf("\nElapsed time is %d.  You have %d mobuls left",(long)((gtime+99)/100+1),(long)((TIMELIMIT-gtime)/100));
252 	more();		nosignal=sigsav;
253 	}
254 
255 /*
256  *	subroutine to clear screen depending on # lines to display
257  */
258 t_setup(count)
259 	register int count;
260 	{
261 	if (count<20)  /* how do we clear the screen? */
262 		{
263 		cl_up(79,count);  cursor(1,1);
264 		}
265 	else
266 		{
267 		resetscroll(); clear();
268 		}
269 	}
270 
271 /*
272  *	subroutine to restore normal display screen depending on t_setup()
273  */
274 t_endup(count)
275 	register int count;
276 	{
277 	if (count<18)  /* how did we clear the screen? */
278 		draws(0,MAXX,0,(count>MAXY) ? MAXY : count);
279 	else
280 		{
281 		drawscreen(); setscroll();
282 		}
283 	}
284 
285 /*
286 	function to show the things player is wearing only
287  */
288 showwear()
289 	{
290 	register int i,j,sigsav,count;
291 	sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
292 	srcount=0;
293 
294 	 for (count=2,j=0; j<=26; j++)	 /* count number of items we will display */
295 	   if (i=iven[j])
296 		switch(i)
297 			{
298 			case OLEATHER:	case OPLATE:	case OCHAIN:
299 			case ORING:		case OSTUDLEATHER:	case OSPLINT:
300 			case OPLATEARMOR:	case OSSPLATE:	case OSHIELD:
301 			count++;
302 			};
303 
304 	t_setup(count);
305 
306 	for (i=22; i<84; i++)
307 		 for (j=0; j<=26; j++)
308 		   if (i==iven[j])
309 			switch(i)
310 				{
311 				case OLEATHER:	case OPLATE:	case OCHAIN:
312 				case ORING:		case OSTUDLEATHER:	case OSPLINT:
313 				case OPLATEARMOR:	case OSSPLATE:	case OSHIELD:
314 				show3(j);
315 				};
316 	more();		nosignal=sigsav;	t_endup(count);
317 	}
318 
319 /*
320 	function to show the things player can wield only
321  */
322 showwield()
323 	{
324 	register int i,j,sigsav,count;
325 	sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
326 	srcount=0;
327 
328 	 for (count=2,j=0; j<=26; j++)	/* count how many items */
329 	   if (i=iven[j])
330 		switch(i)
331 			{
332 			case ODIAMOND:  case ORUBY:  case OEMERALD:  case OSAPPHIRE:
333 			case OBOOK:     case OCHEST:  case OLARNEYE: case ONOTHEFT:
334 			case OSPIRITSCARAB:  case OCUBEofUNDEAD:
335 			case OPOTION:   case OSCROLL:  break;
336 			default:  count++;
337 			};
338 
339 	t_setup(count);
340 
341 	for (i=22; i<84; i++)
342 		 for (j=0; j<=26; j++)
343 		   if (i==iven[j])
344 			switch(i)
345 				{
346 				case ODIAMOND:  case ORUBY:  case OEMERALD:  case OSAPPHIRE:
347 				case OBOOK:     case OCHEST:  case OLARNEYE: case ONOTHEFT:
348 				case OSPIRITSCARAB:  case OCUBEofUNDEAD:
349 				case OPOTION:   case OSCROLL:  break;
350 				default:  show3(j);
351 				};
352 	more();		nosignal=sigsav;	t_endup(count);
353 	}
354 
355 /*
356  *	function to show the things player can read only
357  */
358 showread()
359 	{
360 	register int i,j,sigsav,count;
361 	sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
362 	srcount=0;
363 
364 	for (count=2,j=0; j<=26; j++)
365 		switch(iven[j])
366 			{
367 			case OBOOK:	case OSCROLL:	count++;
368 			};
369 	t_setup(count);
370 
371 	for (i=22; i<84; i++)
372 		 for (j=0; j<=26; j++)
373 		   if (i==iven[j])
374 			switch(i)
375 				{
376 				case OBOOK:	case OSCROLL:	show3(j);
377 				};
378 	more();		nosignal=sigsav;	t_endup(count);
379 	}
380 
381 /*
382  *	function to show the things player can eat only
383  */
384 showeat()
385 	{
386 	register int i,j,sigsav,count;
387 	sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
388 	srcount=0;
389 
390 	for (count=2,j=0; j<=26; j++)
391 		switch(iven[j])
392 			{
393 			case OCOOKIE:	count++;
394 			};
395 	t_setup(count);
396 
397 	for (i=22; i<84; i++)
398 		 for (j=0; j<=26; j++)
399 		   if (i==iven[j])
400 			switch(i)
401 				{
402 				case OCOOKIE:	show3(j);
403 				};
404 	more();		nosignal=sigsav;	t_endup(count);
405 	}
406 
407 /*
408 	function to show the things player can quaff only
409  */
410 showquaff()
411 	{
412 	register int i,j,sigsav,count;
413 	sigsav=nosignal;  nosignal=1; /* don't allow ^c etc */
414 	srcount=0;
415 
416 	for (count=2,j=0; j<=26; j++)
417 		switch(iven[j])
418 			{
419 			case OPOTION:	count++;
420 			};
421 	t_setup(count);
422 
423 	for (i=22; i<84; i++)
424 		 for (j=0; j<=26; j++)
425 		   if (i==iven[j])
426 			switch(i)
427 				{
428 				case OPOTION:	show3(j);
429 				};
430 	more();		nosignal=sigsav;		t_endup(count);
431 	}
432 
433 show1(idx,str2)
434 	register int idx;
435 	register char *str2[];
436 	{
437 	if (str2==0)  lprintf("\n%c)   %s",idx+'a',objectname[iven[idx]]);
438 	else if (*str2[ivenarg[idx]]==0)  lprintf("\n%c)   %s",idx+'a',objectname[iven[idx]]);
439 	else lprintf("\n%c)   %s of%s",idx+'a',objectname[iven[idx]],str2[ivenarg[idx]]);
440 	}
441 
442 show3(index)
443 	register int index;
444 	{
445 	switch(iven[index])
446 		{
447 		case OPOTION:	show1(index,potionname);  break;
448 		case OSCROLL:	show1(index,scrollname);  break;
449 
450 		case OLARNEYE:		case OBOOK:			case OSPIRITSCARAB:
451 		case ODIAMOND:		case ORUBY:			case OCUBEofUNDEAD:
452 		case OEMERALD:		case OCHEST:		case OCOOKIE:
453 		case OSAPPHIRE:		case ONOTHEFT:		show1(index,(char **)0);  break;
454 
455 		default:		lprintf("\n%c)   %s",index+'a',objectname[iven[index]]);
456 						if (ivenarg[index]>0) lprintf(" + %d",(long)ivenarg[index]);
457 						else if (ivenarg[index]<0) lprintf(" %d",(long)ivenarg[index]);
458 						break;
459 		}
460 	if (c[WIELD]==index) lprcat(" (weapon in hand)");
461 	if ((c[WEAR]==index) || (c[SHIELD]==index))  lprcat(" (being worn)");
462 	if (++srcount>=22) { srcount=0; more(); clear(); }
463 	}
464 
465 /*
466 	subroutine to randomly create monsters if needed
467  */
468 randmonst()
469 	{
470 	if (c[TIMESTOP]) return;	/*	don't make monsters if time is stopped	*/
471 	if (--rmst <= 0)
472 		{
473 		rmst = 120 - (level<<2);  fillmonst(makemonst(level));
474 		}
475 	}
476 
477 
478 /*
479 	parse()
480 
481 	get and execute a command
482  */
483 parse()
484 	{
485 	register int i,j,k,flag;
486 	while	(1)
487 		{
488 		k = yylex();
489 		switch(k)	/*	get the token from the input and switch on it	*/
490 			{
491 			case 'h':	moveplayer(4);	return;		/*	west		*/
492 			case 'H':	run(4);			return;		/*	west		*/
493 			case 'l':	moveplayer(2);	return;		/*	east		*/
494 			case 'L':	run(2);			return;		/*	east		*/
495 			case 'j':	moveplayer(1);	return;		/*	south		*/
496 			case 'J':	run(1);			return;		/*	south		*/
497 			case 'k':	moveplayer(3);	return;		/*	north		*/
498 			case 'K':	run(3);			return;		/*	north		*/
499 			case 'u':	moveplayer(5);	return;		/*	northeast	*/
500 			case 'U':	run(5);			return;		/*	northeast	*/
501 			case 'y':	moveplayer(6);  return;		/*	northwest	*/
502 			case 'Y':	run(6);			return;		/*	northwest	*/
503 			case 'n':	moveplayer(7);	return;		/*	southeast	*/
504 			case 'N':	run(7);			return;		/*	southeast	*/
505 			case 'b':	moveplayer(8);	return;		/*	southwest	*/
506 			case 'B':	run(8);			return;		/*	southwest	*/
507 
508 			case '.':	if (yrepcount) viewflag=1; return;		/*	stay here		*/
509 
510 			case 'w':	yrepcount=0;	wield();	return;		/*	wield a weapon */
511 
512 			case 'W':	yrepcount=0;	wear();		return;	/*	wear armor	*/
513 
514 			case 'r':	yrepcount=0;
515 						if (c[BLINDCOUNT]) { cursors(); lprcat("\nYou can't read anything when you're blind!"); } else
516 						if (c[TIMESTOP]==0) readscr(); return;		/*	to read a scroll	*/
517 
518 			case 'q':	yrepcount=0;	if (c[TIMESTOP]==0) quaff();	return;	/*	quaff a potion		*/
519 
520 			case 'd':	yrepcount=0;	if (c[TIMESTOP]==0) dropobj(); return;	/*	to drop an object	*/
521 
522 			case 'c':	yrepcount=0;	cast();		return;		/*	cast a spell	*/
523 
524 			case 'i':	yrepcount=0;	nomove=1;  showstr();	return;		/*	status		*/
525 
526 			case 'e':	yrepcount=0;
527 						if (c[TIMESTOP]==0) eatcookie(); return;	/*	to eat a fortune cookie */
528 
529 			case 'D':	yrepcount=0;	seemagic(0);	nomove=1; return;	/*	list spells and scrolls */
530 
531 			case '?':	yrepcount=0;	help(); nomove=1; return;	/*	give the help screen*/
532 
533 			case 'S':	clear();  lprcat("Saving . . ."); lflush();
534 						savegame(savefilename); wizard=1; died(-257);	/*	save the game - doesn't return	*/
535 
536 			case 'Z':	yrepcount=0;	if (c[LEVEL]>9) { oteleport(1); return; }
537 						cursors(); lprcat("\nAs yet, you don't have enough experience to use teleportation");
538 						return;	/*	teleport yourself	*/
539 
540 			case '^':	/* identify traps */  flag=yrepcount=0;  cursors();
541 						lprc('\n');  for (j=playery-1; j<playery+2; j++)
542 							{
543 							if (j < 0) j=0;		if (j >= MAXY) break;
544 							for (i=playerx-1; i<playerx+2; i++)
545 								{
546 								if (i < 0) i=0;	if (i >= MAXX) break;
547 								switch(item[i][j])
548 									{
549 									case OTRAPDOOR:		case ODARTRAP:
550 									case OTRAPARROW:	case OTELEPORTER:
551 										lprcat("\nIts "); lprcat(objectname[item[i][j]]);  flag++;
552 									};
553 								}
554 							}
555 						if (flag==0) lprcat("\nNo traps are visible");
556 						return;
557 
558 #if WIZID
559 			case '_':	/*	this is the fudge player password for wizard mode*/
560 						yrepcount=0;	cursors(); nomove=1;
561 						if (userid!=wisid)
562 							{
563 							lprcat("Sorry, you are not empowered to be a wizard.\n");
564 							scbr(); /* system("stty -echo cbreak"); */
565 							lflush();  return;
566 							}
567 						if (getpassword()==0)
568 							{
569 							scbr(); /* system("stty -echo cbreak"); */ return;
570 							}
571 						wizard=1;  scbr(); /* system("stty -echo cbreak"); */
572 						for (i=0; i<6; i++)  c[i]=70;  iven[0]=iven[1]=0;
573 						take(OPROTRING,50);   take(OLANCE,25);  c[WIELD]=1;
574 						c[LANCEDEATH]=1;   c[WEAR] = c[SHIELD] = -1;
575 						raiseexperience(6000000L);  c[AWARENESS] += 25000;
576 						{
577 						register int i,j;
578 						for (i=0; i<MAXY; i++)
579 							for (j=0; j<MAXX; j++)  know[j][i]=1;
580 						for (i=0; i<SPNUM; i++)	spelknow[i]=1;
581 						for (i=0; i<MAXSCROLL; i++)  scrollname[i][0]=' ';
582 						for (i=0; i<MAXPOTION; i++)  potionname[i][0]=' ';
583 						}
584 						for (i=0; i<MAXSCROLL; i++)
585 						  if (strlen(scrollname[i])>2) /* no null items */
586 							{ item[i][0]=OSCROLL; iarg[i][0]=i; }
587 						for (i=MAXX-1; i>MAXX-1-MAXPOTION; i--)
588 						  if (strlen(potionname[i-MAXX+MAXPOTION])>2) /* no null items */
589 							{ item[i][0]=OPOTION; iarg[i][0]=i-MAXX+MAXPOTION; }
590 						for (i=1; i<MAXY; i++)
591 							{ item[0][i]=i; iarg[0][i]=0; }
592 						for (i=MAXY; i<MAXY+MAXX; i++)
593 							{ item[i-MAXY][MAXY-1]=i; iarg[i-MAXY][MAXY-1]=0; }
594 						for (i=MAXX+MAXY; i<MAXX+MAXY+MAXY; i++)
595 							{ item[MAXX-1][i-MAXX-MAXY]=i; iarg[MAXX-1][i-MAXX-MAXY]=0; }
596 						c[GOLD]+=25000;	drawscreen();	return;
597 #endif
598 
599 			case 'T':	yrepcount=0;	cursors();  if (c[SHIELD] != -1) { c[SHIELD] = -1; lprcat("\nYour shield is off"); bottomline(); } else
600 										if (c[WEAR] != -1) { c[WEAR] = -1; lprcat("\nYour armor is off"); bottomline(); }
601 						else lprcat("\nYou aren't wearing anything");
602 						return;
603 
604 			case 'g':	cursors();
605 						lprintf("\nThe stuff you are carrying presently weighs %d pounds",(long)packweight());
606 			case ' ':	yrepcount=0;	nomove=1;  return;
607 
608 			case 'v':	yrepcount=0;	cursors();
609 						lprintf("\nCaverns of Larn, Version %d.%d, Diff=%d",(long)VERSION,(long)SUBVERSION,(long)c[HARDGAME]);
610 						if (wizard) lprcat(" Wizard"); nomove=1;
611 						if (cheat) lprcat(" Cheater");
612 						lprcat(copyright);
613 						return;
614 
615 			case 'Q':	yrepcount=0;	quit(); nomove=1;	return;	/*	quit		*/
616 
617 			case 'L'-64:  yrepcount=0;	drawscreen();  nomove=1; return;	/*	look		*/
618 
619 #if WIZID
620 #ifdef EXTRA
621 			case 'A':	yrepcount=0;	nomove=1; if (wizard) { diag(); return; }  /*	create diagnostic file */
622 						return;
623 #endif
624 #endif
625 			case 'P':	cursors();
626 						if (outstanding_taxes>0)
627 							lprintf("\nYou presently owe %d gp in taxes.",(long)outstanding_taxes);
628 						else
629 							lprcat("\nYou do not owe any taxes.");
630 						return;
631 			};
632 		}
633 	}
634 
635 parse2()
636 	{
637 	if (c[HASTEMONST]) movemonst(); movemonst(); /*	move the monsters		*/
638 	randmonst();	regen();
639 	}
640 
641 run(dir)
642 	int dir;
643 	{
644 	register int i;
645 	i=1; while (i)
646 		{
647 		i=moveplayer(dir);
648 		if (i>0) {  if (c[HASTEMONST]) movemonst();  movemonst(); randmonst(); regen(); }
649 		if (hitflag) i=0;
650 		if (i!=0)  showcell(playerx,playery);
651 		}
652 	}
653 
654 /*
655 	function to wield a weapon
656  */
657 wield()
658 	{
659 	register int i;
660 	while (1)
661 		{
662 		if ((i = whatitem("wield"))=='\33')  return;
663 		if (i != '.')
664 			{
665 			if (i=='*') showwield();
666 			else  if (iven[i-'a']==0) { ydhi(i); return; }
667 			else if (iven[i-'a']==OPOTION) { ycwi(i); return; }
668 			else if (iven[i-'a']==OSCROLL) { ycwi(i); return; }
669 			else  if ((c[SHIELD]!= -1) && (iven[i-'a']==O2SWORD)) { lprcat("\nBut one arm is busy with your shield!"); return; }
670 			else  { c[WIELD]=i-'a'; if (iven[i-'a'] == OLANCE) c[LANCEDEATH]=1; else c[LANCEDEATH]=0;  bottomline(); return; }
671 			}
672 		}
673 	}
674 
675 /*
676 	common routine to say you don't have an item
677  */
678 ydhi(x)
679 	int x;
680 	{ cursors();  lprintf("\nYou don't have item %c!",x); }
681 ycwi(x)
682 	int x;
683 	{ cursors();  lprintf("\nYou can't wield item %c!",x); }
684 
685 /*
686 	function to wear armor
687  */
688 wear()
689 	{
690 	register int i;
691 	while (1)
692 		{
693 		if ((i = whatitem("wear"))=='\33')  return;
694 		if (i != '.')
695 			{
696 			if (i=='*') showwear(); else
697 			switch(iven[i-'a'])
698 				{
699 				case 0:  ydhi(i); return;
700 				case OLEATHER:  case OCHAIN:  case OPLATE:	case OSTUDLEATHER:
701 				case ORING:		case OSPLINT:	case OPLATEARMOR:	case OSSPLATE:
702 						if (c[WEAR] != -1) { lprcat("\nYou're already wearing some armor"); return; }
703 							c[WEAR]=i-'a';  bottomline(); return;
704 				case OSHIELD:	if (c[SHIELD] != -1) { lprcat("\nYou are already wearing a shield"); return; }
705 								if (iven[c[WIELD]]==O2SWORD) { lprcat("\nYour hands are busy with the two handed sword!"); return; }
706 								c[SHIELD] = i-'a';  bottomline(); return;
707 				default:	lprcat("\nYou can't wear that!");
708 				};
709 			}
710 		}
711 	}
712 
713 /*
714 	function to drop an object
715  */
716 dropobj()
717 	{
718 	register int i;
719 	register char *p;
720 	long amt;
721 	p = &item[playerx][playery];
722 	while (1)
723 		{
724 		if ((i = whatitem("drop"))=='\33')  return;
725 		if (i=='*') showstr(); else
726 			{
727 			if (i=='.')	/* drop some gold */
728 				{
729 				if (*p) { lprcat("\nThere's something here already!"); return; }
730 				lprcat("\n\n");
731 				cl_dn(1,23);
732 				lprcat("How much gold do you drop? ");
733 				if ((amt=readnum((long)c[GOLD])) == 0) return;
734 				if (amt>c[GOLD])
735 					{ lprcat("\nYou don't have that much!"); return; }
736 				if (amt<=32767)
737 					{ *p=OGOLDPILE; i=amt; }
738 				else if (amt<=327670L)
739 					{ *p=ODGOLD; i=amt/10; amt = 10*i; }
740 				else if (amt<=3276700L)
741 					{ *p=OMAXGOLD; i=amt/100; amt = 100*i; }
742 				else if (amt<=32767000L)
743 					{ *p=OKGOLD; i=amt/1000; amt = 1000*i; }
744 				else
745 					{ *p=OKGOLD; i=32767; amt = 32767000L; }
746 				c[GOLD] -= amt;
747 				lprintf("You drop %d gold pieces",(long)amt);
748 				iarg[playerx][playery]=i; bottomgold();
749 				know[playerx][playery]=0; dropflag=1;  return;
750 				}
751 			drop_object(i-'a');
752 			return;
753 			}
754 		}
755 	}
756 
757 /*
758  *	readscr()		Subroutine to read a scroll one is carrying
759  */
760 readscr()
761 	{
762 	register int i;
763 	while (1)
764 		{
765 		if ((i = whatitem("read"))=='\33')  return;
766 		if (i != '.')
767 			{
768 			if (i=='*') showread(); else
769 				{
770 				if (iven[i-'a']==OSCROLL) { read_scroll(ivenarg[i-'a']); iven[i-'a']=0; return; }
771 				if (iven[i-'a']==OBOOK)   { readbook(ivenarg[i-'a']);  iven[i-'a']=0; return; }
772 				if (iven[i-'a']==0) { ydhi(i); return; }
773 				lprcat("\nThere's nothing on it to read");  return;
774 				}
775 			}
776 		}
777 	}
778 
779 /*
780  *	subroutine to eat a cookie one is carrying
781  */
782 eatcookie()
783 {
784 register int i;
785 char *p;
786 while (1)
787 	{
788 	if ((i = whatitem("eat"))=='\33')  return;
789 	if (i != '.')
790 		if (i=='*') showeat(); else
791 			{
792 			if (iven[i-'a']==OCOOKIE)
793 				{
794 				lprcat("\nThe cookie was delicious.");
795 				iven[i-'a']=0;
796 				if (!c[BLINDCOUNT])
797 					{
798 					if (p=fortune(fortfile))
799 						{
800 						lprcat("  Inside you find a scrap of paper that says:\n");
801 						lprcat(p);
802 						}
803 					}
804 				return;
805 				}
806 			if (iven[i-'a']==0) { ydhi(i); return; }
807 			lprcat("\nYou can't eat that!");  return;
808 			}
809 	}
810 }
811 
812 /*
813  *	subroutine to quaff a potion one is carrying
814  */
815 quaff()
816 	{
817 	register int i;
818 	while (1)
819 		{
820 		if ((i = whatitem("quaff"))=='\33')  return;
821 		if (i != '.')
822 			{
823 			if (i=='*') showquaff(); else
824 				{
825 				if (iven[i-'a']==OPOTION) { quaffpotion(ivenarg[i-'a']); iven[i-'a']=0; return; }
826 				if (iven[i-'a']==0) { ydhi(i); return; }
827 				lprcat("\nYou wouldn't want to quaff that, would you? ");  return;
828 				}
829 			}
830 		}
831 	}
832 
833 /*
834 	function to ask what player wants to do
835  */
836 whatitem(str)
837 	char *str;
838 	{
839 	int i;
840 	cursors();  lprintf("\nWhat do you want to %s [* for all] ? ",str);
841 	i=0; while (i>'z' || (i<'a' && i!='*' && i!='\33' && i!='.')) i=getchar();
842 	if (i=='\33')  lprcat(" aborted");
843 	return(i);
844 	}
845 
846 /*
847 	subroutine to get a number from the player
848 	and allow * to mean return amt, else return the number entered
849  */
850 unsigned long readnum(mx)
851 	long mx;
852 	{
853 	register int i;
854 	register unsigned long amt=0;
855 	sncbr();
856 	if ((i=getchar()) == '*')  amt = mx;   /* allow him to say * for all gold */
857 	else
858 		while (i != '\n')
859 			{
860 			if (i=='\033') { scbr(); lprcat(" aborted"); return(0); }
861 			if ((i <= '9') && (i >= '0') && (amt<99999999))
862 				amt = amt*10+i-'0';
863 			i = getchar();
864 			}
865 	scbr();  return(amt);
866 	}
867 
868 #ifdef HIDEBYLINK
869 /*
870  *	routine to zero every byte in a string
871  */
872 szero(str)
873 	register char *str;
874 	{
875 	while (*str)
876 		*str++ = 0;
877 	}
878 #endif HIDEBYLINK
879