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