Source:NetHack 2.3e/unixmain.c
Jump to navigation
Jump to search
Below is the full text to unixmain.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: @(#)unixmain.c 2.3 88/01/21 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. /* main.c - (Unix) version */ 4. 5. #include <stdio.h> 6. #include <signal.h> 7. #include "hack.h" 8. 9. #ifdef QUEST 10. #define gamename "NetQuest" 11. #else 12. #define gamename "NetHack" 13. #endif 14. 15. extern char *getlogin(), *getenv(); 16. extern char plname[PL_NSIZ], pl_character[PL_CSIZ]; 17. 18. int (*afternmv)(); 19. int (*occupation)(); 20. 21. int done1(); 22. int hangup(); 23. 24. int hackpid; /* current pid */ 25. int locknum; /* max num of players */ 26. #ifdef DEF_PAGER 27. char *catmore; /* default pager */ 28. #endif 29. char SAVEF[PL_NSIZ + 11] = "save/"; /* save/99999player */ 30. char *hname; /* name of the game (argv[0] of call) */ 31. char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */ 32. 33. extern char *nomovemsg; 34. extern long wailmsg; 35. 36. main(argc,argv) 37. int argc; 38. char *argv[]; 39. { 40. register int fd; 41. #ifdef CHDIR 42. register char *dir; 43. #endif 44. 45. hname = argv[0]; 46. hackpid = getpid(); 47. 48. #ifdef CHDIR /* otherwise no chdir() */ 49. /* 50. * See if we must change directory to the playground. 51. * (Perhaps hack runs suid and playground is inaccessible 52. * for the player.) 53. * The environment variable HACKDIR is overridden by a 54. * -d command line option (must be the first option given) 55. */ 56. 57. dir = getenv("HACKDIR"); 58. if(argc > 1 && !strncmp(argv[1], "-d", 2)) { 59. argc--; 60. argv++; 61. dir = argv[0]+2; 62. if(*dir == '=' || *dir == ':') dir++; 63. if(!*dir && argc > 1) { 64. argc--; 65. argv++; 66. dir = argv[0]; 67. } 68. if(!*dir) 69. error("Flag -d must be followed by a directory name."); 70. } 71. #endif /* CHDIR /**/ 72. #ifdef GRAPHICS 73. /* Set the default values of the presentation characters */ 74. memcpy((char *) &showsyms, (char *) &defsyms, sizeof(struct symbols)); 75. #endif 76. #ifdef HACKOPTIONS 77. initoptions(); 78. #endif 79. whoami(); 80. /* 81. * Now we know the directory containing 'record' and 82. * may do a prscore(). 83. */ 84. if(argc > 1 && !strncmp(argv[1], "-s", 2)) { 85. #ifdef CHDIR 86. chdirx(dir,0); 87. #endif 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. (void) signal(SIGHUP, hangup); 105. 106. /* 107. * Find the creation date of this game, 108. * so as to avoid restoring outdated savefiles. 109. */ 110. gethdate(hname); 111. 112. /* 113. * We cannot do chdir earlier, otherwise gethdate will fail. 114. */ 115. #ifdef CHDIR 116. chdirx(dir,1); 117. #endif 118. 119. /* 120. * Process options. 121. */ 122. while(argc > 1 && argv[1][0] == '-'){ 123. argv++; 124. argc--; 125. switch(argv[0][1]){ 126. #ifdef WIZARD 127. case 'D': 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. break; 136. #endif 137. #ifdef NEWS 138. case 'n': 139. flags.nonews = TRUE; 140. break; 141. #endif 142. case 'u': 143. if(argv[0][2]) 144. (void) strncpy(plname, argv[0]+2, sizeof(plname)-1); 145. else if(argc > 1) { 146. argc--; 147. argv++; 148. (void) strncpy(plname, argv[0], sizeof(plname)-1); 149. } else 150. printf("Player name expected after -u\n"); 151. break; 152. default: 153. /* allow -T for Tourist, etc. */ 154. (void) strncpy(pl_character, argv[0]+1, 155. sizeof(pl_character)-1); 156. 157. /* printf("Unknown option: %s\n", *argv); */ 158. } 159. } 160. 161. if(argc > 1) 162. locknum = atoi(argv[1]); 163. #ifdef MAX_NR_OF_PLAYERS 164. if(!locknum || locknum > MAX_NR_OF_PLAYERS) 165. locknum = MAX_NR_OF_PLAYERS; 166. #endif 167. #ifdef DEF_PAGER 168. if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER"))) 169. catmore = DEF_PAGER; 170. #endif 171. #ifdef MAIL 172. getmailstatus(); 173. #endif 174. #ifdef WIZARD 175. if(wizard) (void) strcpy(plname, "wizard"); else 176. #endif 177. if(!*plname || !strncmp(plname, "player", 4) 178. || !strncmp(plname, "games", 4)) 179. askname(); 180. plnamesuffix(); /* strip suffix from name; calls askname() */ 181. /* again if suffix was whole name */ 182. /* accepts any suffix */ 183. #ifdef WIZARD 184. if(!wizard) { 185. #endif 186. /* 187. * check for multiple games under the same name 188. * (if !locknum) or check max nr of players (otherwise) 189. */ 190. (void) signal(SIGQUIT,SIG_IGN); 191. (void) signal(SIGINT,SIG_IGN); 192. if(!locknum) 193. (void) strcpy(lock,plname); 194. getlock(); /* sets lock if locknum != 0 */ 195. #ifdef WIZARD 196. } else { 197. register char *sfoo; 198. extern char genocided[], fut_geno[]; 199. (void) strcpy(lock,plname); 200. if(sfoo = getenv("MAGIC")) 201. while(*sfoo) { 202. switch(*sfoo++) { 203. case 'n': (void) srand(*sfoo++); 204. break; 205. } 206. } 207. if(sfoo = getenv("GENOCIDED")){ 208. if(*sfoo == '!'){ 209. extern struct permonst mons[CMNUM+2]; 210. register struct permonst *pm = mons; 211. register char *gp = genocided; 212. 213. while(pm < mons+CMNUM+2){ 214. if(!index(sfoo, pm->mlet)) 215. *gp++ = pm->mlet; 216. pm++; 217. } 218. *gp = 0; 219. } else 220. (void) strcpy(genocided, sfoo); 221. (void) strcpy(fut_geno, genocided); 222. } 223. } 224. #endif /* WIZARD /**/ 225. setftty(); 226. (void) sprintf(SAVEF, "save/%d%s", getuid(), plname); 227. regularize(SAVEF+5); /* avoid . or / in name */ 228. if((fd = open(SAVEF,0)) >= 0 && 229. (uptodate(fd) || unlink(SAVEF) == 666)) { 230. (void) signal(SIGINT,done1); 231. pline("Restoring old save file..."); 232. (void) fflush(stdout); 233. if(!dorecover(fd)) 234. goto not_recovered; 235. pline("Hello %s%s, welcome to %s!", 236. (Badged) ? "Officer " : "", plname, gamename); 237. flags.move = 0; 238. } else { 239. not_recovered: 240. newgame(); 241. /* give welcome message before pickup messages */ 242. pline("Hello %s, welcome to %s!", plname, gamename); 243. #ifdef WIZARD 244. if (wizard && dlevel == 1) 245. # ifdef STOOGES 246. pline ("The wiz is at %d, the medusa is at %d, and the stooges are at %d", 247. u.wiz_level, u.medusa_level, u.stooge_level); 248. # else 249. pline ("The wiz is at %d, and the medusa at %d", 250. u.wiz_level, u.medusa_level); 251. # endif 252. #endif 253. pickup(1); 254. read_engr_at(u.ux,u.uy); 255. flags.move = 1; 256. } 257. 258. flags.moonphase = phase_of_the_moon(); 259. if(flags.moonphase == FULL_MOON) { 260. pline("You are lucky! Full moon tonight."); 261. if(!u.uluck) change_luck(1); 262. } else if(flags.moonphase == NEW_MOON) { 263. pline("Be careful! New moon tonight."); 264. } 265. 266. initrack(); 267. 268. for(;;) { 269. if(flags.move) { /* actual time passed */ 270. 271. settrack(); 272. 273. if(moves%2 == 0 || 274. (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) { 275. extern struct monst *makemon(); 276. movemon(); 277. #ifdef HARD 278. if(!rn2(u.udemigod?25:(dlevel>30)?50:70)) 279. #else 280. if(!rn2(70)) 281. #endif 282. (void) makemon((struct permonst *)0, 0, 0); 283. } 284. if(Glib) glibr(); 285. timeout(); 286. ++moves; 287. #ifdef PRAYERS 288. if (u.ublesscnt) u.ublesscnt--; 289. #endif 290. if(flags.time) flags.botl = 1; 291. #ifdef KAA 292. if(u.mtimedone) 293. if(u.mh < 1) rehumanize(); 294. else 295. #endif 296. if(u.uhp < 1) { 297. pline("You die..."); 298. done("died"); 299. } 300. if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){ 301. wailmsg = moves; 302. #ifdef KAA 303. if(index("WEV", pl_character[0])) { 304. if (u.uhp == 1) 305. pline("%s is about to die.", pl_character); 306. else 307. pline("%s, your life force is running out.", 308. pl_character); 309. } else { 310. #endif 311. if(u.uhp == 1) 312. pline("You hear the wailing of the Banshee..."); 313. else 314. pline("You hear the howling of the CwnAnnwn..."); 315. #ifdef KAA 316. } 317. #endif 318. } 319. #ifdef KAA 320. if (u.mtimedone) { 321. if (u.mh < u.mhmax) { 322. if (Regeneration || !(moves%20)) { 323. flags.botl = 1; 324. u.mh++; 325. } 326. } 327. } 328. #endif 329. if(u.uhp < u.uhpmax) { 330. if(u.ulevel > 9) { 331. if(HRegeneration || !(moves%3)) { 332. flags.botl = 1; 333. u.uhp += rnd((int) u.ulevel-9); 334. if(u.uhp > u.uhpmax) 335. u.uhp = u.uhpmax; 336. } 337. } else if(HRegeneration || 338. (!(moves%(22-u.ulevel*2)))) { 339. flags.botl = 1; 340. u.uhp++; 341. } 342. } 343. #ifdef SPELLS 344. if ((u.uen<u.uenmax) && (!(moves%(21-u.ulevel/2)))) { 345. u.uen += rn2(u.ulevel/4 + 1) + 1; 346. if (u.uen > u.uenmax) u.uen = u.uenmax; 347. flags.botl = 1; 348. } 349. #endif 350. if(Teleportation && !rn2(85)) tele(); 351. #if defined(KAA) && defined(BVH) 352. if(Polymorph && !rn2(100)) polyself(); 353. #endif 354. if(Searching && multi >= 0) (void) dosearch(); 355. gethungry(); 356. invault(); 357. amulet(); 358. #ifdef HARD 359. if (!rn2(50+(u.ulevel*3))) u_wipe_engr(rnd(3)); 360. if (u.udemigod) { 361. 362. u.udg_cnt--; 363. if(u.udg_cnt <= 0) { 364. 365. intervene(); 366. u.udg_cnt = rn1(200, 50); 367. } 368. } 369. #endif 370. } 371. if(multi < 0) { 372. if(!++multi){ 373. pline(nomovemsg ? nomovemsg : 374. "You can move again."); 375. nomovemsg = 0; 376. if(afternmv) (*afternmv)(); 377. afternmv = 0; 378. } 379. } 380. 381. find_ac(); 382. #ifndef QUEST 383. if(!flags.mv || Blind) 384. #endif 385. { 386. seeobjs(); 387. seemons(); 388. nscr(); 389. } 390. #ifdef DGK 391. if(flags.time) flags.botl = 1; 392. #endif 393. if(flags.botl || flags.botlx) bot(); 394. 395. flags.move = 1; 396. 397. if(multi >= 0 && occupation) { 398. 399. if (monster_nearby()) 400. stop_occupation(); 401. else if ((*occupation)() == 0) 402. occupation = 0; 403. continue; 404. } 405. 406. if(multi > 0) { 407. #ifdef QUEST 408. if(flags.run >= 4) finddir(); 409. #endif 410. lookaround(); 411. if(!multi) { /* lookaround may clear multi */ 412. flags.move = 0; 413. continue; 414. } 415. if(flags.mv) { 416. if(multi < COLNO && !--multi) 417. flags.mv = flags.run = 0; 418. domove(); 419. } else { 420. --multi; 421. rhack(save_cm); 422. } 423. } else if(multi == 0) { 424. #ifdef MAIL 425. ckmailstatus(); 426. #endif 427. rhack((char *) 0); 428. } 429. if(multi && multi%7 == 0) 430. (void) fflush(stdout); 431. } 432. } 433. 434. glo(foo) 435. register foo; 436. { 437. /* construct the string xlock.n */ 438. register char *tf; 439. 440. tf = lock; 441. while(*tf && *tf != '.') tf++; 442. (void) sprintf(tf, ".%d", foo); 443. } 444. 445. /* 446. * plname is filled either by an option (-u Player or -uPlayer) or 447. * explicitly (-w implies wizard) or by askname. 448. * It may still contain a suffix denoting pl_character. 449. */ 450. askname(){ 451. register int c,ct; 452. printf("\nWho are you? "); 453. (void) fflush(stdout); 454. ct = 0; 455. while((c = getchar()) != '\n'){ 456. if(c == EOF) error("End of input\n"); 457. /* some people get confused when their erase char is not ^H */ 458. if(c == '\010') { 459. if(ct) ct--; 460. continue; 461. } 462. if(c != '-') 463. if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_'; 464. if(ct < sizeof(plname)-1) plname[ct++] = c; 465. } 466. plname[ct] = 0; 467. if(ct == 0) askname(); 468. } 469. 470. /*VARARGS1*/ 471. impossible(s,x1,x2) 472. register char *s; 473. { 474. pline(s,x1,x2); 475. pline("Program in disorder - perhaps you'd better Quit."); 476. } 477. 478. #ifdef CHDIR 479. static 480. chdirx(dir, wr) 481. char *dir; 482. boolean wr; 483. { 484. 485. # ifdef SECURE 486. if(dir /* User specified directory? */ 487. # ifdef HACKDIR 488. && strcmp(dir, HACKDIR) /* and not the default? */ 489. # endif 490. ) { 491. (void) setuid(getuid()); /* Ron Wessels */ 492. (void) setgid(getgid()); 493. } 494. # endif 495. 496. # ifdef HACKDIR 497. if(dir == NULL) 498. dir = HACKDIR; 499. # endif 500. 501. if(dir && chdir(dir) < 0) { 502. perror(dir); 503. error("Cannot chdir to %s.", dir); 504. } 505. 506. /* warn the player if he cannot write the record file */ 507. /* perhaps we should also test whether . is writable */ 508. /* unfortunately the access systemcall is worthless */ 509. if(wr) { 510. register fd; 511. 512. if(dir == NULL) 513. dir = "."; 514. if((fd = open(RECORD, 2)) < 0) { 515. printf("Warning: cannot write %s/%s", dir, RECORD); 516. getret(); 517. } else 518. (void) close(fd); 519. } 520. } 521. #endif /* CHDIR /**/ 522. 523. stop_occupation() 524. { 525. extern void pushch(); 526. 527. if(occupation) { 528. pline("You stop %s.", occtxt); 529. occupation = 0; 530. #ifdef REDO 531. multi = 0; 532. pushch(0); 533. #endif 534. } 535. } 536. 537. whoami() { 538. /* 539. * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS 540. * 2. Use $USER or $LOGNAME (if 1. fails) 541. * 3. Use getlogin() (if 2. fails) 542. * The resulting name is overridden by command line options. 543. * If everything fails, or if the resulting name is some generic 544. * account like "games", "play", "player", "hack" then eventually 545. * we'll ask him. 546. * Note that we trust him here; it is possible to play under 547. * somebody else's name. 548. */ 549. register char *s; 550. 551. #ifndef DGKMOD 552. initoptions(); 553. #endif 554. if(!*plname && (s = getenv("USER"))) 555. (void) strncpy(plname, s, sizeof(plname)-1); 556. if(!*plname && (s = getenv("LOGNAME"))) 557. (void) strncpy(plname, s, sizeof(plname)-1); 558. if(!*plname && (s = getlogin())) 559. (void) strncpy(plname, s, sizeof(plname)-1); 560. } 561. 562. newgame() { 563. extern struct monst *makedog(); 564. 565. fobj = fcobj = invent = 0; 566. fmon = fallen_down = 0; 567. ftrap = 0; 568. fgold = 0; 569. flags.ident = 1; 570. init_objects(); 571. u_init(); 572. 573. (void) signal(SIGINT,done1); 574. mklev(); 575. u.ux = xupstair; 576. u.uy = yupstair; 577. (void) inshop(); 578. setsee(); 579. flags.botlx = 1; 580. { 581. register struct monst *mtmp; 582. 583. /* Move the monster from under you or else 584. * makedog() will fail when it calls makemon(). 585. * - ucsfcgl!kneller 586. */ 587. if (mtmp = m_at(u.ux, u.uy)) mnexto(mtmp); 588. } 589. (void) makedog(); 590. seemons(); 591. #ifdef NEWS 592. if(flags.nonews || !readnews()) 593. /* after reading news we did docrt() already */ 594. #endif 595. docrt(); 596. return(0); 597. } 598. 599. #ifdef GENIX 600. jhndist(x1,y1,x2,y2) 601. { 602. int x,y; 603. x=x1-x2; 604. y=y1-y2; 605. return (x*x + y*y); 606. } 607. #endif