Annotation of 43BSDReno/games/hack/hack.unix.c, revision 1.1.1.1

1.1       root        1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
                      2: /* hack.unix.c - version 1.0.3 */
                      3: 
                      4: /* This file collects some Unix dependencies; hack.pager.c contains some more */
                      5: 
                      6: /*
                      7:  * The time is used for:
                      8:  *     - seed for random()
                      9:  *     - year on tombstone and yymmdd in record file
                     10:  *     - phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
                     11:  *     - night and midnight (the undead are dangerous at midnight)
                     12:  *     - determination of what files are "very old"
                     13:  */
                     14: 
                     15: #include <stdio.h>
                     16: #include <errno.h>
                     17: #include "hack.h"      /* mainly for index() which depends on BSD */
                     18: 
                     19: #include       <sys/types.h>           /* for time_t and stat */
                     20: #include       <sys/stat.h>
                     21: #ifdef BSD
                     22: #include       <sys/time.h>
                     23: #else
                     24: #include       <time.h>
                     25: #endif BSD
                     26: 
                     27: extern char *getenv();
                     28: extern time_t time();
                     29: 
                     30: setrandom()
                     31: {
                     32:        (void) srandom((int) time ((time_t *) 0));
                     33: }
                     34: 
                     35: struct tm *
                     36: getlt()
                     37: {
                     38:        time_t date;
                     39:        struct tm *localtime();
                     40: 
                     41:        (void) time(&date);
                     42:        return(localtime(&date));
                     43: }
                     44: 
                     45: getyear()
                     46: {
                     47:        return(1900 + getlt()->tm_year);
                     48: }
                     49: 
                     50: char *
                     51: getdate()
                     52: {
                     53:        static char datestr[7];
                     54:        register struct tm *lt = getlt();
                     55: 
                     56:        (void) sprintf(datestr, "%2d%2d%2d",
                     57:                lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
                     58:        if(datestr[2] == ' ') datestr[2] = '0';
                     59:        if(datestr[4] == ' ') datestr[4] = '0';
                     60:        return(datestr);
                     61: }
                     62: 
                     63: phase_of_the_moon()                    /* 0-7, with 0: new, 4: full */
                     64: {                                      /* moon period: 29.5306 days */
                     65:                                        /* year: 365.2422 days */
                     66:        register struct tm *lt = getlt();
                     67:        register int epact, diy, golden;
                     68: 
                     69:        diy = lt->tm_yday;
                     70:        golden = (lt->tm_year % 19) + 1;
                     71:        epact = (11 * golden + 18) % 30;
                     72:        if ((epact == 25 && golden > 11) || epact == 24)
                     73:                epact++;
                     74: 
                     75:        return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
                     76: }
                     77: 
                     78: night()
                     79: {
                     80:        register int hour = getlt()->tm_hour;
                     81: 
                     82:        return(hour < 6 || hour > 21);
                     83: }
                     84: 
                     85: midnight()
                     86: {
                     87:        return(getlt()->tm_hour == 0);
                     88: }
                     89: 
                     90: struct stat buf, hbuf;
                     91: 
                     92: gethdate(name) char *name; {
                     93: /* old version - for people short of space */
                     94: /*
                     95: /* register char *np;
                     96: /*     if(stat(name, &hbuf))
                     97: /*             error("Cannot get status of %s.",
                     98: /*                     (np = rindex(name, '/')) ? np+1 : name);
                     99: /*
                    100: /* version using PATH from: [email protected] (Greg Couch) */
                    101: 
                    102: 
                    103: /*
                    104:  * The problem with   #include <sys/param.h>   is that this include file
                    105:  * does not exist on all systems, and moreover, that it sometimes includes
                    106:  * <sys/types.h> again, so that the compiler sees these typedefs twice.
                    107:  */
                    108: #define                MAXPATHLEN      1024
                    109: 
                    110: register char *np, *path;
                    111: char filename[MAXPATHLEN+1];
                    112:        if (index(name, '/') != NULL || (path = getenv("PATH")) == NULL)
                    113:                path = "";
                    114: 
                    115:        for (;;) {
                    116:                if ((np = index(path, ':')) == NULL)
                    117:                        np = path + strlen(path);       /* point to end str */
                    118:                if (np - path <= 1)                     /* %% */
                    119:                        (void) strcpy(filename, name);
                    120:                else {
                    121:                        (void) strncpy(filename, path, np - path);
                    122:                        filename[np - path] = '/';
                    123:                        (void) strcpy(filename + (np - path) + 1, name);
                    124:                }
                    125:                if (stat(filename, &hbuf) == 0)
                    126:                        return;
                    127:                if (*np == '\0')
                    128:                        break;
                    129:                path = np + 1;
                    130:        }
                    131:        error("Cannot get status of %s.",
                    132:                (np = rindex(name, '/')) ? np+1 : name);
                    133: }
                    134: 
                    135: uptodate(fd) {
                    136:        if(fstat(fd, &buf)) {
                    137:                pline("Cannot get status of saved level? ");
                    138:                return(0);
                    139:        }
                    140:        if(buf.st_mtime < hbuf.st_mtime) {
                    141:                pline("Saved level is out of date. ");
                    142:                return(0);
                    143:        }
                    144:        return(1);
                    145: }
                    146: 
                    147: /* see whether we should throw away this xlock file */
                    148: veryold(fd) {
                    149:        register int i;
                    150:        time_t date;
                    151: 
                    152:        if(fstat(fd, &buf)) return(0);                  /* cannot get status */
                    153:        if(buf.st_size != sizeof(int)) return(0);       /* not an xlock file */
                    154:        (void) time(&date);
                    155:        if(date - buf.st_mtime < 3L*24L*60L*60L) {      /* recent */
                    156:                extern int errno;
                    157:                int lockedpid;  /* should be the same size as hackpid */
                    158: 
                    159:                if(read(fd, (char *)&lockedpid, sizeof(lockedpid)) !=
                    160:                        sizeof(lockedpid))
                    161:                        /* strange ... */
                    162:                        return(0);
                    163: 
                    164:                /* From: Rick Adams <seismo!rick>
                    165:                /* This will work on 4.1cbsd, 4.2bsd and system 3? & 5.
                    166:                /* It will do nothing on V7 or 4.1bsd. */
                    167:                if(!(kill(lockedpid, 0) == -1 && errno == ESRCH))
                    168:                        return(0);
                    169:        }
                    170:        (void) close(fd);
                    171:        for(i = 1; i <= MAXLEVEL; i++) {                /* try to remove all */
                    172:                glo(i);
                    173:                (void) unlink(lock);
                    174:        }
                    175:        glo(0);
                    176:        if(unlink(lock)) return(0);                     /* cannot remove it */
                    177:        return(1);                                      /* success! */
                    178: }
                    179: 
                    180: getlock()
                    181: {
                    182:        extern int errno, hackpid, locknum;
                    183:        register int i = 0, fd;
                    184: 
                    185:        (void) fflush(stdout);
                    186: 
                    187:        /* we ignore QUIT and INT at this point */
                    188:        if (link(HLOCK, LLOCK) == -1) {
                    189:                register int errnosv = errno;
                    190: 
                    191:                perror(HLOCK);
                    192:                printf("Cannot link %s to %s\n", LLOCK, HLOCK);
                    193:                switch(errnosv) {
                    194:                case ENOENT:
                    195:                    printf("Perhaps there is no (empty) file %s ?\n", HLOCK);
                    196:                    break;
                    197:                case EACCES:
                    198:                    printf("It seems you don't have write permission here.\n");
                    199:                    break;
                    200:                case EEXIST:
                    201:                    printf("(Try again or rm %s.)\n", LLOCK);
                    202:                    break;
                    203:                default:
                    204:                    printf("I don't know what is wrong.");
                    205:                }
                    206:                getret();
                    207:                error("");
                    208:                /*NOTREACHED*/
                    209:        }
                    210: 
                    211:        regularize(lock);
                    212:        glo(0);
                    213:        if(locknum > 25) locknum = 25;
                    214: 
                    215:        do {
                    216:                if(locknum) lock[0] = 'a' + i++;
                    217: 
                    218:                if((fd = open(lock, 0)) == -1) {
                    219:                        if(errno == ENOENT) goto gotlock;    /* no such file */
                    220:                        perror(lock);
                    221:                        (void) unlink(LLOCK);
                    222:                        error("Cannot open %s", lock);
                    223:                }
                    224: 
                    225:                if(veryold(fd)) /* if true, this closes fd and unlinks lock */
                    226:                        goto gotlock;
                    227:                (void) close(fd);
                    228:        } while(i < locknum);
                    229: 
                    230:        (void) unlink(LLOCK);
                    231:        error(locknum ? "Too many hacks running now."
                    232:                      : "There is a game in progress under your name.");
                    233: gotlock:
                    234:        fd = creat(lock, FMASK);
                    235:        if(unlink(LLOCK) == -1)
                    236:                error("Cannot unlink %s.", LLOCK);
                    237:        if(fd == -1) {
                    238:                error("cannot creat lock file.");
                    239:        } else {
                    240:                if(write(fd, (char *) &hackpid, sizeof(hackpid))
                    241:                    != sizeof(hackpid)){
                    242:                        error("cannot write lock");
                    243:                }
                    244:                if(close(fd) == -1) {
                    245:                        error("cannot close lock");
                    246:                }
                    247:        }
                    248: }      
                    249: 
                    250: #ifdef MAIL
                    251: 
                    252: /*
                    253:  * Notify user when new mail has arrived. [Idea from Merlyn Leroy, but
                    254:  * I don't know the details of his implementation.]
                    255:  * { Later note: he disliked my calling a general mailreader and felt that
                    256:  *   hack should do the paging itself. But when I get mail, I want to put it
                    257:  *   in some folder, reply, etc. - it would be unreasonable to put all these
                    258:  *   functions in hack. }
                    259:  * The mail daemon '2' is at present not a real monster, but only a visual
                    260:  * effect. Thus, makemon() is superfluous. This might become otherwise,
                    261:  * however. The motion of '2' is less restrained than usual: diagonal moves
                    262:  * from a DOOR are possible. He might also use SDOOR's. Also, '2' is visible
                    263:  * in a ROOM, even when you are Blind.
                    264:  * Its path should be longer when you are Telepat-hic and Blind.
                    265:  *
                    266:  * Interesting side effects:
                    267:  *     - You can get rich by sending yourself a lot of mail and selling
                    268:  *       it to the shopkeeper. Unfortunately mail isn't very valuable.
                    269:  *     - You might die in case '2' comes along at a critical moment during
                    270:  *       a fight and delivers a scroll the weight of which causes you to
                    271:  *       collapse.
                    272:  *
                    273:  * Possible extensions:
                    274:  *     - Open the file MAIL and do fstat instead of stat for efficiency.
                    275:  *       (But sh uses stat, so this cannot be too bad.)
                    276:  *     - Examine the mail and produce a scroll of mail called "From somebody".
                    277:  *     - Invoke MAILREADER in such a way that only this single letter is read.
                    278:  *
                    279:  *     - Make him lose his mail when a Nymph steals the letter.
                    280:  *     - Do something to the text when the scroll is enchanted or cancelled.
                    281:  */
                    282: #include       "def.mkroom.h"
                    283: static struct stat omstat,nmstat;
                    284: static char *mailbox;
                    285: static long laststattime;
                    286: 
                    287: getmailstatus() {
                    288:        if(!(mailbox = getenv("MAIL")))
                    289:                return;
                    290:        if(stat(mailbox, &omstat)){
                    291: #ifdef PERMANENT_MAILBOX
                    292:                pline("Cannot get status of MAIL=%s .", mailbox);
                    293:                mailbox = 0;
                    294: #else
                    295:                omstat.st_mtime = 0;
                    296: #endif PERMANENT_MAILBOX
                    297:        }
                    298: }
                    299: 
                    300: ckmailstatus() {
                    301:        if(!mailbox
                    302: #ifdef MAILCKFREQ
                    303:                    || moves < laststattime + MAILCKFREQ
                    304: #endif MAILCKFREQ
                    305:                                                        )
                    306:                return;
                    307:        laststattime = moves;
                    308:        if(stat(mailbox, &nmstat)){
                    309: #ifdef PERMANENT_MAILBOX
                    310:                pline("Cannot get status of MAIL=%s anymore.", mailbox);
                    311:                mailbox = 0;
                    312: #else
                    313:                nmstat.st_mtime = 0;
                    314: #endif PERMANENT_MAILBOX
                    315:        } else if(nmstat.st_mtime > omstat.st_mtime) {
                    316:                if(nmstat.st_size)
                    317:                        newmail();
                    318:                getmailstatus();        /* might be too late ... */
                    319:        }
                    320: }
                    321: 
                    322: newmail() {
                    323:        /* produce a scroll of mail */
                    324:        register struct obj *obj;
                    325:        register struct monst *md;
                    326:        extern char plname[];
                    327:        extern struct obj *mksobj(), *addinv();
                    328:        extern struct monst *makemon();
                    329:        extern struct permonst pm_mail_daemon;
                    330: 
                    331:        obj = mksobj(SCR_MAIL);
                    332:        if(md = makemon(&pm_mail_daemon, u.ux, u.uy)) /* always succeeds */
                    333:                mdrush(md,0);
                    334: 
                    335:        pline("\"Hello, %s! I have some mail for you.\"", plname);
                    336:        if(md) {
                    337:                if(dist(md->mx,md->my) > 2)
                    338:                        pline("\"Catch!\"");
                    339:                more();
                    340: 
                    341:                /* let him disappear again */
                    342:                mdrush(md,1);
                    343:                mondead(md);
                    344:        }
                    345: 
                    346:        obj = addinv(obj);
                    347:        (void) identify(obj);           /* set known and do prinv() */
                    348: }
                    349: 
                    350: /* make md run through the cave */
                    351: mdrush(md,away)
                    352: register struct monst *md;
                    353: boolean away;
                    354: {
                    355:        register int uroom = inroom(u.ux, u.uy);
                    356:        if(uroom >= 0) {
                    357:                register int tmp = rooms[uroom].fdoor;
                    358:                register int cnt = rooms[uroom].doorct;
                    359:                register int fx = u.ux, fy = u.uy;
                    360:                while(cnt--) {
                    361:                        if(dist(fx,fy) < dist(doors[tmp].x, doors[tmp].y)){
                    362:                                fx = doors[tmp].x;
                    363:                                fy = doors[tmp].y;
                    364:                        }
                    365:                        tmp++;
                    366:                }
                    367:                tmp_at(-1, md->data->mlet);     /* open call */
                    368:                if(away) {      /* interchange origin and destination */
                    369:                        unpmon(md);
                    370:                        tmp = fx; fx = md->mx; md->mx = tmp;
                    371:                        tmp = fy; fy = md->my; md->my = tmp;
                    372:                }
                    373:                while(fx != md->mx || fy != md->my) {
                    374:                        register int dx,dy,nfx = fx,nfy = fy,d1,d2;
                    375: 
                    376:                        tmp_at(fx,fy);
                    377:                        d1 = DIST(fx,fy,md->mx,md->my);
                    378:                        for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++)
                    379:                            if(dx || dy) {
                    380:                                d2 = DIST(fx+dx,fy+dy,md->mx,md->my);
                    381:                                if(d2 < d1) {
                    382:                                    d1 = d2;
                    383:                                    nfx = fx+dx;
                    384:                                    nfy = fy+dy;
                    385:                                }
                    386:                            }
                    387:                        if(nfx != fx || nfy != fy) {
                    388:                            fx = nfx;
                    389:                            fy = nfy;
                    390:                        } else {
                    391:                            if(!away) {
                    392:                                md->mx = fx;
                    393:                                md->my = fy;
                    394:                            }
                    395:                            break;
                    396:                        } 
                    397:                }
                    398:                tmp_at(-1,-1);                  /* close call */
                    399:        }
                    400:        if(!away)
                    401:                pmon(md);
                    402: }
                    403: 
                    404: readmail() {
                    405: #ifdef DEF_MAILREADER                  /* This implies that UNIX is defined */
                    406:        register char *mr = 0;
                    407:        more();
                    408:        if(!(mr = getenv("MAILREADER")))
                    409:                mr = DEF_MAILREADER;
                    410:        if(child(1)){
                    411:                execl(mr, mr, (char *) 0);
                    412:                exit(1);
                    413:        }
                    414: #else DEF_MAILREADER
                    415:        (void) page_file(mailbox, FALSE);
                    416: #endif DEF_MAILREADER
                    417:        /* get new stat; not entirely correct: there is a small time
                    418:           window where we do not see new mail */
                    419:        getmailstatus();
                    420: }
                    421: #endif MAIL
                    422: 
                    423: regularize(s)  /* normalize file name - we don't like ..'s or /'s */
                    424: register char *s;
                    425: {
                    426:        register char *lp;
                    427: 
                    428:        while((lp = index(s, '.')) || (lp = index(s, '/')))
                    429:                *lp = '_';
                    430: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.