Source:NetHack 1.3d/pcmain.c

From NetHackWiki
Jump to: navigation, search

Below is the full text to pcmain.c from the source code of NetHack 1.3d. To link to a particular line, write [[NetHack 1.3d/pcmain.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: @(#)pcmain.c	1.3	87/07/14
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* main.c - (PC) version 1.0.3 */
4.    
5.    #include <stdio.h>
6.    #include <signal.h>
7.    #include "hack.h"
8.    
9.    #ifdef QUEST
10.   #define	gamename	"PC NetQuest"
11.   #else
12.   #define	gamename	"PC NetHack"
13.   #endif
14.   
15.   char orgdir[PATHLEN], *getcwd();
16.   
17.   extern struct permonst mons[CMNUM+2];
18.   extern char genocided[], fut_geno[];
19.   extern char *getlogin(), *getenv();
20.   extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
21.   
22.   int (*afternmv)(), done1(), (*occupation)();
23.   
24.   char SAVEF[FILENAME];
25.   char *hname = gamename;
26.   char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */
27.   int hackpid;		/* not used anymore, but kept in for save files */
28.   
29.   extern char *nomovemsg;
30.   extern long wailmsg;
31.   
32.   main(argc,argv)
33.   int argc;
34.   char *argv[];
35.   {
36.   	register int fd;
37.   	register char *dir;
38.   #ifdef MSDOS
39.   	static void moveloop();	/* a helper function for MSC optimizer */
40.   
41.   	/* Save current directory and make sure it gets restored when
42.   	 * the game is exited.
43.   	 */
44.   	int (*funcp)();
45.   
46.   	if (getcwd(orgdir, sizeof orgdir) == NULL) {
47.   		xputs("hack: current directory path too long\n");
48.   		_exit(1);
49.   	}
50.   	funcp = exit;	/* Kludge to get around LINT_ARGS of signal.
51.   			 * This will produce a compiler warning, but that's OK.
52.   			 */
53.   	signal(SIGINT, funcp);	/* restore original directory */
54.   #endif
55.   #ifdef DGK
56.   	initoptions();
57.   	if (!hackdir[0])
58.   		(void) strcpy(hackdir, orgdir);
59.   	dir = hackdir;
60.   #else
61.   	dir = getenv("HACKDIR");
62.   	if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
63.   		argc--;
64.   		argv++;
65.   		dir = argv[0]+2;
66.   		if(*dir == '=' || *dir == ':') dir++;
67.   		if(!*dir && argc > 1) {
68.   			argc--;
69.   			argv++;
70.   			dir = argv[0];
71.   		}
72.   		if(!*dir)
73.   		    error("Flag -d must be followed by a directory name.");
74.   	}
75.   #endif /* DGK */
76.   
77.   	/*
78.   	 * Now we know the directory containing 'record' and
79.   	 * may do a prscore().
80.   	 */
81.   	if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
82.   		chdirx(dir,0);
83.   		prscore(argc, argv);
84.   		exit(0);
85.   	}
86.   
87.   	/*
88.   	 * It seems he really wants to play.
89.   	 * Remember tty modes, to be restored on exit.
90.   	 */
91.   	gettty();
92.   	setbuf(stdout,obuf);
93.   	setrandom();
94.   	startup();
95.   	init_corpses();	/* initialize optional corpse names */
96.   	cls();
97.   	u.uhp = 1;	/* prevent RIP on early quits */
98.   	u.ux = FAR;	/* prevent nscr() */
99.   
100.  	/*
101.  	 * We cannot do chdir earlier, otherwise gethdate will fail.
102.  	 */
103.  	chdirx(dir,1);
104.  
105.  	/*
106.  	 * Process options.
107.  	 */
108.  	while(argc > 1 && argv[1][0] == '-'){
109.  		argv++;
110.  		argc--;
111.  		switch(argv[0][1]){
112.  #ifdef WIZARD
113.  		case 'D':
114.  # ifdef MSDOS
115.  			wizard = TRUE;
116.  # else
117.  			if(!strcmp(getlogin(), WIZARD))
118.  				wizard = TRUE;
119.  			else
120.  				printf("Sorry.\n");
121.  # endif
122.  			break;
123.  #endif
124.  		case 'u':
125.  			if(argv[0][2])
126.  			  (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
127.  			else if(argc > 1) {
128.  			  argc--;
129.  			  argv++;
130.  			  (void) strncpy(plname, argv[0], sizeof(plname)-1);
131.  			} else
132.  				printf("Player name expected after -u\n");
133.  			break;
134.  #ifdef DGK
135.  		/* Person does not want to use a ram disk
136.  		 */
137.  		case 'R':
138.  			ramdisk = FALSE;
139.  			break;
140.  #endif
141.  		default:
142.  			/* allow -T for Tourist, etc. */
143.  			(void) strncpy(pl_character, argv[0]+1,
144.  				sizeof(pl_character)-1);
145.  
146.  			/* printf("Unknown option: %s\n", *argv); */
147.  		}
148.  	}
149.  
150.  #ifdef DGK
151.  	set_lock_and_bones();
152.  	copybones(FROMPERM);
153.  #endif
154.  #ifdef WIZARD
155.  	if (wizard)
156.  		(void) strcpy(plname, "wizard");
157.  	else
158.  #endif
159.  	if (!*plname)
160.  		askname();
161.  	plnamesuffix();		/* strip suffix from name; calls askname() */
162.  				/* again if suffix was whole name */
163.  				/* accepts any suffix */
164.  #ifdef WIZARD
165.  	if(wizard) {
166.  		register char *sfoo;
167.  # ifndef DGK
168.  		/* lock is set in read_config_file */
169.  		(void) strcpy(lock,plname);
170.  # endif
171.  		if(sfoo = getenv("MAGIC"))
172.  			while(*sfoo) {
173.  				switch(*sfoo++) {
174.  				case 'n': (void) srand(*sfoo++);
175.  					break;
176.  				}
177.  			}
178.  		if(sfoo = getenv("GENOCIDED")){
179.  			if(*sfoo == '!'){
180.  				register struct permonst *pm = mons;
181.  				register char *gp = genocided;
182.  
183.  				while(pm < mons+CMNUM+2){
184.  					if(!index(sfoo, pm->mlet))
185.  						*gp++ = pm->mlet;
186.  					pm++;
187.  				}
188.  				*gp = 0;
189.  			} else
190.  				(void) strcpy(genocided, sfoo);
191.  			(void) strcpy(fut_geno, genocided);
192.  		}
193.  	}
194.  #endif /* WIZARD */
195.  	start_screen();
196.  #ifdef DGK
197.  	strncat(SAVEF, plname, 8);
198.  	strcat(SAVEF, ".sav");
199.  	cls();
200.  	if (saveDiskPrompt(1) && ((fd = open(SAVEF, 0)) >= 0)) {
201.  #else 
202.  	(void) sprintf(SAVEF, "save/%d%s", getuid(), plname);
203.  	regularize(SAVEF+5);		/* avoid . or / in name */
204.  	if((fd = open(SAVEF,0)) >= 0 &&
205.  	   (uptodate(fd) || unlink(SAVEF) == 666)) {
206.  #endif /* DGK */
207.  		(void) signal(SIGINT,done1);
208.  		pline("Restoring old save file...");
209.  		(void) fflush(stdout);
210.  		if(!dorecover(fd))
211.  			goto not_recovered;
212.  		pline("Hello %s, welcome to %s!", plname, hname);
213.  		flags.move = 0;
214.  	} else {
215.  not_recovered:
216.  #ifdef DGK
217.  		gameDiskPrompt();
218.  #endif
219.  		fobj = fcobj = invent = 0;
220.  		fmon = fallen_down = 0;
221.  		ftrap = 0;
222.  		fgold = 0;
223.  		flags.ident = 1;
224.  		init_objects();
225.  		u_init();
226.  
227.  		(void) signal(SIGINT,done1);
228.  		mklev();
229.  		u.ux = xupstair;
230.  		u.uy = yupstair;
231.  		(void) inshop();
232.  		setsee();
233.  		flags.botlx = 1;
234.  		/* Fix bug with dog not being made because a monster
235.  		 * was on the level 1 staircase
236.  		 */
237.  		{
238.  			struct monst *mtmp;
239.  
240.  			if (mtmp = m_at(u.ux, u.uy))
241.  				mnexto(mtmp);
242.  		}
243.  		makedog();
244.  		{ register struct monst *mtmp;
245.  		  if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp);	/* riv05!a3 */
246.  		}
247.  		seemons();
248.  		docrt();
249.  
250.  		/* give welcome message before pickup messages */
251.  		pline("Hello %s, welcome to %s!", plname, hname);
252.  
253.  		pickup(1);
254.  		if(!Blind) read_engr_at(u.ux,u.uy);
255.  		flags.move = 1;
256.  	}
257.  	flags.moonphase = phase_of_the_moon();
258.  	if(flags.moonphase == FULL_MOON) {
259.  		pline("You are lucky! Full moon tonight.");
260.  		if(!u.uluck) u.uluck++;
261.  	} else if(flags.moonphase == NEW_MOON) {
262.  		pline("Be careful! New moon tonight.");
263.  	}
264.  
265.  	initrack();
266.  	(void) signal(SIGINT, SIG_IGN);
267.  #ifdef MSDOS
268.  	/* Help for Microsoft optimizer.  Otherwise main is too large -dgk*/
269.  	moveloop();
270.  }
271.  
272.  static void
273.  moveloop()
274.  {
275.  	char ch;
276.  	int abort;
277.  #endif /* MSDOS */
278.  	for(;;) {
279.  		if(flags.move) {	/* actual time passed */
280.  
281.  			settrack();
282.  
283.  			if(moves%2 == 0 ||
284.  			  (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
285.  				extern struct monst *makemon();
286.  				movemon();
287.  				if(!rn2(70))
288.  				    (void) makemon((struct permonst *)0, 0, 0);
289.  			}
290.  			if(Glib) glibr();
291.  			timeout();
292.  			++moves;
293.  #ifdef PRAYERS
294.  			if (u.ublesscnt)  u.ublesscnt--;
295.  #endif
296.  #ifndef DGK
297.  			if(flags.time) flags.botl = 1;
298.  #endif
299.  #ifdef KAA
300.  			if(u.mtimedone)
301.  			    if(u.mh < 1) rehumanize();
302.  			else
303.  #endif
304.  			    if(u.uhp < 1) {
305.  				pline("You die...");
306.  				done("died");
307.  			    }
308.  			if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
309.  			    wailmsg = moves;
310.  #ifdef KAA
311.  				if(index("WEV", pl_character[0])) {
312.  					if (u.uhp == 1)
313.  					   pline("%s is about to die.", pl_character);
314.  					else
315.  					   pline("%s, your life force is running out.",
316.  						pl_character);
317.  				} else {
318.  #endif
319.  			    if(u.uhp == 1)
320.  			    pline("You hear the wailing of the Banshee...");
321.  			    else
322.  			    pline("You hear the howling of the CwnAnnwn...");
323.  #ifdef KAA
324.  				}
325.  #endif
326.  			}
327.  #ifdef KAA
328.  			if (u.mtimedone) {
329.  			    if (u.mh < u.mhmax) {
330.  				if (Regeneration || !(moves%20)) {
331.  					flags.botl = 1;
332.  					u.mh++;
333.  				}
334.  			    }
335.  			}
336.  #endif
337.  			if(u.uhp < u.uhpmax) {
338.  				if(u.ulevel > 9) {
339.  					if(HRegeneration || !(moves%3)) {
340.  					    flags.botl = 1;
341.  					    u.uhp += rnd((int) u.ulevel-9);
342.  					    if(u.uhp > u.uhpmax)
343.  						u.uhp = u.uhpmax;
344.  					}
345.  				} else if(HRegeneration ||
346.  					(!(moves%(22-u.ulevel*2)))) {
347.  					flags.botl = 1;
348.  					u.uhp++;
349.  				}
350.  			}
351.  #ifdef SPELLS
352.  			if ((u.uen<u.uenmax) && (!(moves%(21-u.ulevel/2)))) {
353.  				u.uen += rn2(u.ulevel/4 + 1) + 1;
354.  				if (u.uen > u.uenmax)  u.uen = u.uenmax;
355.  				flags.botl = 1;
356.  			}
357.  #endif
358.  			if(Teleportation && !rn2(85)) tele();
359.  			if(Searching && multi >= 0) (void) dosearch();
360.  			gethungry();
361.  			invault();
362.  			amulet();
363.  #ifdef HARD
364.  			if (u.udemigod) {
365.  
366.  				u.udg_cnt--;
367.  				if(u.udg_cnt <= 0) {
368.  
369.  					intervene();
370.  					u.udg_cnt = rn1(200, 50);
371.  				}
372.  			}
373.  #endif
374.  		}
375.  		if(multi < 0) {
376.  			if(!++multi){
377.  				pline(nomovemsg ? nomovemsg :
378.  					"You can move again.");
379.  				nomovemsg = 0;
380.  				if(afternmv) (*afternmv)();
381.  				afternmv = 0;
382.  			}
383.  		}
384.  
385.  		find_ac();
386.  #ifndef QUEST
387.  		if(!flags.mv || Blind)
388.  #endif
389.  		{
390.  			seeobjs();
391.  			seemons();
392.  			nscr();
393.  		}
394.  #ifdef DGK
395.  		if(flags.time) flags.botl = 1;
396.  #endif
397.  		if(flags.botl || flags.botlx) bot();
398.  
399.  		flags.move = 1;
400.  
401.  		if(multi >= 0 && occupation) {
402.  #ifdef DGK
403.  			abort = 0;
404.  			if (kbhit()) {
405.  				if ((ch = getchar()) == ABORT)
406.  					abort++;
407.  				else
408.  					pushch(ch);
409.  			}
410.  			if (abort || monster_nearby())
411.  				stop_occupation();
412.  			else if ((*occupation)() == 0)
413.  				occupation = 0;
414.  			if (!(++occtime % 7))
415.  				(void) fflush(stdout);
416.  #else
417.  			if (monster_nearby())
418.  				stop_occupation();
419.  			else if ((*occupation)() == 0)
420.  				occupation = 0;
421.  #endif
422.  			continue;
423.  		}
424.  
425.  		if(multi > 0) {
426.  #ifdef QUEST
427.  			if(flags.run >= 4) finddir();
428.  #endif
429.  			lookaround();
430.  			if(!multi) {	/* lookaround may clear multi */
431.  				flags.move = 0;
432.  				continue;
433.  			}
434.  			if(flags.mv) {
435.  				if(multi < COLNO && !--multi)
436.  					flags.mv = flags.run = 0;
437.  				domove();
438.  			} else {
439.  				--multi;
440.  				rhack(save_cm);
441.  			}
442.  		} else if(multi == 0) {
443.  			rhack((char *) 0);
444.  		}
445.  		if(multi && multi%7 == 0)
446.  			(void) fflush(stdout);
447.  	}
448.  }
449.  
450.  #ifndef DGK
451.  /* This function is unnecessary and incompatible with the #define
452.   * of glo(x) in config.h -dgk
453.   */
454.  glo(foo)
455.  register foo;
456.  {
457.  	/* construct the string  xlock.n  */
458.  	register char *tf;
459.  
460.  	tf = lock;
461.  	while(*tf && *tf != '.') tf++;
462.  	(void) sprintf(tf, ".%d", foo);
463.  }
464.  #endif
465.  
466.  /*
467.   * plname is filled either by an option (-u Player  or  -uPlayer) or
468.   * explicitly (-w implies wizard) or by askname.
469.   * It may still contain a suffix denoting pl_character.
470.   */
471.  askname(){
472.  register int c,ct;
473.  	printf("\nWho are you? ");
474.  	(void) fflush(stdout);
475.  	ct = 0;
476.  	while((c = getchar()) != '\n'){
477.  #ifdef MSDOS
478.  		msmsg("%c", c);
479.  #endif
480.  		if(c == EOF) error("End of input\n");
481.  		/* some people get confused when their erase char is not ^H */
482.  		if(c == '\010') {
483.  			if(ct) ct--;
484.  			continue;
485.  		}
486.  		if(c != '-')
487.  		if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
488.  		if(ct < sizeof(plname)-1) plname[ct++] = c;
489.  	}
490.  	plname[ct] = 0;
491.  	if(ct == 0) askname();
492.  }
493.  
494.  /*VARARGS1*/
495.  impossible(s,x1,x2)
496.  register char *s;
497.  {
498.  	pline(s,x1,x2);
499.  	pline("Program in disorder - perhaps you'd better Quit.");
500.  }
501.  
502.  #ifdef CHDIR
503.  chdirx(dir, wr)
504.  char *dir;
505.  boolean wr;
506.  {
507.  
508.  	if(dir && chdir(dir) < 0) {
509.  		error("Cannot chdir to %s.", dir);
510.  	}
511.  
512.  #ifdef DGK
513.  	/* Change the default drive as well.
514.  	 */
515.  	chdrive(dir);
516.  #endif
517.  
518.  	/* warn the player if he cannot write the record file */
519.  	/* perhaps we should also test whether . is writable */
520.  	/* unfortunately the access systemcall is worthless */
521.  	if(wr) {
522.  	    register fd;
523.  
524.  	    if(dir == NULL)
525.  		dir = ".";
526.  	    if((fd = open(RECORD, 2)) < 0) {
527.  #ifdef DGK
528.  		char tmp[PATHLEN];
529.  
530.  		strcpy(tmp, dir);
531.  		append_slash(tmp);
532.  		msmsg("Warning: cannot write %s%s\n", tmp, RECORD);
533.  		getreturn("to continue");
534.  #else
535.  		printf("Warning: cannot write %s/%s", dir, RECORD);
536.  		getret();
537.  #endif
538.  	    } else
539.  		(void) close(fd);
540.  	}
541.  }
542.  #endif /* CHDIR /**/
543.  
544.  stop_occupation()
545.  {
546.  	if(occupation) {
547.  		pline("You stop %s.", occtxt);
548.  		occupation = 0;
549.  #ifdef DGK
550.  		multi = 0;
551.  		pushch(0);		
552.  #endif
553.  	}
554.  }