xref: /csrg-svn/games/hack/hack.main.c (revision 47699)
133149Sbostic /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
233149Sbostic /* hack.main.c - version 1.0.3 */
333149Sbostic 
433149Sbostic #include <stdio.h>
533149Sbostic #include <signal.h>
633149Sbostic #include "hack.h"
733149Sbostic 
833149Sbostic #ifdef QUEST
933149Sbostic #define	gamename	"quest"
1033149Sbostic #else
1133149Sbostic #define	gamename	"hack"
12*47699Sbostic #endif
1333149Sbostic 
1433149Sbostic extern char *getlogin(), *getenv();
1533149Sbostic extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
1633150Sbostic extern struct permonst mons[CMNUM+2];
1733150Sbostic extern char genocided[], fut_geno[];
1833149Sbostic 
1933149Sbostic int (*afternmv)();
2033149Sbostic int (*occupation)();
2133149Sbostic char *occtxt;			/* defined when occupation != NULL */
2233149Sbostic 
23*47699Sbostic void done1();
24*47699Sbostic void hangup();
2533149Sbostic 
2633149Sbostic int hackpid;				/* current pid */
2733149Sbostic int locknum;				/* max num of players */
2833149Sbostic #ifdef DEF_PAGER
2933149Sbostic char *catmore;				/* default pager */
30*47699Sbostic #endif
3133149Sbostic char SAVEF[PL_NSIZ + 11] = "save/";	/* save/99999player */
3233149Sbostic char *hname;		/* name of the game (argv[0] of call) */
3333149Sbostic char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */
3433149Sbostic 
3533149Sbostic extern char *nomovemsg;
3633149Sbostic extern long wailmsg;
3733149Sbostic 
38*47699Sbostic #ifdef CHDIR
39*47699Sbostic static void chdirx();
40*47699Sbostic #endif
41*47699Sbostic 
main(argc,argv)4233149Sbostic main(argc,argv)
4333149Sbostic int argc;
4433149Sbostic char *argv[];
4533149Sbostic {
4633149Sbostic 	register int fd;
4733149Sbostic #ifdef CHDIR
4833149Sbostic 	register char *dir;
49*47699Sbostic #endif
5033149Sbostic 
5133149Sbostic 	hname = argv[0];
5233149Sbostic 	hackpid = getpid();
5333149Sbostic 
5433149Sbostic #ifdef CHDIR			/* otherwise no chdir() */
5533149Sbostic 	/*
5633149Sbostic 	 * See if we must change directory to the playground.
5733149Sbostic 	 * (Perhaps hack runs suid and playground is inaccessible
5833149Sbostic 	 *  for the player.)
5933149Sbostic 	 * The environment variable HACKDIR is overridden by a
6033149Sbostic 	 *  -d command line option (must be the first option given)
6133149Sbostic 	 */
6233149Sbostic 
6333149Sbostic 	dir = getenv("HACKDIR");
6433149Sbostic 	if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
6533149Sbostic 		argc--;
6633149Sbostic 		argv++;
6733149Sbostic 		dir = argv[0]+2;
6833149Sbostic 		if(*dir == '=' || *dir == ':') dir++;
6933149Sbostic 		if(!*dir && argc > 1) {
7033149Sbostic 			argc--;
7133149Sbostic 			argv++;
7233149Sbostic 			dir = argv[0];
7333149Sbostic 		}
7433149Sbostic 		if(!*dir)
7533149Sbostic 		    error("Flag -d must be followed by a directory name.");
7633149Sbostic 	}
77*47699Sbostic #endif
7833149Sbostic 
7933149Sbostic 	/*
8033149Sbostic 	 * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
8133149Sbostic 	 *			2. Use $USER or $LOGNAME	(if 1. fails)
8233149Sbostic 	 *			3. Use getlogin()		(if 2. fails)
8333149Sbostic 	 * The resulting name is overridden by command line options.
8433149Sbostic 	 * If everything fails, or if the resulting name is some generic
8533149Sbostic 	 * account like "games", "play", "player", "hack" then eventually
8633149Sbostic 	 * we'll ask him.
8733149Sbostic 	 * Note that we trust him here; it is possible to play under
8833149Sbostic 	 * somebody else's name.
8933149Sbostic 	 */
9033149Sbostic 	{ register char *s;
9133149Sbostic 
9233149Sbostic 	  initoptions();
9333149Sbostic 	  if(!*plname && (s = getenv("USER")))
9433149Sbostic 		(void) strncpy(plname, s, sizeof(plname)-1);
9533149Sbostic 	  if(!*plname && (s = getenv("LOGNAME")))
9633149Sbostic 		(void) strncpy(plname, s, sizeof(plname)-1);
9733149Sbostic 	  if(!*plname && (s = getlogin()))
9833149Sbostic 		(void) strncpy(plname, s, sizeof(plname)-1);
9933149Sbostic 	}
10033149Sbostic 
10133149Sbostic 	/*
10233149Sbostic 	 * Now we know the directory containing 'record' and
10333149Sbostic 	 * may do a prscore().
10433149Sbostic 	 */
10533149Sbostic 	if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
10633149Sbostic #ifdef CHDIR
10733149Sbostic 		chdirx(dir,0);
108*47699Sbostic #endif
10933149Sbostic 		prscore(argc, argv);
11033149Sbostic 		exit(0);
11133149Sbostic 	}
11233149Sbostic 
11333149Sbostic 	/*
11433149Sbostic 	 * It seems he really wants to play.
11533149Sbostic 	 * Remember tty modes, to be restored on exit.
11633149Sbostic 	 */
11733149Sbostic 	gettty();
11833149Sbostic 	setbuf(stdout,obuf);
11933149Sbostic 	setrandom();
12033149Sbostic 	startup();
12133149Sbostic 	cls();
12233149Sbostic 	u.uhp = 1;	/* prevent RIP on early quits */
12333149Sbostic 	u.ux = FAR;	/* prevent nscr() */
12433149Sbostic 	(void) signal(SIGHUP, hangup);
12533149Sbostic 
12633149Sbostic 	/*
12733149Sbostic 	 * Find the creation date of this game,
12833149Sbostic 	 * so as to avoid restoring outdated savefiles.
12933149Sbostic 	 */
13033149Sbostic 	gethdate(hname);
13133149Sbostic 
13233149Sbostic 	/*
13333149Sbostic 	 * We cannot do chdir earlier, otherwise gethdate will fail.
13433149Sbostic 	 */
13533149Sbostic #ifdef CHDIR
13633149Sbostic 	chdirx(dir,1);
137*47699Sbostic #endif
13833149Sbostic 
13933149Sbostic 	/*
14033149Sbostic 	 * Process options.
14133149Sbostic 	 */
14233149Sbostic 	while(argc > 1 && argv[1][0] == '-'){
14333149Sbostic 		argv++;
14433149Sbostic 		argc--;
14533149Sbostic 		switch(argv[0][1]){
14633149Sbostic #ifdef WIZARD
14733149Sbostic 		case 'D':
14833149Sbostic /*			if(!strcmp(getlogin(), WIZARD)) */
14933149Sbostic 				wizard = TRUE;
15033149Sbostic /*			else
15133149Sbostic 				printf("Sorry.\n"); */
15233149Sbostic 			break;
153*47699Sbostic #endif
15433149Sbostic #ifdef NEWS
15533149Sbostic 		case 'n':
15633149Sbostic 			flags.nonews = TRUE;
15733149Sbostic 			break;
158*47699Sbostic #endif
15933149Sbostic 		case 'u':
16033149Sbostic 			if(argv[0][2])
16133149Sbostic 			  (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
16233149Sbostic 			else if(argc > 1) {
16333149Sbostic 			  argc--;
16433149Sbostic 			  argv++;
16533149Sbostic 			  (void) strncpy(plname, argv[0], sizeof(plname)-1);
16633149Sbostic 			} else
16733149Sbostic 				printf("Player name expected after -u\n");
16833149Sbostic 			break;
16933149Sbostic 		default:
17033149Sbostic 			/* allow -T for Tourist, etc. */
17133149Sbostic 			(void) strncpy(pl_character, argv[0]+1,
17233149Sbostic 				sizeof(pl_character)-1);
17333149Sbostic 
17433149Sbostic 			/* printf("Unknown option: %s\n", *argv); */
17533149Sbostic 		}
17633149Sbostic 	}
17733149Sbostic 
17833149Sbostic 	if(argc > 1)
17933149Sbostic 		locknum = atoi(argv[1]);
18033149Sbostic #ifdef MAX_NR_OF_PLAYERS
18133149Sbostic 	if(!locknum || locknum > MAX_NR_OF_PLAYERS)
18233149Sbostic 		locknum = MAX_NR_OF_PLAYERS;
183*47699Sbostic #endif
18433149Sbostic #ifdef DEF_PAGER
18533149Sbostic 	if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER")))
18633149Sbostic 		catmore = DEF_PAGER;
187*47699Sbostic #endif
18833149Sbostic #ifdef MAIL
18933149Sbostic 	getmailstatus();
190*47699Sbostic #endif
19133149Sbostic #ifdef WIZARD
19233149Sbostic 	if(wizard) (void) strcpy(plname, "wizard"); else
193*47699Sbostic #endif
19433149Sbostic 	if(!*plname || !strncmp(plname, "player", 4)
19533149Sbostic 		    || !strncmp(plname, "games", 4))
19633149Sbostic 		askname();
19733149Sbostic 	plnamesuffix();		/* strip suffix from name; calls askname() */
19833149Sbostic 				/* again if suffix was whole name */
19933149Sbostic 				/* accepts any suffix */
20033149Sbostic #ifdef WIZARD
20133149Sbostic 	if(!wizard) {
202*47699Sbostic #endif
20333149Sbostic 		/*
20433149Sbostic 		 * check for multiple games under the same name
20533149Sbostic 		 * (if !locknum) or check max nr of players (otherwise)
20633149Sbostic 		 */
20733149Sbostic 		(void) signal(SIGQUIT,SIG_IGN);
20833149Sbostic 		(void) signal(SIGINT,SIG_IGN);
20933149Sbostic 		if(!locknum)
21033149Sbostic 			(void) strcpy(lock,plname);
21133149Sbostic 		getlock();	/* sets lock if locknum != 0 */
21233149Sbostic #ifdef WIZARD
21333149Sbostic 	} else {
21433149Sbostic 		register char *sfoo;
21533149Sbostic 		(void) strcpy(lock,plname);
21633149Sbostic 		if(sfoo = getenv("MAGIC"))
21733149Sbostic 			while(*sfoo) {
21833149Sbostic 				switch(*sfoo++) {
21933149Sbostic 				case 'n': (void) srandom(*sfoo++);
22033149Sbostic 					break;
22133149Sbostic 				}
22233149Sbostic 			}
22333149Sbostic 		if(sfoo = getenv("GENOCIDED")){
22433149Sbostic 			if(*sfoo == '!'){
22533149Sbostic 				register struct permonst *pm = mons;
22633149Sbostic 				register char *gp = genocided;
22733149Sbostic 
22833149Sbostic 				while(pm < mons+CMNUM+2){
22933149Sbostic 					if(!index(sfoo, pm->mlet))
23033149Sbostic 						*gp++ = pm->mlet;
23133149Sbostic 					pm++;
23233149Sbostic 				}
23333149Sbostic 				*gp = 0;
23433149Sbostic 			} else
23533149Sbostic 				(void) strcpy(genocided, sfoo);
23633149Sbostic 			(void) strcpy(fut_geno, genocided);
23733149Sbostic 		}
23833149Sbostic 	}
239*47699Sbostic #endif
24033149Sbostic 	setftty();
24133149Sbostic 	(void) sprintf(SAVEF, "save/%d%s", getuid(), plname);
24233149Sbostic 	regularize(SAVEF+5);		/* avoid . or / in name */
24333149Sbostic 	if((fd = open(SAVEF,0)) >= 0 &&
24433149Sbostic 	   (uptodate(fd) || unlink(SAVEF) == 666)) {
24533149Sbostic 		(void) signal(SIGINT,done1);
24633149Sbostic 		pline("Restoring old save file...");
24733149Sbostic 		(void) fflush(stdout);
24833149Sbostic 		if(!dorecover(fd))
24933149Sbostic 			goto not_recovered;
25033149Sbostic 		pline("Hello %s, welcome to %s!", plname, gamename);
25133149Sbostic 		flags.move = 0;
25233149Sbostic 	} else {
25333149Sbostic not_recovered:
25433149Sbostic 		fobj = fcobj = invent = 0;
25533149Sbostic 		fmon = fallen_down = 0;
25633149Sbostic 		ftrap = 0;
25733149Sbostic 		fgold = 0;
25833149Sbostic 		flags.ident = 1;
25933149Sbostic 		init_objects();
26033149Sbostic 		u_init();
26133149Sbostic 
26233149Sbostic 		(void) signal(SIGINT,done1);
26333149Sbostic 		mklev();
26433149Sbostic 		u.ux = xupstair;
26533149Sbostic 		u.uy = yupstair;
26633149Sbostic 		(void) inshop();
26733149Sbostic 		setsee();
26833149Sbostic 		flags.botlx = 1;
26933149Sbostic 		makedog();
27033149Sbostic 		{ register struct monst *mtmp;
27133149Sbostic 		  if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp);	/* riv05!a3 */
27233149Sbostic 		}
27333149Sbostic 		seemons();
27433149Sbostic #ifdef NEWS
27533149Sbostic 		if(flags.nonews || !readnews())
27633149Sbostic 			/* after reading news we did docrt() already */
277*47699Sbostic #endif
27833149Sbostic 			docrt();
27933149Sbostic 
28033149Sbostic 		/* give welcome message before pickup messages */
28133149Sbostic 		pline("Hello %s, welcome to %s!", plname, gamename);
28233149Sbostic 
28333149Sbostic 		pickup(1);
28433149Sbostic 		read_engr_at(u.ux,u.uy);
28533149Sbostic 		flags.move = 1;
28633149Sbostic 	}
28733149Sbostic 
28833149Sbostic 	flags.moonphase = phase_of_the_moon();
28933149Sbostic 	if(flags.moonphase == FULL_MOON) {
29033149Sbostic 		pline("You are lucky! Full moon tonight.");
29133149Sbostic 		u.uluck++;
29233149Sbostic 	} else if(flags.moonphase == NEW_MOON) {
29333149Sbostic 		pline("Be careful! New moon tonight.");
29433149Sbostic 	}
29533149Sbostic 
29633149Sbostic 	initrack();
29733149Sbostic 
29833149Sbostic 	for(;;) {
29933149Sbostic 		if(flags.move) {	/* actual time passed */
30033149Sbostic 
30133149Sbostic 			settrack();
30233149Sbostic 
30333149Sbostic 			if(moves%2 == 0 ||
30433149Sbostic 			  (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
30533149Sbostic 				extern struct monst *makemon();
30633149Sbostic 				movemon();
30733149Sbostic 				if(!rn2(70))
30833149Sbostic 				    (void) makemon((struct permonst *)0, 0, 0);
30933149Sbostic 			}
31033149Sbostic 			if(Glib) glibr();
31133149Sbostic 			timeout();
31233149Sbostic 			++moves;
31333149Sbostic 			if(flags.time) flags.botl = 1;
31433149Sbostic 			if(u.uhp < 1) {
31533149Sbostic 				pline("You die...");
31633149Sbostic 				done("died");
31733149Sbostic 			}
31833149Sbostic 			if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
31933149Sbostic 			    wailmsg = moves;
32033149Sbostic 			    if(u.uhp == 1)
32133149Sbostic 			    pline("You hear the wailing of the Banshee...");
32233149Sbostic 			    else
32333149Sbostic 			    pline("You hear the howling of the CwnAnnwn...");
32433149Sbostic 			}
32533149Sbostic 			if(u.uhp < u.uhpmax) {
32633149Sbostic 				if(u.ulevel > 9) {
32733149Sbostic 					if(Regeneration || !(moves%3)) {
32833149Sbostic 					    flags.botl = 1;
32933149Sbostic 					    u.uhp += rnd((int) u.ulevel-9);
33033149Sbostic 					    if(u.uhp > u.uhpmax)
33133149Sbostic 						u.uhp = u.uhpmax;
33233149Sbostic 					}
33333149Sbostic 				} else if(Regeneration ||
33433149Sbostic 					(!(moves%(22-u.ulevel*2)))) {
33533149Sbostic 					flags.botl = 1;
33633149Sbostic 					u.uhp++;
33733149Sbostic 				}
33833149Sbostic 			}
33933149Sbostic 			if(Teleportation && !rn2(85)) tele();
34033149Sbostic 			if(Searching && multi >= 0) (void) dosearch();
34133149Sbostic 			gethungry();
34233149Sbostic 			invault();
34333149Sbostic 			amulet();
34433149Sbostic 		}
34533149Sbostic 		if(multi < 0) {
34633149Sbostic 			if(!++multi){
34733149Sbostic 				pline(nomovemsg ? nomovemsg :
34833149Sbostic 					"You can move again.");
34933149Sbostic 				nomovemsg = 0;
35033149Sbostic 				if(afternmv) (*afternmv)();
35133149Sbostic 				afternmv = 0;
35233149Sbostic 			}
35333149Sbostic 		}
35433149Sbostic 
35533149Sbostic 		find_ac();
35633149Sbostic #ifndef QUEST
35733149Sbostic 		if(!flags.mv || Blind)
358*47699Sbostic #endif
35933149Sbostic 		{
36033149Sbostic 			seeobjs();
36133149Sbostic 			seemons();
36233149Sbostic 			nscr();
36333149Sbostic 		}
36433149Sbostic 		if(flags.botl || flags.botlx) bot();
36533149Sbostic 
36633149Sbostic 		flags.move = 1;
36733149Sbostic 
36833149Sbostic 		if(multi >= 0 && occupation) {
36933149Sbostic 			if(monster_nearby())
37033149Sbostic 				stop_occupation();
37133149Sbostic 			else if ((*occupation)() == 0)
37233149Sbostic 				occupation = 0;
37333149Sbostic 			continue;
37433149Sbostic 		}
37533149Sbostic 
37633149Sbostic 		if(multi > 0) {
37733149Sbostic #ifdef QUEST
37833149Sbostic 			if(flags.run >= 4) finddir();
379*47699Sbostic #endif
38033149Sbostic 			lookaround();
38133149Sbostic 			if(!multi) {	/* lookaround may clear multi */
38233149Sbostic 				flags.move = 0;
38333149Sbostic 				continue;
38433149Sbostic 			}
38533149Sbostic 			if(flags.mv) {
38633149Sbostic 				if(multi < COLNO && !--multi)
38733149Sbostic 					flags.mv = flags.run = 0;
38833149Sbostic 				domove();
38933149Sbostic 			} else {
39033149Sbostic 				--multi;
39133149Sbostic 				rhack(save_cm);
39233149Sbostic 			}
39333149Sbostic 		} else if(multi == 0) {
39433149Sbostic #ifdef MAIL
39533149Sbostic 			ckmailstatus();
396*47699Sbostic #endif
39733149Sbostic 			rhack((char *) 0);
39833149Sbostic 		}
39933149Sbostic 		if(multi && multi%7 == 0)
40033149Sbostic 			(void) fflush(stdout);
40133149Sbostic 	}
40233149Sbostic }
40333149Sbostic 
glo(foo)40433149Sbostic glo(foo)
40533149Sbostic register foo;
40633149Sbostic {
40733149Sbostic 	/* construct the string  xlock.n  */
40833149Sbostic 	register char *tf;
40933149Sbostic 
41033149Sbostic 	tf = lock;
41133149Sbostic 	while(*tf && *tf != '.') tf++;
41233149Sbostic 	(void) sprintf(tf, ".%d", foo);
41333149Sbostic }
41433149Sbostic 
41533149Sbostic /*
41633149Sbostic  * plname is filled either by an option (-u Player  or  -uPlayer) or
41733149Sbostic  * explicitly (-w implies wizard) or by askname.
41833149Sbostic  * It may still contain a suffix denoting pl_character.
41933149Sbostic  */
askname()42033149Sbostic askname(){
42133149Sbostic register int c,ct;
42233149Sbostic 	printf("\nWho are you? ");
42333149Sbostic 	(void) fflush(stdout);
42433149Sbostic 	ct = 0;
42533149Sbostic 	while((c = getchar()) != '\n'){
42633149Sbostic 		if(c == EOF) error("End of input\n");
42733149Sbostic 		/* some people get confused when their erase char is not ^H */
42833149Sbostic 		if(c == '\010') {
42933149Sbostic 			if(ct) ct--;
43033149Sbostic 			continue;
43133149Sbostic 		}
43233149Sbostic 		if(c != '-')
43333149Sbostic 		if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
43433149Sbostic 		if(ct < sizeof(plname)-1) plname[ct++] = c;
43533149Sbostic 	}
43633149Sbostic 	plname[ct] = 0;
43733149Sbostic 	if(ct == 0) askname();
43833149Sbostic }
43933149Sbostic 
44033149Sbostic /*VARARGS1*/
impossible(s,x1,x2)44133149Sbostic impossible(s,x1,x2)
44233149Sbostic register char *s;
44333149Sbostic {
44433149Sbostic 	pline(s,x1,x2);
44533149Sbostic 	pline("Program in disorder - perhaps you'd better Quit.");
44633149Sbostic }
44733149Sbostic 
44833149Sbostic #ifdef CHDIR
449*47699Sbostic static void
chdirx(dir,wr)45033149Sbostic chdirx(dir, wr)
45133149Sbostic char *dir;
45233149Sbostic boolean wr;
45333149Sbostic {
45433149Sbostic 
45533149Sbostic #ifdef SECURE
45633149Sbostic 	if(dir					/* User specified directory? */
45733149Sbostic #ifdef HACKDIR
45833149Sbostic 	       && strcmp(dir, HACKDIR)		/* and not the default? */
459*47699Sbostic #endif
46033149Sbostic 		) {
46133149Sbostic 		(void) setuid(getuid());		/* Ron Wessels */
46233149Sbostic 		(void) setgid(getgid());
46333149Sbostic 	}
464*47699Sbostic #endif
46533149Sbostic 
46633149Sbostic #ifdef HACKDIR
46733149Sbostic 	if(dir == NULL)
46833149Sbostic 		dir = HACKDIR;
469*47699Sbostic #endif
47033149Sbostic 
47133149Sbostic 	if(dir && chdir(dir) < 0) {
47233149Sbostic 		perror(dir);
47333149Sbostic 		error("Cannot chdir to %s.", dir);
47433149Sbostic 	}
47533149Sbostic 
47633149Sbostic 	/* warn the player if he cannot write the record file */
47733149Sbostic 	/* perhaps we should also test whether . is writable */
47833149Sbostic 	/* unfortunately the access systemcall is worthless */
47933149Sbostic 	if(wr) {
48033149Sbostic 	    register fd;
48133149Sbostic 
48233149Sbostic 	    if(dir == NULL)
48333149Sbostic 		dir = ".";
48433149Sbostic 	    if((fd = open(RECORD, 2)) < 0) {
48533149Sbostic 		printf("Warning: cannot write %s/%s", dir, RECORD);
48633149Sbostic 		getret();
48733149Sbostic 	    } else
48833149Sbostic 		(void) close(fd);
48933149Sbostic 	}
49033149Sbostic }
491*47699Sbostic #endif
49233149Sbostic 
stop_occupation()49333149Sbostic stop_occupation()
49433149Sbostic {
49533149Sbostic 	if(occupation) {
49633149Sbostic 		pline("You stop %s.", occtxt);
49733149Sbostic 		occupation = 0;
49833149Sbostic 	}
49933149Sbostic }
500