xref: /openbsd/games/hack/hack.main.c (revision 42ceebb3)
1*42ceebb3Sderaadt /*	$OpenBSD: hack.main.c,v 1.10 2003/04/06 18:50:37 deraadt Exp $	*/
2d0b779f3Sniklas 
3df930be7Sderaadt /*
4d25013f2Scamield  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5d25013f2Scamield  * Amsterdam
6d25013f2Scamield  * All rights reserved.
7d25013f2Scamield  *
8d25013f2Scamield  * Redistribution and use in source and binary forms, with or without
9d25013f2Scamield  * modification, are permitted provided that the following conditions are
10d25013f2Scamield  * met:
11d25013f2Scamield  *
12d25013f2Scamield  * - Redistributions of source code must retain the above copyright notice,
13d25013f2Scamield  * this list of conditions and the following disclaimer.
14d25013f2Scamield  *
15d25013f2Scamield  * - Redistributions in binary form must reproduce the above copyright
16d25013f2Scamield  * notice, this list of conditions and the following disclaimer in the
17d25013f2Scamield  * documentation and/or other materials provided with the distribution.
18d25013f2Scamield  *
19d25013f2Scamield  * - Neither the name of the Stichting Centrum voor Wiskunde en
20d25013f2Scamield  * Informatica, nor the names of its contributors may be used to endorse or
21d25013f2Scamield  * promote products derived from this software without specific prior
22d25013f2Scamield  * written permission.
23d25013f2Scamield  *
24d25013f2Scamield  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25d25013f2Scamield  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26d25013f2Scamield  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27d25013f2Scamield  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28d25013f2Scamield  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29d25013f2Scamield  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30d25013f2Scamield  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31d25013f2Scamield  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32d25013f2Scamield  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33d25013f2Scamield  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34d25013f2Scamield  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35d25013f2Scamield  */
36d25013f2Scamield 
37d25013f2Scamield /*
38d25013f2Scamield  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39d25013f2Scamield  * All rights reserved.
40d25013f2Scamield  *
41d25013f2Scamield  * Redistribution and use in source and binary forms, with or without
42d25013f2Scamield  * modification, are permitted provided that the following conditions
43d25013f2Scamield  * are met:
44d25013f2Scamield  * 1. Redistributions of source code must retain the above copyright
45d25013f2Scamield  *    notice, this list of conditions and the following disclaimer.
46d25013f2Scamield  * 2. Redistributions in binary form must reproduce the above copyright
47d25013f2Scamield  *    notice, this list of conditions and the following disclaimer in the
48d25013f2Scamield  *    documentation and/or other materials provided with the distribution.
49d25013f2Scamield  * 3. The name of the author may not be used to endorse or promote products
50d25013f2Scamield  *    derived from this software without specific prior written permission.
51d25013f2Scamield  *
52d25013f2Scamield  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53d25013f2Scamield  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54d25013f2Scamield  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55d25013f2Scamield  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56d25013f2Scamield  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57d25013f2Scamield  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58d25013f2Scamield  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59d25013f2Scamield  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60d25013f2Scamield  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61d25013f2Scamield  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62df930be7Sderaadt  */
63df930be7Sderaadt 
64df930be7Sderaadt #ifndef lint
65*42ceebb3Sderaadt static char rcsid[] = "$OpenBSD: hack.main.c,v 1.10 2003/04/06 18:50:37 deraadt Exp $";
66df930be7Sderaadt #endif /* not lint */
67df930be7Sderaadt 
68df930be7Sderaadt #include <stdio.h>
69df930be7Sderaadt #include <signal.h>
70df930be7Sderaadt #include "hack.h"
71df930be7Sderaadt 
72df930be7Sderaadt #ifdef QUEST
73df930be7Sderaadt #define	gamename	"quest"
74df930be7Sderaadt #else
75df930be7Sderaadt #define	gamename	"hack"
76df930be7Sderaadt #endif
77df930be7Sderaadt 
78df930be7Sderaadt extern char *getlogin(), *getenv();
79df930be7Sderaadt extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
80df930be7Sderaadt extern struct permonst mons[CMNUM+2];
81df930be7Sderaadt extern char genocided[], fut_geno[];
82df930be7Sderaadt 
83df930be7Sderaadt int (*afternmv)();
84df930be7Sderaadt int (*occupation)();
85df930be7Sderaadt char *occtxt;			/* defined when occupation != NULL */
86df930be7Sderaadt 
87df930be7Sderaadt void done1();
88df930be7Sderaadt void hangup();
89df930be7Sderaadt 
90df930be7Sderaadt int hackpid;				/* current pid */
91df930be7Sderaadt int locknum;				/* max num of players */
92df930be7Sderaadt #ifdef DEF_PAGER
93df930be7Sderaadt char *catmore;				/* default pager */
94df930be7Sderaadt #endif
95df930be7Sderaadt char SAVEF[PL_NSIZ + 11] = "save/";	/* save/99999player */
96df930be7Sderaadt char *hname;		/* name of the game (argv[0] of call) */
97df930be7Sderaadt char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */
98df930be7Sderaadt 
99df930be7Sderaadt extern char *nomovemsg;
100df930be7Sderaadt extern long wailmsg;
101df930be7Sderaadt 
102df930be7Sderaadt #ifdef CHDIR
103df930be7Sderaadt static void chdirx();
104df930be7Sderaadt #endif
105df930be7Sderaadt 
106df930be7Sderaadt main(argc,argv)
107df930be7Sderaadt int argc;
108df930be7Sderaadt char *argv[];
109df930be7Sderaadt {
110df930be7Sderaadt 	register int fd;
111df930be7Sderaadt #ifdef CHDIR
112df930be7Sderaadt 	register char *dir;
113df930be7Sderaadt #endif
114df930be7Sderaadt 
115df930be7Sderaadt 	hname = argv[0];
116df930be7Sderaadt 	hackpid = getpid();
117df930be7Sderaadt 
118df930be7Sderaadt #ifdef CHDIR			/* otherwise no chdir() */
119df930be7Sderaadt 	/*
120df930be7Sderaadt 	 * See if we must change directory to the playground.
121df930be7Sderaadt 	 * (Perhaps hack runs suid and playground is inaccessible
122df930be7Sderaadt 	 *  for the player.)
123df930be7Sderaadt 	 * The environment variable HACKDIR is overridden by a
124df930be7Sderaadt 	 *  -d command line option (must be the first option given)
125df930be7Sderaadt 	 */
126df930be7Sderaadt 
127df930be7Sderaadt 	dir = getenv("HACKDIR");
128df930be7Sderaadt 	if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
129df930be7Sderaadt 		argc--;
130df930be7Sderaadt 		argv++;
131df930be7Sderaadt 		dir = argv[0]+2;
132df930be7Sderaadt 		if(*dir == '=' || *dir == ':') dir++;
133df930be7Sderaadt 		if(!*dir && argc > 1) {
134df930be7Sderaadt 			argc--;
135df930be7Sderaadt 			argv++;
136df930be7Sderaadt 			dir = argv[0];
137df930be7Sderaadt 		}
138df930be7Sderaadt 		if(!*dir)
139df930be7Sderaadt 		    error("Flag -d must be followed by a directory name.");
140df930be7Sderaadt 	}
141df930be7Sderaadt #endif
142df930be7Sderaadt 
143df930be7Sderaadt 	/*
144df930be7Sderaadt 	 * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
145c7b2accbSmillert 	 *			2. Use $LOGNAME or $USER	(if 1. fails)
146df930be7Sderaadt 	 *			3. Use getlogin()		(if 2. fails)
147df930be7Sderaadt 	 * The resulting name is overridden by command line options.
148df930be7Sderaadt 	 * If everything fails, or if the resulting name is some generic
149df930be7Sderaadt 	 * account like "games", "play", "player", "hack" then eventually
150df930be7Sderaadt 	 * we'll ask him.
151df930be7Sderaadt 	 * Note that we trust him here; it is possible to play under
152df930be7Sderaadt 	 * somebody else's name.
153df930be7Sderaadt 	 */
154df930be7Sderaadt 	{ register char *s;
155df930be7Sderaadt 
156df930be7Sderaadt 	  initoptions();
157df930be7Sderaadt 	  if(!*plname && (s = getenv("LOGNAME")))
158df930be7Sderaadt 		(void) strncpy(plname, s, sizeof(plname)-1);
159c7b2accbSmillert 	  if(!*plname && (s = getenv("USER")))
160c7b2accbSmillert 		(void) strncpy(plname, s, sizeof(plname)-1);
161df930be7Sderaadt 	  if(!*plname && (s = getlogin()))
162df930be7Sderaadt 		(void) strncpy(plname, s, sizeof(plname)-1);
163c7b2accbSmillert 	  if(*plname)
164c7b2accbSmillert 		plname[sizeof(plname)-1] = '\0';
165df930be7Sderaadt 	}
166df930be7Sderaadt 
167df930be7Sderaadt 	/*
168df930be7Sderaadt 	 * Now we know the directory containing 'record' and
169df930be7Sderaadt 	 * may do a prscore().
170df930be7Sderaadt 	 */
171df930be7Sderaadt 	if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
172df930be7Sderaadt #ifdef CHDIR
173df930be7Sderaadt 		chdirx(dir,0);
174df930be7Sderaadt #endif
175df930be7Sderaadt 		prscore(argc, argv);
176df930be7Sderaadt 		exit(0);
177df930be7Sderaadt 	}
178df930be7Sderaadt 
179df930be7Sderaadt 	/*
180df930be7Sderaadt 	 * It seems he really wants to play.
181df930be7Sderaadt 	 * Remember tty modes, to be restored on exit.
182df930be7Sderaadt 	 */
183df930be7Sderaadt 	gettty();
184df930be7Sderaadt 	setbuf(stdout,obuf);
185a7a85d61Stholo 	umask(007);
186df930be7Sderaadt 	setrandom();
187df930be7Sderaadt 	startup();
188df930be7Sderaadt 	cls();
189df930be7Sderaadt 	u.uhp = 1;	/* prevent RIP on early quits */
190df930be7Sderaadt 	u.ux = FAR;	/* prevent nscr() */
191df930be7Sderaadt 	(void) signal(SIGHUP, hangup);
192df930be7Sderaadt 
193df930be7Sderaadt 	/*
194df930be7Sderaadt 	 * Find the creation date of this game,
195df930be7Sderaadt 	 * so as to avoid restoring outdated savefiles.
196df930be7Sderaadt 	 */
197df930be7Sderaadt 	gethdate(hname);
198df930be7Sderaadt 
199df930be7Sderaadt 	/*
200df930be7Sderaadt 	 * We cannot do chdir earlier, otherwise gethdate will fail.
201df930be7Sderaadt 	 */
202df930be7Sderaadt #ifdef CHDIR
203df930be7Sderaadt 	chdirx(dir,1);
204df930be7Sderaadt #endif
205df930be7Sderaadt 
206df930be7Sderaadt 	/*
207df930be7Sderaadt 	 * Process options.
208df930be7Sderaadt 	 */
209df930be7Sderaadt 	while(argc > 1 && argv[1][0] == '-'){
210df930be7Sderaadt 		argv++;
211df930be7Sderaadt 		argc--;
212df930be7Sderaadt 		switch(argv[0][1]){
213df930be7Sderaadt #ifdef WIZARD
214df930be7Sderaadt 		case 'D':
215df930be7Sderaadt /*			if(!strcmp(getlogin(), WIZARD)) */
216df930be7Sderaadt 				wizard = TRUE;
217df930be7Sderaadt /*			else
218df930be7Sderaadt 				printf("Sorry.\n"); */
219df930be7Sderaadt 			break;
220df930be7Sderaadt #endif
221df930be7Sderaadt #ifdef NEWS
222df930be7Sderaadt 		case 'n':
223df930be7Sderaadt 			flags.nonews = TRUE;
224df930be7Sderaadt 			break;
225df930be7Sderaadt #endif
226df930be7Sderaadt 		case 'u':
227c7b2accbSmillert 			if(argv[0][2]) {
228df930be7Sderaadt 			  (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
229c7b2accbSmillert 			  plname[sizeof(plname)-1] = '\0';
230c7b2accbSmillert 			} else if(argc > 1) {
231df930be7Sderaadt 			  argc--;
232df930be7Sderaadt 			  argv++;
233df930be7Sderaadt 			  (void) strncpy(plname, argv[0], sizeof(plname)-1);
234c7b2accbSmillert 			  plname[sizeof(plname)-1] = '\0';
235df930be7Sderaadt 			} else
236df930be7Sderaadt 				printf("Player name expected after -u\n");
237df930be7Sderaadt 			break;
238df930be7Sderaadt 		default:
239df930be7Sderaadt 			/* allow -T for Tourist, etc. */
240df930be7Sderaadt 			(void) strncpy(pl_character, argv[0]+1,
241df930be7Sderaadt 				sizeof(pl_character)-1);
242c7b2accbSmillert 			plname[sizeof(pl_character)-1] = '\0';
243df930be7Sderaadt 
244df930be7Sderaadt 			/* printf("Unknown option: %s\n", *argv); */
245df930be7Sderaadt 		}
246df930be7Sderaadt 	}
247df930be7Sderaadt 
248df930be7Sderaadt 	if(argc > 1)
249df930be7Sderaadt 		locknum = atoi(argv[1]);
250df930be7Sderaadt #ifdef MAX_NR_OF_PLAYERS
251df930be7Sderaadt 	if(!locknum || locknum > MAX_NR_OF_PLAYERS)
252df930be7Sderaadt 		locknum = MAX_NR_OF_PLAYERS;
253df930be7Sderaadt #endif
254df930be7Sderaadt #ifdef DEF_PAGER
255df930be7Sderaadt 	if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER")))
256df930be7Sderaadt 		catmore = DEF_PAGER;
257df930be7Sderaadt #endif
258df930be7Sderaadt #ifdef MAIL
259df930be7Sderaadt 	getmailstatus();
260df930be7Sderaadt #endif
261df930be7Sderaadt #ifdef WIZARD
262*42ceebb3Sderaadt 	if(wizard) (void) strlcpy(plname, "wizard", sizeof plname); else
263df930be7Sderaadt #endif
264df930be7Sderaadt 	if(!*plname || !strncmp(plname, "player", 4)
265df930be7Sderaadt 		    || !strncmp(plname, "games", 4))
266df930be7Sderaadt 		askname();
267df930be7Sderaadt 	plnamesuffix();		/* strip suffix from name; calls askname() */
268df930be7Sderaadt 				/* again if suffix was whole name */
269df930be7Sderaadt 				/* accepts any suffix */
270df930be7Sderaadt #ifdef WIZARD
271df930be7Sderaadt 	if(!wizard) {
272df930be7Sderaadt #endif
273df930be7Sderaadt 		/*
274df930be7Sderaadt 		 * check for multiple games under the same name
275df930be7Sderaadt 		 * (if !locknum) or check max nr of players (otherwise)
276df930be7Sderaadt 		 */
277df930be7Sderaadt 		(void) signal(SIGQUIT,SIG_IGN);
278df930be7Sderaadt 		(void) signal(SIGINT,SIG_IGN);
279df930be7Sderaadt 		if(!locknum)
280df930be7Sderaadt 			(void) strcpy(lock,plname);
281df930be7Sderaadt 		getlock();	/* sets lock if locknum != 0 */
282df930be7Sderaadt #ifdef WIZARD
283df930be7Sderaadt 	} else {
284df930be7Sderaadt 		register char *sfoo;
285df930be7Sderaadt 		(void) strcpy(lock,plname);
286df930be7Sderaadt 		if(sfoo = getenv("MAGIC"))
287df930be7Sderaadt 			while(*sfoo) {
288df930be7Sderaadt 				switch(*sfoo++) {
289df930be7Sderaadt 				case 'n': (void) srandom(*sfoo++);
290df930be7Sderaadt 					break;
291df930be7Sderaadt 				}
292df930be7Sderaadt 			}
293df930be7Sderaadt 		if(sfoo = getenv("GENOCIDED")){
294df930be7Sderaadt 			if(*sfoo == '!'){
295df930be7Sderaadt 				register struct permonst *pm = mons;
296df930be7Sderaadt 				register char *gp = genocided;
297df930be7Sderaadt 
298df930be7Sderaadt 				while(pm < mons+CMNUM+2){
299180acc8fSmillert 					if(!strchr(sfoo, pm->mlet))
300df930be7Sderaadt 						*gp++ = pm->mlet;
301df930be7Sderaadt 					pm++;
302df930be7Sderaadt 				}
303df930be7Sderaadt 				*gp = 0;
304df930be7Sderaadt 			} else
305df930be7Sderaadt 				(void) strcpy(genocided, sfoo);
306df930be7Sderaadt 			(void) strcpy(fut_geno, genocided);
307df930be7Sderaadt 		}
308df930be7Sderaadt 	}
309df930be7Sderaadt #endif
310df930be7Sderaadt 	setftty();
311*42ceebb3Sderaadt 	(void) snprintf(SAVEF, sizeof SAVEF, "save/%u%s", getuid(), plname);
312df930be7Sderaadt 	regularize(SAVEF+5);		/* avoid . or / in name */
3136cd28e42Smillert 	if((fd = open(SAVEF, O_RDONLY)) >= 0 &&
314df930be7Sderaadt 	   (uptodate(fd) || unlink(SAVEF) == 666)) {
315df930be7Sderaadt 		(void) signal(SIGINT,done1);
316df930be7Sderaadt 		pline("Restoring old save file...");
317df930be7Sderaadt 		(void) fflush(stdout);
318df930be7Sderaadt 		if(!dorecover(fd))
319df930be7Sderaadt 			goto not_recovered;
320df930be7Sderaadt 		pline("Hello %s, welcome to %s!", plname, gamename);
321df930be7Sderaadt 		flags.move = 0;
322df930be7Sderaadt 	} else {
323df930be7Sderaadt not_recovered:
324df930be7Sderaadt 		fobj = fcobj = invent = 0;
325df930be7Sderaadt 		fmon = fallen_down = 0;
326df930be7Sderaadt 		ftrap = 0;
327df930be7Sderaadt 		fgold = 0;
328df930be7Sderaadt 		flags.ident = 1;
329df930be7Sderaadt 		init_objects();
330df930be7Sderaadt 		u_init();
331df930be7Sderaadt 
332df930be7Sderaadt 		(void) signal(SIGINT,done1);
333df930be7Sderaadt 		mklev();
334df930be7Sderaadt 		u.ux = xupstair;
335df930be7Sderaadt 		u.uy = yupstair;
336df930be7Sderaadt 		(void) inshop();
337df930be7Sderaadt 		setsee();
338df930be7Sderaadt 		flags.botlx = 1;
339df930be7Sderaadt 		makedog();
340df930be7Sderaadt 		{ register struct monst *mtmp;
341df930be7Sderaadt 		  if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp);	/* riv05!a3 */
342df930be7Sderaadt 		}
343df930be7Sderaadt 		seemons();
344df930be7Sderaadt #ifdef NEWS
345df930be7Sderaadt 		if(flags.nonews || !readnews())
346df930be7Sderaadt 			/* after reading news we did docrt() already */
347df930be7Sderaadt #endif
348df930be7Sderaadt 			docrt();
349df930be7Sderaadt 
350df930be7Sderaadt 		/* give welcome message before pickup messages */
351df930be7Sderaadt 		pline("Hello %s, welcome to %s!", plname, gamename);
352df930be7Sderaadt 
353df930be7Sderaadt 		pickup(1);
354df930be7Sderaadt 		read_engr_at(u.ux,u.uy);
355df930be7Sderaadt 		flags.move = 1;
356df930be7Sderaadt 	}
357df930be7Sderaadt 
358df930be7Sderaadt 	flags.moonphase = phase_of_the_moon();
359df930be7Sderaadt 	if(flags.moonphase == FULL_MOON) {
360df930be7Sderaadt 		pline("You are lucky! Full moon tonight.");
361df930be7Sderaadt 		u.uluck++;
362df930be7Sderaadt 	} else if(flags.moonphase == NEW_MOON) {
363df930be7Sderaadt 		pline("Be careful! New moon tonight.");
364df930be7Sderaadt 	}
365df930be7Sderaadt 
366df930be7Sderaadt 	initrack();
367df930be7Sderaadt 
368df930be7Sderaadt 	for(;;) {
369df930be7Sderaadt 		if(flags.move) {	/* actual time passed */
370df930be7Sderaadt 
371df930be7Sderaadt 			settrack();
372df930be7Sderaadt 
373df930be7Sderaadt 			if(moves%2 == 0 ||
374df930be7Sderaadt 			  (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
375df930be7Sderaadt 				extern struct monst *makemon();
376df930be7Sderaadt 				movemon();
377df930be7Sderaadt 				if(!rn2(70))
378df930be7Sderaadt 				    (void) makemon((struct permonst *)0, 0, 0);
379df930be7Sderaadt 			}
380df930be7Sderaadt 			if(Glib) glibr();
381df930be7Sderaadt 			timeout();
382df930be7Sderaadt 			++moves;
383df930be7Sderaadt 			if(flags.time) flags.botl = 1;
384df930be7Sderaadt 			if(u.uhp < 1) {
385df930be7Sderaadt 				pline("You die...");
386df930be7Sderaadt 				done("died");
387df930be7Sderaadt 			}
388df930be7Sderaadt 			if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
389df930be7Sderaadt 			    wailmsg = moves;
390df930be7Sderaadt 			    if(u.uhp == 1)
391df930be7Sderaadt 			    pline("You hear the wailing of the Banshee...");
392df930be7Sderaadt 			    else
393df930be7Sderaadt 			    pline("You hear the howling of the CwnAnnwn...");
394df930be7Sderaadt 			}
395df930be7Sderaadt 			if(u.uhp < u.uhpmax) {
396df930be7Sderaadt 				if(u.ulevel > 9) {
397df930be7Sderaadt 					if(Regeneration || !(moves%3)) {
398df930be7Sderaadt 					    flags.botl = 1;
399df930be7Sderaadt 					    u.uhp += rnd((int) u.ulevel-9);
400df930be7Sderaadt 					    if(u.uhp > u.uhpmax)
401df930be7Sderaadt 						u.uhp = u.uhpmax;
402df930be7Sderaadt 					}
403df930be7Sderaadt 				} else if(Regeneration ||
404df930be7Sderaadt 					(!(moves%(22-u.ulevel*2)))) {
405df930be7Sderaadt 					flags.botl = 1;
406df930be7Sderaadt 					u.uhp++;
407df930be7Sderaadt 				}
408df930be7Sderaadt 			}
409df930be7Sderaadt 			if(Teleportation && !rn2(85)) tele();
410df930be7Sderaadt 			if(Searching && multi >= 0) (void) dosearch();
411df930be7Sderaadt 			gethungry();
412df930be7Sderaadt 			invault();
413df930be7Sderaadt 			amulet();
414df930be7Sderaadt 		}
415df930be7Sderaadt 		if(multi < 0) {
416df930be7Sderaadt 			if(!++multi){
417df930be7Sderaadt 				pline(nomovemsg ? nomovemsg :
418df930be7Sderaadt 					"You can move again.");
419df930be7Sderaadt 				nomovemsg = 0;
420df930be7Sderaadt 				if(afternmv) (*afternmv)();
421df930be7Sderaadt 				afternmv = 0;
422df930be7Sderaadt 			}
423df930be7Sderaadt 		}
424df930be7Sderaadt 
425df930be7Sderaadt 		find_ac();
426df930be7Sderaadt #ifndef QUEST
427df930be7Sderaadt 		if(!flags.mv || Blind)
428df930be7Sderaadt #endif
429df930be7Sderaadt 		{
430df930be7Sderaadt 			seeobjs();
431df930be7Sderaadt 			seemons();
432df930be7Sderaadt 			nscr();
433df930be7Sderaadt 		}
434df930be7Sderaadt 		if(flags.botl || flags.botlx) bot();
435df930be7Sderaadt 
436df930be7Sderaadt 		flags.move = 1;
437df930be7Sderaadt 
438df930be7Sderaadt 		if(multi >= 0 && occupation) {
439df930be7Sderaadt 			if(monster_nearby())
440df930be7Sderaadt 				stop_occupation();
441df930be7Sderaadt 			else if ((*occupation)() == 0)
442df930be7Sderaadt 				occupation = 0;
443df930be7Sderaadt 			continue;
444df930be7Sderaadt 		}
445df930be7Sderaadt 
446df930be7Sderaadt 		if(multi > 0) {
447df930be7Sderaadt #ifdef QUEST
448df930be7Sderaadt 			if(flags.run >= 4) finddir();
449df930be7Sderaadt #endif
450df930be7Sderaadt 			lookaround();
451df930be7Sderaadt 			if(!multi) {	/* lookaround may clear multi */
452df930be7Sderaadt 				flags.move = 0;
453df930be7Sderaadt 				continue;
454df930be7Sderaadt 			}
455df930be7Sderaadt 			if(flags.mv) {
456df930be7Sderaadt 				if(multi < COLNO && !--multi)
457df930be7Sderaadt 					flags.mv = flags.run = 0;
458df930be7Sderaadt 				domove();
459df930be7Sderaadt 			} else {
460df930be7Sderaadt 				--multi;
461df930be7Sderaadt 				rhack(save_cm);
462df930be7Sderaadt 			}
463df930be7Sderaadt 		} else if(multi == 0) {
464df930be7Sderaadt #ifdef MAIL
465df930be7Sderaadt 			ckmailstatus();
466df930be7Sderaadt #endif
467df930be7Sderaadt 			rhack((char *) 0);
468df930be7Sderaadt 		}
469df930be7Sderaadt 		if(multi && multi%7 == 0)
470df930be7Sderaadt 			(void) fflush(stdout);
471df930be7Sderaadt 	}
472df930be7Sderaadt }
473df930be7Sderaadt 
474df930be7Sderaadt glo(foo)
475df930be7Sderaadt register foo;
476df930be7Sderaadt {
477df930be7Sderaadt 	/* construct the string  xlock.n  */
478df930be7Sderaadt 	register char *tf;
479df930be7Sderaadt 
480df930be7Sderaadt 	tf = lock;
481df930be7Sderaadt 	while(*tf && *tf != '.') tf++;
482df930be7Sderaadt 	(void) sprintf(tf, ".%d", foo);
483df930be7Sderaadt }
484df930be7Sderaadt 
485df930be7Sderaadt /*
486df930be7Sderaadt  * plname is filled either by an option (-u Player  or  -uPlayer) or
487df930be7Sderaadt  * explicitly (-w implies wizard) or by askname.
488df930be7Sderaadt  * It may still contain a suffix denoting pl_character.
489df930be7Sderaadt  */
490df930be7Sderaadt askname(){
491df930be7Sderaadt register int c,ct;
492df930be7Sderaadt 	printf("\nWho are you? ");
493df930be7Sderaadt 	(void) fflush(stdout);
494df930be7Sderaadt 	ct = 0;
495df930be7Sderaadt 	while((c = getchar()) != '\n'){
496df930be7Sderaadt 		if(c == EOF) error("End of input\n");
497df930be7Sderaadt 		/* some people get confused when their erase char is not ^H */
498df930be7Sderaadt 		if(c == '\010') {
499df930be7Sderaadt 			if(ct) ct--;
500df930be7Sderaadt 			continue;
501df930be7Sderaadt 		}
502df930be7Sderaadt 		if(c != '-')
503df930be7Sderaadt 		if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
504df930be7Sderaadt 		if(ct < sizeof(plname)-1) plname[ct++] = c;
505df930be7Sderaadt 	}
506df930be7Sderaadt 	plname[ct] = 0;
507df930be7Sderaadt 	if(ct == 0) askname();
508df930be7Sderaadt }
509df930be7Sderaadt 
510df930be7Sderaadt /*VARARGS1*/
511df930be7Sderaadt impossible(s,x1,x2)
512df930be7Sderaadt register char *s;
513df930be7Sderaadt {
514df930be7Sderaadt 	pline(s,x1,x2);
515df930be7Sderaadt 	pline("Program in disorder - perhaps you'd better Quit.");
516df930be7Sderaadt }
517df930be7Sderaadt 
518df930be7Sderaadt #ifdef CHDIR
519df930be7Sderaadt static void
520df930be7Sderaadt chdirx(dir, wr)
521df930be7Sderaadt char *dir;
522df930be7Sderaadt boolean wr;
523df930be7Sderaadt {
524df930be7Sderaadt 
525df930be7Sderaadt #ifdef SECURE
526df930be7Sderaadt 	if(dir					/* User specified directory? */
527df930be7Sderaadt #ifdef HACKDIR
528df930be7Sderaadt 	       && strcmp(dir, HACKDIR)		/* and not the default? */
529df930be7Sderaadt #endif
530df930be7Sderaadt 		) {
531161033a1Sderaadt 		/* revoke */
532161033a1Sderaadt 		setegid(getgid());
533161033a1Sderaadt 		setgid(getgid());
534df930be7Sderaadt 	}
535df930be7Sderaadt #endif
536df930be7Sderaadt 
537df930be7Sderaadt #ifdef HACKDIR
538df930be7Sderaadt 	if(dir == NULL)
539df930be7Sderaadt 		dir = HACKDIR;
540df930be7Sderaadt #endif
541df930be7Sderaadt 
542df930be7Sderaadt 	if(dir && chdir(dir) < 0) {
543df930be7Sderaadt 		perror(dir);
544df930be7Sderaadt 		error("Cannot chdir to %s.", dir);
545df930be7Sderaadt 	}
546df930be7Sderaadt 
547df930be7Sderaadt 	/* warn the player if he cannot write the record file */
548df930be7Sderaadt 	/* perhaps we should also test whether . is writable */
549df930be7Sderaadt 	/* unfortunately the access systemcall is worthless */
550df930be7Sderaadt 	if(wr) {
551df930be7Sderaadt 	    register fd;
552df930be7Sderaadt 
553df930be7Sderaadt 	    if(dir == NULL)
554df930be7Sderaadt 		dir = ".";
5556cd28e42Smillert 	    if((fd = open(RECORD, O_RDWR)) < 0) {
556df930be7Sderaadt 		printf("Warning: cannot write %s/%s", dir, RECORD);
557df930be7Sderaadt 		getret();
558df930be7Sderaadt 	    } else
559df930be7Sderaadt 		(void) close(fd);
560df930be7Sderaadt 	}
561df930be7Sderaadt }
562df930be7Sderaadt #endif
563df930be7Sderaadt 
564df930be7Sderaadt stop_occupation()
565df930be7Sderaadt {
566df930be7Sderaadt 	if(occupation) {
567df930be7Sderaadt 		pline("You stop %s.", occtxt);
568df930be7Sderaadt 		occupation = 0;
569df930be7Sderaadt 	}
570df930be7Sderaadt }
571