Source:NetHack 1.3d/unixmain.c

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