Source:NetHack 1.4f/pcmain.c
Jump to navigation
Jump to search
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
Screenshots and source code from Hack are used under the CWI license.
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 <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. 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) && (!(moves%(21-u.ulevel/2)))) { 358. u.uen += rn2(u.ulevel/4 + 1) + 1; 359. 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. }