Source:NetHack 1.4f/pcmain.c

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