Source:NetHack 2.2a/pcmain.c

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

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

1.   /*	SCCS Id: @(#)pcmain.c	2.1	87/10/18 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* main.c - (PC) version */ 4.    5.    #include   6.    #include   7.    #include "hack.h"  8. 9.   #ifdef QUEST 10.  #define	gamename	"PC NetQuest" 11.  #else 12.  #define	gamename	"PC NetHack" 13.  #endif 14.   15.   char orgdir[PATHLEN], *getcwd; 16.   17.   extern struct permonst mons[CMNUM+2]; 18.  extern char genocided[], fut_geno[]; 19.  extern char *getlogin, *getenv; 20.  extern char plname[PL_NSIZ], pl_character[PL_CSIZ]; 21.   22.   int (*afternmv), done1, (*occupation); 23.   24.   char SAVEF[FILENAME]; 25.  char *hname = gamename; 26.  char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */ 27.  int hackpid;		/* not used anymore, but kept in for save files */ 28.   29.   extern char *nomovemsg; 30.  extern long wailmsg; 31.   32.   main(argc,argv) 33.  int argc; 34.  char *argv[]; 35.  {  36.   	register int fd; 37.  	register char *dir; 38.  #ifdef MSDOS 39.  	static void moveloop;	/* a helper function for MSC optimizer */ 40.   41.   	/* Save current directory and make sure it gets restored when 42.  	 * the game is exited. 43.  	 */  44.   	int (*funcp); 45.   46.   	if (getcwd(orgdir, sizeof orgdir) == NULL) { 47.  		xputs("hack: current directory path too long\n"); 48.  		_exit(1); 49.  	}  50.   	funcp = exit;	/* Kludge to get around LINT_ARGS of signal. 51.  			 * This will produce a compiler warning, but that's OK. 52.  			 */  53.   	signal(SIGINT, funcp);	/* restore original directory */ 54.  #endif 55.   56.   #ifdef GRAPHICS 57.  	/* Set the default values of the presentation characters */ 58.  	memcpy((char *) &showsyms, (char *) &defsyms, sizeof(struct symbols)); 59.  #endif 60.  #ifdef DGK 61.  	if ((dir = getenv("HACKDIR")) != (char *) NULL) { 62.  		(void) strcpy(hackdir, dir); 63.  		chdirx (dir, 1); 64.  	}  65.   	zero_finfo; 66.  	initoptions; 67.  	if (!hackdir[0]) 68.  		(void) strcpy(hackdir, orgdir); 69.  	dir = hackdir; 70.  #else 71.  	dir = getenv("HACKDIR"); 72.  	if(argc > 1 && !strncmp(argv[1], "-d", 2)) { 73.  		argc--; 74.  		argv++; 75.  		dir = argv[0]+2; 76.  		if(*dir == '=' || *dir == ':') dir++; 77.  		if(!*dir && argc > 1) { 78.  			argc--; 79.  			argv++; 80.  			dir = argv[0]; 81.  		}  82.   		if(!*dir) 83.  		    error("Flag -d must be followed by a directory name."); 84.  	}  85.   #endif /* DGK */ 86.   87.   	/*  88.   	 * Now we know the directory containing 'record' and 89.  	 * may do a prscore. 90.  	 */  91.   	if(argc > 1 && !strncmp(argv[1], "-s", 2)) { 92.  		chdirx(dir,0); 93.  		prscore(argc, argv); 94.  		exit(0); 95.  	}  96.    97.   	/*  98.   	 * It seems he really wants to play. 99.  	 * Remember tty modes, to be restored on exit. 100. 	 */  101.  	gettty; 102. 	setbuf(stdout,obuf); 103. 	setrandom; 104. 	startup; 105. 	init_corpses;	/* initialize optional corpse names */ 106. 	cls; 107. 	u.uhp = 1;	/* prevent RIP on early quits */ 108. 	u.ux = FAR;	/* prevent nscr */ 109.  110.  	/*  111.  	 * We cannot do chdir earlier, otherwise gethdate will fail. 112. 	 */  113.  	chdirx(dir,1); 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. # ifdef MSDOS 125. 			wizard = TRUE; 126. # else 127. 			if(!strcmp(getlogin, WIZARD)) 128. 				wizard = TRUE; 129. 			else { 130. 				settty("Sorry, you can't operate in debug mode.\n"); 131. 				clearlocks; 132. 				exit(0); 133. 			}  134.  			break; 135. #endif 136. 		case 'u': 137. 			if(argv[0][2]) 138. 			  (void) strncpy(plname, argv[0]+2, sizeof(plname)-1); 139. 			else if(argc > 1) { 140. 			  argc--; 141. 			  argv++; 142. 			  (void) strncpy(plname, argv[0], sizeof(plname)-1); 143. 			} else 144. 				printf("Player name expected after -u\n"); 145. 			break; 146. #ifdef DGK 147. 		/* Person does not want to use a ram disk 148. 		 */  149.  		case 'R': 150. 			ramdisk = FALSE; 151. 			break; 152. #endif 153. 		default: 154. 			/* allow -T for Tourist, etc. */ 155. 			(void) strncpy(pl_character, argv[0]+1,  156.  				sizeof(pl_character)-1); 157.  158.  			/* printf("Unknown option: %s\n", *argv); */ 159. 		}  160.  	}  161.   162.  #ifdef DGK 163. 	set_lock_and_bones; 164. 	copybones(FROMPERM); 165. #endif 166. #ifdef WIZARD 167. 	if (wizard) 168. 		(void) strcpy(plname, "wizard"); 169. 	else 170. #endif 171. 	if (!*plname) 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. 		register char *sfoo; 179. # ifndef DGK 180. 		/* lock is set in read_config_file */ 181. 		(void) strcpy(lock,plname); 182. # endif 183. 		if(sfoo = getenv("MAGIC")) 184. 			while(*sfoo) { 185. 				switch(*sfoo++) { 186. 				case 'n': (void) srand(*sfoo++); 187. 					break; 188. 				}  189.  			}  190.  		if(sfoo = getenv("GENOCIDED")){ 191. 			if(*sfoo == '!'){ 192. 				register struct permonst *pm = mons; 193. 				register char *gp = genocided; 194.  195.  				while(pm < mons+CMNUM+2){ 196. 					if(!index(sfoo, pm->mlet)) 197. 						*gp++ = pm->mlet; 198. 					pm++; 199. 				}  200.  				*gp = 0; 201. 			} else 202. 				(void) strcpy(genocided, sfoo); 203. 			(void) strcpy(fut_geno, genocided); 204. 		}  205.  	}  206.  #endif /* WIZARD */ 207. 	start_screen; 208. #ifdef DGK 209. 	strncat(SAVEF, plname, 8); 210. 	strcat(SAVEF, ".sav"); 211. 	cls; 212. 	if (saveDiskPrompt(1) && ((fd = open(SAVEF, 0)) >= 0) &&  213.  	   (uptodate(fd) || !unlink(SAVEF))) { 214. #else 215. 	(void) sprintf(SAVEF, "save/%d%s", getuid, plname); 216. 	regularize(SAVEF+5);		/* avoid. or / in name */ 217. 	if((fd = open(SAVEF,0)) >= 0 &&  218.  	   (uptodate(fd) || unlink(SAVEF) == 666)) { 219. #endif /* DGK */ 220. 		(void) signal(SIGINT,done1); 221. 		pline("Restoring old save file..."); 222. 		(void) fflush(stdout); 223. 		if(!dorecover(fd)) 224. 			goto not_recovered; 225. 		pline("Hello %s, welcome to %s!", plname, hname); 226. 		flags.move = 0; 227. 	} else { 228. not_recovered: 229. #ifdef DGK 230. 		gameDiskPrompt; 231. #endif 232. 		fobj = fcobj = invent = 0; 233. 		fmon = fallen_down = 0; 234. 		ftrap = 0; 235. 		fgold = 0; 236. 		flags.ident = 1; 237. 		init_objects; 238. 		u_init; 239.  240.  		(void) signal(SIGINT,done1); 241. 		mklev; 242. 		u.ux = xupstair; 243. 		u.uy = yupstair; 244. 		(void) inshop; 245. 		setsee; 246. 		flags.botlx = 1; 247. 		/* Fix bug with dog not being made because a monster 248. 		 * was on the level 1 staircase 249. 		 */  250.  		{  251.  			struct monst *mtmp; 252.  253.  			if (mtmp = m_at(u.ux, u.uy)) 254. 				mnexto(mtmp); 255. 		}  256.  		makedog; 257. 		{ register struct monst *mtmp; 258. 		  if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp);	/* riv05!a3 */ 259. 		}  260.  		seemons; 261. 		docrt; 262.  263.  		/* give welcome message before pickup messages */ 264. 		pline("Hello %s, welcome to %s!", plname, hname); 265.  266.  		pickup(1); 267. 		read_engr_at(u.ux,u.uy); 268. 		flags.move = 1; 269. 	}  270.  	flags.moonphase = phase_of_the_moon; 271. 	if(flags.moonphase == FULL_MOON) { 272. 		pline("You are lucky! Full moon tonight."); 273. 		if(!u.uluck) u.uluck++; 274. 	} else if(flags.moonphase == NEW_MOON) { 275. 		pline("Be careful! New moon tonight."); 276. 	}  277.   278.  	initrack; 279. 	(void) signal(SIGINT, SIG_IGN); 280. #ifdef MSDOS 281. 	/* Help for Microsoft optimizer. Otherwise main is too large -dgk*/ 282. 	moveloop; 283. }  284.   285.  static void 286. moveloop 287. {  288.  	char ch; 289. 	int abort; 290. #endif /* MSDOS */ 291. 	for { 292. 		if(flags.move) {	/* actual time passed */ 293.  294.  			settrack; 295.  296.  			if(moves%2 == 0 ||  297.  			  (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) { 298. 				extern struct monst *makemon; 299. 				movemon; 300. #ifdef HARD 301. 				if(!rn2(u.udemigod?25:(dlevel>30)?50:70)) 302. #else 303. 				if(!rn2(70)) 304. #endif 305. 				    (void) makemon((struct permonst *)0, 0, 0); 306. 			}  307.  			if(Glib) glibr; 308. 			timeout; 309. 			++moves; 310. #ifdef PRAYERS 311. 			if (u.ublesscnt)  u.ublesscnt--; 312. #endif 313. #ifndef DGK 314. 			if(flags.time) flags.botl = 1; 315. #endif 316. #ifdef KAA 317. 			if(u.mtimedone) 318. 			    if(u.mh < 1) rehumanize; 319. 			else 320. #endif 321. 			    if(u.uhp < 1) { 322. 				pline("You die..."); 323. 				done("died"); 324. 			    }  325.  			if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){ 326. 			    wailmsg = moves; 327. #ifdef KAA 328. 				if(index("WEV", pl_character[0])) { 329. 					if (u.uhp == 1) 330. 					   pline("%s is about to die.", pl_character); 331. 					else 332. 					   pline("%s, your life force is running out.",  333.  						pl_character); 334. 				} else { 335. #endif 336. 			    if(u.uhp == 1) 337. 			    pline("You hear the wailing of the Banshee..."); 338. 			    else 339. 			    pline("You hear the howling of the CwnAnnwn..."); 340. #ifdef KAA 341. 				}  342.  #endif 343. 			}  344.  #ifdef KAA 345. 			if (u.mtimedone) { 346. 			    if (u.mh < u.mhmax) { 347. 				if (Regeneration || !(moves%20)) { 348. 					flags.botl = 1; 349. 					u.mh++; 350. 				}  351.  			    }  352.  			}  353.  #endif 354. 			if(u.uhp < u.uhpmax) { 355. 				if(u.ulevel > 9) { 356. 					if(HRegeneration || !(moves%3)) { 357. 					    flags.botl = 1; 358. 					    u.uhp += rnd((int) u.ulevel-9); 359. 					    if(u.uhp > u.uhpmax) 360. 						u.uhp = u.uhpmax; 361. 					}  362.  				} else if(HRegeneration ||  363.  					(!(moves%(22-u.ulevel*2)))) { 364. 					flags.botl = 1; 365. 					u.uhp++; 366. 				}  367.  			}  368.  #ifdef SPELLS 369. 			if ((u.uen u.uenmax)  u.uen = u.uenmax; 372. 				flags.botl = 1; 373. 			}  374.  #endif 375. 			if(Teleportation && !rn2(85)) tele; 376. #if defined(KAA) && defined(BVH) 377. 			if(Polymorph && !rn2(100)) polyself; 378. #endif 379. 			if(Searching && multi >= 0) (void) dosearch; 380. 			gethungry; 381. 			invault; 382. 			amulet; 383. #ifdef HARD 384. 			if (!rn2(50+(u.ulevel*3))) u_wipe_engr(rnd(3)); 385. 			if (u.udemigod) { 386.  387.  				u.udg_cnt--; 388. 				if(u.udg_cnt <= 0) { 389.  390.  					intervene; 391. 					u.udg_cnt = rn1(200, 50); 392. 				}  393.  			}  394.  #endif 395. 		}  396.  		if(multi < 0) { 397. 			if(!++multi){ 398. 				pline(nomovemsg ? nomovemsg :  399.  					"You can move again."); 400. 				nomovemsg = 0; 401. 				if(afternmv) (*afternmv); 402. 				afternmv = 0; 403. 			}  404.  		}  405.   406.  		find_ac; 407. #ifndef QUEST 408. 		if(!flags.mv || Blind) 409. #endif 410. 		{  411.  			seeobjs; 412. 			seemons; 413. 			nscr; 414. 		}  415.  #ifdef DGK 416. 		if(flags.time) flags.botl = 1; 417. #endif 418. 		if(flags.botl || flags.botlx) bot; 419.  420.  		flags.move = 1; 421.  422.  		if(multi >= 0 && occupation) { 423. #ifdef DGK 424. 			abort = 0; 425. 			if (kbhit) { 426. 				if ((ch = getchar) == ABORT) 427. 					abort++; 428. # ifdef REDO 429. 				else 430. 					pushch(ch); 431. # endif 432. 			}  433.  			if (abort || monster_nearby) 434. 				stop_occupation; 435. 			else if ((*occupation) == 0) 436. 				occupation = 0; 437. 			if (!(++occtime % 7)) 438. 				(void) fflush(stdout); 439. #else 440. 			if (monster_nearby) 441. 				stop_occupation; 442. 			else if ((*occupation) == 0) 443. 				occupation = 0; 444. #endif 445. 			continue; 446. 		}  447.   448.  		if(multi > 0) { 449. #ifdef QUEST 450. 			if(flags.run >= 4) finddir; 451. #endif 452. 			lookaround; 453. 			if(!multi) {	/* lookaround may clear multi */ 454. 				flags.move = 0; 455. 				continue; 456. 			}  457.  			if(flags.mv) { 458. 				if(multi < COLNO && !--multi) 459. 					flags.mv = flags.run = 0; 460. 				domove; 461. 			} else { 462. 				--multi; 463. 				rhack(save_cm); 464. 			}  465.  		} else if(multi == 0) { 466. 			rhack((char *) 0); 467. 		}  468.  		if(multi && multi%7 == 0) 469. 			(void) fflush(stdout); 470. 	}  471.  }  472.   473.  #ifndef DGK 474. /* This function is unnecessary and incompatible with the #define 475.  * of glo(x) in config.h -dgk 476.  */  477.  glo(foo) 478. register foo; 479. {  480.  	/* construct the string  xlock.n  */ 481. 	register char *tf; 482.  483.  	tf = lock; 484. 	while(*tf && *tf != '.') tf++; 485. 	(void) sprintf(tf, ".%d", foo); 486. }  487.  #endif 488.  489.  /*  490.   * plname is filled either by an option (-u Player  or  -uPlayer) or  491. * explicitly (-w implies wizard) or by askname. 492.  * It may still contain a suffix denoting pl_character. 493.  */  494.  askname{ 495. register int c,ct; 496. 	printf("\nWho are you? "); 497. 	(void) fflush(stdout); 498. 	ct = 0; 499. 	while((c = getchar) != '\n'){ 500. #ifdef MSDOS 501. 		msmsg("%c", c); 502. #endif 503. 		if(c == EOF) error("End of input\n"); 504. 		/* some people get confused when their erase char is not ^H */ 505. 		if(c == '\010') { 506. 			if(ct) ct--; 507. 			continue; 508. 		}  509.  		if(c != '-') 510. 		if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_'; 511. 		if(ct < sizeof(plname)-1) plname[ct++] = c;  512. } 513.  	plname[ct] = 0; 514. 	if(ct == 0) askname; 515. }  516.   517.  /*VARARGS1*/ 518. impossible(s,x1,x2) 519. register char *s; 520. {  521.  	pline(s,x1,x2); 522. 	pline("Program in disorder - perhaps you'd better Quit."); 523. }  524.   525.  #ifdef CHDIR 526. chdirx(dir, wr) 527. char *dir; 528. boolean wr; 529. {  530.   531.  	if(dir && chdir(dir) < 0) { 532. 		error("Cannot chdir to %s.", dir); 533. 	}  534.   535.  #ifdef DGK 536. 	/* Change the default drive as well. 537. 	 */  538.  	chdrive(dir); 539. #endif 540.  541.  	/* warn the player if he cannot write the record file */ 542. 	/* perhaps we should also test whether. is writable */ 543. 	/* unfortunately the access systemcall is worthless */ 544. 	if(wr) { 545. 	    register fd; 546.  547.  	    if(dir == NULL) 548. 		dir = "."; 549. 	    if((fd = open(RECORD, 2)) < 0) { 550. #ifdef DGK 551. 		char tmp[PATHLEN]; 552.  553.  		strcpy(tmp, dir); 554. 		append_slash(tmp); 555. 		msmsg("Warning: cannot write %s%s\n", tmp, RECORD); 556. 		getreturn("to continue"); 557. #else 558. 		printf("Warning: cannot write %s/%s", dir, RECORD); 559. 		getret; 560. #endif 561. 	    } else 562. 		(void) close(fd); 563. 	}  564.  }  565.  #endif /* CHDIR /**/ 566.  567.  stop_occupation 568. {  569.  	if(occupation) { 570. 		pline("You stop %s.", occtxt); 571. 		occupation = 0; 572. #ifdef REDO 573. 		multi = 0; 574. 		pushch(0); 575. #endif 576. 	}  577.  }  578.   579.  #ifdef DGK 580. struct finfo	zfinfo = ZFINFO; 581.  582.  zero_finfo {	/* zero "fileinfo" array to prevent crashes on level change */ 583. 	int i;  584. 585. 	for (i = 0 ; i <= MAXLEVEL; i++) 586. 		fileinfo[i] = zfinfo; 587. }  588.  #endif