Source:NetHack 1.3d/pcmain.c

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