xref: /netbsd-src/games/hack/hack.main.c (revision 2c0ecb1ab63c4e87a4abcff12e0a9e999ff836d9)
1*2c0ecb1aSdholland /*	$NetBSD: hack.main.c,v 1.17 2011/08/06 20:42:43 dholland Exp $	*/
23ea4a95cSchristos 
302ded532Smycroft /*
41c7f94e5Sjsm  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
51c7f94e5Sjsm  * Amsterdam
61c7f94e5Sjsm  * All rights reserved.
71c7f94e5Sjsm  *
81c7f94e5Sjsm  * Redistribution and use in source and binary forms, with or without
91c7f94e5Sjsm  * modification, are permitted provided that the following conditions are
101c7f94e5Sjsm  * met:
111c7f94e5Sjsm  *
121c7f94e5Sjsm  * - Redistributions of source code must retain the above copyright notice,
131c7f94e5Sjsm  * this list of conditions and the following disclaimer.
141c7f94e5Sjsm  *
151c7f94e5Sjsm  * - Redistributions in binary form must reproduce the above copyright
161c7f94e5Sjsm  * notice, this list of conditions and the following disclaimer in the
171c7f94e5Sjsm  * documentation and/or other materials provided with the distribution.
181c7f94e5Sjsm  *
191c7f94e5Sjsm  * - Neither the name of the Stichting Centrum voor Wiskunde en
201c7f94e5Sjsm  * Informatica, nor the names of its contributors may be used to endorse or
211c7f94e5Sjsm  * promote products derived from this software without specific prior
221c7f94e5Sjsm  * written permission.
231c7f94e5Sjsm  *
241c7f94e5Sjsm  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
251c7f94e5Sjsm  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
261c7f94e5Sjsm  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
271c7f94e5Sjsm  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
281c7f94e5Sjsm  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
291c7f94e5Sjsm  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
301c7f94e5Sjsm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
311c7f94e5Sjsm  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
321c7f94e5Sjsm  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
331c7f94e5Sjsm  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
341c7f94e5Sjsm  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
351c7f94e5Sjsm  */
361c7f94e5Sjsm 
371c7f94e5Sjsm /*
381c7f94e5Sjsm  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
391c7f94e5Sjsm  * All rights reserved.
401c7f94e5Sjsm  *
411c7f94e5Sjsm  * Redistribution and use in source and binary forms, with or without
421c7f94e5Sjsm  * modification, are permitted provided that the following conditions
431c7f94e5Sjsm  * are met:
441c7f94e5Sjsm  * 1. Redistributions of source code must retain the above copyright
451c7f94e5Sjsm  *    notice, this list of conditions and the following disclaimer.
461c7f94e5Sjsm  * 2. Redistributions in binary form must reproduce the above copyright
471c7f94e5Sjsm  *    notice, this list of conditions and the following disclaimer in the
481c7f94e5Sjsm  *    documentation and/or other materials provided with the distribution.
491c7f94e5Sjsm  * 3. The name of the author may not be used to endorse or promote products
501c7f94e5Sjsm  *    derived from this software without specific prior written permission.
511c7f94e5Sjsm  *
521c7f94e5Sjsm  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
531c7f94e5Sjsm  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
541c7f94e5Sjsm  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
551c7f94e5Sjsm  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
561c7f94e5Sjsm  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
571c7f94e5Sjsm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
581c7f94e5Sjsm  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
591c7f94e5Sjsm  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
601c7f94e5Sjsm  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
611c7f94e5Sjsm  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6202ded532Smycroft  */
6302ded532Smycroft 
643ea4a95cSchristos #include <sys/cdefs.h>
6502ded532Smycroft #ifndef lint
66*2c0ecb1aSdholland __RCSID("$NetBSD: hack.main.c,v 1.17 2011/08/06 20:42:43 dholland Exp $");
6702ded532Smycroft #endif				/* not lint */
6861f28255Scgd 
6961f28255Scgd #include <signal.h>
703ea4a95cSchristos #include <stdlib.h>
713ea4a95cSchristos #include <unistd.h>
723ea4a95cSchristos #include <fcntl.h>
7361f28255Scgd #include "hack.h"
743ea4a95cSchristos #include "extern.h"
7561f28255Scgd 
7661f28255Scgd #ifdef QUEST
7761f28255Scgd #define	gamename	"quest"
7861f28255Scgd #else
7961f28255Scgd #define	gamename	"hack"
8061f28255Scgd #endif
8161f28255Scgd 
82cb5fd834Sjsm int             (*afternmv)(void);
83cb5fd834Sjsm int             (*occupation)(void);
84ab8b6343Sjsm const char           *occtxt;		/* defined when occupation != NULL */
8561f28255Scgd 
8661f28255Scgd int             hackpid;	/* current pid */
8761f28255Scgd int             locknum;	/* max num of players */
8861f28255Scgd #ifdef DEF_PAGER
89ab8b6343Sjsm const char     *catmore;	/* default pager */
9061f28255Scgd #endif
9161f28255Scgd char            SAVEF[PL_NSIZ + 11] = "save/";	/* save/99999player */
9261f28255Scgd char           *hname;		/* name of the game (argv[0] of call) */
939b92b189Sdholland 
949b92b189Sdholland static char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */
9561f28255Scgd 
96cb5fd834Sjsm int main(int, char *[]);
97cb5fd834Sjsm static void chdirx(const char *, boolean);
9861f28255Scgd 
993ea4a95cSchristos int
main(int argc,char * argv[])1001fa8a9a6Sdholland main(int argc, char *argv[])
10161f28255Scgd {
1023ea4a95cSchristos 	int             fd;
10361f28255Scgd #ifdef CHDIR
1043ea4a95cSchristos 	char           *dir;
10561f28255Scgd #endif
10661f28255Scgd 
107ab8b6343Sjsm 	/* Check for dirty tricks with closed fds 0, 1, 2 */
108ab8b6343Sjsm 	fd = open("/dev/null", O_RDONLY);
109ab8b6343Sjsm 	if (fd < 3)
110ab8b6343Sjsm 		exit(1);
111ab8b6343Sjsm 	close(fd);
112ab8b6343Sjsm 
11361f28255Scgd 	hname = argv[0];
11461f28255Scgd 	hackpid = getpid();
11561f28255Scgd 
11661f28255Scgd #ifdef CHDIR			/* otherwise no chdir() */
11761f28255Scgd 	/*
11861f28255Scgd 	 * See if we must change directory to the playground.
11961f28255Scgd 	 * (Perhaps hack runs suid and playground is inaccessible
12061f28255Scgd 	 *  for the player.)
12161f28255Scgd 	 * The environment variable HACKDIR is overridden by a
12261f28255Scgd 	 *  -d command line option (must be the first option given)
12361f28255Scgd 	 */
12461f28255Scgd 
12561f28255Scgd 	dir = getenv("HACKDIR");
12661f28255Scgd 	if (argc > 1 && !strncmp(argv[1], "-d", 2)) {
12761f28255Scgd 		argc--;
12861f28255Scgd 		argv++;
12961f28255Scgd 		dir = argv[0] + 2;
1303ea4a95cSchristos 		if (*dir == '=' || *dir == ':')
1313ea4a95cSchristos 			dir++;
13261f28255Scgd 		if (!*dir && argc > 1) {
13361f28255Scgd 			argc--;
13461f28255Scgd 			argv++;
13561f28255Scgd 			dir = argv[0];
13661f28255Scgd 		}
13761f28255Scgd 		if (!*dir)
13861f28255Scgd 			error("Flag -d must be followed by a directory name.");
13961f28255Scgd 	}
14061f28255Scgd #endif
14161f28255Scgd 
14261f28255Scgd 	/*
14361f28255Scgd 	 * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
14461f28255Scgd 	 *			2. Use $USER or $LOGNAME	(if 1. fails)
14561f28255Scgd 	 *			3. Use getlogin()		(if 2. fails)
14661f28255Scgd 	 * The resulting name is overridden by command line options.
14761f28255Scgd 	 * If everything fails, or if the resulting name is some generic
14861f28255Scgd 	 * account like "games", "play", "player", "hack" then eventually
14961f28255Scgd 	 * we'll ask him.
15061f28255Scgd 	 * Note that we trust him here; it is possible to play under
15161f28255Scgd 	 * somebody else's name.
15261f28255Scgd 	 */
1533ea4a95cSchristos 	{
1543ea4a95cSchristos 		char           *s;
15561f28255Scgd 
15661f28255Scgd 		initoptions();
15761f28255Scgd 		if (!*plname && (s = getenv("USER")))
15861f28255Scgd 			(void) strncpy(plname, s, sizeof(plname) - 1);
15961f28255Scgd 		if (!*plname && (s = getenv("LOGNAME")))
16061f28255Scgd 			(void) strncpy(plname, s, sizeof(plname) - 1);
16161f28255Scgd 		if (!*plname && (s = getlogin()))
16261f28255Scgd 			(void) strncpy(plname, s, sizeof(plname) - 1);
16361f28255Scgd 	}
16461f28255Scgd 
16561f28255Scgd 	/*
16661f28255Scgd 	 * Now we know the directory containing 'record' and
16761f28255Scgd 	 * may do a prscore().
16861f28255Scgd 	 */
16961f28255Scgd 	if (argc > 1 && !strncmp(argv[1], "-s", 2)) {
17061f28255Scgd #ifdef CHDIR
17161f28255Scgd 		chdirx(dir, 0);
17261f28255Scgd #endif
17361f28255Scgd 		prscore(argc, argv);
17461f28255Scgd 		exit(0);
17561f28255Scgd 	}
17661f28255Scgd 	/*
17761f28255Scgd 	 * It seems he really wants to play.
17861f28255Scgd 	 * Remember tty modes, to be restored on exit.
17961f28255Scgd 	 */
18061f28255Scgd 	gettty();
18161f28255Scgd 	setbuf(stdout, obuf);
18261f28255Scgd 	setrandom();
18361f28255Scgd 	startup();
18461f28255Scgd 	cls();
18561f28255Scgd 	u.uhp = 1;		/* prevent RIP on early quits */
18661f28255Scgd 	u.ux = FAR;		/* prevent nscr() */
18798eb8895Sroy 	(void) signal(SIGHUP, hang_up);
18861f28255Scgd 
18961f28255Scgd 	/*
19061f28255Scgd 	 * Find the creation date of this game,
19161f28255Scgd 	 * so as to avoid restoring outdated savefiles.
19261f28255Scgd 	 */
19361f28255Scgd 	gethdate(hname);
19461f28255Scgd 
19561f28255Scgd 	/*
19661f28255Scgd 	 * We cannot do chdir earlier, otherwise gethdate will fail.
19761f28255Scgd 	 */
19861f28255Scgd #ifdef CHDIR
19961f28255Scgd 	chdirx(dir, 1);
20061f28255Scgd #endif
20161f28255Scgd 
20261f28255Scgd 	/*
20361f28255Scgd 	 * Process options.
20461f28255Scgd 	 */
20561f28255Scgd 	while (argc > 1 && argv[1][0] == '-') {
20661f28255Scgd 		argv++;
20761f28255Scgd 		argc--;
20861f28255Scgd 		switch (argv[0][1]) {
20961f28255Scgd #ifdef WIZARD
21061f28255Scgd 		case 'D':
21161f28255Scgd 			/* if(!strcmp(getlogin(), WIZARD)) */
21261f28255Scgd 			wizard = TRUE;
2133ea4a95cSchristos 			/*
2143ea4a95cSchristos 			 * else printf("Sorry.\n");
2153ea4a95cSchristos 			 */
21661f28255Scgd 			break;
21761f28255Scgd #endif
21861f28255Scgd #ifdef NEWS
21961f28255Scgd 		case 'n':
22061f28255Scgd 			flags.nonews = TRUE;
22161f28255Scgd 			break;
22261f28255Scgd #endif
22361f28255Scgd 		case 'u':
22461f28255Scgd 			if (argv[0][2])
22561f28255Scgd 				(void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1);
22661f28255Scgd 			else if (argc > 1) {
22761f28255Scgd 				argc--;
22861f28255Scgd 				argv++;
22961f28255Scgd 				(void) strncpy(plname, argv[0], sizeof(plname) - 1);
23061f28255Scgd 			} else
23161f28255Scgd 				printf("Player name expected after -u\n");
23261f28255Scgd 			break;
23361f28255Scgd 		default:
23461f28255Scgd 			/* allow -T for Tourist, etc. */
23561f28255Scgd 			(void) strncpy(pl_character, argv[0] + 1,
23661f28255Scgd 				       sizeof(pl_character) - 1);
23761f28255Scgd 
23861f28255Scgd 			/* printf("Unknown option: %s\n", *argv); */
23961f28255Scgd 		}
24061f28255Scgd 	}
24161f28255Scgd 
24261f28255Scgd 	if (argc > 1)
24361f28255Scgd 		locknum = atoi(argv[1]);
24461f28255Scgd #ifdef MAX_NR_OF_PLAYERS
24561f28255Scgd 	if (!locknum || locknum > MAX_NR_OF_PLAYERS)
24661f28255Scgd 		locknum = MAX_NR_OF_PLAYERS;
24761f28255Scgd #endif
24861f28255Scgd #ifdef DEF_PAGER
249f48d30b9Skleink 	if (((catmore = getenv("HACKPAGER")) == NULL &&
250f48d30b9Skleink 	    (catmore = getenv("PAGER")) == NULL) ||
251f48d30b9Skleink 	    catmore[0] == '\0')
25261f28255Scgd 		catmore = DEF_PAGER;
25361f28255Scgd #endif
25461f28255Scgd #ifdef MAIL
25561f28255Scgd 	getmailstatus();
25661f28255Scgd #endif
25761f28255Scgd #ifdef WIZARD
2583ea4a95cSchristos 	if (wizard)
2593ea4a95cSchristos 		(void) strcpy(plname, "wizard");
2603ea4a95cSchristos 	else
26161f28255Scgd #endif
26261f28255Scgd 		if (!*plname || !strncmp(plname, "player", 4)
26361f28255Scgd 		    || !strncmp(plname, "games", 4))
26461f28255Scgd 		askname();
26561f28255Scgd 	plnamesuffix();		/* strip suffix from name; calls askname() */
26661f28255Scgd 	/* again if suffix was whole name */
26761f28255Scgd 	/* accepts any suffix */
26861f28255Scgd #ifdef WIZARD
26961f28255Scgd 	if (!wizard) {
27061f28255Scgd #endif
27161f28255Scgd 		/*
27261f28255Scgd 		 * check for multiple games under the same name
27361f28255Scgd 		 * (if !locknum) or check max nr of players (otherwise)
27461f28255Scgd 		 */
27561f28255Scgd 		(void) signal(SIGQUIT, SIG_IGN);
27661f28255Scgd 		(void) signal(SIGINT, SIG_IGN);
27761f28255Scgd 		if (!locknum)
27861f28255Scgd 			(void) strcpy(lock, plname);
27961f28255Scgd 		getlock();	/* sets lock if locknum != 0 */
28061f28255Scgd #ifdef WIZARD
28161f28255Scgd 	} else {
2823ea4a95cSchristos 		char           *sfoo;
28361f28255Scgd 		(void) strcpy(lock, plname);
2843ea4a95cSchristos 		if ((sfoo = getenv("MAGIC")) != NULL)
28561f28255Scgd 			while (*sfoo) {
28661f28255Scgd 				switch (*sfoo++) {
2873ea4a95cSchristos 				case 'n':
2883ea4a95cSchristos 					(void) srandom(*sfoo++);
28961f28255Scgd 					break;
29061f28255Scgd 				}
29161f28255Scgd 			}
2923ea4a95cSchristos 		if ((sfoo = getenv("GENOCIDED")) != NULL) {
29361f28255Scgd 			if (*sfoo == '!') {
294ab8b6343Sjsm 				const struct permonst *pm = mons;
2953ea4a95cSchristos 				char           *gp = genocided;
29661f28255Scgd 
29761f28255Scgd 				while (pm < mons + CMNUM + 2) {
2983ea4a95cSchristos 					if (!strchr(sfoo, pm->mlet))
29961f28255Scgd 						*gp++ = pm->mlet;
30061f28255Scgd 					pm++;
30161f28255Scgd 				}
30261f28255Scgd 				*gp = 0;
30361f28255Scgd 			} else
304165c915bSdholland 				(void) strlcpy(genocided, sfoo,
305165c915bSdholland 						sizeof(genocided));
30661f28255Scgd 			(void) strcpy(fut_geno, genocided);
30761f28255Scgd 		}
30861f28255Scgd 	}
30961f28255Scgd #endif
31061f28255Scgd 	setftty();
311907fca1bSdholland 	(void) snprintf(SAVEF, sizeof(SAVEF), "save/%d%s", getuid(), plname);
31261f28255Scgd 	regularize(SAVEF + 5);	/* avoid . or / in name */
313ab8b6343Sjsm 	if ((fd = open(SAVEF, O_RDONLY)) >= 0 &&
31461f28255Scgd 	    (uptodate(fd) || unlink(SAVEF) == 666)) {
31561f28255Scgd 		(void) signal(SIGINT, done1);
31661f28255Scgd 		pline("Restoring old save file...");
31761f28255Scgd 		(void) fflush(stdout);
31861f28255Scgd 		if (!dorecover(fd))
31961f28255Scgd 			goto not_recovered;
32061f28255Scgd 		pline("Hello %s, welcome to %s!", plname, gamename);
32161f28255Scgd 		flags.move = 0;
32261f28255Scgd 	} else {
32361f28255Scgd not_recovered:
32461f28255Scgd 		fobj = fcobj = invent = 0;
32561f28255Scgd 		fmon = fallen_down = 0;
32661f28255Scgd 		ftrap = 0;
32761f28255Scgd 		fgold = 0;
32861f28255Scgd 		flags.ident = 1;
32961f28255Scgd 		init_objects();
33061f28255Scgd 		u_init();
33161f28255Scgd 
33261f28255Scgd 		(void) signal(SIGINT, done1);
33361f28255Scgd 		mklev();
33461f28255Scgd 		u.ux = xupstair;
33561f28255Scgd 		u.uy = yupstair;
33661f28255Scgd 		(void) inshop();
33761f28255Scgd 		setsee();
33861f28255Scgd 		flags.botlx = 1;
33961f28255Scgd 		makedog();
3403ea4a95cSchristos 		{
3413ea4a95cSchristos 			struct monst   *mtmp;
3423ea4a95cSchristos 			if ((mtmp = m_at(u.ux, u.uy)) != NULL)
3433ea4a95cSchristos 				mnexto(mtmp);	/* riv05!a3 */
34461f28255Scgd 		}
34561f28255Scgd 		seemons();
34661f28255Scgd #ifdef NEWS
34761f28255Scgd 		if (flags.nonews || !readnews())
34861f28255Scgd 			/* after reading news we did docrt() already */
34961f28255Scgd #endif
35061f28255Scgd 			docrt();
35161f28255Scgd 
35261f28255Scgd 		/* give welcome message before pickup messages */
35361f28255Scgd 		pline("Hello %s, welcome to %s!", plname, gamename);
35461f28255Scgd 
35561f28255Scgd 		pickup(1);
35661f28255Scgd 		read_engr_at(u.ux, u.uy);
35761f28255Scgd 		flags.move = 1;
35861f28255Scgd 	}
35961f28255Scgd 
36061f28255Scgd 	flags.moonphase = phase_of_the_moon();
36161f28255Scgd 	if (flags.moonphase == FULL_MOON) {
36261f28255Scgd 		pline("You are lucky! Full moon tonight.");
36361f28255Scgd 		u.uluck++;
36461f28255Scgd 	} else if (flags.moonphase == NEW_MOON) {
36561f28255Scgd 		pline("Be careful! New moon tonight.");
36661f28255Scgd 	}
36761f28255Scgd 	initrack();
36861f28255Scgd 
36961f28255Scgd 	for (;;) {
37061f28255Scgd 		if (flags.move) {	/* actual time passed */
37161f28255Scgd 
37261f28255Scgd 			settrack();
37361f28255Scgd 
37461f28255Scgd 			if (moves % 2 == 0 ||
37561f28255Scgd 			    (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
37661f28255Scgd 				movemon();
37761f28255Scgd 				if (!rn2(70))
37861f28255Scgd 					(void) makemon((struct permonst *) 0, 0, 0);
37961f28255Scgd 			}
3803ea4a95cSchristos 			if (Glib)
3813ea4a95cSchristos 				glibr();
38261f28255Scgd 			timeout();
38361f28255Scgd 			++moves;
3843ea4a95cSchristos 			if (flags.time)
3853ea4a95cSchristos 				flags.botl = 1;
38661f28255Scgd 			if (u.uhp < 1) {
38761f28255Scgd 				pline("You die...");
38861f28255Scgd 				done("died");
38961f28255Scgd 			}
39061f28255Scgd 			if (u.uhp * 10 < u.uhpmax && moves - wailmsg > 50) {
39161f28255Scgd 				wailmsg = moves;
39261f28255Scgd 				if (u.uhp == 1)
39361f28255Scgd 					pline("You hear the wailing of the Banshee...");
39461f28255Scgd 				else
39561f28255Scgd 					pline("You hear the howling of the CwnAnnwn...");
39661f28255Scgd 			}
39761f28255Scgd 			if (u.uhp < u.uhpmax) {
39861f28255Scgd 				if (u.ulevel > 9) {
39961f28255Scgd 					if (Regeneration || !(moves % 3)) {
40061f28255Scgd 						flags.botl = 1;
40161f28255Scgd 						u.uhp += rnd((int) u.ulevel - 9);
40261f28255Scgd 						if (u.uhp > u.uhpmax)
40361f28255Scgd 							u.uhp = u.uhpmax;
40461f28255Scgd 					}
40561f28255Scgd 				} else if (Regeneration ||
40661f28255Scgd 					 (!(moves % (22 - u.ulevel * 2)))) {
40761f28255Scgd 					flags.botl = 1;
40861f28255Scgd 					u.uhp++;
40961f28255Scgd 				}
41061f28255Scgd 			}
4113ea4a95cSchristos 			if (Teleportation && !rn2(85))
4123ea4a95cSchristos 				tele();
4133ea4a95cSchristos 			if (Searching && multi >= 0)
4143ea4a95cSchristos 				(void) dosearch();
41561f28255Scgd 			gethungry();
41661f28255Scgd 			invault();
41761f28255Scgd 			amulet();
41861f28255Scgd 		}
41961f28255Scgd 		if (multi < 0) {
42061f28255Scgd 			if (!++multi) {
42157c13365Sjoerg 				if (nomovemsg)
42257c13365Sjoerg 					pline("%s", nomovemsg);
42357c13365Sjoerg 				else
42457c13365Sjoerg 					pline("You can move again.");
42561f28255Scgd 				nomovemsg = 0;
4263ea4a95cSchristos 				if (afternmv)
4273ea4a95cSchristos 					(*afternmv) ();
42861f28255Scgd 				afternmv = 0;
42961f28255Scgd 			}
43061f28255Scgd 		}
43161f28255Scgd 		find_ac();
43261f28255Scgd #ifndef QUEST
43361f28255Scgd 		if (!flags.mv || Blind)
43461f28255Scgd #endif
43561f28255Scgd 		{
43661f28255Scgd 			seeobjs();
43761f28255Scgd 			seemons();
43861f28255Scgd 			nscr();
43961f28255Scgd 		}
4403ea4a95cSchristos 		if (flags.botl || flags.botlx)
4413ea4a95cSchristos 			bot();
44261f28255Scgd 
44361f28255Scgd 		flags.move = 1;
44461f28255Scgd 
44561f28255Scgd 		if (multi >= 0 && occupation) {
44661f28255Scgd 			if (monster_nearby())
44761f28255Scgd 				stop_occupation();
44861f28255Scgd 			else if ((*occupation) () == 0)
44961f28255Scgd 				occupation = 0;
45061f28255Scgd 			continue;
45161f28255Scgd 		}
45261f28255Scgd 		if (multi > 0) {
45361f28255Scgd #ifdef QUEST
4543ea4a95cSchristos 			if (flags.run >= 4)
4553ea4a95cSchristos 				finddir();
45661f28255Scgd #endif
45761f28255Scgd 			lookaround();
45861f28255Scgd 			if (!multi) {	/* lookaround may clear multi */
45961f28255Scgd 				flags.move = 0;
46061f28255Scgd 				continue;
46161f28255Scgd 			}
46261f28255Scgd 			if (flags.mv) {
46361f28255Scgd 				if (multi < COLNO && !--multi)
46461f28255Scgd 					flags.mv = flags.run = 0;
46561f28255Scgd 				domove();
46661f28255Scgd 			} else {
46761f28255Scgd 				--multi;
46861f28255Scgd 				rhack(save_cm);
46961f28255Scgd 			}
47061f28255Scgd 		} else if (multi == 0) {
47161f28255Scgd #ifdef MAIL
47261f28255Scgd 			ckmailstatus();
47361f28255Scgd #endif
474*2c0ecb1aSdholland 			rhack(NULL);
47561f28255Scgd 		}
47661f28255Scgd 		if (multi && multi % 7 == 0)
47761f28255Scgd 			(void) fflush(stdout);
47861f28255Scgd 	}
47961f28255Scgd }
48061f28255Scgd 
4813ea4a95cSchristos void
glo(int foo)4821fa8a9a6Sdholland glo(int foo)
48361f28255Scgd {
48461f28255Scgd 	/* construct the string  xlock.n  */
485165c915bSdholland 	size_t pos;
48661f28255Scgd 
487165c915bSdholland 	pos = 0;
488165c915bSdholland 	while (lock[pos] && lock[pos] != '.')
489165c915bSdholland 		pos++;
490165c915bSdholland 	(void) snprintf(lock + pos, sizeof(lock) - pos, ".%d", foo);
49161f28255Scgd }
49261f28255Scgd 
49361f28255Scgd /*
49461f28255Scgd  * plname is filled either by an option (-u Player  or  -uPlayer) or
49561f28255Scgd  * explicitly (-w implies wizard) or by askname.
49661f28255Scgd  * It may still contain a suffix denoting pl_character.
49761f28255Scgd  */
4983ea4a95cSchristos void
askname(void)4991fa8a9a6Sdholland askname(void)
5003ea4a95cSchristos {
5013ea4a95cSchristos 	int             c, ct;
50261f28255Scgd 	printf("\nWho are you? ");
50361f28255Scgd 	(void) fflush(stdout);
50461f28255Scgd 	ct = 0;
50561f28255Scgd 	while ((c = getchar()) != '\n') {
5063ea4a95cSchristos 		if (c == EOF)
5073ea4a95cSchristos 			error("End of input\n");
50861f28255Scgd 		/* some people get confused when their erase char is not ^H */
50961f28255Scgd 		if (c == '\010') {
5103ea4a95cSchristos 			if (ct)
5113ea4a95cSchristos 				ct--;
51261f28255Scgd 			continue;
51361f28255Scgd 		}
51461f28255Scgd 		if (c != '-')
5153ea4a95cSchristos 			if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z')
5163ea4a95cSchristos 				c = '_';
5173c439f43Sdholland 		if (ct < (int)sizeof(plname) - 1)
5183ea4a95cSchristos 			plname[ct++] = c;
51961f28255Scgd 	}
52061f28255Scgd 	plname[ct] = 0;
5213ea4a95cSchristos 	if (ct == 0)
5223ea4a95cSchristos 		askname();
52361f28255Scgd }
52461f28255Scgd 
52561f28255Scgd /* VARARGS1 */
5263ea4a95cSchristos void
impossible(const char * s,...)5273ea4a95cSchristos impossible(const char *s, ...)
52861f28255Scgd {
5293ea4a95cSchristos 	va_list ap;
5303ea4a95cSchristos 
5313ea4a95cSchristos 	va_start(ap, s);
5323ea4a95cSchristos 	vpline(s, ap);
5333ea4a95cSchristos 	va_end(ap);
53461f28255Scgd 	pline("Program in disorder - perhaps you'd better Quit.");
53561f28255Scgd }
53661f28255Scgd 
53761f28255Scgd #ifdef CHDIR
53861f28255Scgd static void
chdirx(const char * dir,boolean wr)5391fa8a9a6Sdholland chdirx(const char *dir, boolean wr)
54061f28255Scgd {
54161f28255Scgd 
54261f28255Scgd #ifdef SECURE
54361f28255Scgd 	if (dir			/* User specified directory? */
54461f28255Scgd #ifdef HACKDIR
54561f28255Scgd 	    && strcmp(dir, HACKDIR)	/* and not the default? */
54661f28255Scgd #endif
54761f28255Scgd 		) {
54861f28255Scgd 		(void) setuid(getuid());	/* Ron Wessels */
54961f28255Scgd 		(void) setgid(getgid());
55061f28255Scgd 	}
55161f28255Scgd #endif
55261f28255Scgd 
55361f28255Scgd #ifdef HACKDIR
55461f28255Scgd 	if (dir == NULL)
55561f28255Scgd 		dir = HACKDIR;
55661f28255Scgd #endif
55761f28255Scgd 
55861f28255Scgd 	if (dir && chdir(dir) < 0) {
55961f28255Scgd 		perror(dir);
56061f28255Scgd 		error("Cannot chdir to %s.", dir);
56161f28255Scgd 	}
56261f28255Scgd 	/* warn the player if he cannot write the record file */
56361f28255Scgd 	/* perhaps we should also test whether . is writable */
56461f28255Scgd 	/* unfortunately the access systemcall is worthless */
56561f28255Scgd 	if (wr) {
5663ea4a95cSchristos 		int fd;
56761f28255Scgd 
56861f28255Scgd 		if (dir == NULL)
56961f28255Scgd 			dir = ".";
570ab8b6343Sjsm 		if ((fd = open(RECORD, O_RDWR)) < 0) {
57161f28255Scgd 			printf("Warning: cannot write %s/%s", dir, RECORD);
57261f28255Scgd 			getret();
57361f28255Scgd 		} else
57461f28255Scgd 			(void) close(fd);
57561f28255Scgd 	}
57661f28255Scgd }
57761f28255Scgd #endif
57861f28255Scgd 
5793ea4a95cSchristos void
stop_occupation(void)5801fa8a9a6Sdholland stop_occupation(void)
58161f28255Scgd {
58261f28255Scgd 	if (occupation) {
58361f28255Scgd 		pline("You stop %s.", occtxt);
58461f28255Scgd 		occupation = 0;
58561f28255Scgd 	}
58661f28255Scgd }
587