Source:NetHack 2.2a/unixmain.c

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

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

1.   /*	SCCS Id: @(#)unixmain.c	2.1	87/10/18 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* main.c - (Unix) version */ 4.    5.    #include   6.    #include   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, welcome to %s!", plname, gamename); 236. 		flags.move = 0; 237. 	} else { 238. not_recovered: 239. 		newgame; 240. 		/* give welcome message before pickup messages */ 241. 		pline("Hello %s, welcome to %s!", plname, gamename); 242.  243.  		pickup(1); 244. 		read_engr_at(u.ux,u.uy); 245. 		flags.move = 1; 246. 	}  247.   248.  	flags.moonphase = phase_of_the_moon; 249. 	if(flags.moonphase == FULL_MOON) { 250. 		pline("You are lucky! Full moon tonight."); 251. 		if(!u.uluck) u.uluck++; 252. 	} else if(flags.moonphase == NEW_MOON) { 253. 		pline("Be careful! New moon tonight."); 254. 	}  255.   256.  	initrack; 257.  258.  	for { 259. 		if(flags.move) {	/* actual time passed */ 260.  261.  			settrack; 262.  263.  			if(moves%2 == 0 ||  264.  			  (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) { 265. 				extern struct monst *makemon; 266. 				movemon; 267. #ifdef HARD 268. 				if(!rn2(u.udemigod?25:(dlevel>30)?50:70)) 269. #else 270. 				if(!rn2(70)) 271. #endif 272. 				    (void) makemon((struct permonst *)0, 0, 0); 273. 			}  274.  			if(Glib) glibr; 275. 			timeout; 276. 			++moves; 9) {  321.  					if(HRegeneration || !(moves%3)) {  322.  					    flags.botl = 1;  323.  					    u.uhp += rnd((int) u.ulevel-9);  324.  					    if(u.uhp > u.uhpmax)  325.  						u.uhp = u.uhpmax;  326.  					}  327.  				} else if(HRegeneration ||  328.  					(!(moves%(302">302.  				pline("You hear the wailing of the Banshee...");  303.  				else  304.  				pline("You hear the howling of the CwnAnnwn...");  305.  #ifdef KAA 306. 			    }  307.  #endif 308. 			}  309.  #ifdef KAA 310. 			if (u.mtimedone) { 311. 			    if (u.mh < u.mhmax) { 312. 				if (Regeneration || !(moves%20)) { 313. 					flags.botl = 1; 314. 					u.mh++; 315. 				}  316.  			    }  317.  			}  318.  #endif 319. 			if(u.uhp < u.uhpmax) { 320. 				if(u.ulevel > 9) { 321. 					if(HRegeneration || !(moves%3)) { 322. 					    flags.botl = 1; 323. 					    u.uhp += rnd((int) u.ulevel-9); 324. 					    if(u.uhp > u.uhpmax) 325. 						u.uhp = u.uhpmax; 326. 					}  327.  				} else if(HRegeneration ||  328.  					(!(moves%(22-u.ulevel*2)))) { 329. 					flags.botl = 1; 330. 					u.uhp++; 331. 				}  332.  			}  333.  #ifdef SPELLS 334. 			if ((u.uen u.uenmax)  u.uen = u.uenmax; 337. 				flags.botl = 1; 338. 			}  339.  #endif 340. 			if(Teleportation && !rn2(85)) tele; 341. #if defined(KAA) && defined(BVH) 342. 			if(Polymorph && !rn2(100)) polyself; 343. #endif 344. 			if(Searching && multi >= 0) (void) dosearch; 345. 			gethungry; 346. 			invault; 347. 			amulet; 348. #ifdef HARD 349. 			if (!rn2(50+(u.ulevel*3))) u_wipe_engr(rnd(3)); 350. 			if (u.udemigod) { 351.  352.  				u.udg_cnt--; 353. 				if(u.udg_cnt <= 0) { 354.  355.  					intervene; 356. 					u.udg_cnt = rn1(200, 50); 357. 				}  358.  			}  359.  #endif 360. 		}  361.  		if(multi < 0) { 362. 			if(!++multi){ 363. 				pline(nomovemsg ? nomovemsg :  364.  					"You can move again."); 365. 				nomovemsg = 0; 366. 				if(afternmv) (*afternmv); 367. 				afternmv = 0; 368. 			}  369.  		}  370.   371.  		find_ac; 372. #ifndef QUEST 373. 		if(!flags.mv || Blind) 374. #endif 375. 		{  376.  			seeobjs; 377. 			seemons; 378. 			nscr; 379. 		}  380.  #ifdef DGK 381. 		if(flags.time) flags.botl = 1; 382. #endif 383. 		if(flags.botl || flags.botlx) bot; 384.  385.  		flags.move = 1; 386.  387.  		if(multi >= 0 && occupation) { 388.  389.  			if (monster_nearby) 390. 				stop_occupation; 391. 			else if ((*occupation) == 0) 392. 				occupation = 0; 393. 			continue; 394. 		}  395.   396.  		if(multi > 0) { 397. #ifdef QUEST 398. 			if(flags.run >= 4) finddir; 399. #endif 400. 			lookaround; 401. 			if(!multi) {	/* lookaround may clear multi */ 402. 				flags.move = 0; 403. 				continue; 404. 			}  405.  			if(flags.mv) { 406. 				if(multi < COLNO && !--multi) 407. 					flags.mv = flags.run = 0; 408. 				domove; 409. 			} else { 410. 				--multi; 411. 				rhack(save_cm); 412. 			}  413.  		} else if(multi == 0) { 414. #ifdef MAIL 415. 			ckmailstatus; 416. #endif 417. 			rhack((char *) 0); 418. 		}  419.  		if(multi && multi%7 == 0) 420. 			(void) fflush(stdout); 421. 	}  422.  }  423.   424.  glo(foo) 425. register foo; 426. {  427.  	/* construct the string  xlock.n  */ 428. 	register char *tf; 429.  430.  	tf = lock; 431. 	while(*tf && *tf != '.') tf++; 432. 	(void) sprintf(tf, ".%d", foo); 433. }  434.   435.  /*  436.   * plname is filled either by an option (-u Player  or  -uPlayer) or  437. * explicitly (-w implies wizard) or by askname. 438.  * It may still contain a suffix denoting pl_character. 439.  */  440.  askname{ 441. register int c,ct; 442. 	printf("\nWho are you? "); 443. 	(void) fflush(stdout); 444. 	ct = 0; 445. 	while((c = getchar) != '\n'){ 446. 		if(c == EOF) error("End of input\n"); 447. 		/* some people get confused when their erase char is not ^H */ 448. 		if(c == '\010') { 449. 			if(ct) ct--; 450. 			continue; 451. 		}  452.  		if(c != '-') 453. 		if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_'; 454. 		if(ct < sizeof(plname)-1) plname[ct++] = c;  455. } 456.  	plname[ct] = 0; 457. 	if(ct == 0) askname; 458. }  459.   460.  /*VARARGS1*/ 461. impossible(s,x1,x2) 462. register char *s; 463. {  464.  	pline(s,x1,x2); 465. 	pline("Program in disorder - perhaps you'd better Quit."); 466. }  467.   468.  #ifdef CHDIR 469. static 470. chdirx(dir, wr) 471. char *dir; 472. boolean wr; 473. {  474.   475.  # ifdef SECURE 476. 	if(dir					/* User specified directory? */  477.  #  ifdef HACKDIR  478.  	       && strcmp(dir, HACKDIR)		/* and not the default? */  479.  #  endif  480.  		) { 481. 		(void) setuid(getuid);		/* Ron Wessels */ 482. 		(void) setgid(getgid); 483. 	}  484.  # endif 485.  486.  # ifdef HACKDIR 487. 	if(dir == NULL) 488. 		dir = HACKDIR; 489. # endif 490.  491.  	if(dir && chdir(dir) < 0) { 492. 		perror(dir); 493. 		error("Cannot chdir to %s.", dir); 494. 	}  495.   496.  	/* warn the player if he cannot write the record file */ 497. 	/* perhaps we should also test whether. is writable */ 498. 	/* unfortunately the access systemcall is worthless */ 499. 	if(wr) { 500. 	    register fd; 501.  502.  	    if(dir == NULL) 503. 		dir = "."; 504. 	    if((fd = open(RECORD, 2)) < 0) { 505. 		printf("Warning: cannot write %s/%s", dir, RECORD); 506. 		getret; 507. 	    } else 508. 		(void) close(fd); 509. 	}  510.  }  511.  #endif /* CHDIR /**/ 512.  513.  stop_occupation 514. {  515.  	if(occupation) { 516. 		pline("You stop %s.", occtxt); 517. 		occupation = 0; 518. #ifdef REDO 519. 		multi = 0; 520. 		pushch(0); 521. #endif 522. 	}  523.  }  524.   525.  whoami { 526. 	/*  527.  	 * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS 528. 	 *			2. Use $USER or $LOGNAME	(if 1. fails) 529. 	 *			3. Use getlogin		(if 2. fails) 530. 	 * The resulting name is overridden by command line options. 531. 	 * If everything fails, or if the resulting name is some generic 532. 	 * account like "games", "play", "player", "hack" then eventually 533. 	 * we'll ask him. 534. 	 * Note that we trust him here; it is possible to play under 535. 	 * somebody else's name. 536. 	 */  537.  	register char *s; 538.  539.  #ifndef DGKMOD 540. 	initoptions; 541. #endif 542. 	if(!*plname && (s = getenv("USER"))) 543. 		(void) strncpy(plname, s, sizeof(plname)-1); 544. 	if(!*plname && (s = getenv("LOGNAME"))) 545. 		(void) strncpy(plname, s, sizeof(plname)-1); 546. 	if(!*plname && (s = getlogin)) 547. 		(void) strncpy(plname, s, sizeof(plname)-1); 548. }  549.   550.  newgame { 551. 	fobj = fcobj = invent = 0; 552. 	fmon = fallen_down = 0; 553. 	ftrap = 0; 554. 	fgold = 0; 555. 	flags.ident = 1; 556. 	init_objects; 557. 	u_init; 558.  559.  	(void) signal(SIGINT,done1); 560. 	mklev; 561. 	u.ux = xupstair; 562. 	u.uy = yupstair; 563. 	(void) inshop; 564. 	setsee; 565. 	flags.botlx = 1; 566. 	{  567.  		register struct monst *mtmp; 568.  569.  		/* Move the monster from under you or else 570. 		 * makedog will fail when it calls makemon. 571. 		 * 			- ucsfcgl!kneller 572. 		 */  573.  		if (mtmp = m_at(u.ux, u.uy))  mnexto(mtmp); 574. 	}  575.  	(void) makedog; 576. 	seemons; 577. #ifdef NEWS 578. 	if(flags.nonews || !readnews) 579. 		/* after reading news we did docrt already */ 580. #endif 581. 		docrt; 582. 	return(0); 583. }  584.   585.  #ifdef GENIX 586. jhndist(x1,y1,x2,y2) 587. {  588.  	int x,y; 589. 	x=x1-x2; 590. 	y=y1-y2; 591. 	return (x*x + y*y); 592. }  593.  #endif