123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- /* $NetBSD: hack.main.c,v 1.9 2004/01/27 20:30:29 jsm Exp $ */
- /*
- * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
- * Amsterdam
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of the Stichting Centrum voor Wiskunde en
- * Informatica, nor the names of its contributors may be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- /*
- * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <sys/cdefs.h>
- #ifndef lint
- __RCSID("$NetBSD: hack.main.c,v 1.9 2004/01/27 20:30:29 jsm Exp $");
- #endif /* not lint */
- #include <signal.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include "hack.h"
- #include "extern.h"
- #ifdef QUEST
- #define gamename "quest"
- #else
- #define gamename "hack"
- #endif
- int (*afternmv)(void);
- int (*occupation)(void);
- const char *occtxt; /* defined when occupation != NULL */
- int hackpid; /* current pid */
- int locknum; /* max num of players */
- #ifdef DEF_PAGER
- const char *catmore; /* default pager */
- #endif
- char SAVEF[PL_NSIZ + 11] = "save/"; /* save/99999player */
- char *hname; /* name of the game (argv[0] of call) */
- char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */
- int main(int, char *[]);
- static void chdirx(const char *, boolean);
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int fd;
- #ifdef CHDIR
- char *dir;
- #endif
- /* Check for dirty tricks with closed fds 0, 1, 2 */
- fd = open("/dev/null", O_RDONLY);
- if (fd < 3)
- exit(1);
- close(fd);
- hname = argv[0];
- hackpid = getpid();
- #ifdef CHDIR /* otherwise no chdir() */
- /*
- * See if we must change directory to the playground.
- * (Perhaps hack runs suid and playground is inaccessible
- * for the player.)
- * The environment variable HACKDIR is overridden by a
- * -d command line option (must be the first option given)
- */
- dir = getenv("HACKDIR");
- if (argc > 1 && !strncmp(argv[1], "-d", 2)) {
- argc--;
- argv++;
- dir = argv[0] + 2;
- if (*dir == '=' || *dir == ':')
- dir++;
- if (!*dir && argc > 1) {
- argc--;
- argv++;
- dir = argv[0];
- }
- if (!*dir)
- error("Flag -d must be followed by a directory name.");
- }
- #endif
- /*
- * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
- * 2. Use $USER or $LOGNAME (if 1. fails)
- * 3. Use getlogin() (if 2. fails)
- * The resulting name is overridden by command line options.
- * If everything fails, or if the resulting name is some generic
- * account like "games", "play", "player", "hack" then eventually
- * we'll ask him.
- * Note that we trust him here; it is possible to play under
- * somebody else's name.
- */
- {
- char *s;
- initoptions();
- if (!*plname && (s = getenv("USER")))
- (void) strncpy(plname, s, sizeof(plname) - 1);
- if (!*plname && (s = getenv("LOGNAME")))
- (void) strncpy(plname, s, sizeof(plname) - 1);
- if (!*plname && (s = getlogin()))
- (void) strncpy(plname, s, sizeof(plname) - 1);
- }
- /*
- * Now we know the directory containing 'record' and
- * may do a prscore().
- */
- if (argc > 1 && !strncmp(argv[1], "-s", 2)) {
- #ifdef CHDIR
- chdirx(dir, 0);
- #endif
- prscore(argc, argv);
- exit(0);
- }
- /*
- * It seems he really wants to play.
- * Remember tty modes, to be restored on exit.
- */
- gettty();
- setbuf(stdout, obuf);
- setrandom();
- startup();
- cls();
- u.uhp = 1; /* prevent RIP on early quits */
- u.ux = FAR; /* prevent nscr() */
- (void) signal(SIGHUP, hangup);
- /*
- * Find the creation date of this game,
- * so as to avoid restoring outdated savefiles.
- */
- gethdate(hname);
- /*
- * We cannot do chdir earlier, otherwise gethdate will fail.
- */
- #ifdef CHDIR
- chdirx(dir, 1);
- #endif
- /*
- * Process options.
- */
- while (argc > 1 && argv[1][0] == '-') {
- argv++;
- argc--;
- switch (argv[0][1]) {
- #ifdef WIZARD
- case 'D':
- /* if(!strcmp(getlogin(), WIZARD)) */
- wizard = TRUE;
- /*
- * else printf("Sorry.\n");
- */
- break;
- #endif
- #ifdef NEWS
- case 'n':
- flags.nonews = TRUE;
- break;
- #endif
- case 'u':
- if (argv[0][2])
- (void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1);
- else if (argc > 1) {
- argc--;
- argv++;
- (void) strncpy(plname, argv[0], sizeof(plname) - 1);
- } else
- printf("Player name expected after -u\n");
- break;
- default:
- /* allow -T for Tourist, etc. */
- (void) strncpy(pl_character, argv[0] + 1,
- sizeof(pl_character) - 1);
- /* printf("Unknown option: %s\n", *argv); */
- }
- }
- if (argc > 1)
- locknum = atoi(argv[1]);
- #ifdef MAX_NR_OF_PLAYERS
- if (!locknum || locknum > MAX_NR_OF_PLAYERS)
- locknum = MAX_NR_OF_PLAYERS;
- #endif
- #ifdef DEF_PAGER
- if (((catmore = getenv("HACKPAGER")) == NULL &&
- (catmore = getenv("PAGER")) == NULL) ||
- catmore[0] == '\0')
- catmore = DEF_PAGER;
- #endif
- #ifdef MAIL
- getmailstatus();
- #endif
- #ifdef WIZARD
- if (wizard)
- (void) strcpy(plname, "wizard");
- else
- #endif
- if (!*plname || !strncmp(plname, "player", 4)
- || !strncmp(plname, "games", 4))
- askname();
- plnamesuffix(); /* strip suffix from name; calls askname() */
- /* again if suffix was whole name */
- /* accepts any suffix */
- #ifdef WIZARD
- if (!wizard) {
- #endif
- /*
- * check for multiple games under the same name
- * (if !locknum) or check max nr of players (otherwise)
- */
- (void) signal(SIGQUIT, SIG_IGN);
- (void) signal(SIGINT, SIG_IGN);
- if (!locknum)
- (void) strcpy(lock, plname);
- getlock(); /* sets lock if locknum != 0 */
- #ifdef WIZARD
- } else {
- char *sfoo;
- (void) strcpy(lock, plname);
- if ((sfoo = getenv("MAGIC")) != NULL)
- while (*sfoo) {
- switch (*sfoo++) {
- case 'n':
- (void) srandom(*sfoo++);
- break;
- }
- }
- if ((sfoo = getenv("GENOCIDED")) != NULL) {
- if (*sfoo == '!') {
- const struct permonst *pm = mons;
- char *gp = genocided;
- while (pm < mons + CMNUM + 2) {
- if (!strchr(sfoo, pm->mlet))
- *gp++ = pm->mlet;
- pm++;
- }
- *gp = 0;
- } else
- (void) strcpy(genocided, sfoo);
- (void) strcpy(fut_geno, genocided);
- }
- }
- #endif
- setftty();
- (void) sprintf(SAVEF, "save/%d%s", getuid(), plname);
- regularize(SAVEF + 5); /* avoid . or / in name */
- if ((fd = open(SAVEF, O_RDONLY)) >= 0 &&
- (uptodate(fd) || unlink(SAVEF) == 666)) {
- (void) signal(SIGINT, done1);
- pline("Restoring old save file...");
- (void) fflush(stdout);
- if (!dorecover(fd))
- goto not_recovered;
- pline("Hello %s, welcome to %s!", plname, gamename);
- flags.move = 0;
- } else {
- not_recovered:
- fobj = fcobj = invent = 0;
- fmon = fallen_down = 0;
- ftrap = 0;
- fgold = 0;
- flags.ident = 1;
- init_objects();
- u_init();
- (void) signal(SIGINT, done1);
- mklev();
- u.ux = xupstair;
- u.uy = yupstair;
- (void) inshop();
- setsee();
- flags.botlx = 1;
- makedog();
- {
- struct monst *mtmp;
- if ((mtmp = m_at(u.ux, u.uy)) != NULL)
- mnexto(mtmp); /* riv05!a3 */
- }
- seemons();
- #ifdef NEWS
- if (flags.nonews || !readnews())
- /* after reading news we did docrt() already */
- #endif
- docrt();
- /* give welcome message before pickup messages */
- pline("Hello %s, welcome to %s!", plname, gamename);
- pickup(1);
- read_engr_at(u.ux, u.uy);
- flags.move = 1;
- }
- flags.moonphase = phase_of_the_moon();
- if (flags.moonphase == FULL_MOON) {
- pline("You are lucky! Full moon tonight.");
- u.uluck++;
- } else if (flags.moonphase == NEW_MOON) {
- pline("Be careful! New moon tonight.");
- }
- initrack();
- for (;;) {
- if (flags.move) { /* actual time passed */
- settrack();
- if (moves % 2 == 0 ||
- (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
- movemon();
- if (!rn2(70))
- (void) makemon((struct permonst *) 0, 0, 0);
- }
- if (Glib)
- glibr();
- timeout();
- ++moves;
- if (flags.time)
- flags.botl = 1;
- if (u.uhp < 1) {
- pline("You die...");
- done("died");
- }
- if (u.uhp * 10 < u.uhpmax && moves - wailmsg > 50) {
- wailmsg = moves;
- if (u.uhp == 1)
- pline("You hear the wailing of the Banshee...");
- else
- pline("You hear the howling of the CwnAnnwn...");
- }
- if (u.uhp < u.uhpmax) {
- if (u.ulevel > 9) {
- if (Regeneration || !(moves % 3)) {
- flags.botl = 1;
- u.uhp += rnd((int) u.ulevel - 9);
- if (u.uhp > u.uhpmax)
- u.uhp = u.uhpmax;
- }
- } else if (Regeneration ||
- (!(moves % (22 - u.ulevel * 2)))) {
- flags.botl = 1;
- u.uhp++;
- }
- }
- if (Teleportation && !rn2(85))
- tele();
- if (Searching && multi >= 0)
- (void) dosearch();
- gethungry();
- invault();
- amulet();
- }
- if (multi < 0) {
- if (!++multi) {
- pline(nomovemsg ? nomovemsg :
- "You can move again.");
- nomovemsg = 0;
- if (afternmv)
- (*afternmv) ();
- afternmv = 0;
- }
- }
- find_ac();
- #ifndef QUEST
- if (!flags.mv || Blind)
- #endif
- {
- seeobjs();
- seemons();
- nscr();
- }
- if (flags.botl || flags.botlx)
- bot();
- flags.move = 1;
- if (multi >= 0 && occupation) {
- if (monster_nearby())
- stop_occupation();
- else if ((*occupation) () == 0)
- occupation = 0;
- continue;
- }
- if (multi > 0) {
- #ifdef QUEST
- if (flags.run >= 4)
- finddir();
- #endif
- lookaround();
- if (!multi) { /* lookaround may clear multi */
- flags.move = 0;
- continue;
- }
- if (flags.mv) {
- if (multi < COLNO && !--multi)
- flags.mv = flags.run = 0;
- domove();
- } else {
- --multi;
- rhack(save_cm);
- }
- } else if (multi == 0) {
- #ifdef MAIL
- ckmailstatus();
- #endif
- rhack((char *) 0);
- }
- if (multi && multi % 7 == 0)
- (void) fflush(stdout);
- }
- }
- void
- glo(foo)
- int foo;
- {
- /* construct the string xlock.n */
- char *tf;
- tf = lock;
- while (*tf && *tf != '.')
- tf++;
- (void) sprintf(tf, ".%d", foo);
- }
- /*
- * plname is filled either by an option (-u Player or -uPlayer) or
- * explicitly (-w implies wizard) or by askname.
- * It may still contain a suffix denoting pl_character.
- */
- void
- askname()
- {
- int c, ct;
- printf("\nWho are you? ");
- (void) fflush(stdout);
- ct = 0;
- while ((c = getchar()) != '\n') {
- if (c == EOF)
- error("End of input\n");
- /* some people get confused when their erase char is not ^H */
- if (c == '\010') {
- if (ct)
- ct--;
- continue;
- }
- if (c != '-')
- if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z')
- c = '_';
- if ((size_t)ct < sizeof(plname) - 1)
- plname[ct++] = c;
- }
- plname[ct] = 0;
- if (ct == 0)
- askname();
- }
- /* VARARGS1 */
- void
- impossible(const char *s, ...)
- {
- va_list ap;
- va_start(ap, s);
- vpline(s, ap);
- va_end(ap);
- pline("Program in disorder - perhaps you'd better Quit.");
- }
- #ifdef CHDIR
- static void
- chdirx(dir, wr)
- const char *dir;
- boolean wr;
- {
- #ifdef SECURE
- if (dir /* User specified directory? */
- #ifdef HACKDIR
- && strcmp(dir, HACKDIR) /* and not the default? */
- #endif
- ) {
- (void) setuid(getuid()); /* Ron Wessels */
- (void) setregid(getgid(), getgid());
- }
- #endif
- #ifdef HACKDIR
- if (dir == NULL)
- dir = HACKDIR;
- #endif
- if (dir && chdir(dir) < 0) {
- perror(dir);
- error("Cannot chdir to %s.", dir);
- }
- /* warn the player if he cannot write the record file */
- /* perhaps we should also test whether . is writable */
- /* unfortunately the access systemcall is worthless */
- if (wr) {
- int fd;
- if (dir == NULL)
- dir = ".";
- if ((fd = open(RECORD, O_RDWR)) < 0) {
- printf("Warning: cannot write %s/%s", dir, RECORD);
- getret();
- } else
- (void) close(fd);
- }
- }
- #endif
- void
- stop_occupation()
- {
- if (occupation) {
- pline("You stop %s.", occtxt);
- occupation = 0;
- }
- }
|