Source:NetHack 2.3e/pcmain.c
Jump to navigation
Jump to search
Below is the full text to pcmain.c from the source code of NetHack 2.3e.
Warning! This is the source code from an old release. For newer releases, see Source code
Screenshots and source code from Hack are used under the CWI license.
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 <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. 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) && (!(moves%(21-u.ulevel/2)))) { 383. u.uen += rn2(u.ulevel/4 + 1) + 1; 384. 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