Source:NetHack 3.0.0/unixmain.c

Below is the full text to unixmain.c from the source code of NetHack 3.0.0. To link to a particular line, write [[NetHack 3.0.0/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	3.0	89/01/13 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.    /* main.c - (Unix) version */ 5.    6.    #include   7.    #include   8. 9.   #include "hack.h"  10. 11.  int hackpid = 0;				/* current pid */ 12.  int locknum = 0;				/* max num of players */ 13.  #ifdef DEF_PAGER 14.  char *catmore = 0;				/* default pager */ 15.  #endif 16.  char SAVEF[PL_NSIZ + 11] = "save/";	/* save/99999player */ 17.  char *hname = 0;		/* name of the game (argv[0] of call) */ 18.  char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */ 19.   20.   int (*occupation) = DUMMY; 21.  int (*afternmv) = DUMMY; 22.  #ifdef CHDIR 23.  static void chdirx; 24.  #endif /* CHDIR */ 25.  static void whoami, newgame; 26.   27.   main(argc,argv) 28.  int argc; 29.  char *argv[]; 30.  {  31.   	struct passwd *pw; 32.  	extern struct passwd *getpwuid; 33.  	extern int x_maze_max, y_maze_max; 34.  	register int fd; 35.  #ifdef CHDIR 36.  	register char *dir; 37.  #endif 38.  #ifdef COMPRESS 39.  	char	cmd[80], old[80]; 40.  #endif 41.  	hname = argv[0]; 42.  	hackpid = getpid; 43.  	(void) umask(0); 44.   45.   #ifdef CHDIR			/* otherwise no chdir */ 46.  	/*  47.   	 * See if we must change directory to the playground. 48.  	 * (Perhaps hack runs suid and playground is inaccessible  49.   	 *  for the player.) 50.  	 * The environment variable HACKDIR is overridden by a  51. * -d command line option (must be the first option given) 52.  	 */  53.    54.   	dir = getenv("HACKDIR"); 55.  	if(argc > 1 && !strncmp(argv[1], "-d", 2)) { 56.  		argc--; 57.  		argv++; 58.  		dir = argv[0]+2; 59.  		if(*dir == '=' || *dir == ':') dir++; 60.  		if(!*dir && argc > 1) { 61.  			argc--; 62.  			argv++; 63.  			dir = argv[0]; 64.  		}  65.   		if(!*dir) 66.  		    error("Flag -d must be followed by a directory name."); 67.  	}  68.   #endif /* CHDIR /**/ 69.  	/* Set the default values of the presentation characters */ 70.  	(void) memcpy((char *) &showsyms,  71.   		(char *) &defsyms, sizeof(struct symbols)); 72.  	initoptions; 73.  	whoami; 74.  	/*  75.   	 * Now we know the directory containing 'record' and 76.  	 * may do a prscore. 77.  	 */  78.   	if(argc > 1 && !strncmp(argv[1], "-s", 2)) { 79.  #ifdef CHDIR 80.  		chdirx(dir,0); 81.  #endif 82.  		prscore(argc, argv); 83.  		exit(0); 84.  	}  85.    86.   	/*  87.   	 * It seems he really wants to play. 88.  	 * Remember tty modes, to be restored on exit. 89.  	 */  90.   	gettty; 91.  	setbuf(stdout,obuf); 92.  	setrandom; 93.  	startup; 94.  	cls; 95.  	u.uhp = 1;	/* prevent RIP on early quits */ 96.  	u.ux = FAR;	/* prevent nscr */ 97.  	(void) signal(SIGHUP, (SIG_RET_TYPE) hangup); 98.   99.   	/*  100.  	 * Find the creation date of this game, 101. 	 * so as to avoid restoring outdated savefiles. 102. 	 */  103.  	gethdate(hname); 104.  105.  	/*  106.  	 * We cannot do chdir earlier, otherwise gethdate will fail. 107. 	 */  108.  #ifdef CHDIR 109. 	chdirx(dir,1); 110. #endif 111.  112.  	/*  113.  	 * Process options. 114. 	 */  115.  	while(argc > 1 && argv[1][0] == '-'){ 116. 		argv++; 117. 		argc--; 118. 		switch(argv[0][1]){ 119. #if defined(WIZARD) || defined(EXPLORE_MODE) 120. 		case 'D': 121. 		case 'X': 122. 			pw = getpwuid(getuid); 123. # ifdef WIZARD 124. 			if(!strcmp(pw->pw_name, WIZARD)) 125. 				wizard = TRUE; 126. # endif 127. # if defined(WIZARD) && defined(EXPLORE_MODE) 128. 			else 129. # endif 130. # ifdef EXPLORE_MODE 131. 				discover = TRUE; 132. # endif 133. 			break; 134. #endif 135. #ifdef NEWS 136. 		case 'n': 137. 			flags.nonews = TRUE; 138. 			break; 139. #endif 140. 		case 'u': 141. 			if(argv[0][2]) 142. 			  (void) strncpy(plname, argv[0]+2, sizeof(plname)-1); 143. 			else if(argc > 1) { 144. 			  argc--; 145. 			  argv++; 146. 			  (void) strncpy(plname, argv[0], sizeof(plname)-1); 147. 			} else 148. 				Printf("Player name expected after -u\n"); 149. 			break; 150. 		default: 151. 			/* allow -T for Tourist, etc. */ 152. 			(void) strncpy(pl_character, argv[0]+1,  153.  				sizeof(pl_character)-1); 154.  155.  			/* Printf("Unknown option: %s\n", *argv); */ 156. 		}  157.  	}  158.   159.  	if(argc > 1) 160. 		locknum = atoi(argv[1]); 161. #ifdef MAX_NR_OF_PLAYERS 162. 	if(!locknum || locknum > MAX_NR_OF_PLAYERS) 163. 		locknum = MAX_NR_OF_PLAYERS; 164. #endif 165. #ifdef DEF_PAGER 166. 	if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER"))) 167. 		catmore = DEF_PAGER; 168. #endif 169. #ifdef MAIL 170. 	getmailstatus; 171. #endif 172. #ifdef WIZARD 173. 	if(wizard) Strcpy(plname, "wizard"); else 174. #endif 175. 	if(!*plname || !strncmp(plname, "player", 4)  176.  		    || !strncmp(plname, "games", 4)) 177. 		askname; 178. 	plnamesuffix;		/* strip suffix from name; calls askname */ 179. 				/* again if suffix was whole name */ 180. 				/* accepts any suffix */ 181. #ifdef WIZARD 182. 	if(!wizard) { 183. #endif 184. 		/*  185.  		 * check for multiple games under the same name 186. 		 * (if !locknum) or check max nr of players (otherwise) 187. 		 */  188.  		(void) signal(SIGQUIT,SIG_IGN); 189. 		(void) signal(SIGINT,SIG_IGN); 190. 		if(!locknum) 191. 			Strcpy(lock,plname); 192. 		getlock;	/* sets lock if locknum != 0 */ 193. #ifdef WIZARD 194. 	} else 195. 		Strcpy(lock,plname); 196. #endif /* WIZARD /**/ 197. 	setftty; 198.  199.  	/*  200.  	 * Initialisation of the boundaries of the mazes 201. 	 * Both boundaries have to be even. 202. 	 */  203.  	  204.  	x_maze_max = COLNO-1; 205. 	if (x_maze_max % 2) 206. 		x_maze_max--; 207. 	y_maze_max = ROWNO-1; 208. 	if (y_maze_max % 2) 209. 		y_maze_max--; 210.  211.  	/* initialize static monster strength array */ 212. 	init_monstr; 213.  214.  	Sprintf(SAVEF, "save/%d%s", getuid, plname); 215. 	regularize(SAVEF+5);		/* avoid. or / in name */ 216. #ifdef COMPRESS 217. 	Strcpy(old,SAVEF); 218. 	Strcat(SAVEF,".Z"); 219. 	if((fd = open(SAVEF,0)) >= 0) { 220.  	    (void) close(fd); 221. 	    Strcpy(cmd, COMPRESS); 222. 	    Strcat(cmd, " -d ");	/* uncompress */ 223. # ifdef COMPRESS_OPTIONS 224. 	    Strcat(cmd, COMPRESS_OPTIONS); 225. 	    Strcat(cmd, " "); 226. # endif 227. 	    Strcat(cmd,SAVEF); 228. 	    (void) system(cmd); 229. 	}  230.  	Strcpy(SAVEF,old); 231. #endif 232. 	if((fd = open(SAVEF,0)) >= 0 &&  233.  	   (uptodate(fd) || unlink(SAVEF) == 666)) { 234. 		(void) signal(SIGINT, (SIG_RET_TYPE) done1); 235. 		pline("Restoring old save file..."); 236. 		(void) fflush(stdout); 237. 		if(!dorecover(fd)) 238. 			goto not_recovered; 239. 		pline("Hello %s, welcome to NetHack!", plname); 240. 		/* get shopkeeper set properly if restore is in shop */ 241. 		(void) inshop; 242. #ifdef EXPLORE_MODE 243. 		if (discover) { 244. 			You("are in non-scoring discovery mode."); 245. 			pline("Do you want to keep the save file? "); 246. 			if(yn == 'n') 247. 				(void) unlink(SAVEF); 248. 		}  249.  #endif 250. 		flags.move = 0; 251. 	} else { 252. not_recovered: 253. 		newgame; 254. 		/* give welcome message before pickup messages */ 255. 		pline("Hello %s, welcome to NetHack!", plname); 256. #ifdef EXPLORE_MODE 257. 		if (discover) 258. 			You("are in non-scoring discovery mode."); 259. #endif 260. 		flags.move = 0; 261. 		set_wear; 262. 		pickup(1); 263. 		read_engr_at(u.ux,u.uy); 264. 	}  265.   266.  	flags.moonphase = phase_of_the_moon; 267. 	if(flags.moonphase == FULL_MOON) { 268. 		You("are lucky!  Full moon tonight."); 269. 		if(!u.uluck) change_luck(1); 270. 	} else if(flags.moonphase == NEW_MOON) { 271. 		pline("Be careful!  New moon tonight."); 272. 	}  273.   274.  	initrack; 275.  276.  	for { 277. 		if(flags.move) {	/* actual time passed */ 278.  279.  #ifdef SOUNDS 280. 			dosounds; 281. #endif 282. 			settrack; 283.  284.  			if(moves%2 == 0 ||  285.  			  (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) { 286. 				movemon; 287. #ifdef HARD 288. 				if(!rn2(u.udemigod?25:(dlevel>30)?50:70)) 289. #else 290. 				if(!rn2(70)) 291. #endif 292. 				    (void) makemon((struct permonst *)0, 0, 0); 293. 			}  294.  			if(Glib) glibr; 295. 			timeout; 296. 			++moves; 297. #ifdef THEOLOGY 298. 			if (u.ublesscnt)  u.ublesscnt--; 299. #endif 300. 			if(flags.time) flags.botl = 1; 301. #ifdef POLYSELF 302. 			if(u.mtimedone) 303. 			    if(u.mh < 1) rehumanize; 304. 			else 305. #endif 306. 			    if(u.uhp < 1) { 307. 				You("die..."); 308. 				done("died"); 309. 			    }  310.  #ifdef POLYSELF 311. 			if (u.mtimedone) { 312. 			    if (u.mh < u.mhmax) { 313. 				if (Regeneration || !(moves%20)) { 314. 					flags.botl = 1; 315. 					u.mh++; 316. 				}  317.  			    }  318.  			}  319.  #endif 320. 			if(u.uhp < u.uhpmax) { 321. 				if(u.ulevel > 9) { 322. 				    int heal; 323.  324.  				    if(HRegeneration || !(moves%3)) { 325. 					flags.botl = 1; 326. 					if (ACURR(A_CON) <= 12) heal = 1; 327. 					else heal = rnd((int) ACURR(A_CON)-12); 328. 					if (heal > u.ulevel-9) heal = u.ulevel-9; 329. 					u.uhp += heal; 330. 					if(u.uhp > u.uhpmax) 331. 					    u.uhp = u.uhpmax; 332. 				    }  333.  				} else if(HRegeneration ||  334.  				      (!(moves%((MAXULEV+12)/(u.ulevel+2)+1)))) { 335. 					flags.botl = 1; 336. 					u.uhp++; 337. 				}  338.  			}  339.  #ifdef SPELLS 340. 			if ((u.uen u.uenmax)  u.uen = u.uenmax; 343. 				flags.botl = 1; 344. 			}  345.  #endif 346. 			if(Teleportation && !rn2(85)) tele; 347. #ifdef POLYSELF 348. 			if(Polymorph && !rn2(100)) polyself; 349. 			if(u.ulycn >= 0 && !rn2(80 - (20 * night))) 350. 				you_were; 351. #endif 352. 			if(Searching && multi >= 0) (void) dosearch0(1); 353. 			hatch_eggs; 354. 			gethungry; 355. 			invault; 356. 			amulet; 357. #ifdef HARD 358. 			if (!rn2(40+(int)(ACURR(A_DEX)*3))) u_wipe_engr(rnd(3)); 359. 			if (u.udemigod) { 360.  361.  				if(u.udg_cnt) u.udg_cnt--; 362. 				if(!u.udg_cnt) { 363.  364.  					intervene; 365. 					u.udg_cnt = rn1(200, 50); 366. 				}  367.  			}  368.  #endif 369. 			restore_attrib; 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. 		if(!flags.mv || Blind) 383. 		{  384.  			seeobjs; 385. 			seemons; 386. 			seeglds; 387. 			nscr; 388. 		}  389.  		if(flags.botl || flags.botlx) bot; 390.  391.  		flags.move = 1; 392.  393.  		if(multi >= 0 && occupation) { 394.  395.  			if(monster_nearby) 396. 				stop_occupation; 397. 			else if ((*occupation) == 0) 398. 				occupation = 0; 399. 			continue; 400. 		}  401.   402.  		if((u.uhave_amulet || Clairvoyant) &&  403.  #ifdef ENDGAME  404.  			dlevel != ENDLEVEL &&  405.  #endif  406.  			!(moves%15) && !rn2(2)) do_vicinity_map; 407.  408.  		u.umoved = FALSE; 409. 		if(multi > 0) { 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(NULL); 428. 		}  429.  		if(multi && multi%7 == 0) 430. 			(void) fflush(stdout); 431. 	}  432.  }  433.   434.  void 435. glo(foo) 436. register int foo; 437. {  438.  	/* construct the string  xlock.n  */ 439. 	register char *tf; 440.  441.  	tf = lock; 442. 	while(*tf && *tf != '.') tf++; 443. 	Sprintf(tf, ".%d", foo); 444. }  445.   446.  /*  447.   * plname is filled either by an option (-u Player  or  -uPlayer) or  448. * explicitly (by being the wizard) or by askname. 449.  * It may still contain a suffix denoting pl_character. 450.  */  451.  void 452. askname{ 453. register int c,ct; 454. 	Printf("\nWho are you? "); 455. 	(void) fflush(stdout); 456. 	ct = 0; 457. 	while((c = Getchar) != '\n'){ 458. 		if(c == EOF) error("End of input\n"); 459. 		/* some people get confused when their erase char is not ^H */ 460. 		if(c == '\010') { 461. 			if(ct) ct--; 462. 			continue; 463. 		}  464.  		if(c != '-') 465. 		if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_'; 466. 		if(ct < sizeof(plname)-1) plname[ct++] = c;  467. } 468.  	plname[ct] = 0; 469. 	if(ct == 0) askname; 470. }  471.   472.  /*VARARGS1*/ 473. void 474. impossible(s,x1,x2) 475. register char *s, *x1, *x2; 476. {  477.  	pline(s,x1,x2); 478. 	pline("Program in disorder - perhaps you'd better Quit."); 479. }  480.   481.  #ifdef CHDIR 482. static void 483. chdirx(dir, wr) 484. char *dir; 485. boolean wr; 486. {  487.   488.  # ifdef SECURE 489. 	if(dir					/* User specified directory? */  490.  #  ifdef HACKDIR  491.  	       && strcmp(dir, HACKDIR)		/* and not the default? */  492.  #  endif  493.  		) { 494. 		(void) setgid(getgid); 495. 		(void) setuid(getuid);		/* Ron Wessels */ 496. 	}  497.  # endif 498.  499.  # ifdef HACKDIR 500. 	if(dir == NULL) 501. 		dir = HACKDIR; 502. # endif 503.  504.  	if(dir && chdir(dir) < 0) { 505. 		perror(dir); 506. 		error("Cannot chdir to %s.", dir); 507. 	}  508.   509.  	/* warn the player if he cannot write the record file */ 510. 	/* perhaps we should also test whether. is writable */ 511. 	/* unfortunately the access systemcall is worthless */ 512. 	if(wr) { 513. 	    register int fd; 514.  515.  	    if(dir == NULL) 516. 		dir = "."; 517. 	    if((fd = open(RECORD, 2)) < 0) { 518. 		Printf("Warning: cannot write %s/%s", dir, RECORD); 519. 		getret; 520. 	    } else 521. 		(void) close(fd); 522. 	}  523.  }  524.  #endif /* CHDIR /**/ 525.  526.  void 527. stop_occupation 528. {  529.  	if(occupation) { 530. 		You("stop %s.", occtxt); 531. 		occupation = 0; 532. #ifdef REDO 533. 		multi = 0; 534. 		pushch(0); 535. #endif 536. 	}  537.  }  538.   539.  static void 540. whoami { 541. 	/*  542.  	 * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS 543. 	 *			2. Use $USER or $LOGNAME	(if 1. fails) 544. 	 *			3. Use getlogin		(if 2. fails) 545. 	 * The resulting name is overridden by command line options. 546. 	 * If everything fails, or if the resulting name is some generic 547. 	 * account like "games", "play", "player", "hack" then eventually 548. 	 * we'll ask him. 549. 	 * Note that we trust him here; it is possible to play under 550. 	 * somebody else's name. 551. 	 */  552.  	register char *s; 553.  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.  static void 563. newgame { 564. 	fobj = fcobj = invent = 0; 565. 	fmon = fallen_down = 0; 566. 	ftrap = 0; 567. 	fgold = 0; 568. 	flags.ident = 1; 569.  570.  	init_objects; 571. 	u_init; 572.  573.  	(void) signal(SIGINT, (SIG_RET_TYPE) done1); 574.  575.  	mklev; 576. 	u.ux = xupstair; 577. 	u.uy = yupstair; 578. 	(void) inshop; 579.  580.  	setsee; 581. 	flags.botlx = 1; 582.  583.  	/* Move the monster from under you or else 584. 	 * makedog will fail when it calls makemon. 585. 	 * 			- ucsfcgl!kneller 586. 	 */  587.  	if(levl[u.ux][u.uy].mmask) mnexto(m_at(u.ux, u.uy)); 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.  597.  	return; 598. }