133149Sbostic /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 233149Sbostic /* hack.main.c - version 1.0.3 */ 333149Sbostic 433149Sbostic #include <stdio.h> 533149Sbostic #include <signal.h> 633149Sbostic #include "hack.h" 733149Sbostic 833149Sbostic #ifdef QUEST 933149Sbostic #define gamename "quest" 1033149Sbostic #else 1133149Sbostic #define gamename "hack" 1233149Sbostic #endif QUEST 1333149Sbostic 1433149Sbostic extern char *getlogin(), *getenv(); 1533149Sbostic extern char plname[PL_NSIZ], pl_character[PL_CSIZ]; 16*33150Sbostic extern struct permonst mons[CMNUM+2]; 17*33150Sbostic extern char genocided[], fut_geno[]; 1833149Sbostic 1933149Sbostic int (*afternmv)(); 2033149Sbostic int (*occupation)(); 2133149Sbostic char *occtxt; /* defined when occupation != NULL */ 2233149Sbostic 2333149Sbostic int done1(); 2433149Sbostic int hangup(); 2533149Sbostic 2633149Sbostic int hackpid; /* current pid */ 2733149Sbostic int locknum; /* max num of players */ 2833149Sbostic #ifdef DEF_PAGER 2933149Sbostic char *catmore; /* default pager */ 3033149Sbostic #endif DEF_PAGER 3133149Sbostic char SAVEF[PL_NSIZ + 11] = "save/"; /* save/99999player */ 3233149Sbostic char *hname; /* name of the game (argv[0] of call) */ 3333149Sbostic char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */ 3433149Sbostic 3533149Sbostic extern char *nomovemsg; 3633149Sbostic extern long wailmsg; 3733149Sbostic 3833149Sbostic main(argc,argv) 3933149Sbostic int argc; 4033149Sbostic char *argv[]; 4133149Sbostic { 4233149Sbostic register int fd; 4333149Sbostic #ifdef CHDIR 4433149Sbostic register char *dir; 4533149Sbostic #endif CHDIR 4633149Sbostic 4733149Sbostic hname = argv[0]; 4833149Sbostic hackpid = getpid(); 4933149Sbostic 5033149Sbostic #ifdef CHDIR /* otherwise no chdir() */ 5133149Sbostic /* 5233149Sbostic * See if we must change directory to the playground. 5333149Sbostic * (Perhaps hack runs suid and playground is inaccessible 5433149Sbostic * for the player.) 5533149Sbostic * The environment variable HACKDIR is overridden by a 5633149Sbostic * -d command line option (must be the first option given) 5733149Sbostic */ 5833149Sbostic 5933149Sbostic dir = getenv("HACKDIR"); 6033149Sbostic if(argc > 1 && !strncmp(argv[1], "-d", 2)) { 6133149Sbostic argc--; 6233149Sbostic argv++; 6333149Sbostic dir = argv[0]+2; 6433149Sbostic if(*dir == '=' || *dir == ':') dir++; 6533149Sbostic if(!*dir && argc > 1) { 6633149Sbostic argc--; 6733149Sbostic argv++; 6833149Sbostic dir = argv[0]; 6933149Sbostic } 7033149Sbostic if(!*dir) 7133149Sbostic error("Flag -d must be followed by a directory name."); 7233149Sbostic } 7333149Sbostic #endif CHDIR 7433149Sbostic 7533149Sbostic /* 7633149Sbostic * Who am i? Algorithm: 1. Use name as specified in HACKOPTIONS 7733149Sbostic * 2. Use $USER or $LOGNAME (if 1. fails) 7833149Sbostic * 3. Use getlogin() (if 2. fails) 7933149Sbostic * The resulting name is overridden by command line options. 8033149Sbostic * If everything fails, or if the resulting name is some generic 8133149Sbostic * account like "games", "play", "player", "hack" then eventually 8233149Sbostic * we'll ask him. 8333149Sbostic * Note that we trust him here; it is possible to play under 8433149Sbostic * somebody else's name. 8533149Sbostic */ 8633149Sbostic { register char *s; 8733149Sbostic 8833149Sbostic initoptions(); 8933149Sbostic if(!*plname && (s = getenv("USER"))) 9033149Sbostic (void) strncpy(plname, s, sizeof(plname)-1); 9133149Sbostic if(!*plname && (s = getenv("LOGNAME"))) 9233149Sbostic (void) strncpy(plname, s, sizeof(plname)-1); 9333149Sbostic if(!*plname && (s = getlogin())) 9433149Sbostic (void) strncpy(plname, s, sizeof(plname)-1); 9533149Sbostic } 9633149Sbostic 9733149Sbostic /* 9833149Sbostic * Now we know the directory containing 'record' and 9933149Sbostic * may do a prscore(). 10033149Sbostic */ 10133149Sbostic if(argc > 1 && !strncmp(argv[1], "-s", 2)) { 10233149Sbostic #ifdef CHDIR 10333149Sbostic chdirx(dir,0); 10433149Sbostic #endif CHDIR 10533149Sbostic prscore(argc, argv); 10633149Sbostic exit(0); 10733149Sbostic } 10833149Sbostic 10933149Sbostic /* 11033149Sbostic * It seems he really wants to play. 11133149Sbostic * Remember tty modes, to be restored on exit. 11233149Sbostic */ 11333149Sbostic gettty(); 11433149Sbostic setbuf(stdout,obuf); 11533149Sbostic setrandom(); 11633149Sbostic startup(); 11733149Sbostic cls(); 11833149Sbostic u.uhp = 1; /* prevent RIP on early quits */ 11933149Sbostic u.ux = FAR; /* prevent nscr() */ 12033149Sbostic (void) signal(SIGHUP, hangup); 12133149Sbostic 12233149Sbostic /* 12333149Sbostic * Find the creation date of this game, 12433149Sbostic * so as to avoid restoring outdated savefiles. 12533149Sbostic */ 12633149Sbostic gethdate(hname); 12733149Sbostic 12833149Sbostic /* 12933149Sbostic * We cannot do chdir earlier, otherwise gethdate will fail. 13033149Sbostic */ 13133149Sbostic #ifdef CHDIR 13233149Sbostic chdirx(dir,1); 13333149Sbostic #endif CHDIR 13433149Sbostic 13533149Sbostic /* 13633149Sbostic * Process options. 13733149Sbostic */ 13833149Sbostic while(argc > 1 && argv[1][0] == '-'){ 13933149Sbostic argv++; 14033149Sbostic argc--; 14133149Sbostic switch(argv[0][1]){ 14233149Sbostic #ifdef WIZARD 14333149Sbostic case 'D': 14433149Sbostic /* if(!strcmp(getlogin(), WIZARD)) */ 14533149Sbostic wizard = TRUE; 14633149Sbostic /* else 14733149Sbostic printf("Sorry.\n"); */ 14833149Sbostic break; 14933149Sbostic #endif WIZARD 15033149Sbostic #ifdef NEWS 15133149Sbostic case 'n': 15233149Sbostic flags.nonews = TRUE; 15333149Sbostic break; 15433149Sbostic #endif NEWS 15533149Sbostic case 'u': 15633149Sbostic if(argv[0][2]) 15733149Sbostic (void) strncpy(plname, argv[0]+2, sizeof(plname)-1); 15833149Sbostic else if(argc > 1) { 15933149Sbostic argc--; 16033149Sbostic argv++; 16133149Sbostic (void) strncpy(plname, argv[0], sizeof(plname)-1); 16233149Sbostic } else 16333149Sbostic printf("Player name expected after -u\n"); 16433149Sbostic break; 16533149Sbostic default: 16633149Sbostic /* allow -T for Tourist, etc. */ 16733149Sbostic (void) strncpy(pl_character, argv[0]+1, 16833149Sbostic sizeof(pl_character)-1); 16933149Sbostic 17033149Sbostic /* printf("Unknown option: %s\n", *argv); */ 17133149Sbostic } 17233149Sbostic } 17333149Sbostic 17433149Sbostic if(argc > 1) 17533149Sbostic locknum = atoi(argv[1]); 17633149Sbostic #ifdef MAX_NR_OF_PLAYERS 17733149Sbostic if(!locknum || locknum > MAX_NR_OF_PLAYERS) 17833149Sbostic locknum = MAX_NR_OF_PLAYERS; 17933149Sbostic #endif MAX_NR_OF_PLAYERS 18033149Sbostic #ifdef DEF_PAGER 18133149Sbostic if(!(catmore = getenv("HACKPAGER")) && !(catmore = getenv("PAGER"))) 18233149Sbostic catmore = DEF_PAGER; 18333149Sbostic #endif DEF_PAGER 18433149Sbostic #ifdef MAIL 18533149Sbostic getmailstatus(); 18633149Sbostic #endif MAIL 18733149Sbostic #ifdef WIZARD 18833149Sbostic if(wizard) (void) strcpy(plname, "wizard"); else 18933149Sbostic #endif WIZARD 19033149Sbostic if(!*plname || !strncmp(plname, "player", 4) 19133149Sbostic || !strncmp(plname, "games", 4)) 19233149Sbostic askname(); 19333149Sbostic plnamesuffix(); /* strip suffix from name; calls askname() */ 19433149Sbostic /* again if suffix was whole name */ 19533149Sbostic /* accepts any suffix */ 19633149Sbostic #ifdef WIZARD 19733149Sbostic if(!wizard) { 19833149Sbostic #endif WIZARD 19933149Sbostic /* 20033149Sbostic * check for multiple games under the same name 20133149Sbostic * (if !locknum) or check max nr of players (otherwise) 20233149Sbostic */ 20333149Sbostic (void) signal(SIGQUIT,SIG_IGN); 20433149Sbostic (void) signal(SIGINT,SIG_IGN); 20533149Sbostic if(!locknum) 20633149Sbostic (void) strcpy(lock,plname); 20733149Sbostic getlock(); /* sets lock if locknum != 0 */ 20833149Sbostic #ifdef WIZARD 20933149Sbostic } else { 21033149Sbostic register char *sfoo; 21133149Sbostic (void) strcpy(lock,plname); 21233149Sbostic if(sfoo = getenv("MAGIC")) 21333149Sbostic while(*sfoo) { 21433149Sbostic switch(*sfoo++) { 21533149Sbostic case 'n': (void) srandom(*sfoo++); 21633149Sbostic break; 21733149Sbostic } 21833149Sbostic } 21933149Sbostic if(sfoo = getenv("GENOCIDED")){ 22033149Sbostic if(*sfoo == '!'){ 22133149Sbostic register struct permonst *pm = mons; 22233149Sbostic register char *gp = genocided; 22333149Sbostic 22433149Sbostic while(pm < mons+CMNUM+2){ 22533149Sbostic if(!index(sfoo, pm->mlet)) 22633149Sbostic *gp++ = pm->mlet; 22733149Sbostic pm++; 22833149Sbostic } 22933149Sbostic *gp = 0; 23033149Sbostic } else 23133149Sbostic (void) strcpy(genocided, sfoo); 23233149Sbostic (void) strcpy(fut_geno, genocided); 23333149Sbostic } 23433149Sbostic } 23533149Sbostic #endif WIZARD 23633149Sbostic setftty(); 23733149Sbostic (void) sprintf(SAVEF, "save/%d%s", getuid(), plname); 23833149Sbostic regularize(SAVEF+5); /* avoid . or / in name */ 23933149Sbostic if((fd = open(SAVEF,0)) >= 0 && 24033149Sbostic (uptodate(fd) || unlink(SAVEF) == 666)) { 24133149Sbostic (void) signal(SIGINT,done1); 24233149Sbostic pline("Restoring old save file..."); 24333149Sbostic (void) fflush(stdout); 24433149Sbostic if(!dorecover(fd)) 24533149Sbostic goto not_recovered; 24633149Sbostic pline("Hello %s, welcome to %s!", plname, gamename); 24733149Sbostic flags.move = 0; 24833149Sbostic } else { 24933149Sbostic not_recovered: 25033149Sbostic fobj = fcobj = invent = 0; 25133149Sbostic fmon = fallen_down = 0; 25233149Sbostic ftrap = 0; 25333149Sbostic fgold = 0; 25433149Sbostic flags.ident = 1; 25533149Sbostic init_objects(); 25633149Sbostic u_init(); 25733149Sbostic 25833149Sbostic (void) signal(SIGINT,done1); 25933149Sbostic mklev(); 26033149Sbostic u.ux = xupstair; 26133149Sbostic u.uy = yupstair; 26233149Sbostic (void) inshop(); 26333149Sbostic setsee(); 26433149Sbostic flags.botlx = 1; 26533149Sbostic makedog(); 26633149Sbostic { register struct monst *mtmp; 26733149Sbostic if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp); /* riv05!a3 */ 26833149Sbostic } 26933149Sbostic seemons(); 27033149Sbostic #ifdef NEWS 27133149Sbostic if(flags.nonews || !readnews()) 27233149Sbostic /* after reading news we did docrt() already */ 27333149Sbostic #endif NEWS 27433149Sbostic docrt(); 27533149Sbostic 27633149Sbostic /* give welcome message before pickup messages */ 27733149Sbostic pline("Hello %s, welcome to %s!", plname, gamename); 27833149Sbostic 27933149Sbostic pickup(1); 28033149Sbostic read_engr_at(u.ux,u.uy); 28133149Sbostic flags.move = 1; 28233149Sbostic } 28333149Sbostic 28433149Sbostic flags.moonphase = phase_of_the_moon(); 28533149Sbostic if(flags.moonphase == FULL_MOON) { 28633149Sbostic pline("You are lucky! Full moon tonight."); 28733149Sbostic u.uluck++; 28833149Sbostic } else if(flags.moonphase == NEW_MOON) { 28933149Sbostic pline("Be careful! New moon tonight."); 29033149Sbostic } 29133149Sbostic 29233149Sbostic initrack(); 29333149Sbostic 29433149Sbostic for(;;) { 29533149Sbostic if(flags.move) { /* actual time passed */ 29633149Sbostic 29733149Sbostic settrack(); 29833149Sbostic 29933149Sbostic if(moves%2 == 0 || 30033149Sbostic (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) { 30133149Sbostic extern struct monst *makemon(); 30233149Sbostic movemon(); 30333149Sbostic if(!rn2(70)) 30433149Sbostic (void) makemon((struct permonst *)0, 0, 0); 30533149Sbostic } 30633149Sbostic if(Glib) glibr(); 30733149Sbostic timeout(); 30833149Sbostic ++moves; 30933149Sbostic if(flags.time) flags.botl = 1; 31033149Sbostic if(u.uhp < 1) { 31133149Sbostic pline("You die..."); 31233149Sbostic done("died"); 31333149Sbostic } 31433149Sbostic if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){ 31533149Sbostic wailmsg = moves; 31633149Sbostic if(u.uhp == 1) 31733149Sbostic pline("You hear the wailing of the Banshee..."); 31833149Sbostic else 31933149Sbostic pline("You hear the howling of the CwnAnnwn..."); 32033149Sbostic } 32133149Sbostic if(u.uhp < u.uhpmax) { 32233149Sbostic if(u.ulevel > 9) { 32333149Sbostic if(Regeneration || !(moves%3)) { 32433149Sbostic flags.botl = 1; 32533149Sbostic u.uhp += rnd((int) u.ulevel-9); 32633149Sbostic if(u.uhp > u.uhpmax) 32733149Sbostic u.uhp = u.uhpmax; 32833149Sbostic } 32933149Sbostic } else if(Regeneration || 33033149Sbostic (!(moves%(22-u.ulevel*2)))) { 33133149Sbostic flags.botl = 1; 33233149Sbostic u.uhp++; 33333149Sbostic } 33433149Sbostic } 33533149Sbostic if(Teleportation && !rn2(85)) tele(); 33633149Sbostic if(Searching && multi >= 0) (void) dosearch(); 33733149Sbostic gethungry(); 33833149Sbostic invault(); 33933149Sbostic amulet(); 34033149Sbostic } 34133149Sbostic if(multi < 0) { 34233149Sbostic if(!++multi){ 34333149Sbostic pline(nomovemsg ? nomovemsg : 34433149Sbostic "You can move again."); 34533149Sbostic nomovemsg = 0; 34633149Sbostic if(afternmv) (*afternmv)(); 34733149Sbostic afternmv = 0; 34833149Sbostic } 34933149Sbostic } 35033149Sbostic 35133149Sbostic find_ac(); 35233149Sbostic #ifndef QUEST 35333149Sbostic if(!flags.mv || Blind) 35433149Sbostic #endif QUEST 35533149Sbostic { 35633149Sbostic seeobjs(); 35733149Sbostic seemons(); 35833149Sbostic nscr(); 35933149Sbostic } 36033149Sbostic if(flags.botl || flags.botlx) bot(); 36133149Sbostic 36233149Sbostic flags.move = 1; 36333149Sbostic 36433149Sbostic if(multi >= 0 && occupation) { 36533149Sbostic if(monster_nearby()) 36633149Sbostic stop_occupation(); 36733149Sbostic else if ((*occupation)() == 0) 36833149Sbostic occupation = 0; 36933149Sbostic continue; 37033149Sbostic } 37133149Sbostic 37233149Sbostic if(multi > 0) { 37333149Sbostic #ifdef QUEST 37433149Sbostic if(flags.run >= 4) finddir(); 37533149Sbostic #endif QUEST 37633149Sbostic lookaround(); 37733149Sbostic if(!multi) { /* lookaround may clear multi */ 37833149Sbostic flags.move = 0; 37933149Sbostic continue; 38033149Sbostic } 38133149Sbostic if(flags.mv) { 38233149Sbostic if(multi < COLNO && !--multi) 38333149Sbostic flags.mv = flags.run = 0; 38433149Sbostic domove(); 38533149Sbostic } else { 38633149Sbostic --multi; 38733149Sbostic rhack(save_cm); 38833149Sbostic } 38933149Sbostic } else if(multi == 0) { 39033149Sbostic #ifdef MAIL 39133149Sbostic ckmailstatus(); 39233149Sbostic #endif MAIL 39333149Sbostic rhack((char *) 0); 39433149Sbostic } 39533149Sbostic if(multi && multi%7 == 0) 39633149Sbostic (void) fflush(stdout); 39733149Sbostic } 39833149Sbostic } 39933149Sbostic 40033149Sbostic glo(foo) 40133149Sbostic register foo; 40233149Sbostic { 40333149Sbostic /* construct the string xlock.n */ 40433149Sbostic register char *tf; 40533149Sbostic 40633149Sbostic tf = lock; 40733149Sbostic while(*tf && *tf != '.') tf++; 40833149Sbostic (void) sprintf(tf, ".%d", foo); 40933149Sbostic } 41033149Sbostic 41133149Sbostic /* 41233149Sbostic * plname is filled either by an option (-u Player or -uPlayer) or 41333149Sbostic * explicitly (-w implies wizard) or by askname. 41433149Sbostic * It may still contain a suffix denoting pl_character. 41533149Sbostic */ 41633149Sbostic askname(){ 41733149Sbostic register int c,ct; 41833149Sbostic printf("\nWho are you? "); 41933149Sbostic (void) fflush(stdout); 42033149Sbostic ct = 0; 42133149Sbostic while((c = getchar()) != '\n'){ 42233149Sbostic if(c == EOF) error("End of input\n"); 42333149Sbostic /* some people get confused when their erase char is not ^H */ 42433149Sbostic if(c == '\010') { 42533149Sbostic if(ct) ct--; 42633149Sbostic continue; 42733149Sbostic } 42833149Sbostic if(c != '-') 42933149Sbostic if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_'; 43033149Sbostic if(ct < sizeof(plname)-1) plname[ct++] = c; 43133149Sbostic } 43233149Sbostic plname[ct] = 0; 43333149Sbostic if(ct == 0) askname(); 43433149Sbostic } 43533149Sbostic 43633149Sbostic /*VARARGS1*/ 43733149Sbostic impossible(s,x1,x2) 43833149Sbostic register char *s; 43933149Sbostic { 44033149Sbostic pline(s,x1,x2); 44133149Sbostic pline("Program in disorder - perhaps you'd better Quit."); 44233149Sbostic } 44333149Sbostic 44433149Sbostic #ifdef CHDIR 44533149Sbostic static 44633149Sbostic chdirx(dir, wr) 44733149Sbostic char *dir; 44833149Sbostic boolean wr; 44933149Sbostic { 45033149Sbostic 45133149Sbostic #ifdef SECURE 45233149Sbostic if(dir /* User specified directory? */ 45333149Sbostic #ifdef HACKDIR 45433149Sbostic && strcmp(dir, HACKDIR) /* and not the default? */ 45533149Sbostic #endif HACKDIR 45633149Sbostic ) { 45733149Sbostic (void) setuid(getuid()); /* Ron Wessels */ 45833149Sbostic (void) setgid(getgid()); 45933149Sbostic } 46033149Sbostic #endif SECURE 46133149Sbostic 46233149Sbostic #ifdef HACKDIR 46333149Sbostic if(dir == NULL) 46433149Sbostic dir = HACKDIR; 46533149Sbostic #endif HACKDIR 46633149Sbostic 46733149Sbostic if(dir && chdir(dir) < 0) { 46833149Sbostic perror(dir); 46933149Sbostic error("Cannot chdir to %s.", dir); 47033149Sbostic } 47133149Sbostic 47233149Sbostic /* warn the player if he cannot write the record file */ 47333149Sbostic /* perhaps we should also test whether . is writable */ 47433149Sbostic /* unfortunately the access systemcall is worthless */ 47533149Sbostic if(wr) { 47633149Sbostic register fd; 47733149Sbostic 47833149Sbostic if(dir == NULL) 47933149Sbostic dir = "."; 48033149Sbostic if((fd = open(RECORD, 2)) < 0) { 48133149Sbostic printf("Warning: cannot write %s/%s", dir, RECORD); 48233149Sbostic getret(); 48333149Sbostic } else 48433149Sbostic (void) close(fd); 48533149Sbostic } 48633149Sbostic } 48733149Sbostic #endif CHDIR 48833149Sbostic 48933149Sbostic stop_occupation() 49033149Sbostic { 49133149Sbostic if(occupation) { 49233149Sbostic pline("You stop %s.", occtxt); 49333149Sbostic occupation = 0; 49433149Sbostic } 49533149Sbostic } 496