Source:NetHack 1.4f/unixmain.c

Below is the full text to unixmain.c from the source code of NetHack 1.4f. To link to a particular line, write [[NetHack 1.4f/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	1.4	87/08/08 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* main.c - (Unix) version 1.0.3 */ 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. 				printf("Sorry.\n"); 132. 			break; 133. #endif 134. #ifdef NEWS 135. 		case 'n': 136. 			flags.nonews = TRUE; 137. 			break; 138. #endif 139. 		case 'u': 140. 			if(argv[0][2]) 141. 			  (void) strncpy(plname, argv[0]+2, sizeof(plname)-1); 142. 			else if(argc > 1) { 143. 			  argc--; 144. 			  argv++; 145. 			  (void) strncpy(plname, argv[0], sizeof(plname)-1); 146. 			} else 147. 				printf("Player name expected after -u\n"); 148. 			break; 149. 		default: 150. 			/* allow -T for Tourist, etc. */ 151. 			(void) strncpy(pl_character, argv[0]+1,  152.  				sizeof(pl_character)-1); 153.  154.  			/* printf("Unknown option: %s\n", *argv); */ 155. 		}  156.  	}  157.   158.  	if(argc > 1) 159. 		locknum = atoi(argv[1]); 160. #ifdef MAX_NR_OF_PLAYERS 161. 	if(!locknum || locknum > MAX_NR_OF_PLAYERS) 162. 		locknum = MAX_NR_OF_PLAYERS; 163. #endif 164. #ifdef DEF_PAGER 165. 	if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER"))) 166. 		catmore = DEF_PAGER; 167. #endif 168. #ifdef MAIL 169. 	getmailstatus; 170. #endif 171. #ifdef WIZARD 172. 	if(wizard) (void) strcpy(plname, "wizard"); else 173. #endif 174. 	if(!*plname || !strncmp(plname, "player", 4)  175.  		    || !strncmp(plname, "games", 4)) 176. 		askname; 177. 	plnamesuffix;		/* strip suffix from name; calls askname */ 178. 				/* again if suffix was whole name */ 179. 				/* accepts any suffix */ 180. #ifdef WIZARD 181. 	if(!wizard) { 182. #endif 183. 		/*  184.  		 * check for multiple games under the same name 185. 		 * (if !locknum) or check max nr of players (otherwise) 186. 		 */  187.  		(void) signal(SIGQUIT,SIG_IGN); 188. 		(void) signal(SIGINT,SIG_IGN); 189. 		if(!locknum) 190. 			(void) strcpy(lock,plname); 191. 		getlock;	/* sets lock if locknum != 0 */ 192. #ifdef WIZARD 193. 	} else { 194. 		register char *sfoo; 195. 		extern char genocided[], fut_geno[]; 196. 		(void) strcpy(lock,plname); 197. 		if(sfoo = getenv("MAGIC")) 198. 			while(*sfoo) { 199. 				switch(*sfoo++) { 200. 				case 'n': (void) srand(*sfoo++); 201. 					break; 202. 				}  203.  			}  204.  		if(sfoo = getenv("GENOCIDED")){ 205. 			if(*sfoo == '!'){ 206. 				extern struct permonst mons[CMNUM+2]; 207. 				register struct permonst *pm = mons; 208. 				register char *gp = genocided; 209.  210.  				while(pm < mons+CMNUM+2){ 211. 					if(!index(sfoo, pm->mlet)) 212. 						*gp++ = pm->mlet; 213. 					pm++; 214. 				}  215.  				*gp = 0; 216. 			} else 217. 				(void) strcpy(genocided, sfoo); 218. 			(void) strcpy(fut_geno, genocided); 219. 		}  220.  	}  221.  #endif /* WIZARD /**/ 222. 	setftty; 223. 	(void) sprintf(SAVEF, "save/%d%s", getuid, plname); 224. 	regularize(SAVEF+5);		/* avoid. or / in name */ 225. 	if((fd = open(SAVEF,0)) >= 0 &&  226.  	   (uptodate(fd) || unlink(SAVEF) == 666)) { 227. 		(void) signal(SIGINT,done1); 228. 		pline("Restoring old save file..."); 229. 		(void) fflush(stdout); 230. 		if(!dorecover(fd)) 231. 			goto not_recovered; 232. 		pline("Hello %s, welcome to %s!", plname, gamename); 233. 		flags.move = 0; 234. 	} else { 235. not_recovered: 236. 		newgame; 237. 		/* give welcome message before pickup messages */ 238. 		pline("Hello %s, welcome to %s!", plname, gamename); 239.  240.  		pickup(1); 241. 		read_engr_at(u.ux,u.uy); 242. 		flags.move = 1; 243. 	}  244.   245.  	flags.moonphase = phase_of_the_moon; 246. 	if(flags.moonphase == FULL_MOON) { 247. 		pline("You are lucky! Full moon tonight."); 248. 		if(!u.uluck) u.uluck++; 249. 	} else if(flags.moonphase == NEW_MOON) { 250. 		pline("Be careful! New moon tonight."); 251. 	}  252.   253.  	initrack; 254.  255.  	for { 256. 		if(flags.move) {	/* actual time passed */ 257.  258.  			settrack; 259.  260.  			if(moves%2 == 0 ||  261.  			  (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) { 262. 				extern struct monst *makemon; 263. 				movemon; 264. 				if(!rn2(70)) 265. 				    (void) makemon((struct permonst *)0, 0, 0); 266. 			}  267.  			if(Glib) glibr; 268. 			timeout; 269. 			++moves; 270. #ifdef PRAYERS 271. 			if (u.ublesscnt)  u.ublesscnt--; 272. #endif 273. 			if(flags.time) flags.botl = 1; 274. #ifdef KAA 275. 			if(u.mtimedone) 276. 			    if(u.mh < 1) rehumanize; 277. 			else 278. #endif 279. 			    if(u.uhp < 1) { 280. 				pline("You die..."); 281. 				done("died"); 282. 			    }  283.  			if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){ 284. 			    wailmsg = moves; 285. #ifdef KAA 286. 			    if(index("WEV", pl_character[0])) { 287. 				if (u.uhp == 1) 288. 				pline("%s is about to die.", pl_character); 289. 				else 290. 				pline("%s, your life force is running out.",  291.  					pl_character); 292. 			    } else { 293. #endif 294. 				if(u.uhp == 1) 295. 				pline("You hear the wailing of the Banshee..."); 296. 				else 297. 				pline("You hear the howling of the CwnAnnwn..."); 298. #ifdef KAA 299. 			    }  300.  #endif 301. 			}  302.  #ifdef KAA 303. 			if (u.mtimedone) { 304. 			    if (u.mh < u.mhmax) { 305. 				if (Regeneration || !(moves%20)) { 306. 					flags.botl = 1; 307. 					u.mh++; 308. 				}  309.  			    }  310.  			}  311.  #endif 312. 			if(u.uhp < u.uhpmax) { 313. 				if(u.ulevel > 9) { 314. 					if(HRegeneration || !(moves%3)) { 315. 					    flags.botl = 1; 316. 					    u.uhp += rnd((int) u.ulevel-9); 317. 					    if(u.uhp > u.uhpmax) 318. 						u.uhp = u.uhpmax; 319. 					}  320.  				} else if(HRegeneration ||  321.  					(!(moves%(22-u.ulevel*2)))) { 322. 					flags.botl = 1; 323. 					u.uhp++; 324. 				}  325.  			}  326.  #ifdef SPELLS 327. 			if ((u.uen u.uenmax)  u.uen = u.uenmax; 330. 				flags.botl = 1; 331. 			}  332.  #endif 333. 			if(Teleportation && !rn2(85)) tele; 334. 			if(Searching && multi >= 0) (void) dosearch; 335. 			gethungry; 336. 			invault; 337. 			amulet; 338. #ifdef HARD 339. 			if (!rn2(4)) u_wipe_engr(rnd(3)); 340. 			if (u.udemigod) { 341.  342.  				u.udg_cnt--; 343. 				if(u.udg_cnt <= 0) { 344.  345.  					intervene; 346. 					u.udg_cnt = rn1(200, 50); 347. 				}  348.  			}  349.  #endif 350. 		}  351.  		if(multi < 0) { 352. 			if(!++multi){ 353. 				pline(nomovemsg ? nomovemsg :  354.  					"You can move again."); 355. 				nomovemsg = 0; 356. 				if(afternmv) (*afternmv); 357. 				afternmv = 0; 358. 			}  359.  		}  360.   361.  		find_ac; 362. #ifndef QUEST 363. 		if(!flags.mv || Blind) 364. #endif 365. 		{  366.  			seeobjs; 367. 			seemons; 368. 			nscr; 369. 		}  370.  #ifdef DGK 371. 		if(flags.time) flags.botl = 1; 372. #endif 373. 		if(flags.botl || flags.botlx) bot; 374.  375.  		flags.move = 1; 376.  377.  		if(multi >= 0 && occupation) { 378.  379.  			if (monster_nearby) 380. 				stop_occupation; 381. 			else if ((*occupation) == 0) 382. 				occupation = 0; 383. 			continue; 384. 		}  385.   386.  		if(multi > 0) { 387. #ifdef QUEST 388. 			if(flags.run >= 4) finddir; 389. #endif 390. 			lookaround; 391. 			if(!multi) {	/* lookaround may clear multi */ 392. 				flags.move = 0; 393. 				continue; 394. 			}  395.  			if(flags.mv) { 396. 				if(multi < COLNO && !--multi) 397. 					flags.mv = flags.run = 0; 398. 				domove; 399. 			} else { 400. 				--multi; 401. 				rhack(save_cm); 402. 			}  403.  		} else if(multi == 0) { 404. #ifdef MAIL 405. 			ckmailstatus; 406. #endif 407. 			rhack((char *) 0); 408. 		}  409.  		if(multi && multi%7 == 0) 410. 			(void) fflush(stdout); 411. 	}  412.  }  413.   414.  glo(foo) 415. register foo; 416. {  417.  	/* construct the string  xlock.n  */ 418. 	register char *tf; 419.  420.  	tf = lock; 421. 	while(*tf && *tf != '.') tf++; 422. 	(void) sprintf(tf, ".%d", foo); 423. }  424.   425.  /*  426.   * plname is filled either by an option (-u Player  or  -uPlayer) or  427. * explicitly (-w implies wizard) or by askname. 428.  * It may still contain a suffix denoting pl_character. 429.  */  430.  askname{ 431. register int c,ct; 432. 	printf("\nWho are you? "); 433. 	(void) fflush(stdout); 434. 	ct = 0; 435. 	while((c = getchar) != '\n'){ 436. 		if(c == EOF) error("End of input\n"); 437. 		/* some people get confused when their erase char is not ^H */ 438. 		if(c == '\010') { 439. 			if(ct) ct--; 440. 			continue; 441. 		}  442.  		if(c != '-') 443. 		if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_'; 444. 		if(ct < sizeof(plname)-1) plname[ct++] = c;  445. } 446.  	plname[ct] = 0; 447. 	if(ct == 0) askname; 448. }  449.   450.  /*VARARGS1*/ 451. impossible(s,x1,x2) 452. register char *s; 453. {  454.  	pline(s,x1,x2); 455. 	pline("Program in disorder - perhaps you'd better Quit."); 456. }  457.   458.  #ifdef CHDIR 459. static 460. chdirx(dir, wr) 461. char *dir; 462. boolean wr; 463. {  464.   465.  # ifdef SECURE 466. 	if(dir					/* User specified directory? */  467.  #  ifdef HACKDIR  468.  	       && strcmp(dir, HACKDIR)		/* and not the default? */  469.  #  endif  470.  		) { 471. 		(void) setuid(getuid);		/* Ron Wessels */ 472. 		(void) setgid(getgid); 473. 	}  474.  # endif 475.  476.  # ifdef HACKDIR 477. 	if(dir == NULL) 478. 		dir = HACKDIR; 479. # endif 480.  481.  	if(dir && chdir(dir) < 0) { 482. 		perror(dir); 483. 		error("Cannot chdir to %s.", dir); 484. 	}  485.   486.  	/* warn the player if he cannot write the record file */ 487. 	/* perhaps we should also test whether. is writable */ 488. 	/* unfortunately the access systemcall is worthless */ 489. 	if(wr) { 490. 	    register fd; 491.  492.  	    if(dir == NULL) 493. 		dir = "."; 494. 	    if((fd = open(RECORD, 2)) < 0) { 495. 		printf("Warning: cannot write %s/%s", dir, RECORD); 496. 		getret; 497. 	    } else 498. 		(void) close(fd); 499. 	}  500.  }  501.  #endif /* CHDIR /**/ 502.  503.  stop_occupation 504. {  505.  	if(occupation) { 506. 		pline("You stop %s.", occtxt); 507. 		occupation = 0; 508. #ifdef REDO 509. 		multi = 0; 510. 		pushch(0); 511. #endif 512. 	}  513.  }  514.   515.  whoami { 516. 	/*  517.  	 * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS 518. 	 *			2. Use $USER or $LOGNAME	(if 1. fails) 519. 	 *			3. Use getlogin		(if 2. fails) 520. 	 * The resulting name is overridden by command line options. 521. 	 * If everything fails, or if the resulting name is some generic 522. 	 * account like "games", "play", "player", "hack" then eventually 523. 	 * we'll ask him. 524. 	 * Note that we trust him here; it is possible to play under 525. 	 * somebody else's name. 526. 	 */  527.  	register char *s; 528.  529.  #ifndef DGKMOD 530. 	initoptions; 531. #endif 532. 	if(!*plname && (s = getenv("USER"))) 533. 		(void) strncpy(plname, s, sizeof(plname)-1); 534. 	if(!*plname && (s = getenv("LOGNAME"))) 535. 		(void) strncpy(plname, s, sizeof(plname)-1); 536. 	if(!*plname && (s = getlogin)) 537. 		(void) strncpy(plname, s, sizeof(plname)-1); 538. }  539.   540.  newgame { 541. 	fobj = fcobj = invent = 0; 542. 	fmon = fallen_down = 0; 543. 	ftrap = 0; 544. 	fgold = 0; 545. 	flags.ident = 1; 546. 	init_objects; 547. 	u_init; 548.  549.  	(void) signal(SIGINT,done1); 550. 	mklev; 551. 	u.ux = xupstair; 552. 	u.uy = yupstair; 553. 	(void) inshop; 554. 	setsee; 555. 	flags.botlx = 1; 556. 	{  557.  		register struct monst *mtmp; 558.  559.  		/* Move the monster from under you or else 560. 		 * makedog will fail when it calls makemon. 561. 		 * 			- ucsfcgl!kneller 562. 		 */  563.  		if (mtmp = m_at(u.ux, u.uy))  mnexto(mtmp); 564. 	}  565.  	(void) makedog; 566. 	seemons; 567. #ifdef NEWS 568. 	if(flags.nonews || !readnews) 569. 		/* after reading news we did docrt already */ 570. #endif 571. 		docrt; 572. 	return(0); 573. }  574.   575.  #ifdef GENIX 576. jhndist(x1,y1,x2,y2) 577. {  578.  	int x,y; 579. 	x=x1-x2; 580. 	y=y1-y2; 581. 	return (x*x + y*y); 582. }  583.  #endif