1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
   2: /* hack.main.c - version 1.0.4 */
   3: 
   4: #include <stdio.h>
   5: #include <signal.h>
   6: #include <stdlib.h>
   7: #include <unistd.h>
   8: #include "hack.h"
   9: 
  10: #ifdef QUEST
  11: #define gamename    "quest"
  12: #else
  13: #define gamename    "hack"
  14: #endif QUEST
  15: 
  16: extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
  17: 
  18: int (*afternmv)();
  19: int (*occupation)();
  20: char *occtxt;           /* defined when occupation != NULL */
  21: 
  22: int done1();
  23: int hangup();
  24: 
  25: int hackpid;                /* current pid */
  26: int locknum;                /* max num of players */
  27: #ifdef DEF_PAGER
  28: char *catmore;              /* default pager */
  29: #endif DEF_PAGER
  30: char SAVEF[PL_NSIZ + 11] = "save/"; /* save/99999player */
  31: char *hname;        /* name of the game (argv[0] of call) */
  32: char obuf[BUFSIZ];  /* BUFSIZ is defined in stdio.h */
  33: 
  34: extern char *nomovemsg;
  35: extern long wailmsg;
  36: 
  37: main(argc,argv)
  38: int argc;
  39: char *argv[];
  40: {
  41:     register int fd;
  42: #ifdef CHDIR
  43:     register char *dir;
  44: #endif CHDIR
  45: 
  46:     hname = argv[0];
  47:     hackpid = getpid();
  48: 
  49: #ifdef CHDIR            /* otherwise no chdir() */
  50:     /*
  51: 	 * See if we must change directory to the playground.
  52: 	 * (Perhaps hack runs suid and playground is inaccessible
  53: 	 *  for the player.)
  54: 	 * The environment variable HACKDIR is overridden by a
  55: 	 *  -d command line option (must be the first option given)
  56: 	 */
  57: 
  58:     dir = getenv("HACKDIR");
  59:     if(argc > 1 && !strncmp(argv[1], "-d", STRLEN("-d"))) {
  60:         argc--;
  61:         argv++;
  62:         dir = argv[0]+STRLEN("-d");
  63:         if(*dir == '=' || *dir == ':') dir++;
  64:         if(!*dir && argc > 1) {
  65:             argc--;
  66:             argv++;
  67:             dir = argv[0];
  68:         }
  69:         if(!*dir)
  70:             error("Flag -d must be followed by a directory name.");
  71:     }
  72: #endif CHDIR
  73: 
  74:     /*
  75: 	 * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS
  76: 	 *			2. Use $USER or $LOGNAME	(if 1. fails)
  77: 	 *			3. Use getlogin()		(if 2. fails)
  78: 	 * The resulting name is overridden by command line options.
  79: 	 * If everything fails, or if the resulting name is some generic
  80: 	 * account like "games", "play", "player", "hack" then eventually
  81: 	 * we'll ask him.
  82: 	 * Note that we trust him here; it is possible to play under
  83: 	 * somebody else's name.
  84: 	 */
  85:     { register char *s;
  86: 
  87:       initoptions();
  88:       if(!*plname && (s = getenv("USER")))
  89:         (void) strncpy(plname, s, sizeof(plname)-1);
  90:       if(!*plname && (s = getenv("LOGNAME")))
  91:         (void) strncpy(plname, s, sizeof(plname)-1);
  92:       if(!*plname && (s = getlogin()))
  93:         (void) strncpy(plname, s, sizeof(plname)-1);
  94:     }
  95: 
  96:     /*
  97: 	 * Now we know the directory containing 'record' and
  98: 	 * may do a prscore().
  99: 	 */
 100:     if(argc > 1 && !strncmp(argv[1], "-s", STRLEN("-s"))) {
 101: #ifdef CHDIR
 102:         chdirx(dir,0);
 103: #endif CHDIR
 104:         prscore(argc, argv);
 105:         exit(0);
 106:     }
 107: 
 108:     /*
 109: 	 * It seems he really wants to play.
 110: 	 * Remember tty modes, to be restored on exit.
 111: 	 */
 112:     gettty();
 113:     setbuf(stdout,obuf);
 114:     setrandom();
 115:     startup();
 116:     cls();
 117:     u.uhp = 1;  /* prevent RIP on early quits */
 118:     u.ux = FAR; /* prevent nscr() */
 119:     (void) signal(SIGHUP, hangup);
 120: 
 121:     /*
 122: 	 * Find the creation date of this game,
 123: 	 * so as to avoid restoring outdated savefiles.
 124: 	 */
 125:     gethdate(hname);
 126: 
 127:     /*
 128: 	 * We cannot do chdir earlier, otherwise gethdate will fail.
 129: 	 */
 130: #ifdef CHDIR
 131:     chdirx(dir,1);
 132: #endif CHDIR
 133: 
 134:     /*
 135: 	 * Process options.
 136: 	 */
 137:     while(argc > 1 && argv[1][0] == '-'){
 138:         argv++;
 139:         argc--;
 140:         switch(argv[0][1]){
 141: #ifdef WIZARD
 142:         case 'D':
 143:             if(!strcmp(getlogin(), WIZARD))
 144:                 wizard = TRUE;
 145:             else
 146:                 printf("Sorry.\n");
 147:             break;
 148: #endif WIZARD
 149: #ifdef NEWS
 150:         case 'n':
 151:             flags.nonews = TRUE;
 152:             break;
 153: #endif NEWS
 154:         case 'u':
 155:             if(argv[0][2])
 156:               (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
 157:             else if(argc > 1) {
 158:               argc--;
 159:               argv++;
 160:               (void) strncpy(plname, argv[0], sizeof(plname)-1);
 161:             } else
 162:                 printf("Player name expected after -u\n");
 163:             break;
 164:         default:
 165:             /* allow -T for Tourist, etc. */
 166:             (void) strncpy(pl_character, argv[0]+1,
 167:                 sizeof(pl_character)-1);
 168: 
 169:             /* printf("Unknown option: %s\n", *argv); */
 170:         }
 171:     }
 172: 
 173:     if(argc > 1)
 174:         locknum = atoi(argv[1]);
 175: #ifdef MAX_NR_OF_PLAYERS
 176:     if(!locknum || locknum > MAX_NR_OF_PLAYERS)
 177:         locknum = MAX_NR_OF_PLAYERS;
 178: #endif MAX_NR_OF_PLAYERS
 179: #ifdef DEF_PAGER
 180:     if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER")))
 181:         catmore = DEF_PAGER;
 182: #endif DEF_PAGER
 183: #ifdef MAIL
 184:     getmailstatus();
 185: #endif MAIL
 186: #ifdef WIZARD
 187:     if(wizard) (void) strcpy(plname, "wizard"); else
 188: #endif WIZARD
 189:     if(!*plname || !strncmp(plname, "player", 4)
 190:             || !strncmp(plname, "games", 4))
 191:         askname();
 192:     plnamesuffix();     /* strip suffix from name; calls askname() */
 193:                 /* again if suffix was whole name */
 194:                 /* accepts any suffix */
 195: #ifdef WIZARD
 196:     if(!wizard) {
 197: #endif WIZARD
 198:         /*
 199: 		 * check for multiple games under the same name
 200: 		 * (if !locknum) or check max nr of players (otherwise)
 201: 		 */
 202:         (void) signal(SIGQUIT,SIG_IGN);
 203:         (void) signal(SIGINT,SIG_IGN);
 204:         if(!locknum)
 205:             (void) strcpy(lock,plname);
 206:         getlock();  /* sets lock if locknum != 0 */
 207: #ifdef WIZARD
 208:     } else {
 209:         register char *sfoo;
 210:         (void) strcpy(lock,plname);
 211:         if(sfoo = getenv("MAGIC"))
 212:             while(*sfoo) {
 213:                 switch(*sfoo++) {
 214:                 case 'n': (void) srand(*sfoo++);
 215:                     break;
 216:                 }
 217:             }
 218:         if(sfoo = getenv("GENOCIDED")){
 219:             /* KLUDGE -- our C doesn't let `extern ...'
 220: 				definitions last for the rest of the file */
 221:             extern char genocided[], fut_geno[];
 222:             if(*sfoo == '!'){
 223:                 extern struct permonst mons[CMNUM+2];
 224:                 extern char genocided[], fut_geno[];
 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 WIZARD
 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 NEWS
 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 QUEST
 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 QUEST
 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 MAIL
 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);	/* readchar already does this */
 424:     ct = 0;
 425:     while((c = readchar()) != '\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
 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 HACKDIR
 460:         ) {
 461:         (void) setuid(getuid());        /* Ron Wessels */
 462:         (void) setgid(getgid());
 463:     }
 464: #endif SECURE
 465: 
 466: #ifdef HACKDIR
 467:     if(dir == NULL)
 468:         dir = HACKDIR;
 469: #endif HACKDIR
 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 CHDIR
 492: 
 493: stop_occupation()
 494: {
 495:     if(occupation) {
 496:         pline("You stop %s.", occtxt);
 497:         occupation = 0;
 498:     }
 499: }

Defined functions

askname defined in line 420; used 3 times
chdirx defined in line 449; used 2 times
main defined in line 37; never used

Defined variables

SAVEF defined in line 30; used 10 times
catmore defined in line 28; used 3 times
hackpid defined in line 25; used 3 times
hname defined in line 31; used 2 times
locknum defined in line 26; used 5 times
obuf defined in line 32; used 1 times

Defined macros

gamename defined in line 13; used 2 times
Last modified: 1997-10-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5023
Valid CSS Valid XHTML 1.0 Strict