Source:NetHack 2.3e/unixmain.c

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