Source:NetHack 2.3e/unixmain.c

From NetHackWiki
Jump to navigation Jump to search

Below is the full text to unixmain.c from the source code of NetHack 2.3e.

Warning! This is the source code from an old release. For newer releases, see Source code

Screenshots and source code from Hack are used under the CWI license.

1.    /*	SCCS Id: @(#)unixmain.c	2.3	88/01/21
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* main.c - (Unix) version */
4.    
5.    #include <stdio.h>
6.    #include <signal.h>
7.    #include "hack.h"
8.    
9.    #ifdef QUEST
10.   #define	gamename	"NetQuest"
11.   #else
12.   #define	gamename	"NetHack"
13.   #endif
14.   
15.   extern char *getlogin(), *getenv();
16.   extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
17.   
18.   int (*afternmv)();
19.   int (*occupation)();
20.   
21.   int done1();
22.   int hangup();
23.   
24.   int hackpid;				/* current pid */
25.   int locknum;				/* max num of players */
26.   #ifdef DEF_PAGER
27.   char *catmore;				/* default pager */
28.   #endif
29.   char SAVEF[PL_NSIZ + 11] = "save/";	/* save/99999player */
30.   char *hname;		/* name of the game (argv[0] of call) */
31.   char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */
32.   
33.   extern char *nomovemsg;
34.   extern long wailmsg;
35.   
36.   main(argc,argv)
37.   int argc;
38.   char *argv[];
39.   {
40.   	register int fd;
41.   #ifdef CHDIR
42.   	register char *dir;
43.   #endif
44.   
45.   	hname = argv[0];
46.   	hackpid = getpid();
47.   
48.   #ifdef CHDIR			/* otherwise no chdir() */
49.   	/*
50.   	 * See if we must change directory to the playground.
51.   	 * (Perhaps hack runs suid and playground is inaccessible
52.   	 *  for the player.)
53.   	 * The environment variable HACKDIR is overridden by a
54.   	 *  -d command line option (must be the first option given)
55.   	 */
56.   
57.   	dir = getenv("HACKDIR");
58.   	if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
59.   		argc--;
60.   		argv++;
61.   		dir = argv[0]+2;
62.   		if(*dir == '=' || *dir == ':') dir++;
63.   		if(!*dir && argc > 1) {
64.   			argc--;
65.   			argv++;
66.   			dir = argv[0];
67.   		}
68.   		if(!*dir)
69.   		    error("Flag -d must be followed by a directory name.");
70.   	}
71.   #endif /* CHDIR /**/
72.   #ifdef GRAPHICS
73.   	/* Set the default values of the presentation characters */
74.   	memcpy((char *) &showsyms, (char *) &defsyms, sizeof(struct symbols));
75.   #endif
76.   #ifdef HACKOPTIONS
77.   	initoptions();
78.   #endif
79.   	whoami();
80.   	/*
81.   	 * Now we know the directory containing 'record' and
82.   	 * may do a prscore().
83.   	 */
84.   	if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
85.   #ifdef CHDIR
86.   		chdirx(dir,0);
87.   #endif
88.   		prscore(argc, argv);
89.   		exit(0);
90.   	}
91.   
92.   	/*
93.   	 * It seems he really wants to play.
94.   	 * Remember tty modes, to be restored on exit.
95.   	 */
96.   	gettty();
97.   	setbuf(stdout,obuf);
98.   	setrandom();
99.   	startup();
100.  	init_corpses();	/* initialize optional corpse names */
101.  	cls();
102.  	u.uhp = 1;	/* prevent RIP on early quits */
103.  	u.ux = FAR;	/* prevent nscr() */
104.  	(void) signal(SIGHUP, hangup);
105.  
106.  	/*
107.  	 * Find the creation date of this game,
108.  	 * so as to avoid restoring outdated savefiles.
109.  	 */
110.  	gethdate(hname);
111.  
112.  	/*
113.  	 * We cannot do chdir earlier, otherwise gethdate will fail.
114.  	 */
115.  #ifdef CHDIR
116.  	chdirx(dir,1);
117.  #endif
118.  
119.  	/*
120.  	 * Process options.
121.  	 */
122.  	while(argc > 1 && argv[1][0] == '-'){
123.  		argv++;
124.  		argc--;
125.  		switch(argv[0][1]){
126.  #ifdef WIZARD
127.  		case 'D':
128.  			if(!strcmp(getlogin(), WIZARD))
129.  				wizard = TRUE;
130.  			else {
131.  				settty("Sorry, you can't operate in debug mode.\n");
132.  				clearlocks();
133.  				exit(0);
134.  			}
135.  			break;
136.  #endif
137.  #ifdef NEWS
138.  		case 'n':
139.  			flags.nonews = TRUE;
140.  			break;
141.  #endif
142.  		case 'u':
143.  			if(argv[0][2])
144.  			  (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
145.  			else if(argc > 1) {
146.  			  argc--;
147.  			  argv++;
148.  			  (void) strncpy(plname, argv[0], sizeof(plname)-1);
149.  			} else
150.  				printf("Player name expected after -u\n");
151.  			break;
152.  		default:
153.  			/* allow -T for Tourist, etc. */
154.  			(void) strncpy(pl_character, argv[0]+1,
155.  				sizeof(pl_character)-1);
156.  
157.  			/* printf("Unknown option: %s\n", *argv); */
158.  		}
159.  	}
160.  
161.  	if(argc > 1)
162.  		locknum = atoi(argv[1]);
163.  #ifdef MAX_NR_OF_PLAYERS
164.  	if(!locknum || locknum > MAX_NR_OF_PLAYERS)
165.  		locknum = MAX_NR_OF_PLAYERS;
166.  #endif
167.  #ifdef DEF_PAGER
168.  	if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER")))
169.  		catmore = DEF_PAGER;
170.  #endif
171.  #ifdef MAIL
172.  	getmailstatus();
173.  #endif
174.  #ifdef WIZARD
175.  	if(wizard) (void) strcpy(plname, "wizard"); else
176.  #endif
177.  	if(!*plname || !strncmp(plname, "player", 4)
178.  		    || !strncmp(plname, "games", 4))
179.  		askname();
180.  	plnamesuffix();		/* strip suffix from name; calls askname() */
181.  				/* again if suffix was whole name */
182.  				/* accepts any suffix */
183.  #ifdef WIZARD
184.  	if(!wizard) {
185.  #endif
186.  		/*
187.  		 * check for multiple games under the same name
188.  		 * (if !locknum) or check max nr of players (otherwise)
189.  		 */
190.  		(void) signal(SIGQUIT,SIG_IGN);
191.  		(void) signal(SIGINT,SIG_IGN);
192.  		if(!locknum)
193.  			(void) strcpy(lock,plname);
194.  		getlock();	/* sets lock if locknum != 0 */
195.  #ifdef WIZARD
196.  	} else {
197.  		register char *sfoo;
198.  		extern char genocided[], fut_geno[];
199.  		(void) strcpy(lock,plname);
200.  		if(sfoo = getenv("MAGIC"))
201.  			while(*sfoo) {
202.  				switch(*sfoo++) {
203.  				case 'n': (void) srand(*sfoo++);
204.  					break;
205.  				}
206.  			}
207.  		if(sfoo = getenv("GENOCIDED")){
208.  			if(*sfoo == '!'){
209.  				extern struct permonst mons[CMNUM+2];
210.  				register struct permonst *pm = mons;
211.  				register char *gp = genocided;
212.  
213.  				while(pm < mons+CMNUM+2){
214.  					if(!index(sfoo, pm->mlet))
215.  						*gp++ = pm->mlet;
216.  					pm++;
217.  				}
218.  				*gp = 0;
219.  			} else
220.  				(void) strcpy(genocided, sfoo);
221.  			(void) strcpy(fut_geno, genocided);
222.  		}
223.  	}
224.  #endif /* WIZARD /**/
225.  	setftty();
226.  	(void) sprintf(SAVEF, "save/%d%s", getuid(), plname);
227.  	regularize(SAVEF+5);		/* avoid . or / in name */
228.  	if((fd = open(SAVEF,0)) >= 0 &&
229.  	   (uptodate(fd) || unlink(SAVEF) == 666)) {
230.  		(void) signal(SIGINT,done1);
231.  		pline("Restoring old save file...");
232.  		(void) fflush(stdout);
233.  		if(!dorecover(fd))
234.  			goto not_recovered;
235.  		pline("Hello %s%s, welcome to %s!", 
236.  			(Badged) ? "Officer " : "", plname, gamename);
237.  		flags.move = 0;
238.  	} else {
239.  not_recovered:
240.  		newgame();
241.  		/* give welcome message before pickup messages */
242.  		pline("Hello %s, welcome to %s!", plname, gamename);
243.  #ifdef WIZARD
244.  		if (wizard && dlevel == 1)
245.  # ifdef STOOGES
246.  pline ("The wiz is at %d, the medusa is at %d, and the stooges are at %d",
247.  			u.wiz_level, u.medusa_level, u.stooge_level);
248.  # else
249.  	            pline ("The wiz is at %d, and the medusa at %d",
250.  			   u.wiz_level, u.medusa_level);
251.  # endif
252.  #endif
253.  		pickup(1);
254.  		read_engr_at(u.ux,u.uy);
255.  		flags.move = 1;
256.  	}
257.  
258.  	flags.moonphase = phase_of_the_moon();
259.  	if(flags.moonphase == FULL_MOON) {
260.  		pline("You are lucky! Full moon tonight.");
261.  		if(!u.uluck) change_luck(1);
262.  	} else if(flags.moonphase == NEW_MOON) {
263.  		pline("Be careful! New moon tonight.");
264.  	}
265.  
266.  	initrack();
267.  
268.  	for(;;) {
269.  		if(flags.move) {	/* actual time passed */
270.  
271.  			settrack();
272.  
273.  			if(moves%2 == 0 ||
274.  			  (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
275.  				extern struct monst *makemon();
276.  				movemon();
277.  #ifdef HARD
278.  				if(!rn2(u.udemigod?25:(dlevel>30)?50:70))
279.  #else
280.  				if(!rn2(70))
281.  #endif
282.  				    (void) makemon((struct permonst *)0, 0, 0);
283.  			}
284.  			if(Glib) glibr();
285.  			timeout();
286.  			++moves;
287.  #ifdef PRAYERS
288.  			if (u.ublesscnt)  u.ublesscnt--;
289.  #endif
290.  			if(flags.time) flags.botl = 1;
291.  #ifdef KAA
292.  			if(u.mtimedone)
293.  			    if(u.mh < 1) rehumanize();
294.  			else
295.  #endif
296.  			    if(u.uhp < 1) {
297.  				pline("You die...");
298.  				done("died");
299.  			    }
300.  			if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
301.  			    wailmsg = moves;
302.  #ifdef KAA
303.  			    if(index("WEV", pl_character[0])) {
304.  				if (u.uhp == 1)
305.  				pline("%s is about to die.", pl_character);
306.  				else
307.  				pline("%s, your life force is running out.",
308.  					pl_character);
309.  			    } else {
310.  #endif
311.  				if(u.uhp == 1)
312.  				pline("You hear the wailing of the Banshee...");
313.  				else
314.  				pline("You hear the howling of the CwnAnnwn...");
315.  #ifdef KAA
316.  			    }
317.  #endif
318.  			}
319.  #ifdef KAA
320.  			if (u.mtimedone) {
321.  			    if (u.mh < u.mhmax) {
322.  				if (Regeneration || !(moves%20)) {
323.  					flags.botl = 1;
324.  					u.mh++;
325.  				}
326.  			    }
327.  			}
328.  #endif
329.  			if(u.uhp < u.uhpmax) {
330.  				if(u.ulevel > 9) {
331.  					if(HRegeneration || !(moves%3)) {
332.  					    flags.botl = 1;
333.  					    u.uhp += rnd((int) u.ulevel-9);
334.  					    if(u.uhp > u.uhpmax)
335.  						u.uhp = u.uhpmax;
336.  					}
337.  				} else if(HRegeneration ||
338.  					(!(moves%(22-u.ulevel*2)))) {
339.  					flags.botl = 1;
340.  					u.uhp++;
341.  				}
342.  			}
343.  #ifdef SPELLS
344.  			if ((u.uen<u.uenmax) && (!(moves%(21-u.ulevel/2)))) {
345.  				u.uen += rn2(u.ulevel/4 + 1) + 1;
346.  				if (u.uen > u.uenmax)  u.uen = u.uenmax;
347.  				flags.botl = 1;
348.  			}
349.  #endif
350.  			if(Teleportation && !rn2(85)) tele();
351.  #if defined(KAA) && defined(BVH)
352.  			if(Polymorph && !rn2(100)) polyself();
353.  #endif
354.  			if(Searching && multi >= 0) (void) dosearch();
355.  			gethungry();
356.  			invault();
357.  			amulet();
358.  #ifdef HARD
359.  			if (!rn2(50+(u.ulevel*3))) u_wipe_engr(rnd(3));
360.  			if (u.udemigod) {
361.  
362.  				u.udg_cnt--;
363.  				if(u.udg_cnt <= 0) {
364.  
365.  					intervene();
366.  					u.udg_cnt = rn1(200, 50);
367.  				}
368.  			}
369.  #endif
370.  		}
371.  		if(multi < 0) {
372.  			if(!++multi){
373.  				pline(nomovemsg ? nomovemsg :
374.  					"You can move again.");
375.  				nomovemsg = 0;
376.  				if(afternmv) (*afternmv)();
377.  				afternmv = 0;
378.  			}
379.  		}
380.  
381.  		find_ac();
382.  #ifndef QUEST
383.  		if(!flags.mv || Blind)
384.  #endif
385.  		{
386.  			seeobjs();
387.  			seemons();
388.  			nscr();
389.  		}
390.  #ifdef DGK
391.  		if(flags.time) flags.botl = 1;
392.  #endif
393.  		if(flags.botl || flags.botlx) bot();
394.  
395.  		flags.move = 1;
396.  
397.  		if(multi >= 0 && occupation) {
398.  
399.  			if (monster_nearby())
400.  				stop_occupation();
401.  			else if ((*occupation)() == 0)
402.  				occupation = 0;
403.  			continue;
404.  		}
405.  
406.  		if(multi > 0) {
407.  #ifdef QUEST
408.  			if(flags.run >= 4) finddir();
409.  #endif
410.  			lookaround();
411.  			if(!multi) {	/* lookaround may clear multi */
412.  				flags.move = 0;
413.  				continue;
414.  			}
415.  			if(flags.mv) {
416.  				if(multi < COLNO && !--multi)
417.  					flags.mv = flags.run = 0;
418.  				domove();
419.  			} else {
420.  				--multi;
421.  				rhack(save_cm);
422.  			}
423.  		} else if(multi == 0) {
424.  #ifdef MAIL
425.  			ckmailstatus();
426.  #endif
427.  			rhack((char *) 0);
428.  		}
429.  		if(multi && multi%7 == 0)
430.  			(void) fflush(stdout);
431.  	}
432.  }
433.  
434.  glo(foo)
435.  register foo;
436.  {
437.  	/* construct the string  xlock.n  */
438.  	register char *tf;
439.  
440.  	tf = lock;
441.  	while(*tf && *tf != '.') tf++;
442.  	(void) sprintf(tf, ".%d", foo);
443.  }
444.  
445.  /*
446.   * plname is filled either by an option (-u Player  or  -uPlayer) or
447.   * explicitly (-w implies wizard) or by askname.
448.   * It may still contain a suffix denoting pl_character.
449.   */
450.  askname(){
451.  register int c,ct;
452.  	printf("\nWho are you? ");
453.  	(void) fflush(stdout);
454.  	ct = 0;
455.  	while((c = getchar()) != '\n'){
456.  		if(c == EOF) error("End of input\n");
457.  		/* some people get confused when their erase char is not ^H */
458.  		if(c == '\010') {
459.  			if(ct) ct--;
460.  			continue;
461.  		}
462.  		if(c != '-')
463.  		if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
464.  		if(ct < sizeof(plname)-1) plname[ct++] = c;
465.  	}
466.  	plname[ct] = 0;
467.  	if(ct == 0) askname();
468.  }
469.  
470.  /*VARARGS1*/
471.  impossible(s,x1,x2)
472.  register char *s;
473.  {
474.  	pline(s,x1,x2);
475.  	pline("Program in disorder - perhaps you'd better Quit.");
476.  }
477.  
478.  #ifdef CHDIR
479.  static
480.  chdirx(dir, wr)
481.  char *dir;
482.  boolean wr;
483.  {
484.  
485.  # ifdef SECURE
486.  	if(dir					/* User specified directory? */
487.  #  ifdef HACKDIR
488.  	       && strcmp(dir, HACKDIR)		/* and not the default? */
489.  #  endif
490.  		) {
491.  		(void) setuid(getuid());		/* Ron Wessels */
492.  		(void) setgid(getgid());
493.  	}
494.  # endif
495.  
496.  # ifdef HACKDIR
497.  	if(dir == NULL)
498.  		dir = HACKDIR;
499.  # endif
500.  
501.  	if(dir && chdir(dir) < 0) {
502.  		perror(dir);
503.  		error("Cannot chdir to %s.", dir);
504.  	}
505.  
506.  	/* warn the player if he cannot write the record file */
507.  	/* perhaps we should also test whether . is writable */
508.  	/* unfortunately the access systemcall is worthless */
509.  	if(wr) {
510.  	    register fd;
511.  
512.  	    if(dir == NULL)
513.  		dir = ".";
514.  	    if((fd = open(RECORD, 2)) < 0) {
515.  		printf("Warning: cannot write %s/%s", dir, RECORD);
516.  		getret();
517.  	    } else
518.  		(void) close(fd);
519.  	}
520.  }
521.  #endif /* CHDIR /**/
522.  
523.  stop_occupation()
524.  {
525.  	extern void pushch();
526.  
527.  	if(occupation) {
528.  		pline("You stop %s.", occtxt);
529.  		occupation = 0;
530.  #ifdef REDO
531.  		multi = 0;
532.  		pushch(0);		
533.  #endif
534.  	}
535.  }
536.  
537.  whoami() {
538.  	/*
539.  	 * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
540.  	 *			2. Use $USER or $LOGNAME	(if 1. fails)
541.  	 *			3. Use getlogin()		(if 2. fails)
542.  	 * The resulting name is overridden by command line options.
543.  	 * If everything fails, or if the resulting name is some generic
544.  	 * account like "games", "play", "player", "hack" then eventually
545.  	 * we'll ask him.
546.  	 * Note that we trust him here; it is possible to play under
547.  	 * somebody else's name.
548.  	 */
549.  	register char *s;
550.  
551.  #ifndef DGKMOD
552.  	initoptions();
553.  #endif
554.  	if(!*plname && (s = getenv("USER")))
555.  		(void) strncpy(plname, s, sizeof(plname)-1);
556.  	if(!*plname && (s = getenv("LOGNAME")))
557.  		(void) strncpy(plname, s, sizeof(plname)-1);
558.  	if(!*plname && (s = getlogin()))
559.  		(void) strncpy(plname, s, sizeof(plname)-1);
560.  }
561.  
562.  newgame() {
563.  	extern struct monst *makedog();
564.  
565.  	fobj = fcobj = invent = 0;
566.  	fmon = fallen_down = 0;
567.  	ftrap = 0;
568.  	fgold = 0;
569.  	flags.ident = 1;
570.  	init_objects();
571.  	u_init();
572.  
573.  	(void) signal(SIGINT,done1);
574.  	mklev();
575.  	u.ux = xupstair;
576.  	u.uy = yupstair;
577.  	(void) inshop();
578.  	setsee();
579.  	flags.botlx = 1;
580.  	{
581.  		register struct monst *mtmp;
582.  
583.  		/* Move the monster from under you or else
584.  		 * makedog() will fail when it calls makemon().
585.  		 * 			- ucsfcgl!kneller
586.  		 */
587.  		if (mtmp = m_at(u.ux, u.uy))  mnexto(mtmp);
588.  	}
589.  	(void) makedog();
590.  	seemons();
591.  #ifdef NEWS
592.  	if(flags.nonews || !readnews())
593.  		/* after reading news we did docrt() already */
594.  #endif
595.  		docrt();
596.  	return(0);
597.  }
598.  
599.  #ifdef GENIX
600.  jhndist(x1,y1,x2,y2)
601.  {
602.  	int x,y;
603.  	x=x1-x2;
604.  	y=y1-y2;
605.  	return (x*x + y*y);
606.  }
607.  #endif