hack.main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. /* $NetBSD: hack.main.c,v 1.9 2004/01/27 20:30:29 jsm Exp $ */
  2. /*
  3. * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
  4. * Amsterdam
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are
  9. * met:
  10. *
  11. * - Redistributions of source code must retain the above copyright notice,
  12. * this list of conditions and the following disclaimer.
  13. *
  14. * - Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. *
  18. * - Neither the name of the Stichting Centrum voor Wiskunde en
  19. * Informatica, nor the names of its contributors may be used to endorse or
  20. * promote products derived from this software without specific prior
  21. * written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  24. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  25. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  26. * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
  27. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  28. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  29. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  30. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  31. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  32. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  33. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. /*
  36. * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
  37. * All rights reserved.
  38. *
  39. * Redistribution and use in source and binary forms, with or without
  40. * modification, are permitted provided that the following conditions
  41. * are met:
  42. * 1. Redistributions of source code must retain the above copyright
  43. * notice, this list of conditions and the following disclaimer.
  44. * 2. Redistributions in binary form must reproduce the above copyright
  45. * notice, this list of conditions and the following disclaimer in the
  46. * documentation and/or other materials provided with the distribution.
  47. * 3. The name of the author may not be used to endorse or promote products
  48. * derived from this software without specific prior written permission.
  49. *
  50. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  51. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  52. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  53. * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  54. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  55. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  56. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  57. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  58. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  59. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  60. */
  61. #include <sys/cdefs.h>
  62. #ifndef lint
  63. __RCSID("$NetBSD: hack.main.c,v 1.9 2004/01/27 20:30:29 jsm Exp $");
  64. #endif /* not lint */
  65. #include <signal.h>
  66. #include <stdlib.h>
  67. #include <unistd.h>
  68. #include <fcntl.h>
  69. #include "hack.h"
  70. #include "extern.h"
  71. #ifdef QUEST
  72. #define gamename "quest"
  73. #else
  74. #define gamename "hack"
  75. #endif
  76. int (*afternmv)(void);
  77. int (*occupation)(void);
  78. const char *occtxt; /* defined when occupation != NULL */
  79. int hackpid; /* current pid */
  80. int locknum; /* max num of players */
  81. #ifdef DEF_PAGER
  82. const char *catmore; /* default pager */
  83. #endif
  84. char SAVEF[PL_NSIZ + 11] = "save/"; /* save/99999player */
  85. char *hname; /* name of the game (argv[0] of call) */
  86. char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */
  87. int main(int, char *[]);
  88. static void chdirx(const char *, boolean);
  89. int
  90. main(argc, argv)
  91. int argc;
  92. char *argv[];
  93. {
  94. int fd;
  95. #ifdef CHDIR
  96. char *dir;
  97. #endif
  98. /* Check for dirty tricks with closed fds 0, 1, 2 */
  99. fd = open("/dev/null", O_RDONLY);
  100. if (fd < 3)
  101. exit(1);
  102. close(fd);
  103. hname = argv[0];
  104. hackpid = getpid();
  105. #ifdef CHDIR /* otherwise no chdir() */
  106. /*
  107. * See if we must change directory to the playground.
  108. * (Perhaps hack runs suid and playground is inaccessible
  109. * for the player.)
  110. * The environment variable HACKDIR is overridden by a
  111. * -d command line option (must be the first option given)
  112. */
  113. dir = getenv("HACKDIR");
  114. if (argc > 1 && !strncmp(argv[1], "-d", 2)) {
  115. argc--;
  116. argv++;
  117. dir = argv[0] + 2;
  118. if (*dir == '=' || *dir == ':')
  119. dir++;
  120. if (!*dir && argc > 1) {
  121. argc--;
  122. argv++;
  123. dir = argv[0];
  124. }
  125. if (!*dir)
  126. error("Flag -d must be followed by a directory name.");
  127. }
  128. #endif
  129. /*
  130. * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
  131. * 2. Use $USER or $LOGNAME (if 1. fails)
  132. * 3. Use getlogin() (if 2. fails)
  133. * The resulting name is overridden by command line options.
  134. * If everything fails, or if the resulting name is some generic
  135. * account like "games", "play", "player", "hack" then eventually
  136. * we'll ask him.
  137. * Note that we trust him here; it is possible to play under
  138. * somebody else's name.
  139. */
  140. {
  141. char *s;
  142. initoptions();
  143. if (!*plname && (s = getenv("USER")))
  144. (void) strncpy(plname, s, sizeof(plname) - 1);
  145. if (!*plname && (s = getenv("LOGNAME")))
  146. (void) strncpy(plname, s, sizeof(plname) - 1);
  147. if (!*plname && (s = getlogin()))
  148. (void) strncpy(plname, s, sizeof(plname) - 1);
  149. }
  150. /*
  151. * Now we know the directory containing 'record' and
  152. * may do a prscore().
  153. */
  154. if (argc > 1 && !strncmp(argv[1], "-s", 2)) {
  155. #ifdef CHDIR
  156. chdirx(dir, 0);
  157. #endif
  158. prscore(argc, argv);
  159. exit(0);
  160. }
  161. /*
  162. * It seems he really wants to play.
  163. * Remember tty modes, to be restored on exit.
  164. */
  165. gettty();
  166. setbuf(stdout, obuf);
  167. setrandom();
  168. startup();
  169. cls();
  170. u.uhp = 1; /* prevent RIP on early quits */
  171. u.ux = FAR; /* prevent nscr() */
  172. (void) signal(SIGHUP, hangup);
  173. /*
  174. * Find the creation date of this game,
  175. * so as to avoid restoring outdated savefiles.
  176. */
  177. gethdate(hname);
  178. /*
  179. * We cannot do chdir earlier, otherwise gethdate will fail.
  180. */
  181. #ifdef CHDIR
  182. chdirx(dir, 1);
  183. #endif
  184. /*
  185. * Process options.
  186. */
  187. while (argc > 1 && argv[1][0] == '-') {
  188. argv++;
  189. argc--;
  190. switch (argv[0][1]) {
  191. #ifdef WIZARD
  192. case 'D':
  193. /* if(!strcmp(getlogin(), WIZARD)) */
  194. wizard = TRUE;
  195. /*
  196. * else printf("Sorry.\n");
  197. */
  198. break;
  199. #endif
  200. #ifdef NEWS
  201. case 'n':
  202. flags.nonews = TRUE;
  203. break;
  204. #endif
  205. case 'u':
  206. if (argv[0][2])
  207. (void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1);
  208. else if (argc > 1) {
  209. argc--;
  210. argv++;
  211. (void) strncpy(plname, argv[0], sizeof(plname) - 1);
  212. } else
  213. printf("Player name expected after -u\n");
  214. break;
  215. default:
  216. /* allow -T for Tourist, etc. */
  217. (void) strncpy(pl_character, argv[0] + 1,
  218. sizeof(pl_character) - 1);
  219. /* printf("Unknown option: %s\n", *argv); */
  220. }
  221. }
  222. if (argc > 1)
  223. locknum = atoi(argv[1]);
  224. #ifdef MAX_NR_OF_PLAYERS
  225. if (!locknum || locknum > MAX_NR_OF_PLAYERS)
  226. locknum = MAX_NR_OF_PLAYERS;
  227. #endif
  228. #ifdef DEF_PAGER
  229. if (((catmore = getenv("HACKPAGER")) == NULL &&
  230. (catmore = getenv("PAGER")) == NULL) ||
  231. catmore[0] == '\0')
  232. catmore = DEF_PAGER;
  233. #endif
  234. #ifdef MAIL
  235. getmailstatus();
  236. #endif
  237. #ifdef WIZARD
  238. if (wizard)
  239. (void) strcpy(plname, "wizard");
  240. else
  241. #endif
  242. if (!*plname || !strncmp(plname, "player", 4)
  243. || !strncmp(plname, "games", 4))
  244. askname();
  245. plnamesuffix(); /* strip suffix from name; calls askname() */
  246. /* again if suffix was whole name */
  247. /* accepts any suffix */
  248. #ifdef WIZARD
  249. if (!wizard) {
  250. #endif
  251. /*
  252. * check for multiple games under the same name
  253. * (if !locknum) or check max nr of players (otherwise)
  254. */
  255. (void) signal(SIGQUIT, SIG_IGN);
  256. (void) signal(SIGINT, SIG_IGN);
  257. if (!locknum)
  258. (void) strcpy(lock, plname);
  259. getlock(); /* sets lock if locknum != 0 */
  260. #ifdef WIZARD
  261. } else {
  262. char *sfoo;
  263. (void) strcpy(lock, plname);
  264. if ((sfoo = getenv("MAGIC")) != NULL)
  265. while (*sfoo) {
  266. switch (*sfoo++) {
  267. case 'n':
  268. (void) srandom(*sfoo++);
  269. break;
  270. }
  271. }
  272. if ((sfoo = getenv("GENOCIDED")) != NULL) {
  273. if (*sfoo == '!') {
  274. const struct permonst *pm = mons;
  275. char *gp = genocided;
  276. while (pm < mons + CMNUM + 2) {
  277. if (!strchr(sfoo, pm->mlet))
  278. *gp++ = pm->mlet;
  279. pm++;
  280. }
  281. *gp = 0;
  282. } else
  283. (void) strcpy(genocided, sfoo);
  284. (void) strcpy(fut_geno, genocided);
  285. }
  286. }
  287. #endif
  288. setftty();
  289. (void) sprintf(SAVEF, "save/%d%s", getuid(), plname);
  290. regularize(SAVEF + 5); /* avoid . or / in name */
  291. if ((fd = open(SAVEF, O_RDONLY)) >= 0 &&
  292. (uptodate(fd) || unlink(SAVEF) == 666)) {
  293. (void) signal(SIGINT, done1);
  294. pline("Restoring old save file...");
  295. (void) fflush(stdout);
  296. if (!dorecover(fd))
  297. goto not_recovered;
  298. pline("Hello %s, welcome to %s!", plname, gamename);
  299. flags.move = 0;
  300. } else {
  301. not_recovered:
  302. fobj = fcobj = invent = 0;
  303. fmon = fallen_down = 0;
  304. ftrap = 0;
  305. fgold = 0;
  306. flags.ident = 1;
  307. init_objects();
  308. u_init();
  309. (void) signal(SIGINT, done1);
  310. mklev();
  311. u.ux = xupstair;
  312. u.uy = yupstair;
  313. (void) inshop();
  314. setsee();
  315. flags.botlx = 1;
  316. makedog();
  317. {
  318. struct monst *mtmp;
  319. if ((mtmp = m_at(u.ux, u.uy)) != NULL)
  320. mnexto(mtmp); /* riv05!a3 */
  321. }
  322. seemons();
  323. #ifdef NEWS
  324. if (flags.nonews || !readnews())
  325. /* after reading news we did docrt() already */
  326. #endif
  327. docrt();
  328. /* give welcome message before pickup messages */
  329. pline("Hello %s, welcome to %s!", plname, gamename);
  330. pickup(1);
  331. read_engr_at(u.ux, u.uy);
  332. flags.move = 1;
  333. }
  334. flags.moonphase = phase_of_the_moon();
  335. if (flags.moonphase == FULL_MOON) {
  336. pline("You are lucky! Full moon tonight.");
  337. u.uluck++;
  338. } else if (flags.moonphase == NEW_MOON) {
  339. pline("Be careful! New moon tonight.");
  340. }
  341. initrack();
  342. for (;;) {
  343. if (flags.move) { /* actual time passed */
  344. settrack();
  345. if (moves % 2 == 0 ||
  346. (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
  347. movemon();
  348. if (!rn2(70))
  349. (void) makemon((struct permonst *) 0, 0, 0);
  350. }
  351. if (Glib)
  352. glibr();
  353. timeout();
  354. ++moves;
  355. if (flags.time)
  356. flags.botl = 1;
  357. if (u.uhp < 1) {
  358. pline("You die...");
  359. done("died");
  360. }
  361. if (u.uhp * 10 < u.uhpmax && moves - wailmsg > 50) {
  362. wailmsg = moves;
  363. if (u.uhp == 1)
  364. pline("You hear the wailing of the Banshee...");
  365. else
  366. pline("You hear the howling of the CwnAnnwn...");
  367. }
  368. if (u.uhp < u.uhpmax) {
  369. if (u.ulevel > 9) {
  370. if (Regeneration || !(moves % 3)) {
  371. flags.botl = 1;
  372. u.uhp += rnd((int) u.ulevel - 9);
  373. if (u.uhp > u.uhpmax)
  374. u.uhp = u.uhpmax;
  375. }
  376. } else if (Regeneration ||
  377. (!(moves % (22 - u.ulevel * 2)))) {
  378. flags.botl = 1;
  379. u.uhp++;
  380. }
  381. }
  382. if (Teleportation && !rn2(85))
  383. tele();
  384. if (Searching && multi >= 0)
  385. (void) dosearch();
  386. gethungry();
  387. invault();
  388. amulet();
  389. }
  390. if (multi < 0) {
  391. if (!++multi) {
  392. pline(nomovemsg ? nomovemsg :
  393. "You can move again.");
  394. nomovemsg = 0;
  395. if (afternmv)
  396. (*afternmv) ();
  397. afternmv = 0;
  398. }
  399. }
  400. find_ac();
  401. #ifndef QUEST
  402. if (!flags.mv || Blind)
  403. #endif
  404. {
  405. seeobjs();
  406. seemons();
  407. nscr();
  408. }
  409. if (flags.botl || flags.botlx)
  410. bot();
  411. flags.move = 1;
  412. if (multi >= 0 && occupation) {
  413. if (monster_nearby())
  414. stop_occupation();
  415. else if ((*occupation) () == 0)
  416. occupation = 0;
  417. continue;
  418. }
  419. if (multi > 0) {
  420. #ifdef QUEST
  421. if (flags.run >= 4)
  422. finddir();
  423. #endif
  424. lookaround();
  425. if (!multi) { /* lookaround may clear multi */
  426. flags.move = 0;
  427. continue;
  428. }
  429. if (flags.mv) {
  430. if (multi < COLNO && !--multi)
  431. flags.mv = flags.run = 0;
  432. domove();
  433. } else {
  434. --multi;
  435. rhack(save_cm);
  436. }
  437. } else if (multi == 0) {
  438. #ifdef MAIL
  439. ckmailstatus();
  440. #endif
  441. rhack((char *) 0);
  442. }
  443. if (multi && multi % 7 == 0)
  444. (void) fflush(stdout);
  445. }
  446. }
  447. void
  448. glo(foo)
  449. int foo;
  450. {
  451. /* construct the string xlock.n */
  452. char *tf;
  453. tf = lock;
  454. while (*tf && *tf != '.')
  455. tf++;
  456. (void) sprintf(tf, ".%d", foo);
  457. }
  458. /*
  459. * plname is filled either by an option (-u Player or -uPlayer) or
  460. * explicitly (-w implies wizard) or by askname.
  461. * It may still contain a suffix denoting pl_character.
  462. */
  463. void
  464. askname()
  465. {
  466. int c, ct;
  467. printf("\nWho are you? ");
  468. (void) fflush(stdout);
  469. ct = 0;
  470. while ((c = getchar()) != '\n') {
  471. if (c == EOF)
  472. error("End of input\n");
  473. /* some people get confused when their erase char is not ^H */
  474. if (c == '\010') {
  475. if (ct)
  476. ct--;
  477. continue;
  478. }
  479. if (c != '-')
  480. if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z')
  481. c = '_';
  482. if ((size_t)ct < sizeof(plname) - 1)
  483. plname[ct++] = c;
  484. }
  485. plname[ct] = 0;
  486. if (ct == 0)
  487. askname();
  488. }
  489. /* VARARGS1 */
  490. void
  491. impossible(const char *s, ...)
  492. {
  493. va_list ap;
  494. va_start(ap, s);
  495. vpline(s, ap);
  496. va_end(ap);
  497. pline("Program in disorder - perhaps you'd better Quit.");
  498. }
  499. #ifdef CHDIR
  500. static void
  501. chdirx(dir, wr)
  502. const char *dir;
  503. boolean wr;
  504. {
  505. #ifdef SECURE
  506. if (dir /* User specified directory? */
  507. #ifdef HACKDIR
  508. && strcmp(dir, HACKDIR) /* and not the default? */
  509. #endif
  510. ) {
  511. (void) setuid(getuid()); /* Ron Wessels */
  512. (void) setregid(getgid(), getgid());
  513. }
  514. #endif
  515. #ifdef HACKDIR
  516. if (dir == NULL)
  517. dir = HACKDIR;
  518. #endif
  519. if (dir && chdir(dir) < 0) {
  520. perror(dir);
  521. error("Cannot chdir to %s.", dir);
  522. }
  523. /* warn the player if he cannot write the record file */
  524. /* perhaps we should also test whether . is writable */
  525. /* unfortunately the access systemcall is worthless */
  526. if (wr) {
  527. int fd;
  528. if (dir == NULL)
  529. dir = ".";
  530. if ((fd = open(RECORD, O_RDWR)) < 0) {
  531. printf("Warning: cannot write %s/%s", dir, RECORD);
  532. getret();
  533. } else
  534. (void) close(fd);
  535. }
  536. }
  537. #endif
  538. void
  539. stop_occupation()
  540. {
  541. if (occupation) {
  542. pline("You stop %s.", occtxt);
  543. occupation = 0;
  544. }
  545. }