home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / games / hack / hack.main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-31  |  10.4 KB  |  500 lines

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