Source:NetHack 2.3e/pcmain.c

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