Source:NetHack 2.3e/pcmain.c

From NetHackWiki
Jump to navigation Jump to search

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