Source:NetHack 3.0.0/unixmain.c
Below is the full text to unixmain.c from the source code of NetHack 3.0.0. To link to a particular line, write [[NetHack 3.0.0/unixmain.c#line123]], for example.
Warning! This is the source code from an old release. For the latest release, see Source code
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.
1. /* SCCS Id: @(#)unixmain.c 3.0 89/01/13 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. /* NetHack may be freely redistributed. See license for details. */ 4. /* main.c - (Unix) version */ 5. 6. #include <signal.h> 7. #include <pwd.h> 8. 9. #include "hack.h" 10. 11. int hackpid = 0; /* current pid */ 12. int locknum = 0; /* max num of players */ 13. #ifdef DEF_PAGER 14. char *catmore = 0; /* default pager */ 15. #endif 16. char SAVEF[PL_NSIZ + 11] = "save/"; /* save/99999player */ 17. char *hname = 0; /* name of the game (argv[0] of call) */ 18. char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */ 19. 20. int (*occupation)() = DUMMY; 21. int (*afternmv)() = DUMMY; 22. #ifdef CHDIR 23. static void chdirx(); 24. #endif /* CHDIR */ 25. static void whoami(), newgame(); 26. 27. main(argc,argv) 28. int argc; 29. char *argv[]; 30. { 31. struct passwd *pw; 32. extern struct passwd *getpwuid(); 33. extern int x_maze_max, y_maze_max; 34. register int fd; 35. #ifdef CHDIR 36. register char *dir; 37. #endif 38. #ifdef COMPRESS 39. char cmd[80], old[80]; 40. #endif 41. hname = argv[0]; 42. hackpid = getpid(); 43. (void) umask(0); 44. 45. #ifdef CHDIR /* otherwise no chdir() */ 46. /* 47. * See if we must change directory to the playground. 48. * (Perhaps hack runs suid and playground is inaccessible 49. * for the player.) 50. * The environment variable HACKDIR is overridden by a 51. * -d command line option (must be the first option given) 52. */ 53. 54. dir = getenv("HACKDIR"); 55. if(argc > 1 && !strncmp(argv[1], "-d", 2)) { 56. argc--; 57. argv++; 58. dir = argv[0]+2; 59. if(*dir == '=' || *dir == ':') dir++; 60. if(!*dir && argc > 1) { 61. argc--; 62. argv++; 63. dir = argv[0]; 64. } 65. if(!*dir) 66. error("Flag -d must be followed by a directory name."); 67. } 68. #endif /* CHDIR /**/ 69. /* Set the default values of the presentation characters */ 70. (void) memcpy((char *) &showsyms, 71. (char *) &defsyms, sizeof(struct symbols)); 72. initoptions(); 73. whoami(); 74. /* 75. * Now we know the directory containing 'record' and 76. * may do a prscore(). 77. */ 78. if(argc > 1 && !strncmp(argv[1], "-s", 2)) { 79. #ifdef CHDIR 80. chdirx(dir,0); 81. #endif 82. prscore(argc, argv); 83. exit(0); 84. } 85. 86. /* 87. * It seems he really wants to play. 88. * Remember tty modes, to be restored on exit. 89. */ 90. gettty(); 91. setbuf(stdout,obuf); 92. setrandom(); 93. startup(); 94. cls(); 95. u.uhp = 1; /* prevent RIP on early quits */ 96. u.ux = FAR; /* prevent nscr() */ 97. (void) signal(SIGHUP, (SIG_RET_TYPE) hangup); 98. 99. /* 100. * Find the creation date of this game, 101. * so as to avoid restoring outdated savefiles. 102. */ 103. gethdate(hname); 104. 105. /* 106. * We cannot do chdir earlier, otherwise gethdate will fail. 107. */ 108. #ifdef CHDIR 109. chdirx(dir,1); 110. #endif 111. 112. /* 113. * Process options. 114. */ 115. while(argc > 1 && argv[1][0] == '-'){ 116. argv++; 117. argc--; 118. switch(argv[0][1]){ 119. #if defined(WIZARD) || defined(EXPLORE_MODE) 120. case 'D': 121. case 'X': 122. pw = getpwuid(getuid()); 123. # ifdef WIZARD 124. if(!strcmp(pw->pw_name, WIZARD)) 125. wizard = TRUE; 126. # endif 127. # if defined(WIZARD) && defined(EXPLORE_MODE) 128. else 129. # endif 130. # ifdef EXPLORE_MODE 131. discover = TRUE; 132. # endif 133. break; 134. #endif 135. #ifdef NEWS 136. case 'n': 137. flags.nonews = TRUE; 138. break; 139. #endif 140. case 'u': 141. if(argv[0][2]) 142. (void) strncpy(plname, argv[0]+2, sizeof(plname)-1); 143. else if(argc > 1) { 144. argc--; 145. argv++; 146. (void) strncpy(plname, argv[0], sizeof(plname)-1); 147. } else 148. Printf("Player name expected after -u\n"); 149. break; 150. default: 151. /* allow -T for Tourist, etc. */ 152. (void) strncpy(pl_character, argv[0]+1, 153. sizeof(pl_character)-1); 154. 155. /* Printf("Unknown option: %s\n", *argv); */ 156. } 157. } 158. 159. if(argc > 1) 160. locknum = atoi(argv[1]); 161. #ifdef MAX_NR_OF_PLAYERS 162. if(!locknum || locknum > MAX_NR_OF_PLAYERS) 163. locknum = MAX_NR_OF_PLAYERS; 164. #endif 165. #ifdef DEF_PAGER 166. if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER"))) 167. catmore = DEF_PAGER; 168. #endif 169. #ifdef MAIL 170. getmailstatus(); 171. #endif 172. #ifdef WIZARD 173. if(wizard) Strcpy(plname, "wizard"); else 174. #endif 175. if(!*plname || !strncmp(plname, "player", 4) 176. || !strncmp(plname, "games", 4)) 177. askname(); 178. plnamesuffix(); /* strip suffix from name; calls askname() */ 179. /* again if suffix was whole name */ 180. /* accepts any suffix */ 181. #ifdef WIZARD 182. if(!wizard) { 183. #endif 184. /* 185. * check for multiple games under the same name 186. * (if !locknum) or check max nr of players (otherwise) 187. */ 188. (void) signal(SIGQUIT,SIG_IGN); 189. (void) signal(SIGINT,SIG_IGN); 190. if(!locknum) 191. Strcpy(lock,plname); 192. getlock(); /* sets lock if locknum != 0 */ 193. #ifdef WIZARD 194. } else 195. Strcpy(lock,plname); 196. #endif /* WIZARD /**/ 197. setftty(); 198. 199. /* 200. * Initialisation of the boundaries of the mazes 201. * Both boundaries have to be even. 202. */ 203. 204. x_maze_max = COLNO-1; 205. if (x_maze_max % 2) 206. x_maze_max--; 207. y_maze_max = ROWNO-1; 208. if (y_maze_max % 2) 209. y_maze_max--; 210. 211. /* initialize static monster strength array */ 212. init_monstr(); 213. 214. Sprintf(SAVEF, "save/%d%s", getuid(), plname); 215. regularize(SAVEF+5); /* avoid . or / in name */ 216. #ifdef COMPRESS 217. Strcpy(old,SAVEF); 218. Strcat(SAVEF,".Z"); 219. if((fd = open(SAVEF,0)) >= 0) { 220. (void) close(fd); 221. Strcpy(cmd, COMPRESS); 222. Strcat(cmd, " -d "); /* uncompress */ 223. # ifdef COMPRESS_OPTIONS 224. Strcat(cmd, COMPRESS_OPTIONS); 225. Strcat(cmd, " "); 226. # endif 227. Strcat(cmd,SAVEF); 228. (void) system(cmd); 229. } 230. Strcpy(SAVEF,old); 231. #endif 232. if((fd = open(SAVEF,0)) >= 0 && 233. (uptodate(fd) || unlink(SAVEF) == 666)) { 234. (void) signal(SIGINT, (SIG_RET_TYPE) done1); 235. pline("Restoring old save file..."); 236. (void) fflush(stdout); 237. if(!dorecover(fd)) 238. goto not_recovered; 239. pline("Hello %s, welcome to NetHack!", plname); 240. /* get shopkeeper set properly if restore is in shop */ 241. (void) inshop(); 242. #ifdef EXPLORE_MODE 243. if (discover) { 244. You("are in non-scoring discovery mode."); 245. pline("Do you want to keep the save file? "); 246. if(yn() == 'n') 247. (void) unlink(SAVEF); 248. } 249. #endif 250. flags.move = 0; 251. } else { 252. not_recovered: 253. newgame(); 254. /* give welcome message before pickup messages */ 255. pline("Hello %s, welcome to NetHack!", plname); 256. #ifdef EXPLORE_MODE 257. if (discover) 258. You("are in non-scoring discovery mode."); 259. #endif 260. flags.move = 0; 261. set_wear(); 262. pickup(1); 263. read_engr_at(u.ux,u.uy); 264. } 265. 266. flags.moonphase = phase_of_the_moon(); 267. if(flags.moonphase == FULL_MOON) { 268. You("are lucky! Full moon tonight."); 269. if(!u.uluck) change_luck(1); 270. } else if(flags.moonphase == NEW_MOON) { 271. pline("Be careful! New moon tonight."); 272. } 273. 274. initrack(); 275. 276. for(;;) { 277. if(flags.move) { /* actual time passed */ 278. 279. #ifdef SOUNDS 280. dosounds(); 281. #endif 282. settrack(); 283. 284. if(moves%2 == 0 || 285. (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) { 286. movemon(); 287. #ifdef HARD 288. if(!rn2(u.udemigod?25:(dlevel>30)?50:70)) 289. #else 290. if(!rn2(70)) 291. #endif 292. (void) makemon((struct permonst *)0, 0, 0); 293. } 294. if(Glib) glibr(); 295. timeout(); 296. ++moves; 297. #ifdef THEOLOGY 298. if (u.ublesscnt) u.ublesscnt--; 299. #endif 300. if(flags.time) flags.botl = 1; 301. #ifdef POLYSELF 302. if(u.mtimedone) 303. if(u.mh < 1) rehumanize(); 304. else 305. #endif 306. if(u.uhp < 1) { 307. You("die..."); 308. done("died"); 309. }
Lines 301 through 309 are an example of a "dangling else", and NetHack 3.0 is rife with them. This particular one is likely a bug. The "else" at line 304 pairs with the "if" at line 303, and not the one at line 302 as the indentation seems to imply. This is an example of why you should use braces when in doubt, and pay attention to your compiler warnings.
In NetHack 3.1.0, the corresponding section is allmain.c, line 96, and the first part is properly braced.
310. #ifdef POLYSELF 311. if (u.mtimedone) { 312. if (u.mh < u.mhmax) { 313. if (Regeneration || !(moves%20)) { 314. flags.botl = 1; 315. u.mh++; 316. } 317. } 318. } 319. #endif 320. if(u.uhp < u.uhpmax) { 321. if(u.ulevel > 9) { 322. int heal; 323. 324. if(HRegeneration || !(moves%3)) { 325. flags.botl = 1; 326. if (ACURR(A_CON) <= 12) heal = 1; 327. else heal = rnd((int) ACURR(A_CON)-12); 328. if (heal > u.ulevel-9) heal = u.ulevel-9; 329. u.uhp += heal; 330. if(u.uhp > u.uhpmax) 331. u.uhp = u.uhpmax; 332. } 333. } else if(HRegeneration || 334. (!(moves%((MAXULEV+12)/(u.ulevel+2)+1)))) { 335. flags.botl = 1; 336. u.uhp++; 337. } 338. } 339. #ifdef SPELLS 340. if ((u.uen<u.uenmax) && (!(moves%(19-ACURR(A_INT)/2)))) { 341. u.uen += rn2((int)ACURR(A_WIS)/5 + 1) + 1; 342. if (u.uen > u.uenmax) u.uen = u.uenmax; 343. flags.botl = 1; 344. } 345. #endif 346. if(Teleportation && !rn2(85)) tele(); 347. #ifdef POLYSELF 348. if(Polymorph && !rn2(100)) polyself(); 349. if(u.ulycn >= 0 && !rn2(80 - (20 * night()))) 350. you_were(); 351. #endif 352. if(Searching && multi >= 0) (void) dosearch0(1); 353. hatch_eggs(); 354. gethungry(); 355. invault(); 356. amulet(); 357. #ifdef HARD 358. if (!rn2(40+(int)(ACURR(A_DEX)*3))) u_wipe_engr(rnd(3)); 359. if (u.udemigod) { 360. 361. if(u.udg_cnt) u.udg_cnt--; 362. if(!u.udg_cnt) { 363. 364. intervene(); 365. u.udg_cnt = rn1(200, 50); 366. } 367. } 368. #endif 369. restore_attrib(); 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. if(!flags.mv || Blind) 383. { 384. seeobjs(); 385. seemons(); 386. seeglds(); 387. nscr(); 388. } 389. if(flags.botl || flags.botlx) bot(); 390. 391. flags.move = 1; 392. 393. if(multi >= 0 && occupation) { 394. 395. if(monster_nearby()) 396. stop_occupation(); 397. else if ((*occupation)() == 0) 398. occupation = 0; 399. continue; 400. } 401. 402. if((u.uhave_amulet || Clairvoyant) && 403. #ifdef ENDGAME 404. dlevel != ENDLEVEL && 405. #endif 406. !(moves%15) && !rn2(2)) do_vicinity_map(); 407. 408. u.umoved = FALSE; 409. if(multi > 0) { 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(NULL); 428. } 429. if(multi && multi%7 == 0) 430. (void) fflush(stdout); 431. } 432. } 433. 434. void 435. glo(foo) 436. register int foo; 437. { 438. /* construct the string xlock.n */ 439. register char *tf; 440. 441. tf = lock; 442. while(*tf && *tf != '.') tf++; 443. Sprintf(tf, ".%d", foo); 444. } 445. 446. /* 447. * plname is filled either by an option (-u Player or -uPlayer) or 448. * explicitly (by being the wizard) or by askname. 449. * It may still contain a suffix denoting pl_character. 450. */ 451. void 452. askname(){ 453. register int c,ct; 454. Printf("\nWho are you? "); 455. (void) fflush(stdout); 456. ct = 0; 457. while((c = Getchar()) != '\n'){ 458. if(c == EOF) error("End of input\n"); 459. /* some people get confused when their erase char is not ^H */ 460. if(c == '\010') { 461. if(ct) ct--; 462. continue; 463. } 464. if(c != '-') 465. if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_'; 466. if(ct < sizeof(plname)-1) plname[ct++] = c; 467. } 468. plname[ct] = 0; 469. if(ct == 0) askname(); 470. } 471. 472. /*VARARGS1*/ 473. void 474. impossible(s,x1,x2) 475. register char *s, *x1, *x2; 476. { 477. pline(s,x1,x2); 478. pline("Program in disorder - perhaps you'd better Quit."); 479. } 480. 481. #ifdef CHDIR 482. static void 483. chdirx(dir, wr) 484. char *dir; 485. boolean wr; 486. { 487. 488. # ifdef SECURE 489. if(dir /* User specified directory? */ 490. # ifdef HACKDIR 491. && strcmp(dir, HACKDIR) /* and not the default? */ 492. # endif 493. ) { 494. (void) setgid(getgid()); 495. (void) setuid(getuid()); /* Ron Wessels */ 496. } 497. # endif 498. 499. # ifdef HACKDIR 500. if(dir == NULL) 501. dir = HACKDIR; 502. # endif 503. 504. if(dir && chdir(dir) < 0) { 505. perror(dir); 506. error("Cannot chdir to %s.", dir); 507. } 508. 509. /* warn the player if he cannot write the record file */ 510. /* perhaps we should also test whether . is writable */ 511. /* unfortunately the access systemcall is worthless */ 512. if(wr) { 513. register int fd; 514. 515. if(dir == NULL) 516. dir = "."; 517. if((fd = open(RECORD, 2)) < 0) { 518. Printf("Warning: cannot write %s/%s", dir, RECORD); 519. getret(); 520. } else 521. (void) close(fd); 522. } 523. } 524. #endif /* CHDIR /**/ 525. 526. void 527. stop_occupation() 528. { 529. if(occupation) { 530. You("stop %s.", occtxt); 531. occupation = 0; 532. #ifdef REDO 533. multi = 0; 534. pushch(0); 535. #endif 536. } 537. } 538. 539. static void 540. whoami() { 541. /* 542. * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS 543. * 2. Use $USER or $LOGNAME (if 1. fails) 544. * 3. Use getlogin() (if 2. fails) 545. * The resulting name is overridden by command line options. 546. * If everything fails, or if the resulting name is some generic 547. * account like "games", "play", "player", "hack" then eventually 548. * we'll ask him. 549. * Note that we trust him here; it is possible to play under 550. * somebody else's name. 551. */ 552. register char *s; 553. 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. static void 563. newgame() { 564. fobj = fcobj = invent = 0; 565. fmon = fallen_down = 0; 566. ftrap = 0; 567. fgold = 0; 568. flags.ident = 1; 569. 570. init_objects(); 571. u_init(); 572. 573. (void) signal(SIGINT, (SIG_RET_TYPE) done1); 574. 575. mklev(); 576. u.ux = xupstair; 577. u.uy = yupstair; 578. (void) inshop(); 579. 580. setsee(); 581. flags.botlx = 1; 582. 583. /* Move the monster from under you or else 584. * makedog() will fail when it calls makemon(). 585. * - ucsfcgl!kneller 586. */ 587. if(levl[u.ux][u.uy].mmask) mnexto(m_at(u.ux, u.uy)); 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. 597. return; 598. }