Source:NetHack 1.3d/unixmain.c

From NetHackWiki
Revision as of 00:36, 4 March 2008 by Kernigh bot (talk | contribs) (NetHack 1.3d/unixmain.c moved to Source:NetHack 1.3d/unixmain.c: Robot: moved page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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