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