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: }