(linenum→info "unix/slp.c:2238")

bsd-games/2.17/hack/hack.main.c

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