abstract
| - 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
"); 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.
"); 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
"); 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
", *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 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("
Who are you? "); 480. (void) fflush(stdout); 481. ct = 0; 482. while((c = getchar()) != '
'){ 483. #ifdef MSDOS 484. msmsg("%c", c); 485. #endif 486. if(c == EOF) error("End of input
"); 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
", 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. }
|