Source:NetHack 1.4f/unixmain.c

From NetHackWiki
(Redirected from NetHack 1.4f/unixmain.c)
Jump to navigation Jump to search

Below is the full text to unixmain.c from the source code of NetHack 1.4f. To link to a particular line, write [[NetHack 1.4f/unixmain.c#line123]], for example.

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

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

1.    /*	SCCS Id: @(#)unixmain.c	1.4	87/08/08
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* main.c - (Unix) version 1.0.3 */
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.  				printf("Sorry.\n");
132.  			break;
133.  #endif
134.  #ifdef NEWS
135.  		case 'n':
136.  			flags.nonews = TRUE;
137.  			break;
138.  #endif
139.  		case 'u':
140.  			if(argv[0][2])
141.  			  (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
142.  			else if(argc > 1) {
143.  			  argc--;
144.  			  argv++;
145.  			  (void) strncpy(plname, argv[0], sizeof(plname)-1);
146.  			} else
147.  				printf("Player name expected after -u\n");
148.  			break;
149.  		default:
150.  			/* allow -T for Tourist, etc. */
151.  			(void) strncpy(pl_character, argv[0]+1,
152.  				sizeof(pl_character)-1);
153.  
154.  			/* printf("Unknown option: %s\n", *argv); */
155.  		}
156.  	}
157.  
158.  	if(argc > 1)
159.  		locknum = atoi(argv[1]);
160.  #ifdef MAX_NR_OF_PLAYERS
161.  	if(!locknum || locknum > MAX_NR_OF_PLAYERS)
162.  		locknum = MAX_NR_OF_PLAYERS;
163.  #endif
164.  #ifdef DEF_PAGER
165.  	if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER")))
166.  		catmore = DEF_PAGER;
167.  #endif
168.  #ifdef MAIL
169.  	getmailstatus();
170.  #endif
171.  #ifdef WIZARD
172.  	if(wizard) (void) strcpy(plname, "wizard"); else
173.  #endif
174.  	if(!*plname || !strncmp(plname, "player", 4)
175.  		    || !strncmp(plname, "games", 4))
176.  		askname();
177.  	plnamesuffix();		/* strip suffix from name; calls askname() */
178.  				/* again if suffix was whole name */
179.  				/* accepts any suffix */
180.  #ifdef WIZARD
181.  	if(!wizard) {
182.  #endif
183.  		/*
184.  		 * check for multiple games under the same name
185.  		 * (if !locknum) or check max nr of players (otherwise)
186.  		 */
187.  		(void) signal(SIGQUIT,SIG_IGN);
188.  		(void) signal(SIGINT,SIG_IGN);
189.  		if(!locknum)
190.  			(void) strcpy(lock,plname);
191.  		getlock();	/* sets lock if locknum != 0 */
192.  #ifdef WIZARD
193.  	} else {
194.  		register char *sfoo;
195.  		extern char genocided[], fut_geno[];
196.  		(void) strcpy(lock,plname);
197.  		if(sfoo = getenv("MAGIC"))
198.  			while(*sfoo) {
199.  				switch(*sfoo++) {
200.  				case 'n': (void) srand(*sfoo++);
201.  					break;
202.  				}
203.  			}
204.  		if(sfoo = getenv("GENOCIDED")){
205.  			if(*sfoo == '!'){
206.  				extern struct permonst mons[CMNUM+2];
207.  				register struct permonst *pm = mons;
208.  				register char *gp = genocided;
209.  
210.  				while(pm < mons+CMNUM+2){
211.  					if(!index(sfoo, pm->mlet))
212.  						*gp++ = pm->mlet;
213.  					pm++;
214.  				}
215.  				*gp = 0;
216.  			} else
217.  				(void) strcpy(genocided, sfoo);
218.  			(void) strcpy(fut_geno, genocided);
219.  		}
220.  	}
221.  #endif /* WIZARD /**/
222.  	setftty();
223.  	(void) sprintf(SAVEF, "save/%d%s", getuid(), plname);
224.  	regularize(SAVEF+5);		/* avoid . or / in name */
225.  	if((fd = open(SAVEF,0)) >= 0 &&
226.  	   (uptodate(fd) || unlink(SAVEF) == 666)) {
227.  		(void) signal(SIGINT,done1);
228.  		pline("Restoring old save file...");
229.  		(void) fflush(stdout);
230.  		if(!dorecover(fd))
231.  			goto not_recovered;
232.  		pline("Hello %s, welcome to %s!", plname, gamename);
233.  		flags.move = 0;
234.  	} else {
235.  not_recovered:
236.  		newgame();
237.  		/* give welcome message before pickup messages */
238.  		pline("Hello %s, welcome to %s!", plname, gamename);
239.  
240.  		pickup(1);
241.  		read_engr_at(u.ux,u.uy);
242.  		flags.move = 1;
243.  	}
244.  
245.  	flags.moonphase = phase_of_the_moon();
246.  	if(flags.moonphase == FULL_MOON) {
247.  		pline("You are lucky! Full moon tonight.");
248.  		if(!u.uluck) u.uluck++;
249.  	} else if(flags.moonphase == NEW_MOON) {
250.  		pline("Be careful! New moon tonight.");
251.  	}
252.  
253.  	initrack();
254.  
255.  	for(;;) {
256.  		if(flags.move) {	/* actual time passed */
257.  
258.  			settrack();
259.  
260.  			if(moves%2 == 0 ||
261.  			  (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
262.  				extern struct monst *makemon();
263.  				movemon();
264.  				if(!rn2(70))
265.  				    (void) makemon((struct permonst *)0, 0, 0);
266.  			}
267.  			if(Glib) glibr();
268.  			timeout();
269.  			++moves;
270.  #ifdef PRAYERS
271.  			if (u.ublesscnt)  u.ublesscnt--;
272.  #endif
273.  			if(flags.time) flags.botl = 1;
274.  #ifdef KAA
275.  			if(u.mtimedone)
276.  			    if(u.mh < 1) rehumanize();
277.  			else
278.  #endif
279.  			    if(u.uhp < 1) {
280.  				pline("You die...");
281.  				done("died");
282.  			    }
283.  			if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
284.  			    wailmsg = moves;
285.  #ifdef KAA
286.  			    if(index("WEV", pl_character[0])) {
287.  				if (u.uhp == 1)
288.  				pline("%s is about to die.", pl_character);
289.  				else
290.  				pline("%s, your life force is running out.",
291.  					pl_character);
292.  			    } else {
293.  #endif
294.  				if(u.uhp == 1)
295.  				pline("You hear the wailing of the Banshee...");
296.  				else
297.  				pline("You hear the howling of the CwnAnnwn...");
298.  #ifdef KAA
299.  			    }
300.  #endif
301.  			}
302.  #ifdef KAA
303.  			if (u.mtimedone) {
304.  			    if (u.mh < u.mhmax) {
305.  				if (Regeneration || !(moves%20)) {
306.  					flags.botl = 1;
307.  					u.mh++;
308.  				}
309.  			    }
310.  			}
311.  #endif
312.  			if(u.uhp < u.uhpmax) {
313.  				if(u.ulevel > 9) {
314.  					if(HRegeneration || !(moves%3)) {
315.  					    flags.botl = 1;
316.  					    u.uhp += rnd((int) u.ulevel-9);
317.  					    if(u.uhp > u.uhpmax)
318.  						u.uhp = u.uhpmax;
319.  					}
320.  				} else if(HRegeneration ||
321.  					(!(moves%(22-u.ulevel*2)))) {
322.  					flags.botl = 1;
323.  					u.uhp++;
324.  				}
325.  			}
326.  #ifdef SPELLS
327.  			if ((u.uen<u.uenmax) && (!(moves%(21-u.ulevel/2)))) {
328.  				u.uen += rn2(u.ulevel/4 + 1) + 1;
329.  				if (u.uen > u.uenmax)  u.uen = u.uenmax;
330.  				flags.botl = 1;
331.  			}
332.  #endif
333.  			if(Teleportation && !rn2(85)) tele();
334.  			if(Searching && multi >= 0) (void) dosearch();
335.  			gethungry();
336.  			invault();
337.  			amulet();
338.  #ifdef HARD
339.  			if (!rn2(4)) u_wipe_engr(rnd(3));
340.  			if (u.udemigod) {
341.  
342.  				u.udg_cnt--;
343.  				if(u.udg_cnt <= 0) {
344.  
345.  					intervene();
346.  					u.udg_cnt = rn1(200, 50);
347.  				}
348.  			}
349.  #endif
350.  		}
351.  		if(multi < 0) {
352.  			if(!++multi){
353.  				pline(nomovemsg ? nomovemsg :
354.  					"You can move again.");
355.  				nomovemsg = 0;
356.  				if(afternmv) (*afternmv)();
357.  				afternmv = 0;
358.  			}
359.  		}
360.  
361.  		find_ac();
362.  #ifndef QUEST
363.  		if(!flags.mv || Blind)
364.  #endif
365.  		{
366.  			seeobjs();
367.  			seemons();
368.  			nscr();
369.  		}
370.  #ifdef DGK
371.  		if(flags.time) flags.botl = 1;
372.  #endif
373.  		if(flags.botl || flags.botlx) bot();
374.  
375.  		flags.move = 1;
376.  
377.  		if(multi >= 0 && occupation) {
378.  
379.  			if (monster_nearby())
380.  				stop_occupation();
381.  			else if ((*occupation)() == 0)
382.  				occupation = 0;
383.  			continue;
384.  		}
385.  
386.  		if(multi > 0) {
387.  #ifdef QUEST
388.  			if(flags.run >= 4) finddir();
389.  #endif
390.  			lookaround();
391.  			if(!multi) {	/* lookaround may clear multi */
392.  				flags.move = 0;
393.  				continue;
394.  			}
395.  			if(flags.mv) {
396.  				if(multi < COLNO && !--multi)
397.  					flags.mv = flags.run = 0;
398.  				domove();
399.  			} else {
400.  				--multi;
401.  				rhack(save_cm);
402.  			}
403.  		} else if(multi == 0) {
404.  #ifdef MAIL
405.  			ckmailstatus();
406.  #endif
407.  			rhack((char *) 0);
408.  		}
409.  		if(multi && multi%7 == 0)
410.  			(void) fflush(stdout);
411.  	}
412.  }
413.  
414.  glo(foo)
415.  register foo;
416.  {
417.  	/* construct the string  xlock.n  */
418.  	register char *tf;
419.  
420.  	tf = lock;
421.  	while(*tf && *tf != '.') tf++;
422.  	(void) sprintf(tf, ".%d", foo);
423.  }
424.  
425.  /*
426.   * plname is filled either by an option (-u Player  or  -uPlayer) or
427.   * explicitly (-w implies wizard) or by askname.
428.   * It may still contain a suffix denoting pl_character.
429.   */
430.  askname(){
431.  register int c,ct;
432.  	printf("\nWho are you? ");
433.  	(void) fflush(stdout);
434.  	ct = 0;
435.  	while((c = getchar()) != '\n'){
436.  		if(c == EOF) error("End of input\n");
437.  		/* some people get confused when their erase char is not ^H */
438.  		if(c == '\010') {
439.  			if(ct) ct--;
440.  			continue;
441.  		}
442.  		if(c != '-')
443.  		if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
444.  		if(ct < sizeof(plname)-1) plname[ct++] = c;
445.  	}
446.  	plname[ct] = 0;
447.  	if(ct == 0) askname();
448.  }
449.  
450.  /*VARARGS1*/
451.  impossible(s,x1,x2)
452.  register char *s;
453.  {
454.  	pline(s,x1,x2);
455.  	pline("Program in disorder - perhaps you'd better Quit.");
456.  }
457.  
458.  #ifdef CHDIR
459.  static
460.  chdirx(dir, wr)
461.  char *dir;
462.  boolean wr;
463.  {
464.  
465.  # ifdef SECURE
466.  	if(dir					/* User specified directory? */
467.  #  ifdef HACKDIR
468.  	       && strcmp(dir, HACKDIR)		/* and not the default? */
469.  #  endif
470.  		) {
471.  		(void) setuid(getuid());		/* Ron Wessels */
472.  		(void) setgid(getgid());
473.  	}
474.  # endif
475.  
476.  # ifdef HACKDIR
477.  	if(dir == NULL)
478.  		dir = HACKDIR;
479.  # endif
480.  
481.  	if(dir && chdir(dir) < 0) {
482.  		perror(dir);
483.  		error("Cannot chdir to %s.", dir);
484.  	}
485.  
486.  	/* warn the player if he cannot write the record file */
487.  	/* perhaps we should also test whether . is writable */
488.  	/* unfortunately the access systemcall is worthless */
489.  	if(wr) {
490.  	    register fd;
491.  
492.  	    if(dir == NULL)
493.  		dir = ".";
494.  	    if((fd = open(RECORD, 2)) < 0) {
495.  		printf("Warning: cannot write %s/%s", dir, RECORD);
496.  		getret();
497.  	    } else
498.  		(void) close(fd);
499.  	}
500.  }
501.  #endif /* CHDIR /**/
502.  
503.  stop_occupation()
504.  {
505.  	if(occupation) {
506.  		pline("You stop %s.", occtxt);
507.  		occupation = 0;
508.  #ifdef REDO
509.  		multi = 0;
510.  		pushch(0);		
511.  #endif
512.  	}
513.  }
514.  
515.  whoami() {
516.  	/*
517.  	 * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
518.  	 *			2. Use $USER or $LOGNAME	(if 1. fails)
519.  	 *			3. Use getlogin()		(if 2. fails)
520.  	 * The resulting name is overridden by command line options.
521.  	 * If everything fails, or if the resulting name is some generic
522.  	 * account like "games", "play", "player", "hack" then eventually
523.  	 * we'll ask him.
524.  	 * Note that we trust him here; it is possible to play under
525.  	 * somebody else's name.
526.  	 */
527.  	register char *s;
528.  
529.  #ifndef DGKMOD
530.  	initoptions();
531.  #endif
532.  	if(!*plname && (s = getenv("USER")))
533.  		(void) strncpy(plname, s, sizeof(plname)-1);
534.  	if(!*plname && (s = getenv("LOGNAME")))
535.  		(void) strncpy(plname, s, sizeof(plname)-1);
536.  	if(!*plname && (s = getlogin()))
537.  		(void) strncpy(plname, s, sizeof(plname)-1);
538.  }
539.  
540.  newgame() {
541.  	fobj = fcobj = invent = 0;
542.  	fmon = fallen_down = 0;
543.  	ftrap = 0;
544.  	fgold = 0;
545.  	flags.ident = 1;
546.  	init_objects();
547.  	u_init();
548.  
549.  	(void) signal(SIGINT,done1);
550.  	mklev();
551.  	u.ux = xupstair;
552.  	u.uy = yupstair;
553.  	(void) inshop();
554.  	setsee();
555.  	flags.botlx = 1;
556.  	{
557.  		register struct monst *mtmp;
558.  
559.  		/* Move the monster from under you or else
560.  		 * makedog() will fail when it calls makemon().
561.  		 * 			- ucsfcgl!kneller
562.  		 */
563.  		if (mtmp = m_at(u.ux, u.uy))  mnexto(mtmp);
564.  	}
565.  	(void) makedog();
566.  	seemons();
567.  #ifdef NEWS
568.  	if(flags.nonews || !readnews())
569.  		/* after reading news we did docrt() already */
570.  #endif
571.  		docrt();
572.  	return(0);
573.  }
574.  
575.  #ifdef GENIX
576.  jhndist(x1,y1,x2,y2)
577.  {
578.  	int x,y;
579.  	x=x1-x2;
580.  	y=y1-y2;
581.  	return (x*x + y*y);
582.  }
583.  #endif