Source:NetHack 2.2a/pcmain.c
Jump to navigation
Jump to search
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
Screenshots and source code from Hack are used under the CWI license.
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 <stdio.h> 6. #include <signal.h> 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) && (!(moves%(21-u.ulevel/2)))) { 370. u.uen += rn2(u.ulevel/4 + 1) + 1; 371. 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