Пример #1
0
int archreader_read_header(carchreader *ai, char *magic, cdico **d, bool allowseek, u16 *fsid)
{
    s64 curpos;
    u16 temp16;
    u32 temp32;
    u32 archid;
    int res;
    
    assert(ai);
    assert(d);
    assert(fsid);
    
    // init
    memset(magic, 0, FSA_SIZEOF_MAGIC);
    *fsid=FSA_FILESYSID_NULL;
    *d=NULL;
    
    if ((*d=dico_alloc())==NULL)
    {   errprintf("dico_alloc() failed\n");
        return OLDERR_FATAL;
    }
    
    // search for next read header marker and magic (it may be further if corruption in archive)
    if ((curpos=lseek64(ai->archfd, 0, SEEK_CUR))<0)
    {   sysprintf("lseek64() failed to get the current position in archive\n");
        return OLDERR_FATAL;
    }
    
    if ((res=archreader_read_data(ai, magic, FSA_SIZEOF_MAGIC))!=FSAERR_SUCCESS)
    {   msgprintf(MSG_STACK, "cannot read header magic: res=%d\n", res);
        return OLDERR_FATAL;
    }
    
    // we don't want to search for the magic if it's a volume header
    if (is_magic_valid(magic)!=true && allowseek!=true)
    {   errprintf("cannot read header magic: this is not a valid fsarchiver file, or it has been created with a different version.\n");
        return OLDERR_FATAL;
    }
    
    while (is_magic_valid(magic)!=true)
    {
        if (lseek64(ai->archfd, curpos++, SEEK_SET)<0)
        {   sysprintf("lseek64(pos=%lld, SEEK_SET) failed\n", (long long)curpos);
            return OLDERR_FATAL;
        }
        if ((res=archreader_read_data(ai, magic, FSA_SIZEOF_MAGIC))!=FSAERR_SUCCESS)
        {   msgprintf(MSG_STACK, "cannot read header magic: res=%d\n", res);
            return OLDERR_FATAL;
        }
    }
    
    // read the archive id
    if ((res=archreader_read_data(ai, &temp32, sizeof(temp32)))!=FSAERR_SUCCESS)
    {   msgprintf(MSG_STACK, "cannot read archive-id in header: res=%d\n", res);
        return OLDERR_FATAL;
    }
    archid=le32_to_cpu(temp32);
    if (ai->archid) // only check archive-id if it's known (when main header has been read)
    {
        if (archid!=ai->archid)
        {   errprintf("archive-id in header does not match: archid=[%.8x], expected=[%.8x]\n", archid, ai->archid);
            return OLDERR_MINOR;
        }
    }
    
    // read the filesystem id
    if ((res=archreader_read_data(ai, &temp16, sizeof(temp16)))!=FSAERR_SUCCESS)
    {   msgprintf(MSG_STACK, "cannot read filesystem-id in header: res=%d\n", res);
        return OLDERR_FATAL;
    }
    *fsid=le16_to_cpu(temp16);
    
    // read the dico of the header
    if ((res=archreader_read_dico(ai, *d))!=FSAERR_SUCCESS)
    {   msgprintf(MSG_STACK, "imgdisk_read_dico() failed\n");
        return res;
    }
    
    return FSAERR_SUCCESS;
}
Пример #2
0
int generic_get_mntinfo(char *devname, int *readwrite, char *mntbuf, int maxmntbuf, char *optbuf, int maxoptbuf, char *fsbuf, int maxfsbuf)
{
    char col_fs[FSA_MAX_FSNAMELEN];
    int devisroot=false;
    struct stat64 devstat;
    struct stat64 rootstat;
    long major, minor;
    char delims[]=" \t\n:";
    struct utsname suname;
    char col_dev[128];
    char col_mnt[128];
    char col_opt[128];
    char line[1024];
    char temp[2048];
    char *saveptr;
    char *result;
    FILE *f;
    int sep;
    int i;

    // init
    uname(&suname);
    *readwrite=-1; // unknown
    memset(mntbuf, 0, maxmntbuf);
    memset(optbuf, 0, maxoptbuf);

    // ---- 1. attempt to find device in "/proc/self/mountinfo"
    if ((stat64(devname, &devstat)==0) && ((f=fopen("/proc/self/mountinfo","rb"))!=NULL))
    {
        msgprintf(MSG_DEBUG1, "device=[%s] has major=[%ld] and minor=[%ld]\n", devname, (long)major(devstat.st_rdev), (long)minor(devstat.st_rdev));

        while(!feof(f))
        {
            if (stream_readline(f, line, 1024)>1)
            {
                result=strtok_r(line, delims, &saveptr);
                major = -1; minor = -1; sep = -1;
                col_dev[0]=col_mnt[0]=col_fs[0]=col_opt[0]=0;
                for(i=0; result != NULL; i++)
                {
                    if (strcmp(result, "-") == 0) // found separator
                        sep = i;

                    switch (i)
                    {
                        case 2:
                            major = atol(result);
                            break;
                        case 3:
                            minor = atol(result);
                            break;
                        case 5:
                            snprintf(col_mnt, sizeof(col_mnt), "%s", result);
                            break;
                    }
                    if ((sep != -1) && (i == sep + 1))
                            snprintf(col_fs, sizeof(col_fs), "%s", result);
                    if ((sep != -1) && (i == sep + 3))
                            snprintf(col_opt, sizeof(col_opt), "%s", result);
                    result = strtok_r(NULL, delims, &saveptr);
                }

                msgprintf(MSG_DEBUG1, "mountinfo entry: major=[%ld] minor=[%ld] filesys=[%s] col_opt=[%s] col_mnt=[%s]\n", major, minor, col_fs, col_opt, col_mnt);

                if ((major==major(devstat.st_rdev)) && (minor==minor(devstat.st_rdev)))
                {
                    if (generic_get_spacestats(devname, col_mnt, temp, sizeof(temp))==0)
                    {
                        msgprintf(MSG_DEBUG1, "found mountinfo entry for device=[%s]: mnt=[%s] fs=[%s] opt=[%s]\n", devname, col_mnt, col_fs, col_opt);
                        *readwrite=generic_get_fsrwstatus(col_opt);
                        snprintf(mntbuf, maxmntbuf, "%s", col_mnt);
                        snprintf(optbuf, maxoptbuf, "%s", col_opt);
                        snprintf(fsbuf, maxfsbuf, "%s", col_fs);
                        fclose(f);
                        return 0;
                    }
                }
            }
        }

        fclose(f);
    }

    // ---- 2. if there is no /proc/self/mountinfo then use "/proc/mounts" instead

    // workaround for systems not having the "/dev/root" node entry.

    // There are systems showing "/dev/root" in "/proc/mounts" instead
    // of the actual root partition such as "/dev/sda1".
    // The consequence is that fsarchiver won't be able to realize
    // that the device it is archiving (such as "/dev/sda1") is the
    // same as "/dev/root" and that it is actually mounted. This 
    // function would then say that the "/dev/sda1" device is not mounted
    // and fsarchiver would try to mount it and mount() fails with EBUSY
    if (stat64(devname, &devstat)==0 && stat64("/", &rootstat)==0 && (devstat.st_rdev==rootstat.st_dev))
    {
        devisroot=true;
        msgprintf(MSG_VERB1, "device [%s] is the root device\n", devname);
    }

    // 2. check device in "/proc/mounts" (typical case)
    if ((f=fopen("/proc/mounts","rb"))==NULL)
    {   sysprintf("Cannot open /proc/mounts\n");
        return 1;
    }

    while(!feof(f))
    {
        if (stream_readline(f, line, 1024)>1)
        {
            result=strtok_r(line, delims, &saveptr);
            col_dev[0]=col_mnt[0]=col_fs[0]=col_opt[0]=0;
            for(i=0; result != NULL && i<=3; i++)
            {
                switch (i) // only the second word is a mount-point
                {
                    case 0:
                        snprintf(col_dev, sizeof(col_dev), "%s", result);
                        break;
                    case 1:
                        snprintf(col_mnt, sizeof(col_mnt), "%s", result);
                        break;
                    case 2:
                        snprintf(col_fs, sizeof(col_fs), "%s", result);
                        break;
                    case 3:
                        snprintf(col_opt, sizeof(col_opt), "%s", result);
                        break;
                }
                result = strtok_r(NULL, delims, &saveptr);
            }

            if ((devisroot==true) && (strcmp(col_mnt, "/")==0) && (strcmp(col_fs, "rootfs")!=0))
                snprintf(col_dev, sizeof(col_dev), "%s", devname);

            msgprintf(MSG_DEBUG1, "mount entry: col_dev=[%s] col_mnt=[%s] col_fs=[%s] col_opt=[%s]\n", col_dev, col_mnt, col_fs, col_opt);

            if (devcmp(col_dev, devname)==0)
            {
                if (generic_get_spacestats(col_dev, col_mnt, temp, sizeof(temp))==0)
                {
                    msgprintf(MSG_DEBUG1, "found mount entry for device=[%s]: mnt=[%s] fs=[%s] opt=[%s]\n", devname, col_mnt, col_fs, col_opt);
                    *readwrite=generic_get_fsrwstatus(col_opt);
                    snprintf(mntbuf, maxmntbuf, "%s", col_mnt);
                    snprintf(optbuf, maxoptbuf, "%s", col_opt);
                    snprintf(fsbuf, maxfsbuf, "%s", col_fs);
                    fclose(f);
                    return 0;
                }
            }
        }
    }
    
    fclose(f);
    return -1;
}
Пример #3
0
const char *
begin_dump(int how)
{
    const char *timestamp, *dumpname, *status, *rolename;
    time_t t;
    struct tm *tmp;

    /* back up the window procs */
    winprocs_original = windowprocs;

    /* Make a timestamp like "2011-11-30 18:45:00".  This now uses UTC time, in
       accordance with the timebase rules (in particular, we never look at the
       system timezone). This also avoids clashes when there are two games an
       hour apart and DST changed in between. (It doesn't help when there are
       two games in the same second, but that only happens as a result of
       extreme startscumming.) */
    t = (time_t)(utc_time() / 1000000LL);
    tmp = gmtime(&t);
    if (tmp)
        timestamp = msgstrftime(TIMESTAMP_FORMAT, tmp);
    else
        timestamp = "unknown time"; /* previously "???" but that's illegal
                                       on many filesystems */

    switch (how) {
    case ASCENDED:
        status = "ascended";
        break;
    case QUIT:
        status = "quit";
        break;
    case ESCAPED:
        status = "escaped";
        break;
    default:
        status = "died";
        break;
    }

    dumpname = msgprintf("%s, %s-%s-%s-%s-%s, %s.txt",
                         timestamp, u.uplname, urole.filecode, urace.filecode,
                         genders[u.ufemale].filecode,
                         aligns[1 - u.ualign.type].filecode, status);
    dumpfp = fopen_datafile(dumpname, "w+", DUMPPREFIX);
    if (!dumpfp)
        return NULL;

#ifdef UNIX
    fchmod(fileno(dumpfp), 0644);
#endif

    rolename = (u.ufemale && urole.name.f) ? urole.name.f : urole.name.m;
    fprintf(dumpfp, "%s, %s %s %s %s\n", u.uplname,
            aligns[1 - u.ualign.type].adj, genders[u.ufemale].adj,
            urace.adj, rolename);

    dump_screen(dumpfp);
    dump_status();

    return dumpname;
}
int compress_block_generic(struct s_blockinfo *blkinfo)
{
    char *bufcomp=NULL;
    int attempt=0;
    int compalgo;
    int complevel;
    u64 compsize;
    u64 bufsize;
    int res;
    
    bufsize = (blkinfo->blkrealsize) + (blkinfo->blkrealsize / 16) + 64 + 3; // alloc bigger buffer else lzo will crash
    if ((bufcomp=malloc(bufsize))==NULL)
    {   errprintf("malloc(%ld) failed: out of memory\n", (long)bufsize);
        return -1;
    }
    
    // compression level/algo to use for the first attempt
    compalgo=g_options.compressalgo;
    complevel=g_options.compresslevel;
    
    // compress the block
    do
    {
        switch (compalgo)
        {
#ifdef OPTION_LZO_SUPPORT
            case COMPRESS_LZO:
                res=compress_block_lzo(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel);
                blkinfo->blkcompalgo=COMPRESS_LZO;
                break;
#endif // OPTION_LZO_SUPPORT
            case COMPRESS_GZIP:
                res=compress_block_gzip(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel);
                blkinfo->blkcompalgo=COMPRESS_GZIP;
                break;
            case COMPRESS_BZIP2:
                res=compress_block_bzip2(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel);
                blkinfo->blkcompalgo=COMPRESS_BZIP2;
                break;
#ifdef OPTION_LZMA_SUPPORT
            case COMPRESS_LZMA:
                res=compress_block_lzma(blkinfo->blkrealsize, &compsize, (u8*)blkinfo->blkdata, (void*)bufcomp, bufsize, complevel);
                blkinfo->blkcompalgo=COMPRESS_LZMA;
                break;
#endif // OPTION_LZMA_SUPPORT
            default:
                free(bufcomp);
                msgprintf(2, "invalid compression level: %d\n", (int)compalgo);
                return -1;
        }
        
        // retry if high compression was used and compression failed because of FSAERR_ENOMEM
        if ((res == FSAERR_ENOMEM) && (compalgo > FSA_DEF_COMPRESS_ALGO))
        {
            errprintf("attempt to compress the current block using an alternative algorithm (\"-z%d\")\n", FSA_DEF_COMPRESS_ALGO);
            compalgo = FSA_DEF_COMPRESS_ALGO;
            complevel = FSA_DEF_COMPRESS_LEVEL;
        }
        
    } while ((res == FSAERR_ENOMEM) && (attempt++ == 0));
    
    // check compression status and efficiency
    if ((res==FSAERR_SUCCESS) && (compsize < blkinfo->blkrealsize)) // compression worked and saved space
    {   free(blkinfo->blkdata); // free old buffer (with uncompressed data)
        blkinfo->blkdata=bufcomp; // new buffer (with compressed data)
        blkinfo->blkcompsize=compsize; // size after compression and before encryption
        blkinfo->blkarsize=compsize; // in case there is no encryption to set this
        //errprintf ("COMP_DBG: block successfully compressed using %s\n", compress_algo_int_to_string(compalgo));
    }
    else // compressed version is bigger or compression failed: keep the original block
    {   memcpy(bufcomp, blkinfo->blkdata, blkinfo->blkrealsize);
        free(blkinfo->blkdata); // free old buffer
        blkinfo->blkdata=bufcomp; // new buffer
        blkinfo->blkcompsize=blkinfo->blkrealsize; // size after compression and before encryption
        blkinfo->blkarsize=blkinfo->blkrealsize;  // in case there is no encryption to set this
        blkinfo->blkcompalgo=COMPRESS_NONE;
        //errprintf ("COMP_DBG: block copied uncompressed, attempted using %s\n", compress_algo_int_to_string(compalgo));
    }
    
    u64 cryptsize;
    char *bufcrypt=NULL;
    if (g_options.encryptalgo==ENCRYPT_BLOWFISH)
    {
        if ((bufcrypt=malloc(bufsize+8))==NULL)
        {   errprintf("malloc(%ld) failed: out of memory\n", (long)bufsize+8);
            return -1;
        }
        if ((res=crypto_blowfish(blkinfo->blkcompsize, &cryptsize, (u8*)bufcomp, (u8*)bufcrypt, 
            g_options.encryptpass, strlen((char*)g_options.encryptpass), 1))!=0)
        {   errprintf("crypt_block_blowfish() failed\n");
            return -1;
        }
        free(bufcomp);
        blkinfo->blkdata=bufcrypt;
        blkinfo->blkarsize=cryptsize;
        blkinfo->blkcryptalgo=ENCRYPT_BLOWFISH;
    }
    else
    {
        blkinfo->blkcryptalgo=ENCRYPT_NONE;
    }
    
    // calculates the final block checksum (block as it will be stored in the archive)
    blkinfo->blkarcsum=fletcher32((void*)blkinfo->blkdata, blkinfo->blkarsize);
    
    return 0;
}
Пример #5
0
/* pick a lock on a chest or door with a given object */
int
pick_lock(struct obj *pick, const struct nh_cmd_arg *arg)
{
    int picktyp, c;
    coord cc;
    schar dx, dy, dz;
    struct rm *door;
    struct obj *otmp;
    const char *qbuf;

    if (!getargdir(arg, NULL, &dx, &dy, &dz))
        return 0;
    cc.x = youmonst.mx + dx;
    cc.y = youmonst.my + dy;
    if (!isok(cc.x, cc.y))
        return 0;

    picktyp = pick->otyp;
    pick->lastused = moves;

    /* Check whether we're resuming an interrupted previous attempt.  For a
       floor pick, we have u.utracked[tos_lock] as a non-zeroobj and dx and dy
       as 0.  For a door, we have u.utracked_location[tl_lock] specifying the
       location and u.utracked[tos_lock] as &zeroobj. */
    if (u.uoccupation_progress[tos_lock] &&
        ((u.utracked_location[tl_lock].x == cc.x &&
          u.utracked_location[tl_lock].y == cc.y &&
          u.utracked[tos_lock] == &zeroobj) ||
         (dx == 0 && dy == 0 && u.utracked[tos_lock] != &zeroobj))) {
        static const char no_longer[] =
            "Unfortunately, you can no longer %s %s.";

        if (nohands(youmonst.data)) {
            const char *what = (picktyp == LOCK_PICK) ? "pick" : "key";

            if (picktyp == CREDIT_CARD)
                what = "card";
            pline(msgc_interrupted, no_longer, "hold the", what);
            return reset_pick();
        } else if (u.utracked[tos_lock] != &zeroobj && !can_reach_floor()) {
            pline(msgc_interrupted, no_longer, "reach the", "lock");
            return reset_pick();
        } else {
            const char *action = lock_action();

            if (turnstate.continue_message)
                pline(msgc_occstart, "You resume your attempt at %s.", action);

            one_occupation_turn(picklock, "picking the lock", occ_lock);
            return 1;
        }
    }

    if (nohands(youmonst.data)) {
        pline(msgc_cancelled, "You can't hold %s -- you have no hands!",
              doname(pick));
        return 0;
    }

    if ((picktyp != LOCK_PICK && picktyp != CREDIT_CARD &&
         picktyp != SKELETON_KEY)) {
        impossible("picking lock with object %d?", picktyp);
        return 0;
    }

    if (!dx && !dy) { /* pick lock on a container */
        const char *verb;
        boolean it;
        int count;

        if (dz < 0) {
            pline(msgc_cancelled, "There isn't any sort of lock up %s.",
                  Levitation ? "here" : "there");
            return 0;
        } else if (is_lava(level, youmonst.mx, youmonst.my)) {
            pline(msgc_cancelled, "Doing that would probably melt your %s.",
                  xname(pick));
            return 0;
        } else if (is_pool(level, youmonst.mx, youmonst.my) && !Underwater) {
            /* better YAFM - AIS */
            pline(msgc_cancelled,
                  "Canals might have locks, but this water doesn't.");
            return 0;
        }

        count = 0;
        c = 'n';        /* in case there are no boxes here */
        for (otmp = level->objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere)
            if (Is_box(otmp)) {
                ++count;
                if (!can_reach_floor()) {
                    pline(msgc_cancelled, "You can't reach %s from up here.",
                          the(xname(otmp)));
                    return 0;
                }
                it = 0;
                if (otmp->obroken)
                    verb = "fix";
                else if (!otmp->olocked)
                    verb = "lock", it = 1;
                else if (picktyp != LOCK_PICK)
                    verb = "unlock", it = 1;
                else
                    verb = "pick";
                qbuf = msgprintf(
                    "There is %s here, %s %s?",
                    safe_qbuf("",
                              sizeof ("There is  here, unlock its lock?"),
                              doname(otmp), an(simple_typename(otmp->otyp)),
                              "a box"), verb, it ? "it" : "its lock");

                c = ynq(qbuf);
                if (c == 'q')
                    return 0;
                if (c == 'n')
                    continue;

                if (otmp->obroken) {
                    pline(msgc_cancelled,
                          "You can't fix its broken lock with %s.",
                          doname(pick));
                    return 0;
                } else if (picktyp == CREDIT_CARD && !otmp->olocked) {
                    /* credit cards are only good for unlocking */
                    pline(msgc_cancelled, "You can't do that with %s.",
                          doname(pick));
                    return 0;
                }

                u.utracked[tos_lock] = otmp;
                u.uoccupation_progress[tos_lock] = 0;
                break;
            }
        if (c != 'y') {
            if (!count)
                pline(msgc_cancelled,
                      "There doesn't seem to be any sort of lock here.");
            return 0;   /* decided against all boxes */
        }
    } else {    /* pick the lock in a door */
        struct monst *mtmp;

        if (u.utrap && u.utraptype == TT_PIT) {
            pline(msgc_cancelled,
                  "You can't reach over the edge of the pit.");
            return 0;
        }

        door = &level->locations[cc.x][cc.y];
        if ((mtmp = m_at(level, cc.x, cc.y)) && canseemon(mtmp)) {
            if (picktyp == CREDIT_CARD &&
                (mx_eshk(mtmp) || mtmp->data == &mons[PM_ORACLE]))
                verbalize(msgc_npcvoice, "No checks, no credit, no problem.");
            else
                pline(msgc_mispaste, "I don't think %s would appreciate that.",
                      mon_nam(mtmp));
            return 0;
        }
        if (mtmp && (mtmp->m_ap_type == M_AP_FURNITURE) &&
            (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) &&
            !Protection_from_shape_changers) {
            stumble_onto_mimic(mtmp, dx, dy);
            return 1;
        }
        if (!IS_DOOR(door->typ)) {
            if (is_drawbridge_wall(cc.x, cc.y) >= 0)
                pline(msgc_cancelled, "You %s no lock on the drawbridge.",
                      Blind ? "feel" : "see");
            else
                pline(msgc_mispaste, "You %s no door there.",
                      Blind ? "feel" : "see");
            return 0;
        }
        switch (door->doormask) {
        case D_NODOOR:
            pline(msgc_cancelled, "This doorway has no door.");
            return 0;
        case D_ISOPEN:
            pline(msgc_cancelled, "You cannot lock an open door.");
            return 0;
        case D_BROKEN:
            pline(msgc_cancelled, "This door is broken.");
            return 0;
        default:
            /* credit cards are only good for unlocking */
            if (picktyp == CREDIT_CARD && !(door->doormask & D_LOCKED)) {
                pline(msgc_cancelled,
                      "You can't lock a door with a credit card.");
                return 0;
            }

            /* At this point, the player knows that the door is a door, and
               whether it's locked, but not whether it's trapped; to do this,
               we set the mem_door_l flag and call map_background, which will
               clear it if necessary (i.e. not a door after all). */
            level->locations[cc.x][cc.y].mem_door_l = 1;
            map_background(cc.x, cc.y, TRUE);

            u.utracked[tos_lock] = &zeroobj;
            u.utracked_location[tl_lock] = cc;
            u.uoccupation_progress[tos_lock] = 0;
        }
    }

    one_occupation_turn(picklock, "picking the lock", occ_lock);
    return 1;
}
Пример #6
0
/* Handles one turn of book reading. Returns 1 if unfinished, 0 if finshed. */
static int
learn(void)
{
    int i;
    short booktype;
    boolean costly = TRUE;
    boolean already_known = FALSE;
    int first_unknown = MAXSPELL;
    int known_spells = 0;
    const char *splname;

    /* JDS: lenses give 50% faster reading; 33% smaller read time */
    if (u.uoccupation_progress[tos_book] &&
        ublindf && ublindf->otyp == LENSES && rn2(2))
        u.uoccupation_progress[tos_book]++;
    if (Confusion) {    /* became confused while learning */
        confused_book(u.utracked[tos_book]);
        u.utracked[tos_book] = 0;       /* no longer studying */
        helpless(-u.uoccupation_progress[tos_book], hr_busy,
                 "absorbed in a spellbook",
                 "You're finally able to put the book down.");
        u.uoccupation_progress[tos_book] = 0;
        return 0;
    }

    booktype = u.utracked[tos_book]->otyp;
    if (booktype == SPE_BOOK_OF_THE_DEAD) {
        deadbook(u.utracked[tos_book], FALSE);
        u.utracked[tos_book] = 0;
        u.uoccupation_progress[tos_book] = 0;
        return 0;
    }

    /* The book might get cursed while we're reading it. In this case,
       immediately stop reading it, cancel progress, and apply a few turns of
       helplessness. (3.4.3 applies negative spellbook effects but lets you
       memorize the spell anyway; this makes no sense. It destroys the spellbook
       on the "contact poison" result, which makes even less sense.) */
    if (u.utracked[tos_book]->cursed) {
        pline("This book isn't making sense any more.");
        helpless(rn1(5,5), hr_busy,
                 "making sense of a spellbook",
                 "You give up trying to make sense of the spellbook.");
        u.uoccupation_progress[tos_book] = 0;
        u.utracked[tos_book] = 0;
        return 0;
    }

    if (++u.uoccupation_progress[tos_book] < 0)
        return 1;       /* still busy */

    if (ACURR(A_WIS) < 12)
        exercise(A_WIS, TRUE); /* you're studying. */

    splname = msgprintf(objects[booktype].oc_name_known ?
                        "\"%s\"" : "the \"%s\" spell",
                        OBJ_NAME(objects[booktype]));
    for (i = 0; i < MAXSPELL; i++) {
        if (spellid(i) == booktype) {
            already_known = TRUE;
            if (u.utracked[tos_book]->spestudied > MAX_SPELL_STUDY) {
                pline("This spellbook is too faint to be read any more.");
                u.utracked[tos_book]->otyp = booktype = SPE_BLANK_PAPER;
            } else if (spellknow(i) <= 1000) {
                pline("Your knowledge of %s is keener.", splname);
                incrnknow(i);
                u.utracked[tos_book]->spestudied++;
                if (ACURR(A_WIS) < 12)
                    exercise(A_WIS, TRUE); /* extra study */
            } else {    /* 1000 < spellknow(i) <= MAX_SPELL_STUDY */
                pline("You know %s quite well already.", splname);
                if (yn("Do you want to read the book anyway?") == 'y') {
                    pline("You refresh your knowledge of %s.", splname);
                    incrnknow(i);
                    u.utracked[tos_book]->spestudied++;
                } else
                    costly = FALSE;
            }
            /* make book become known even when spell is already known, in case
               amnesia made you forget the book */
            makeknown((int)booktype);
            break;
        } else if (spellid(i) == NO_SPELL &&
                   (i < first_unknown ||
                    i == spellno_from_let(objects[booktype].oc_defletter)))
            first_unknown = i;
        else
            known_spells++;
    }

    if (first_unknown == MAXSPELL && !already_known)
        panic("Too many spells memorized!");

    if (!already_known) {
        spl_book[first_unknown].sp_id = booktype;
        spl_book[first_unknown].sp_lev = objects[booktype].oc_level;
        incrnknow(first_unknown);
        u.utracked[tos_book]->spestudied++;
        pline(known_spells > 0 ? "You add %s to your repertoire." :
              "You learn %s.", splname);
        makeknown((int)booktype);
    }

    if (costly)
        check_unpaid(u.utracked[tos_book]);
    u.utracked[tos_book] = 0;
    return 0;
}
Пример #7
0
int
spelleffects(int spell, boolean atme, const struct nh_cmd_arg *arg)
{
    int energy, damage, chance, n, intell;
    int skill, role_skill;
    boolean confused = (Confusion != 0);
    struct obj *pseudo;
    boolean dummy;
    coord cc;
    schar dx = 0, dy = 0, dz = 0;

    if (!SPELL_IS_FROM_SPELLBOOK(spell)) {
        /* At the moment, we implement this via calling the code for the
           shortcut command. Eventually, it would make sense to invert this
           (and make the shortcut commands wrappers for spelleffects). */
        switch (spellid(spell)) {
        case SPID_PRAY:
            return dopray(arg);
        case SPID_TURN:
            return doturn(arg);
        case SPID_RLOC:
            return dotele(arg);
        case SPID_JUMP:
            return dojump(arg);
        case SPID_MONS:
            return domonability(arg);
        default:
            impossible("Unknown spell number %d?", spellid(spell));
            return 0;
        }
    }

    /*
     * Find the skill the hero has in a spell type category.
     * See spell_skilltype for categories.
     */
    skill = spell_skilltype(spellid(spell));
    role_skill = P_SKILL(skill);

    /* Get the direction or target, if applicable.

       We want to do this *before* determining spell success, both for interface
       consistency and to cut down on needless mksobj calls. */
    switch (spellid(spell)) {

    /* These spells ask the user to target a specific space. */
    case SPE_CONE_OF_COLD:
    case SPE_FIREBALL:
        /* If Skilled or better, get a specific space. */
        if (role_skill >= P_SKILLED) {
            if (throwspell(&dx, &dy, arg)) {
                dz = 0;
                break;
            }
            else {
                /* Decided not to target anything.  Abort the spell. */
                pline("Spell canceled.");
                return 0;
            }
        }
        /* If not Skilled, fall through. */

    /* These spells ask the user to target a direction. */
    case SPE_FORCE_BOLT:
    case SPE_SLEEP:
    case SPE_MAGIC_MISSILE:
    case SPE_KNOCK:
    case SPE_SLOW_MONSTER:
    case SPE_WIZARD_LOCK:
    case SPE_DIG:
    case SPE_TURN_UNDEAD:
    case SPE_POLYMORPH:
    case SPE_TELEPORT_AWAY:
    case SPE_CANCELLATION:
    case SPE_FINGER_OF_DEATH:
    case SPE_HEALING:
    case SPE_EXTRA_HEALING:
    case SPE_DRAIN_LIFE:
    case SPE_STONE_TO_FLESH:
        if (atme)
            dx = dy = dz = 0;
        else if (!getargdir(arg, NULL, &dx, &dy, &dz)) {
            /* getdir cancelled, abort */
            pline("Spell canceled.");
            return 0;
        }
        break;
    case SPE_JUMPING:
        if(!get_jump_coords(arg, &cc, max(role_skill, 1))) {
            /* No jumping after all, I guess. */
            pline("Spell canceled.");
            return 0;
        }
        break;

    /* The rest of the spells don't have targeting. */
    default:
        break;
    }


    /* Spell casting no longer affects knowledge of the spell. A decrement of
       spell knowledge is done every turn. */
    if (spellknow(spell) <= 0) {
        pline("Your knowledge of this spell is twisted.");
        pline("It invokes nightmarish images in your mind...");
        spell_backfire(spell);
        return 0;
    } else if (spellknow(spell) <= 200) {       /* 1% */
        pline("You strain to recall the spell.");
    } else if (spellknow(spell) <= 1000) {      /* 5% */
        pline("Your knowledge of this spell is growing faint.");
    }
    energy = (spellev(spell) * 5);      /* 5 <= energy <= 35 */

    if (u.uhunger <= 10 && spellid(spell) != SPE_DETECT_FOOD) {
        pline("You are too hungry to cast that spell.");
        return 0;
    } else if (ACURR(A_STR) < 4) {
        pline("You lack the strength to cast spells.");
        return 0;
    } else
        if (check_capacity
            ("Your concentration falters while carrying so much stuff.")) {
        return 1;
    } else if (!freehand()) {
        pline("Your arms are not free to cast!");
        return 0;
    }

    if (Uhave_amulet) {
        pline("You feel the amulet draining your energy away.");
        energy += rnd(2 * energy);
    }
    if (energy > u.uen) {
        pline("You don't have enough energy to cast that spell.");
        return 0;
    } else {
        if (spellid(spell) != SPE_DETECT_FOOD) {
            int hungr = energy * 2;

            /*
             * If hero is a wizard, their current intelligence
             * (bonuses + temporary + current)
             * affects hunger reduction in casting a spell.
             * 1. int = 17-18 no reduction
             * 2. int = 16    1/4 hungr
             * 3. int = 15    1/2 hungr
             * 4. int = 1-14  normal reduction
             * The reason for this is:
             * a) Intelligence affects the amount of exertion
             * in thinking.
             * b) Wizards have spent their life at magic and
             * understand quite well how to cast spells.
             */
            intell = acurr(A_INT);
            if (!Role_if(PM_WIZARD))
                intell = 10;
            if (intell >= 17)
                hungr = 0;
            else if (intell == 16)
                hungr /= 4;
            else if (intell == 15)
                hungr /= 2;

            /* don't put player (quite) into fainting from casting a spell,
               particularly since they might not even be hungry at the
               beginning; however, this is low enough that they must eat before
               casting anything else except detect food */
            if (hungr > u.uhunger - 3)
                hungr = u.uhunger - 3;
            morehungry(hungr);
        }
    }

    chance = percent_success(spell);
    if (confused || (rnd(100) > chance)) {
        pline("You fail to cast the spell correctly.");
        u.uen -= energy / 2;
        return 1;
    }

    u.uen -= energy;
    /* pseudo is a temporary "false" object containing the spell stats */
    pseudo = mktemp_sobj(level, spellid(spell));
    pseudo->blessed = pseudo->cursed = 0;
    pseudo->quan = 20L; /* do not let useup get it */

    switch (pseudo->otyp) {
        /*
         * At first spells act as expected.  As the hero increases in skill
         * with the appropriate spell type, some spells increase in their
         * effects, e.g. more damage, further distance, and so on, without
         * additional cost to the spellcaster.
         */
    case SPE_CONE_OF_COLD:
    case SPE_FIREBALL:
        if (role_skill >= P_SKILLED) {
            cc.x = dx;
            cc.y = dy;
            n = rnd(8) + 1;
            while (n--) {
                if (!dx && !dy && !dz) {
                    if ((damage = zapyourself(pseudo, TRUE)) != 0)
                        losehp(damage, msgprintf(
                                   "zapped %sself with an exploding spell",
                                   uhim()));
                } else {
                    explode(dx, dy, pseudo->otyp - SPE_MAGIC_MISSILE + 10,
                            u.ulevel / 2 + 1 + spell_damage_bonus(), 0,
                            (pseudo->otyp ==
                             SPE_CONE_OF_COLD) ? EXPL_FROSTY : EXPL_FIERY,
                            NULL, 0);
                }
                dx = cc.x + rnd(3) - 2;
                dy = cc.y + rnd(3) - 2;
                if (!isok(dx, dy) || !cansee(dx, dy) ||
                    IS_STWALL(level->locations[dx][dy].typ) || Engulfed) {
                    /* Spell is reflected back to center */
                    dx = cc.x;
                    dy = cc.y;
                }
            }
            break;
        }

        /* else fall through... */
        /* these spells are all duplicates of wand effects */
    case SPE_FORCE_BOLT:
    case SPE_SLEEP:
    case SPE_MAGIC_MISSILE:
    case SPE_KNOCK:
    case SPE_SLOW_MONSTER:
    case SPE_WIZARD_LOCK:
    case SPE_DIG:
    case SPE_TURN_UNDEAD:
    case SPE_POLYMORPH:
    case SPE_TELEPORT_AWAY:
    case SPE_CANCELLATION:
    case SPE_FINGER_OF_DEATH:
    case SPE_LIGHT:
    case SPE_DETECT_UNSEEN:
    case SPE_HEALING:
    case SPE_EXTRA_HEALING:
    case SPE_DRAIN_LIFE:
    case SPE_STONE_TO_FLESH:
        if (objects[pseudo->otyp].oc_dir != NODIR) {
            if (!dx && !dy && !dz) {
                if ((damage = zapyourself(pseudo, TRUE)) != 0) {
                    losehp(damage, msgprintf("zapped %sself with a spell",
                                             uhim()));
                }
            } else
                weffects(pseudo, dx, dy, dz);
        } else
            weffects(pseudo, 0, 0, 0);
        update_inventory();     /* spell may modify inventory */
        break;

        /* these are all duplicates of scroll effects */
    case SPE_REMOVE_CURSE:
    case SPE_CONFUSE_MONSTER:
    case SPE_DETECT_FOOD:
    case SPE_CAUSE_FEAR:
        /* high skill yields effect equivalent to blessed scroll */
        if (role_skill >= P_SKILLED)
            pseudo->blessed = 1;
        /* fall through */
    case SPE_CHARM_MONSTER:
    case SPE_MAGIC_MAPPING:
    case SPE_CREATE_MONSTER:
    case SPE_IDENTIFY:
        seffects(pseudo, &dummy);
        break;

        /* these are all duplicates of potion effects */
    case SPE_HASTE_SELF:
    case SPE_DETECT_TREASURE:
    case SPE_DETECT_MONSTERS:
    case SPE_LEVITATION:
    case SPE_RESTORE_ABILITY:
        /* high skill yields effect equivalent to blessed potion */
        if (role_skill >= P_SKILLED)
            pseudo->blessed = 1;
        /* fall through */
    case SPE_INVISIBILITY:
        peffects(pseudo);
        break;

    case SPE_CURE_BLINDNESS:
        healup(0, 0, FALSE, TRUE);
        break;
    case SPE_CURE_SICKNESS:
        if (Sick)
            pline("You are no longer ill.");
        if (Slimed) {
            pline("The slime disappears!");
            Slimed = 0;
        }
        healup(0, 0, TRUE, FALSE);
        break;
    case SPE_CREATE_FAMILIAR:
        make_familiar(NULL, u.ux, u.uy, FALSE);
        break;
    case SPE_CLAIRVOYANCE:
        if (!BClairvoyant)
            do_vicinity_map();
        /* at present, only one thing blocks clairvoyance */
        else if (uarmh && uarmh->otyp == CORNUTHAUM)
            pline("You sense a pointy hat on top of your %s.", body_part(HEAD));
        break;
    case SPE_PROTECTION:
        cast_protection();
        break;
    case SPE_JUMPING:
        jump_to_coords(&cc);
        break;
    default:
        impossible("Unknown spell %d attempted.", spell);
        obfree(pseudo, NULL);
        return 0;
    }

    /* gain skill for successful cast */
    use_skill(skill, spellev(spell));

    obfree(pseudo, NULL);       /* now, get rid of it */
    return 1;
}
Пример #8
0
/* Note: I had to choose one of three possible kinds of "type" when writing
 * this function: a wand type (like in zap.c), an adtyp, or an object type.
 * Wand types get complex because they must be converted to adtyps for
 * determining such things as fire resistance.  Adtyps get complex in that
 * they don't supply enough information--was it a player or a monster that
 * did it, and with a wand, spell, or breath weapon?  Object types share both
 * these disadvantages....
 *
 * The descr argument should be used to describe the explosion. It should be
 * a string suitable for use with an().
 * raylevel is used for explosions caused by skilled wand usage (0=no wand)
 */
void
explode(int x, int y, int type, /* the same as in zap.c */
        int dam, char olet, int expltype, const char *descr, int raylevel)
{
    int i, j, k, damu = dam;
    boolean visible, any_shield, resist_death;
    resist_death = FALSE;
    int uhurt = 0;      /* 0=unhurt, 1=items damaged, 2=you and items damaged */
    const char *str;
    const char *dispbuf = "";   /* lint suppression; I think the code's OK */
    boolean expl_needs_the = TRUE;
    int idamres, idamnonres;
    struct monst *mtmp;
    uchar adtyp;
    int explmask[3][3];

    /* 0=normal explosion, 1=do shieldeff, 2=do nothing */
    boolean shopdamage = FALSE;

#if 0
    /* Damage reduction from wand explosions */
    if (olet == WAND_CLASS)     /* retributive strike */
        switch (Role_switch) {
        case PM_PRIEST:
        case PM_MONK:
        case PM_WIZARD:
            damu /= 5;
            break;
        case PM_HEALER:
        case PM_KNIGHT:
            damu /= 2;
            break;
        default:
            break;
        }
#endif
    if (olet == MON_EXPLODE) {
        str = descr;
        adtyp = AD_PHYS;
        if (Hallucination) {
            int name = rndmonidx();

            dispbuf = msgcat(s_suffix(monnam_for_index(name)), " explosion");
            expl_needs_the = !monnam_is_pname(name);
        } else {
            dispbuf = str;
        }
    } else {
        int whattype = abs(type) % 10;

        adtyp = whattype + 1;
        boolean done = FALSE, hallu = Hallucination;

        if (hallu) {
            do {
                whattype = rn2(8);
            } while (whattype == 3);
        }
tryagain:
        switch (whattype) {
        case 0:
            str = "magical blast";
            break;
        case 1:
            str =
                olet == BURNING_OIL ? "burning oil" : olet ==
                SCROLL_CLASS ? "tower of flame" : "fireball";
            break;
        case 2:
            str = "ball of cold";
            break;
        case 3:
            str = "sleeping gas";
            break;
        case 4:
            str = (olet == WAND_CLASS) ? "death field" : "disintegration field";
            break;
        case 5:
            str = "ball of lightning";
            break;
        case 6:
            str = "poison gas cloud";
            break;
        case 7:
            str = "splash of acid";
            break;
        default:
            impossible("explosion base type %d?", type);
            return;
        }
        if (!done) {
            dispbuf = str;
            done = TRUE;
            if (hallu) {
                whattype = adtyp - 1;
                goto tryagain;
            }
        }
    }

    any_shield = visible = FALSE;
    for (i = 0; i < 3; i++)
        for (j = 0; j < 3; j++) {
            if (!isok(i + x - 1, j + y - 1)) {
                explmask[i][j] = 2;
                continue;
            } else
                explmask[i][j] = 0;

            if (i + x - 1 == u.ux && j + y - 1 == u.uy) {
                switch (adtyp) {
                case AD_PHYS:
                    explmask[i][j] = 0;
                    break;
                case AD_MAGM:
                    explmask[i][j] = !!(raylevel >= P_EXPERT || Antimagic);
                    break;
                case AD_FIRE:
                    explmask[i][j] = !!Fire_resistance;
                    break;
                case AD_COLD:
                    explmask[i][j] = !!Cold_resistance;
                    break;
                case AD_SLEE:
                    explmask[i][j] = !!Sleep_resistance;
                    break;
                case AD_DISN:
                    if (raylevel == P_UNSKILLED && Drain_resistance)
                        resist_death = TRUE;
                    /* why MR doesn't resist general deathfields is beyond me, but... */
                    if (nonliving(youmonst.data) ||
                            is_demon(youmonst.data))
                        resist_death = TRUE;
                    if (raylevel && Antimagic)
                        resist_death = TRUE;
                    if (raylevel >= P_EXPERT && !Drain_resistance)
                        resist_death = FALSE;
                    explmask[i][j] =
                        (olet == WAND_CLASS) ? !!resist_death :
                        !!Disint_resistance;
                    break;
                case AD_ELEC:
                    explmask[i][j] = !!Shock_resistance;
                    break;
                case AD_DRST:
                    explmask[i][j] = !!Poison_resistance;
                    break;
                case AD_ACID:
                    explmask[i][j] = !!Acid_resistance;
                    break;
                default:
                    impossible("explosion type %d?", adtyp);
                    break;
                }
            }
            /* can be both you and mtmp if you're swallowed */
            mtmp = m_at(level, i + x - 1, j + y - 1);
            if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
                mtmp = u.usteed;
            if (mtmp) {
                if (mtmp->mhp < 1)
                    explmask[i][j] = 2;
                else
                    switch (adtyp) {
                    case AD_PHYS:
                        break;
                    case AD_MAGM:
                        explmask[i][j] |= (raylevel >= 4 || resists_magm(mtmp));
                        break;
                    case AD_FIRE:
                        explmask[i][j] |= resists_fire(mtmp);
                        break;
                    case AD_COLD:
                        explmask[i][j] |= resists_cold(mtmp);
                        break;
                    case AD_SLEE:
                        explmask[i][j] |= resists_sleep(mtmp);
                    case AD_DISN:
                        if (raylevel == P_UNSKILLED && resists_drli(mtmp))
                            resist_death = TRUE;
                        if (nonliving(mtmp->data) ||
                                is_demon(mtmp->data))
                            resist_death = TRUE;
                        if (raylevel && resists_magm(mtmp))
                            resist_death = TRUE;
                        if (raylevel >= P_EXPERT && !resists_drli(mtmp))
                            resist_death = FALSE;
                        explmask[i][j] |=
                            (olet == WAND_CLASS) ? resist_death :
                            resists_disint(mtmp);
                        break;
                    case AD_ELEC:
                        explmask[i][j] |= resists_elec(mtmp);
                        break;
                    case AD_DRST:
                        explmask[i][j] |= resists_poison(mtmp);
                        break;
                    case AD_ACID:
                        explmask[i][j] |= resists_acid(mtmp);
                        break;
                    default:
                        impossible("explosion type %d?", adtyp);
                        break;
                    }
            }
            reveal_monster_at(i + x - 1, j + y - 1, TRUE);

            if (cansee(i + x - 1, j + y - 1))
                visible = TRUE;
            if (explmask[i][j] == 1)
                any_shield = TRUE;
        }

    if (visible) {
        struct tmp_sym *tsym = tmpsym_init(DISP_BEAM, 0);

        /* Start the explosion */
        for (i = 0; i < 3; i++)
            for (j = 0; j < 3; j++) {
                if (explmask[i][j] == 2)
                    continue;
                tmpsym_change(tsym, dbuf_explosion(expltype, explosion[i][j]));
                tmpsym_at(tsym, i + x - 1, j + y - 1);
            }
        flush_screen(); /* will flush screen and output */

        if (any_shield && flags.sparkle) {      /* simulate shield effect */
            for (k = 0; k < SHIELD_COUNT; k++) {
                for (i = 0; i < 3; i++)
                    for (j = 0; j < 3; j++) {
                        if (explmask[i][j] == 1)
                            /*
                             * Bypass tmpsym_at() and send the shield glyphs
                             * directly to the buffered screen.  tmpsym_at()
                             * will clean up the location for us later.
                             */
                            dbuf_set_effect(i + x - 1, j + y - 1,
                                            dbuf_effect(E_MISC,
                                                        shield_static[k]));
                    }
                flush_screen(); /* will flush screen and output */
                win_delay_output();
            }

            /* Cover last shield glyph with blast symbol. */
            for (i = 0; i < 3; i++)
                for (j = 0; j < 3; j++) {
                    if (explmask[i][j] == 1)
                        dbuf_set_effect(i + x - 1, j + y - 1,
                                        dbuf_explosion(expltype,
                                                       explosion[i][j]));
                }

        } else {        /* delay a little bit. */
            win_delay_output();
            win_delay_output();
        }

        tmpsym_end(tsym);       /* clear the explosion */
    } else {
        if (olet == MON_EXPLODE) {
            str = "explosion";
        }
        You_hear("a blast.");
    }

    if (dam)
        for (i = 0; i < 3; i++)
            for (j = 0; j < 3; j++) {
                if (explmask[i][j] == 2)
                    continue;
                if (i + x - 1 == u.ux && j + y - 1 == u.uy)
                    uhurt = (explmask[i][j] == 1) ? 1 : 2;
                idamres = idamnonres = 0;
                if (type >= 0)
                    zap_over_floor((xchar) (i + x - 1), (xchar) (j + y - 1),
                                   type, &shopdamage);

                mtmp = m_at(level, i + x - 1, j + y - 1);
                if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
                    mtmp = u.usteed;
                if (!mtmp)
                    continue;
                if (Engulfed && mtmp == u.ustuck) {
                    if (is_animal(u.ustuck->data))
                        pline("%s gets %s!", Monnam(u.ustuck),
                              (adtyp == AD_FIRE) ? "heartburn" :
                              (adtyp == AD_COLD) ? "chilly" :
                              (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
                                                    "irradiated by pure energy"
                                                    : "perforated") :
                              (adtyp == AD_ELEC) ? "shocked" :
                              (adtyp == AD_DRST) ? "poisoned" :
                              (adtyp == AD_ACID) ? "an upset stomach" :
                              "fried");
                    else
                        pline("%s gets slightly %s!", Monnam(u.ustuck),
                              (adtyp == AD_FIRE) ? "toasted" :
                              (adtyp == AD_COLD) ? "chilly" :
                              (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
                                                    "overwhelmed by pure energy"
                                                    : "perforated") :
                              (adtyp == AD_ELEC) ? "shocked" :
                              (adtyp == AD_DRST) ? "intoxicated" :
                              (adtyp == AD_ACID) ? "burned" : "fried");
                } else if (cansee(i + x - 1, j + y - 1)) {
                    if (mtmp->m_ap_type) seemimic(mtmp);
                    pline("%s is caught in %s%s!", Monnam(mtmp),
                          expl_needs_the ? "the " : "", dispbuf);
                }

                idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int)adtyp);
                idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int)adtyp);
                idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int)adtyp);
                idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int)adtyp);
                idamnonres += destroy_mitem(mtmp, RING_CLASS, (int)adtyp);

                if (explmask[i][j] == 1) {
                    golemeffects(mtmp, (int)adtyp, dam + idamres);
                    mtmp->mhp -= idamnonres;
                } else {
                    /* call resist with 0 and do damage manually so 1) we can
                       get out the message before doing the damage, and 2) we
                       can call mondied, not killed, if it's not your blast */
                    int mdam = dam;

                    if (resist(mtmp, olet, 0, FALSE)) {
                        if (cansee(i + x - 1, j + y - 1))
                            pline("%s resists %s%s!", Monnam(mtmp),
                                  expl_needs_the ? "the " : "", dispbuf);
                        mdam = dam / 2;
                    }
                    if (mtmp == u.ustuck)
                        mdam *= 2;
                    if (resists_cold(mtmp) && adtyp == AD_FIRE)
                        mdam *= 2;
                    else if (resists_fire(mtmp) && adtyp == AD_COLD)
                        mdam *= 2;
                    if (adtyp == AD_MAGM && raylevel >= P_EXPERT && resists_magm(mtmp))
                        mdam = (mdam + 1) / 2;
                    if (adtyp == AD_SLEE && raylevel) {
                        sleep_monst(mtmp, mdam, WAND_CLASS);
                        mdam = 0;
                    }
                    if (adtyp == AD_DISN && raylevel) {
                        if (nonliving(mtmp->data) ||
                                is_demon(mtmp->data) ||
                                resists_magm(mtmp) ||
                                raylevel == P_UNSKILLED) {
                            /* monster is deathresistant or raylevel==unskilled,
                               since monster apparently failed to resist earlier,
                               monster must be vulnerable to drli */
                            /* FIXME: make a generic losexp() for monsters */
                            mdam = dice(2, 6);
                            if (cansee(i + x - 1, j + y - 1))
                                pline("%s suddenly seems weaker!", Monnam(mtmp));
                            mtmp->mhpmax -= mdam;
                            if (mtmp->m_lev == 0)
                                mdam = mtmp->mhp;
                            else
                                mtmp->m_lev--;
                        } else
                            mdam = mtmp->mhp; /* instadeath */
                    }
                    mtmp->mhp -= mdam;
                    mtmp->mhp -= (idamres + idamnonres);
                }
                if (mtmp->mhp <= 0) {
                    /* KMH -- Don't blame the player for pets killing gas
                       spores */
                    if (!flags.mon_moving)
                        killed(mtmp);
                    else
                        monkilled(mtmp, "", (int)adtyp);
                } else if (!flags.mon_moving)
                    setmangry(mtmp);
            }

    /* Do your injury last */
    if (uhurt) {
        if ((type >= 0 || adtyp == AD_PHYS) &&  /* gas spores */
                flags.verbose && olet != SCROLL_CLASS)
            pline("You are caught in %s%s!", expl_needs_the ? "the " : "",
                  dispbuf);
        /* do property damage first, in case we end up leaving bones */
        if (adtyp == AD_FIRE)
            burn_away_slime();
        if (u.uinvulnerable) {
            damu = 0;
            pline("You are unharmed!");
        } else if (Half_physical_damage && adtyp == AD_PHYS)
            damu = (damu + 1) / 2;
        else if (raylevel) {
            if (adtyp == AD_MAGM && Antimagic)
                damu = (damu + 1) / 2;
            if (adtyp == AD_SLEE) {
                helpless(damu, hr_asleep, "sleeping", NULL);
                damu = 0;
            }
            if (adtyp == AD_DISN) {
                if (nonliving(youmonst.data) ||
                        is_demon(youmonst.data) ||
                        Antimagic ||
                        raylevel == P_UNSKILLED) {
                    losexp("drained by a death field",FALSE);
                    damu = 0;
                } else {
                    done(DIED, "killed by a death field");
                    damu = 0; /* lifesaved */
                }
            }
        }
        if (adtyp == AD_FIRE) {
            burnarmor(&youmonst);
            set_candles_afire();
        }
        destroy_item(SCROLL_CLASS, (int)adtyp);
        destroy_item(SPBOOK_CLASS, (int)adtyp);
        destroy_item(POTION_CLASS, (int)adtyp);
        destroy_item(RING_CLASS, (int)adtyp);
        destroy_item(WAND_CLASS, (int)adtyp);

        ugolemeffects((int)adtyp, damu);
        if (uhurt == 2) {
            if (Upolyd)
                u.mh -= damu;
            else
                u.uhp -= damu;
        }

        if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
            int death = adtyp == AD_FIRE ? BURNING : DIED;
            const char *killer;

            if (olet == MON_EXPLODE) {
                killer = killer_msg(death, an(str));
            } else if (type >= 0 && olet != SCROLL_CLASS) {
                /* check whether or not we were the source of the explosion */
                if (!flags.mon_moving)
                    killer = msgprintf("caught %sself in %s own %s", uhim(),
                                       uhis(), str);
                else
                    killer = msgprintf("killed by a %s", str);
            } else if (!strcmp(str, "burning oil")) {
                /* This manual check hack really sucks */
                killer = killer_msg(death, str);
            } else {
                killer = killer_msg(death, an(str));
            }
            /* Known BUG: BURNING suppresses corpse in bones data, but done
               does not handle killer reason correctly */
            if (Upolyd) {
                rehumanize(death, killer);
            } else {
                done(death, killer);
            }
        }
        exercise(A_STR, FALSE);
    }

    if (shopdamage) {
        pay_for_damage(adtyp == AD_FIRE ? "burn away" : adtyp ==
                       AD_COLD ? "shatter" : adtyp ==
                       AD_DISN ? "disintegrate" : "destroy", FALSE);
    }

    /* explosions are noisy */
    i = dam * dam;
    if (i < 50)
        i = 50; /* in case random damage is very small */
    wake_nearto(x, y, i);
}
Пример #9
0
/* monster attempts ranged weapon attack against a square */
void
thrwmq(struct monst *mtmp, int xdef, int ydef)
{
    struct obj *otmp, *mwep;
    schar skill;
    int multishot;
    const char *onm;

    /* Rearranged beginning so monsters can use polearms not in a line */
    if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
        mtmp->weapon_check = NEED_RANGED_WEAPON;
        /* mon_wield_item resets weapon_check as appropriate */
        if (mon_wield_item(mtmp) != 0)
            return;
    }

    /* Pick a weapon */
    otmp = select_rwep(mtmp);
    if (!otmp)
        return;

    if (is_pole(otmp)) {
        int dam, hitv;

        if (otmp != MON_WEP(mtmp))
            return;  /* polearm must be wielded */

        /* TODO: LOE function between two arbitrary points. */
        if (dist2(mtmp->mx, mtmp->my, xdef, ydef) > POLE_LIM ||
            (xdef == u.ux && ydef == u.uy && !couldsee(mtmp->mx, mtmp->my)))
            return;     /* Out of range, or intervening wall */

        if (mon_visible(mtmp)) {
            onm = singular(otmp, xname);
            pline("%s thrusts %s.", Monnam(mtmp),
                  obj_is_pname(otmp) ? the(onm) : an(onm));
        }

        if (xdef == u.ux && ydef == u.uy) {

            dam = dmgval(otmp, &youmonst);
            hitv = 3 - distmin(u.ux, u.uy, mtmp->mx, mtmp->my);
            if (hitv < -4)
                hitv = -4;
            if (bigmonst(youmonst.data))
                hitv++;
            hitv += 8 + otmp->spe;
            if (objects[otmp->otyp].oc_class == WEAPON_CLASS ||
                objects[otmp->otyp].oc_class == VENOM_CLASS)
                hitv += objects[otmp->otyp].oc_hitbon;
            if (dam < 1)
                dam = 1;

            thitu(hitv, dam, otmp, NULL);
            action_interrupted();

        } else if (MON_AT(level, xdef, ydef))
            (void)ohitmon(m_at(level, xdef, ydef), otmp, 0, FALSE);
        else if (mon_visible(mtmp))
            pline("But it misses wildly.");

        return;
    }

    if (!qlined_up(mtmp, xdef, ydef, FALSE, FALSE) ||
        !ai_use_at_range(BOLT_LIM - distmin(mtmp->mx, mtmp->my, xdef, ydef)))
        return;

    skill = objects[otmp->otyp].oc_skill;
    mwep = MON_WEP(mtmp);       /* wielded weapon */

    /* Multishot calculations */
    multishot = 1;
    if ((ammo_and_launcher(otmp, mwep) || skill == P_DAGGER || skill == -P_DART
         || skill == -P_SHURIKEN) && !mtmp->mconf) {
        /* Assumes lords are skilled, princes are expert */
        if (is_prince(mtmp->data))
            multishot += 2;
        else if (is_lord(mtmp->data))
            multishot++;

        switch (monsndx(mtmp->data)) {
        case PM_RANGER:
            multishot++;
            break;
        case PM_ROGUE:
            if (skill == P_DAGGER)
                multishot++;
            break;
        case PM_NINJA:
        case PM_SAMURAI:
            if (otmp->otyp == YA && mwep && mwep->otyp == YUMI)
                multishot++;
            break;
        default:
            break;
        }
        /* racial bonus */
        if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW && mwep &&
             mwep->otyp == ELVEN_BOW) || (is_orc(mtmp->data) &&
                                          otmp->otyp == ORCISH_ARROW && mwep &&
                                          mwep->otyp == ORCISH_BOW))
            multishot++;

        if ((long)multishot > otmp->quan)
            multishot = (int)otmp->quan;
        if (multishot < 1)
            multishot = 1;
        else
            multishot = rnd(multishot);
    }

    if (mon_visible(mtmp)) {
        if (multishot > 1) {
            /* "N arrows"; multishot > 1 implies otmp->quan > 1, so xname()'s
               result will already be pluralized */
            onm = msgprintf("%d %s", multishot, xname(otmp));
        } else {
            /* "an arrow" */
            onm = singular(otmp, xname);
            onm = obj_is_pname(otmp) ? the(onm) : an(onm);
        }
        m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
        pline("%s %s %s!", Monnam(mtmp), m_shot.s ? "shoots" : "throws", onm);
        m_shot.o = otmp->otyp;
    } else {
        m_shot.o = STRANGE_OBJECT;      /* don't give multishot feedback */
    }

    m_shot.n = multishot;
    for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
        m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
                distmin(mtmp->mx, mtmp->my, xdef, ydef), otmp, TRUE);
        /* conceptually all N missiles are in flight at once, but
           if mtmp gets killed (shot kills adjacent gas spore and
           triggers explosion, perhaps), inventory will be dropped
           and otmp might go away via merging into another stack;
           if we then use it, we could cause undefined behavior */
        if (mtmp->mhp <= 0 && m_shot.i < m_shot.n) {
            /* cancel pending shots (ought to give a message here since
               we gave one above about throwing/shooting N missiles) */
            break;  /* endmultishot(FALSE); */
        }
    }
    m_shot.n = m_shot.i = 0;
    m_shot.o = STRANGE_OBJECT;
    m_shot.s = FALSE;

    action_interrupted();
}
Пример #10
0
int xfs_getinfo(cdico *d, char *devname)
{
    struct xfs_sb sb;
    char uuid[512];
    u64 xfsver;
    u32 temp32;
    int ret=0;
    int fd;
    int res;

    u64 sb_features_compat=0;
    u64 sb_features_ro_compat=0;
    u64 sb_features_incompat=0;
    u64 sb_features_log_incompat=0;

    if ((fd=open64(devname, O_RDONLY|O_LARGEFILE))<0)
    {   ret=-1;
        goto xfs_read_sb_return;
    }
    
    res=read(fd, &sb, sizeof(sb));
    if (res!=sizeof(sb))
    {   ret=-1;
        goto xfs_read_sb_close;
    }
    
    // ---- check it's an XFS file system
    if (be32_to_cpu(sb.sb_magicnum) != XFS_SB_MAGIC)
    {   ret=-1;
        msgprintf(3, "sb.sb_magicnum!=XFS_SB_MAGIC\n");
        goto xfs_read_sb_close;
    }

    // ---- check XFS filesystem version
    xfsver=be16_to_cpu(sb.sb_versionnum) & XFS_SB_VERSION_NUMBITS;
    switch (xfsver)
    {
        case XFS_SB_VERSION_4:
        case XFS_SB_VERSION_5:
            msgprintf(MSG_DEBUG1, "Detected XFS filesystem version %d\n", (int)xfsver);
            dico_add_u64(d, 0, FSYSHEADKEY_FSXFSVERSION, xfsver);
            break;
        default:
            ret=-1;
            msgprintf(MSG_STACK, "Invalid XFS filesystem version: version=[%d]\n", (int)xfsver);
            goto xfs_read_sb_close;
            break;
    }

    // ---- label
    msgprintf(MSG_DEBUG1, "xfs_label=[%s]\n", sb.sb_fname);
    dico_add_string(d, 0, FSYSHEADKEY_FSLABEL, (char*)sb.sb_fname);
    
    // ---- uuid
    /*if ((str=e2p_uuid2str(&sb.sb_uuid))!=NULL)
        dico_add_string(d, 0, FSYSHEADKEY_FSUUID, str);*/
    memset(uuid, 0, sizeof(uuid));
    uuid_unparse_lower((u8*)&sb.sb_uuid, uuid);
    dico_add_string(d, 0, FSYSHEADKEY_FSUUID, uuid);
    msgprintf(MSG_DEBUG1, "xfs_uuid=[%s]\n", uuid);
    
    // ---- block size
    temp32=be32_to_cpu(sb.sb_blocksize);
    if ((temp32%512!=0) || (temp32<512) || (temp32>65536))
    {   ret=-1;
        msgprintf(3, "xfs_blksize=[%ld] is an invalid xfs block size\n", (long)temp32);
        goto xfs_read_sb_close;
    }
    dico_add_u64(d, 0, FSYSHEADKEY_FSXFSBLOCKSIZE, temp32);
    msgprintf(MSG_DEBUG1, "xfs_blksize=[%ld]\n", (long)temp32);

    // ---- get filesystem features (will all be set to 0 if this is an XFSv4)
    if (xfsver == XFS_SB_VERSION_5)
    {
        sb_features_compat=be32_to_cpu(sb.sb_features_compat);
        sb_features_ro_compat=be32_to_cpu(sb.sb_features_ro_compat);
        sb_features_incompat=be32_to_cpu(sb.sb_features_incompat);
        sb_features_log_incompat=be32_to_cpu(sb.sb_features_log_incompat);
    }

    // ---- check fsarchiver is aware of all the filesystem features used on that filesystem
    if (xfs_check_compatibility(sb_features_compat, sb_features_ro_compat, sb_features_incompat, sb_features_log_incompat)!=0)
        return -1;

    // ---- store features in the archive metadata
    dico_add_u64(d, 0, FSYSHEADKEY_FSXFSFEATURECOMPAT, (u64)sb_features_compat);
    dico_add_u64(d, 0, FSYSHEADKEY_FSXFSFEATUREROCOMPAT, (u64)sb_features_ro_compat);
    dico_add_u64(d, 0, FSYSHEADKEY_FSXFSFEATUREINCOMPAT, (u64)sb_features_incompat);
    dico_add_u64(d, 0, FSYSHEADKEY_FSXFSFEATURELOGINCOMPAT, (u64)sb_features_log_incompat);

    // ---- minimum fsarchiver version required to restore
    dico_add_u64(d, 0, FSYSHEADKEY_MINFSAVERSION, FSA_VERSION_BUILD(0, 6, 20, 0));
    
xfs_read_sb_close:
    close(fd);
xfs_read_sb_return:
    return ret;
}
Пример #11
0
int xfs_mkfs(cdico *d, char *partition, char *fsoptions, char *mkfslabel, char *mkfsuuid)
{
    char stdoutbuf[2048];
    char command[2048];
    char buffer[2048];
    char mkfsopts[2048];
    char xadmopts[2048];
    char uuid[64];
    u64 xfstoolsver;
    int exitst;
    u64 temp64;
    u64 xfsver;
    int x, y, z;
    int optval;

    u64 sb_features_compat=0;
    u64 sb_features_ro_compat=0;
    u64 sb_features_incompat=0;
    u64 sb_features_log_incompat=0;

    // ---- check that mkfs is installed and get its version
    if (exec_command(command, sizeof(command), NULL, stdoutbuf, sizeof(stdoutbuf), NULL, 0, "mkfs.xfs -V")!=0)
    {   errprintf("mkfs.xfs not found. please install xfsprogs on your system or check the PATH.\n");
        return -1;
    }
    x=y=z=0;
    sscanf(stdoutbuf, "mkfs.xfs version %d.%d.%d", &x, &y, &z);
    if (x==0 && y==0)
    {   errprintf("Can't parse mkfs.xfs version number: x=y=0\n");
        return -1;
    }
    xfstoolsver=PROGVER(x,y,z);
    msgprintf(MSG_VERB2, "Detected mkfs.xfs version %d.%d.%d\n", x, y, z);

    memset(mkfsopts, 0, sizeof(mkfsopts));
    memset(xadmopts, 0, sizeof(xadmopts));
    memset(uuid, 0, sizeof(uuid));

    strlcatf(mkfsopts, sizeof(mkfsopts), " %s ", fsoptions);

    if (strlen(mkfslabel) > 0)
        strlcatf(mkfsopts, sizeof(mkfsopts), " -L '%.12s' ", mkfslabel);
    else if (dico_get_string(d, 0, FSYSHEADKEY_FSLABEL, buffer, sizeof(buffer))==0 && strlen(buffer)>0)
        strlcatf(mkfsopts, sizeof(mkfsopts), " -L '%.12s' ", buffer);

    if ((dico_get_u64(d, 0, FSYSHEADKEY_FSXFSBLOCKSIZE, &temp64)==0) && (temp64%512==0) && (temp64>=512) && (temp64<=65536))
        strlcatf(mkfsopts, sizeof(mkfsopts), " -b size=%ld ", (long)temp64);

    // ---- get xfs features attributes from the archive
    dico_get_u64(d, 0, FSYSHEADKEY_FSXFSFEATURECOMPAT, &sb_features_compat);
    dico_get_u64(d, 0, FSYSHEADKEY_FSXFSFEATUREROCOMPAT, &sb_features_ro_compat);
    dico_get_u64(d, 0, FSYSHEADKEY_FSXFSFEATUREINCOMPAT, &sb_features_incompat);
    dico_get_u64(d, 0, FSYSHEADKEY_FSXFSFEATURELOGINCOMPAT, &sb_features_log_incompat);

    // ---- check fsarchiver is aware of all the filesystem features used on that filesystem
    if (xfs_check_compatibility(sb_features_compat, sb_features_ro_compat, sb_features_incompat, sb_features_log_incompat)!=0)
        return -1;

    // Preserve version 4 of XFS if the original filesystem was an XFSv4 or if
    // it was saved with fsarchiver <= 0.6.19 which does not store the XFS
    // version in the metadata: make an XFSv4 if unsure for better compatibility,
    // as upgrading later is easier than downgrading
    if ((dico_get_u64(d, 0, FSYSHEADKEY_FSXFSVERSION, &temp64)!=0) || (temp64==XFS_SB_VERSION_4))
        xfsver = XFS_SB_VERSION_4;
    else
        xfsver = XFS_SB_VERSION_5;

    // Unfortunately it is impossible to preserve the UUID (stamped on every
    // metadata block) of an XFSv5 filesystem with mkfs.xfs < 4.3.0.
    // Restoring with a new random UUID would work but could prevent the system
    // from booting if this is a boot/root filesystem because grub/fstab often
    // use the UUID to identify it. Hence it is much safer to restore it as an
    // XFSv4 and it also provides a better compatibility with older kernels.
    // Hence this is the safest option.
    // More details: https://github.com/fdupoux/fsarchiver/issues/4
    if ((xfsver==XFS_SB_VERSION_5) && (xfstoolsver < PROGVER(4,3,0)))
    {
        xfsver = XFS_SB_VERSION_4; // Do not preserve the XFS version
        msgprintf(MSG_FORCE,
            "It is impossible to restore this filesystem as an XFSv5 and preserve its UUID\n"
            "with mkfs.xfs < 4.3.0. This filesystem will be restored as an XFSv4 instead\n"
            "as this is a much safer option (preserving the UUID may be required on\n"
            "boot/root filesystems for the operating system to be able to start). If you\n"
            "really want to have an XFSv5 filesystem, please upgrade xfsprogs to version\n"
            "4.3.0 or more recent and rerun this operation to get an XFSv5 with the same\n"
            "UUID as original filesystem\n");
    }

    // Determine if the "crc" mkfs option should be enabled (checksum)
    // - checksum must be disabled if we want to recreate an XFSv4 filesystem
    // - checksum must be enabled if we want to recreate an XFSv5 filesystem
    if (xfstoolsver >= PROGVER(3,2,0)) // only use "crc" option when it is supported by mkfs
    {
        optval = (xfsver==XFS_SB_VERSION_5);
        strlcatf(mkfsopts, sizeof(mkfsopts), " -m crc=%d ", (int)optval);
    }

    // Determine if the "finobt" mkfs option should be enabled (free inode btree)
    // - starting with linux-3.16 XFS has added a btree that tracks free inodes
    // - this feature relies on the new v5 on-disk format but it is optional
    // - this feature is enabled by default when using xfsprogs 3.2.3 or later
    // - this feature will be enabled if the original filesystem was XFSv5 and had it
    if (xfstoolsver >= PROGVER(3,2,1)) // only use "finobt" option when it is supported by mkfs
    {
        optval = ((xfsver==XFS_SB_VERSION_5) && (sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FINOBT));
        strlcatf(mkfsopts, sizeof(mkfsopts), " -m finobt=%d ", (int)optval);
    }

    // Determine if the "rmapbt" mkfs option should be enabled (reverse mapping btree)
    // - starting with linux-4.8 XFS has added a btree that maps filesystem blocks
    //   to their owner
    // - this feature relies on the new v5 on-disk format but it is optional
    // - this feature will be enabled if the original filesystem was XFSv5 and had it
    if (xfstoolsver >= PROGVER(4,8,0)) // only use "rmapbt" option when it is supported by mkfs
    {
        optval = ((xfsver==XFS_SB_VERSION_5) && (sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_RMAPBT));
        strlcatf(mkfsopts, sizeof(mkfsopts), " -m rmapbt=%d ", (int)optval);
    }

    // Determine if the "reflink" mkfs option should be enabled
    // - starting with linux-4.9 XFS has added support for reflinked files
    // - this feature relies on the new v5 on-disk format but it is optional
    // - this feature will be enabled if the original filesystem was XFSv5 and had it
    if (xfstoolsver >= PROGVER(4,9,0)) // only use "reflink" option when it is supported by mkfs
    {
        optval = ((xfsver==XFS_SB_VERSION_5) && (sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK));
        strlcatf(mkfsopts, sizeof(mkfsopts), " -m reflink=%d ", (int)optval);
    }

    // Attempt to preserve UUID of the filesystem
    // - the "-m uuid=<UUID>" option in mkfs.xfs was added in mkfs.xfs 4.3.0 and is the best way to set UUIDs
    // - the UUID of XFSv4 can be successfully set using either xfs_admin or mkfs.xfs >= 4.3.0
    // - it is impossible to set both types of UUIDs of an XFSv5 filesystem using xfsprogs < 4.3.0
    //   for this reason the XFS version is forced to v4 if xfsprogs version < 4.3.0
    if (strlen(mkfsuuid) > 0)
        snprintf(uuid, sizeof(uuid), "%s", mkfsuuid);
    else if (dico_get_string(d, 0, FSYSHEADKEY_FSUUID, buffer, sizeof(buffer))==0)
        snprintf(uuid, sizeof(uuid), "%s", buffer);
    if (strlen(uuid)==36)
    {
        if (xfstoolsver >= PROGVER(4,3,0))
            strlcatf(mkfsopts, sizeof(mkfsopts), " -m uuid=%s ", uuid);
        else
            strlcatf(xadmopts, sizeof(xadmopts), " -U %s ", uuid);
    }

    // Determine if the "ftype" mkfs option should be enabled (filetype in dirent)
    // - this feature allows the inode type to be stored in the directory structure
    // - mkfs.xfs 4.2.0 enabled ftype by default (supported since mkfs.xfs 3.2.0) for XFSv4 volumes
    // - when CRCs are enabled via -m crc=1, the ftype functionality is always enabled
    // - ftype is madatory in XFSv5 volumes but it is optional for XFSv4 volumes
    // - the "ftype" option must be specified after the "crc" option in mkfs.xfs < 4.2.0:
    //   https://git.kernel.org/cgit/fs/xfs/xfsprogs-dev.git/commit/?id=b990de8ba4e2df2bc76a140799d3ddb4a0eac4ce
    // - do not set ftype=1 with crc=1 as mkfs.xfs may fail when both options are enabled (at least with xfsprogs-3.2.2)
    // - XFSv4 with ftype=1 is supported since linux-3.13. We purposely always
    //   disable ftype for V4 volumes to keep them compatible with older kernels
    if (xfstoolsver >= PROGVER(3,2,0)) // only use "ftype" option when it is supported by mkfs
    {
        // ftype is already set to 1 when it is XFSv5
        if (xfsver==XFS_SB_VERSION_4)
            strlcatf(mkfsopts, sizeof(mkfsopts), " -n ftype=0 ");
    }

    // Determine if the "sparse" mkfs option should be enabled (sparse inode allocation)
    // - starting with linux-4.2 XFS can allocate discontinuous inode chunks
    // - this feature relies on the new v5 on-disk format but it is optional
    // - this feature will be enabled if the original filesystem was XFSv5 and had it
    // - this feature is supported since mkfs.xfs 4.2.0, but unfortunately
    //   mkfs.xfs 4.5.0 in RHEL 7.3 carries a custom patch removing the option,
    //   hence require mkfs.xfs 4.7.0, next version after 4.5.0
    if (xfstoolsver >= PROGVER(4,7,0)) // only use "sparse" option when it is supported by mkfs
    {
        optval = ((xfsver==XFS_SB_VERSION_5) && (sb_features_incompat & XFS_SB_FEAT_INCOMPAT_SPINODES));
        strlcatf(mkfsopts, sizeof(mkfsopts), " -i sparse=%d ", (int)optval);
    }

    // ---- create the new filesystem using mkfs.xfs
    if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "mkfs.xfs -f %s %s", partition, mkfsopts)!=0 || exitst!=0)
    {   errprintf("command [%s] failed\n", command);
        return -1;
    }
    
    // ---- use xfs_admin to set the UUID if not already done with mkfs.xfs
    if (xadmopts[0])
    {
        if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "xfs_admin %s %s", xadmopts, partition)!=0 || exitst!=-0)
        {   errprintf("command [%s] failed\n", command);
            return -1;
        }
    }
    
    return 0;    
}
Пример #12
0
void
mstatusline(struct monst *mtmp)
{
    aligntyp alignment;
    const char *info, *monnambuf;

    if (mtmp->ispriest || (mtmp->isminion && roamer_type(mtmp->data)))
        alignment = CONST_EPRI(mtmp)->shralign;
    else if (mtmp->isminion)
        alignment = EMIN(mtmp)->min_align;
    else {
        alignment = mtmp->data->maligntyp;
        alignment =
            (alignment > 0) ? A_LAWFUL :
            (alignment == A_NONE) ? A_NONE :
            (alignment < 0) ? A_CHAOTIC : A_NEUTRAL;
    }

    info = "";
    if (mtmp->mtame) {
        info = msgcat(info, ", tame");
        if (wizard) {
            info = msgprintf("%s (%d", info, mtmp->mtame);
            if (!mtmp->isminion)
                info = msgprintf("%s; hungry %u; apport %d", info,
                                 EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport);
            info = msgcat(info, ")");
        }
    } else if (mtmp->mpeaceful)
        info = msgcat(info, ", peaceful");
    if (mtmp->meating)
        info = msgcat(info, ", eating");
    if (mtmp->mcan)
        info = msgcat(info, ", cancelled");
    if (mtmp->mconf)
        info = msgcat(info, ", confused");
    if (mtmp->mblinded || !mtmp->mcansee)
        info = msgcat(info, ", blind");
    if (mtmp->mstun)
        info = msgcat(info, ", stunned");
    if (mtmp->msleeping)
        info = msgcat(info, ", asleep");
    else if (mtmp->mfrozen || !mtmp->mcanmove)
        info = msgcat(info, ", can't move");
    /* [arbitrary reason why it isn't moving] */
    else if (mtmp->mstrategy & STRAT_WAITMASK)
        info = msgcat(info, ", meditating");
    else if (mtmp->mflee)
        info = msgcat(info, ", scared");
    if (mtmp->mtrapped)
        info = msgcat(info, ", trapped");
    if (mtmp->mspeed)
        info = msgcat(info,
                      mtmp->mspeed == MFAST ? ", fast" :
                      mtmp->mspeed == MSLOW ? ", slow" : ", ???? speed");
    if (mtmp->mundetected)
        info = msgcat(info, ", concealed");
    if (mtmp->minvis)
        info = msgcat(info, ", invisible");
    if (mtmp == u.ustuck)
        info = msgcat(info,
                      (sticks(youmonst.data)) ? ", held by you" : Engulfed
                      ? (is_animal(u.ustuck->data) ? ", swallowed you" :
                         ", engulfed you") : ", holding you");
    if (mtmp == u.usteed)
        info = msgcat(info, ", carrying you");

    /* avoid "Status of the invisible newt ..., invisible" */
    /* and unlike a normal mon_nam, use "saddled" even if it has a name */
    monnambuf = x_monnam(mtmp, ARTICLE_THE, NULL,
                         (SUPPRESS_IT | SUPPRESS_INVISIBLE), FALSE);

    pline("Status of %s (%s):  Level %d  HP %d(%d)  Def %d%s.", monnambuf,
          align_str(alignment), mtmp->m_lev, mtmp->mhp, mtmp->mhpmax,
          10 - find_mac(mtmp), info);
}
Пример #13
0
int archinfo_show_mainhead(carchreader *ai, cdico *dicomainhead)
{
    char buffer[256];
    
    if (!ai || !dicomainhead)
    {   errprintf("a parameter is null\n");
        return -1;
    }
    
    msgprintf(MSG_FORCE, "====================== archive information ======================\n");
    msgprintf(MSG_FORCE, "Archive type: \t\t\t%s\n", (ai->archtype==ARCHTYPE_FILESYSTEMS)?"filesystems":"flat files");
    if ((ai->archtype==ARCHTYPE_FILESYSTEMS))
        msgprintf(0, "Filesystems count: \t\t%ld\n", (long)ai->fscount);
    msgprintf(MSG_FORCE, "Archive id: \t\t\t%.8x\n", (unsigned int)ai->archid);
    msgprintf(MSG_FORCE, "Archive file format: \t\t%s\n", ai->filefmt);
    msgprintf(MSG_FORCE, "Archive created with: \t\t%s\n", ai->creatver);
    msgprintf(MSG_FORCE, "Archive creation date: \t\t%s\n", format_time(buffer, sizeof(buffer), ai->creattime));
    msgprintf(MSG_FORCE, "Archive label: \t\t\t%s\n", ai->label);
    if (ai->minfsaver > 0) // fsarchiver < 0.6.7 had no per-archive minfsaver version requirement
        msgprintf(MSG_FORCE, "Minimum fsarchiver version:\t%d.%d.%d.%d\n", (int)FSA_VERSION_GET_A(ai->minfsaver), 
            (int)FSA_VERSION_GET_B(ai->minfsaver), (int)FSA_VERSION_GET_C(ai->minfsaver), (int)FSA_VERSION_GET_D(ai->minfsaver));
    msgprintf(MSG_FORCE, "Compression level: \t\t%d (%s level %d)\n", ai->fsacomp, compalgostr(ai->compalgo), ai->complevel);
    msgprintf(MSG_FORCE, "Encryption algorithm: \t\t%s\n", cryptalgostr(ai->cryptalgo));
    msgprintf(MSG_FORCE, "\n");
    
    return 0;
}
Пример #14
0
int archreader_read_block(carchreader *ai, cdico *in_blkdico, int in_skipblock, int *out_sumok, struct s_blockinfo *out_blkinfo)
{
    u32 arblockcsumorig;
    u32 arblockcsumcalc;
    u32 curblocksize; // data size
    u64 blockoffset; // offset of the block in the file
    u16 compalgo; // compression algo used
    u16 cryptalgo; // encryption algo used
    u32 finalsize; // compressed  block size
    u32 compsize;
    u8 *buffer;
    bool corrupt;
    
    assert(ai);
    assert(out_sumok);
    assert(in_blkdico);
    assert(out_blkinfo);
    
    // init
    memset(out_blkinfo, 0, sizeof(struct s_blockinfo));
    *out_sumok=-1;
    
    if (dico_get_u64(in_blkdico, 0, BLOCKHEADITEMKEY_BLOCKOFFSET, &blockoffset)!=0)
    {   msgprintf(3, "cannot get blockoffset from block-header\n");
        return -1;
    }
    
    if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_REALSIZE, &curblocksize)!=0 || curblocksize>FSA_MAX_BLKSIZE)
    {   msgprintf(3, "cannot get blocksize from block-header\n");
        return -1;
    }
    
    if (dico_get_u16(in_blkdico, 0, BLOCKHEADITEMKEY_COMPRESSALGO, &compalgo)!=0)
    {   msgprintf(3, "cannot get BLOCKHEADITEMKEY_COMPRESSALGO from block-header\n");
        return -1;
    }
    
    if (dico_get_u16(in_blkdico, 0, BLOCKHEADITEMKEY_ENCRYPTALGO, &cryptalgo)!=0)
    {   msgprintf(3, "cannot get BLOCKHEADITEMKEY_ENCRYPTALGO from block-header\n");
        return -1;
    }
    
    if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_ARSIZE, &finalsize)!=0)
    {   msgprintf(3, "cannot get BLOCKHEADITEMKEY_ARSIZE from block-header\n");
        return -1;
    }
    
    if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_COMPSIZE, &compsize)!=0)
    {   msgprintf(3, "cannot get BLOCKHEADITEMKEY_COMPSIZE from block-header\n");
        return -1;
    }
    
    if (dico_get_u32(in_blkdico, 0, BLOCKHEADITEMKEY_ARCSUM, &arblockcsumorig)!=0)
    {   msgprintf(3, "cannot get BLOCKHEADITEMKEY_ARCSUM from block-header\n");
        return -1;
    }
    
    if (in_skipblock==true) // the main thread does not need that block (block belongs to a filesys we want to skip)
    {
        if (lseek64(ai->archfd, (long)finalsize, SEEK_CUR)<0)
        {   sysprintf("cannot skip block (finalsize=%ld) failed\n", (long)finalsize);
            return -1;
        }
        return 0;
    }
    
    // ---- allocate memory
    if ((buffer=malloc(finalsize))==NULL)
    {   errprintf("cannot allocate block: malloc(%d) failed\n", finalsize);
        return FSAERR_ENOMEM;
    }
    
    if (read(ai->archfd, buffer, (long)finalsize)!=(long)finalsize)
    {   sysprintf("cannot read block (finalsize=%ld) failed\n", (long)finalsize);
        free(buffer);
        return -1;
    }
    
    // prepare blkinfo
    out_blkinfo->blkdata=(char*)buffer;
    out_blkinfo->blkrealsize=curblocksize;
    out_blkinfo->blkoffset=blockoffset;
    out_blkinfo->blkarcsum=arblockcsumorig;
    out_blkinfo->blkcompalgo=compalgo;
    out_blkinfo->blkcryptalgo=cryptalgo;
    out_blkinfo->blkarsize=finalsize;
    out_blkinfo->blkcompsize=compsize;
    
    // ---- checksum
    arblockcsumcalc=fletcher32(buffer, finalsize);
    corrupt=false;
    if (arblockcsumcalc!=arblockcsumorig) // bad checksum
    {
        errprintf("block is corrupt at offset=%ld, blksize=%ld\n", (long)blockoffset, (long)curblocksize);
        corrupt=!g_options.keepcorrupt;
    }
    if (corrupt) {
        free(out_blkinfo->blkdata);
        if ((out_blkinfo->blkdata=malloc(curblocksize))==NULL)
        {   errprintf("cannot allocate block: malloc(%d) failed\n", curblocksize);
            return FSAERR_ENOMEM;
        }
        memset(out_blkinfo->blkdata, 0, curblocksize);
        *out_sumok=false;
        // go to the beginning of the corrupted contents so that the next header is searched here
        if (lseek64(ai->archfd, -(long long)finalsize, SEEK_CUR)<0)
        {   errprintf("lseek64() failed\n");
        }
    }
    else // no corruption detected
    {
        *out_sumok=true;
    }
    
    return 0;
}
Пример #15
0
void *thread_writer_fct(void *args)
{
    struct s_headinfo headinfo;
    struct s_blockinfo blkinfo;
    carchwriter *ai=NULL;
    s64 blknum;
    int type;
    
    // init
    inc_secthreads();
    
    if ((ai=(carchwriter *)args)==NULL)
    {   errprintf("ai is NULL\n");
        goto thread_writer_fct_error;
    }
    if (archwriter_volpath(ai)!=0)
    {   msgprintf(MSG_STACK, "archwriter_volpath() failed\n");
        goto thread_writer_fct_error;
    }
    if (archwriter_create(ai)!=0)
    {   msgprintf(MSG_STACK, "archwriter_create(%s) failed\n", ai->basepath);
        goto thread_writer_fct_error;
    }
    if (archwriter_write_volheader(ai)!=0)
    {   msgprintf(MSG_STACK, "cannot write volume header: archwriter_write_volheader() failed\n");
        goto thread_writer_fct_error;
    }
    
    while (queue_get_end_of_queue(&g_queue)==false)
    {
        if ((blknum=queue_dequeue_first(&g_queue, &type, &headinfo, &blkinfo))<0 && blknum!=FSAERR_ENDOFFILE) // error
        {   msgprintf(MSG_STACK, "queue_dequeue_first()=%ld=%s failed\n", (long)blknum, error_int_to_string(blknum));
            goto thread_writer_fct_error;
        }
        else if (blknum>0) // block or header found
        {
            switch (type)
            {
                case QITEM_TYPE_BLOCK:
                    if (archwriter_dowrite_block(ai, &blkinfo)!=0)
                    {   msgprintf(MSG_STACK, "archive_dowrite_block() failed\n");
                        goto thread_writer_fct_error;
                    }
                    free(blkinfo.blkdata);
                    break;
                case QITEM_TYPE_HEADER:
                    if (archwriter_dowrite_header(ai, &headinfo)!=0)
                    {   msgprintf(MSG_STACK, "archive_write_header() failed\n");
                        goto thread_writer_fct_error;
                    }
                    dico_destroy(headinfo.dico);
                    break;
                default:
                    errprintf("unexpected item type from queue: type=%d\n", type);
                    break;
            }
        }
    }
    
    // write last volume footer
    if (archwriter_write_volfooter(ai, true)!=0)
    {   msgprintf(MSG_STACK, "cannot write volume footer: archio_write_volfooter() failed\n");
        goto thread_writer_fct_error;
    }
    archwriter_close(ai);
    msgprintf(MSG_DEBUG1, "THREAD-WRITER: exit success\n");
    dec_secthreads();
    return NULL;
    
thread_writer_fct_error:
    msgprintf(MSG_DEBUG1, "THREAD-WRITER: exit remove\n");
    set_stopfillqueue(); // say to the create.c thread that it must stop
    while (queue_get_end_of_queue(&g_queue)==false) // wait until all the compression threads exit
        queue_destroy_first_item(&g_queue); // empty queue
    archwriter_close(ai);
    dec_secthreads();
    return NULL;
}
Пример #16
0
int extfs_mkfs(cdico *d, char *partition, int extfstype, char *fsoptions)
{
    cstrlist strfeatures;
    u64 features_tab[3];
    u64 fsextrevision;
    int origextfstype;
    char buffer[2048];
    char command[2048];
    char options[2048];
    char temp[1024];
    char progname[64];
    u64 e2fstoolsver;
    int compat_type;
    u64 temp64;
    int exitst;
    int ret=0;
    int res;
    int i;
    
    // init    
    memset(options, 0, sizeof(options));
    snprintf(progname, sizeof(progname), "mke2fs");
    strlist_init(&strfeatures);
    
    // ---- check that mkfs is installed and get its version
    if (exec_command(command, sizeof(command), NULL, NULL, 0, NULL, 0, "%s -V", progname)!=0)
    {   errprintf("%s not found. please install a recent e2fsprogs on your system or check the PATH.\n", progname);
        ret=-1;
        goto extfs_mkfs_cleanup;
    }
    e2fstoolsver=check_prog_version(progname);
    
    // ---- filesystem revision (good-old-rev or dynamic)
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTREVISION, &fsextrevision)!=0)
        fsextrevision=EXT2_DYNAMIC_REV; // don't fail (case of fs conversion to extfs)
    
    // "mke2fs -q" prevents problems in exec_command when too many output details printed
    strlcatf(options, sizeof(options), " -q ");
    
    // filesystem revision: good-old-rev or dynamic
    strlcatf(options, sizeof(options), " -r %d ", (int)fsextrevision);

    strlcatf(options, sizeof(options), " %s ", fsoptions);
    
    // ---- set the advanced filesystem settings from the dico
    if (dico_get_string(d, 0, FSYSHEADKEY_FSLABEL, buffer, sizeof(buffer))==0 && strlen(buffer)>0)
        strlcatf(options, sizeof(options), " -L '%.16s' ", buffer);
    
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTBLOCKSIZE, &temp64)==0)
        strlcatf(options, sizeof(options), " -b %ld ", (long)temp64);
    
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSINODESIZE, &temp64)==0)
        strlcatf(options, sizeof(options), " -I %ld ", (long)temp64);
    
    // ---- get original filesystem features (if the original filesystem was an ext{2,3,4})
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFEATURECOMPAT, &features_tab[E2P_FEATURE_COMPAT])!=0 ||
        dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFEATUREINCOMPAT, &features_tab[E2P_FEATURE_INCOMPAT])!=0 ||
        dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFEATUREROCOMPAT, &features_tab[E2P_FEATURE_RO_INCOMPAT])!=0)
    {   // dont fail the original filesystem may not be ext{2,3,4}. in that case set defaults features
        features_tab[E2P_FEATURE_COMPAT]=EXT2_FEATURE_COMPAT_RESIZE_INODE|EXT2_FEATURE_COMPAT_DIR_INDEX;
        features_tab[E2P_FEATURE_INCOMPAT]=EXT2_FEATURE_INCOMPAT_FILETYPE;
        features_tab[E2P_FEATURE_RO_INCOMPAT]=EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
    }
    
    // ---- check that fsarchiver is aware of all the filesystem features used on that filesystem
    if (extfs_check_compatibility(features_tab[E2P_FEATURE_COMPAT], features_tab[E2P_FEATURE_INCOMPAT], features_tab[E2P_FEATURE_RO_INCOMPAT])!=0)
    {   errprintf("this filesystem has ext{2,3,4} features which are not supported by this fsarchiver version.\n");
        return -1;
    }
    
    // ---- get original filesystem type
    origextfstype=extfs_get_fstype_from_compat_flags(features_tab[E2P_FEATURE_COMPAT], 
            features_tab[E2P_FEATURE_INCOMPAT], features_tab[E2P_FEATURE_RO_INCOMPAT]);
    msgprintf(MSG_VERB2, "the filesystem type determined by the original filesystem features is [%s]\n", format_fstype(origextfstype));
    
    // remove all the features not supported by the filesystem to create (conversion = downgrade fs)
    for (i=0; mkfeatures[i].name; i++)
    {
        compat_type=mkfeatures[i].compat;
        if (mkfeatures[i].firstfs > extfstype)
            features_tab[compat_type] &= ~mkfeatures[i].mask;
    }
    
    // add new features if the filesystem to create is newer than the filesystem type that was backed up
    // eg: user did a "savefs" of an ext3 and does a "restfs mkfs=ext4" --> add features to force ext4
    // it's a bit more difficult because we only want to add such a feature if no feature of the new
    // filesystem is currently enabled.
    msgprintf(MSG_VERB2, "the filesystem type to create considering the command options is [%s]\n", format_fstype(extfstype));
    if (origextfstype==EXTFSTYPE_EXT2 && extfstype>EXTFSTYPE_EXT2) // upgrade ext2 to ext{3,4}
    {   fsextrevision=EXT2_DYNAMIC_REV;
        features_tab[E2P_FEATURE_COMPAT]|=EXT3_FEATURE_COMPAT_HAS_JOURNAL;
    }
    if (origextfstype<EXTFSTYPE_EXT4 && extfstype>=EXTFSTYPE_EXT4) // upgrade ext{2,3} to ext4
    {   fsextrevision=EXT2_DYNAMIC_REV;
        features_tab[E2P_FEATURE_INCOMPAT]|=EXT3_FEATURE_INCOMPAT_EXTENTS;
    }
    
    // convert int features to string to be passed to mkfs
    for (i=0; mkfeatures[i].name; i++)
    {
        if (mkfeatures[i].firste2p<=e2fstoolsver) // don't pass an option to a program that does not support it
        {
            compat_type=mkfeatures[i].compat;
            if (features_tab[compat_type] & mkfeatures[i].mask)
            {   msgprintf(MSG_VERB2, "--> feature [%s]=YES\n", mkfeatures[i].name);
                strlist_add(&strfeatures, mkfeatures[i].name);
            }
            else
            {   msgprintf(MSG_VERB2, "--> feature [%s]=NO\n", mkfeatures[i].name);
                snprintf(temp, sizeof(temp), "^%s", mkfeatures[i].name); // exclude feature
                strlist_add(&strfeatures, temp);
            }
        }
    }
    
    // if extfs revision is dynamic and there are features in the list
    if (fsextrevision!=EXT2_GOOD_OLD_REV && strlist_count(&strfeatures)>0)
    {   strlist_merge(&strfeatures, temp, sizeof(temp), ',');
        strlcatf(options, sizeof(options), " -O %s ", temp);
        msgprintf(MSG_VERB2, "features: mkfs_options+=[-O %s]\n", temp);
    }
    
    // ---- check mke2fs version requirement
    msgprintf(MSG_VERB2, "mke2fs version detected: %s\n", format_prog_version(e2fstoolsver, temp, sizeof(temp)));
    msgprintf(MSG_VERB2, "mke2fs version required: %s\n", format_prog_version(e2fsprogs_minver[extfstype], temp, sizeof(temp)));
    if (e2fstoolsver < e2fsprogs_minver[extfstype])
    {   errprintf("mke2fs was found but is too old, please upgrade to a version %s or more recent.\n", 
            format_prog_version(e2fsprogs_minver[extfstype], temp, sizeof(temp)));
        ret=-1;
        goto extfs_mkfs_cleanup;
    }
    
    // ---- extended options
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTEOPTRAIDSTRIDE, &temp64)==0)
        strlcatf(options, sizeof(options), " -E stride=%ld ", (long)temp64);
    if ((dico_get_u64(d, 0, FSYSHEADKEY_FSEXTEOPTRAIDSTRIPEWIDTH, &temp64)==0) && e2fstoolsver>=PROGVER(1,40,7))
        strlcatf(options, sizeof(options), " -E stripe-width=%ld ", (long)temp64);
    
    // ---- execute mke2fs
    msgprintf(MSG_VERB2, "exec: %s\n", command);
    if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "%s %s %s", progname, partition, options)!=0 || exitst!=0)
    {   errprintf("command [%s] failed with return status=%d\n", command, exitst);
        ret=-1;
        goto extfs_mkfs_cleanup;
    }
    
    // ---- use tune2fs to set the other advanced options
    memset(options, 0, sizeof(options));
    if (dico_get_string(d, 0, FSYSHEADKEY_FSUUID, buffer, sizeof(buffer))==0 && strlen(buffer)==36)
        strlcatf(options, sizeof(options), " -U %s ", buffer);
    
    if (dico_get_string(d, 0, FSYSHEADKEY_FSEXTDEFMNTOPT, buffer, sizeof(buffer))==0 && strlen(buffer)>0)
        strlcatf(options, sizeof(options), " -o %s ", buffer);
    
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFSCKMAXMNTCOUNT, &temp64)==0)
        strlcatf(options, sizeof(options), " -c %ld ", (long)temp64);
    
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFSCKCHECKINTERVAL, &temp64)==0)
        strlcatf(options, sizeof(options), " -i %ldd ", (long)(temp64/86400L));
    
    if (options[0])
    {
        if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "tune2fs %s %s", partition, options)!=0 || exitst!=0)
        {   errprintf("command [%s] failed with return status=%d\n", command, exitst);
            ret=-1;
            goto extfs_mkfs_cleanup;
        }
        
        // run e2fsck to workaround an tune2fs bug in e2fsprogs < 1.41.4 on ext4
        // http://article.gmane.org/gmane.comp.file-systems.ext4/11181
        if (extfstype==EXTFSTYPE_EXT4 && e2fstoolsver<PROGVER(1,41,4))
        {
            if ( ((res=exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "e2fsck -fy %s", partition))!=0) || ((exitst!=0) && (exitst!=1)) )
            {   errprintf("command [%s] failed with return status=%d\n", command, exitst);
                ret=-1;
                goto extfs_mkfs_cleanup;
            }
        }
    }
    
extfs_mkfs_cleanup:
    strlist_destroy(&strfeatures);
    return ret;
}
Пример #17
0
int oper_probe(bool details)
{
    struct s_devinfo blkdev[FSA_MAX_BLKDEVICES];
    int diskcount;
    int partcount;
    char temp[1024];
    int res;
    int i, j;
    
    // ---- 0. get info from /proc/partitions + libblkid
    if ((res=partlist_getlist(blkdev, FSA_MAX_BLKDEVICES, &diskcount, &partcount))<1)
    {   msgprintf(MSG_FORCE, "Failed to detect disks and filesystems\n");
        return -1;
    }
    
    // ---- 1. show physical disks
    if (diskcount>0)
    {
        msgprintf(MSG_FORCE, "[======DISK======] [=============NAME==============] [====SIZE====] [MAJ] [MIN]\n");
        for (i=0; i < res; i++)
            if (blkdev[i].devtype==BLKDEV_PHYSDISK)
                msgprintf(MSG_FORCE, "[%-16s] [%-31s] [%12s] [%3d] [%3d]\n", blkdev[i].devname, 
                    blkdev[i].name, blkdev[i].txtsize, blkdev[i].major, blkdev[i].minor);
        msgprintf(MSG_FORCE, "\n");
    }
    else
    {
        msgprintf(MSG_FORCE, "No physical disk found\n");
    }
    
    // ---- 2. show filesystem information
    if (partcount>0)
    {
        // show title for filesystems
        for (j=0; partinfo[j].title[0]; j++)
        {
            if (details==true || partinfo[j].detailed==false)
                msgprintf(MSG_FORCE, "%s", partinfo[j].title);
        }
        msgprintf(MSG_FORCE, "\n");
        
        // show filesystems data
        for (i=0; i < res; i++)
        {
            if (blkdev[i].devtype==BLKDEV_FILESYSDEV)
            {
                for (j=0; partinfo[j].title[0]; j++)
                {
                    if (details==true || partinfo[j].detailed==false)
                        msgprintf(MSG_FORCE, partinfo[j].format, partlist_getinfo(temp, sizeof(temp), &blkdev[i], j));
                }
                msgprintf(MSG_FORCE, "\n");
            }
        }
    }
    else
    {
        msgprintf(MSG_FORCE, "No filesystem found\n");
    }
    
    return 0;
}
Пример #18
0
int extfs_getinfo(cdico *d, char *devname)
{
    struct fsa_ext2_sb *super;
    blk_t use_superblock=0;
    int use_blocksize=0;
    char uuid[512];
    ext2_filsys fs;
    int origextfstype;
    char mntopt[1024];
    char label[80];
    u32 mask, m;
    int count;
    int i;
    
    // ---- open partition
    if (ext2fs_open(devname, EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES, use_superblock,  use_blocksize, unix_io_manager, &fs)!=0)
    {   errprintf("ext2fs_open(%s) failed\n", devname);
        return -1;
    }
    super=(struct fsa_ext2_sb *)fs->super;
    
    // --- label
    memset(label, 0, sizeof(label));
    if (super->s_volume_name[0])
    {   memset(label, 0, sizeof(label));
        strncpy(label, super->s_volume_name, sizeof(super->s_volume_name));
    }
    dico_add_string(d, 0, FSYSHEADKEY_FSLABEL, label);
    
    // ---- uuid
    /*if ((str=e2p_uuid2str(super->s_uuid))!=NULL)
        dico_add_string(d, 0, FSYSHEADKEY_FSUUID, str);*/
    memset(uuid, 0, sizeof(uuid));
    uuid_unparse_lower((u8*)super->s_uuid, uuid);
    dico_add_string(d, 0, FSYSHEADKEY_FSUUID, uuid);
    msgprintf(MSG_DEBUG1, "extfs_uuid=[%s]\n", uuid); 
    
    // ---- block size
    dico_add_u64(d, 0, FSYSHEADKEY_FSEXTBLOCKSIZE, EXT2_BLOCK_SIZE(super));
    
    // ---- filesystem revision (good-old-rev or dynamic)
    dico_add_u64(d, 0, FSYSHEADKEY_FSEXTREVISION, super->s_rev_level);
    
    // ---- inode size
    if (super->s_rev_level >= EXT2_DYNAMIC_REV)
        dico_add_u64(d, 0, FSYSHEADKEY_FSINODESIZE, super->s_inode_size);
    else
        dico_add_u64(d, 0, FSYSHEADKEY_FSINODESIZE, EXT2_GOOD_OLD_INODE_SIZE); // Good old rev
    
    // ---- extended options
    if (super->s_raid_stride > 0)
    {   dico_add_u64(d, 0, FSYSHEADKEY_FSEXTEOPTRAIDSTRIDE, super->s_raid_stride);
        msgprintf(MSG_DEBUG1, "extfs_raid_stride: %u\n", super->s_raid_stride);
    }
    if (super->s_raid_stripe_width > 0)
    {   dico_add_u64(d, 0, FSYSHEADKEY_FSEXTEOPTRAIDSTRIPEWIDTH, super->s_raid_stripe_width);
        msgprintf(MSG_DEBUG1, "extfs_raid_stripe_width: %u\n", super->s_raid_stripe_width);
    }
    
    // ---- fsck details: max_mount_count and check_interval
    dico_add_u64(d, 0, FSYSHEADKEY_FSEXTFSCKMAXMNTCOUNT, max(super->s_max_mnt_count,0));
    dico_add_u64(d, 0, FSYSHEADKEY_FSEXTFSCKCHECKINTERVAL, super->s_checkinterval);
    msgprintf(MSG_DEBUG1, "extfs_max_mount_count: %ld\n", (long)max(super->s_max_mnt_count,0));
    msgprintf(MSG_DEBUG1, "extfs_check_interval: %ld\n", (long)super->s_checkinterval);
    
    // ---- default mount options
    memset(mntopt, 0, sizeof(mntopt));
    count=0;
    mask=super->s_default_mount_opts;
    if (mask & EXT3_DEFM_JMODE)
    {   strlcatf(mntopt, sizeof(mntopt), "%s", e2p_mntopt2string(mask & EXT3_DEFM_JMODE));
        count++;
    }
    for (i=0, m=1; i < 32; i++, m<<=1)
    {
        if (m & EXT3_DEFM_JMODE)
            continue;
        if (mask & m)
        {
            if (count++) strlcatf(mntopt, sizeof(mntopt), ",");
            strlcatf(mntopt, sizeof(mntopt), "%s", e2p_mntopt2string(m));
        }
    }
    dico_add_string(d, 0, FSYSHEADKEY_FSEXTDEFMNTOPT, mntopt);
    msgprintf(MSG_DEBUG1, "default mount options: [%s]\n", mntopt);
    
    // ---- filesystem features
    dico_add_u64(d, 0, FSYSHEADKEY_FSEXTFEATURECOMPAT, (u64)super->s_feature_compat);
    dico_add_u64(d, 0, FSYSHEADKEY_FSEXTFEATUREINCOMPAT, (u64)super->s_feature_incompat);
    dico_add_u64(d, 0, FSYSHEADKEY_FSEXTFEATUREROCOMPAT, (u64)super->s_feature_ro_compat);
    
    origextfstype=extfs_get_fstype_from_compat_flags((u64)super->s_feature_compat, (u64)super->s_feature_incompat, (u64)super->s_feature_ro_compat);
    msgprintf(MSG_DEBUG1, "the filesystem type determined by the features is [%s]\n", format_fstype(origextfstype));
    
    // ---- check that fsarchiver is aware of all the filesystem features used on that filesystem
    if (extfs_check_compatibility((u64)super->s_feature_compat, (u64)super->s_feature_incompat, (u64)super->s_feature_ro_compat)!=0)
    {   errprintf("this filesystem has ext{2,3,4} features which are not supported by this fsarchiver version.\n");
        return -1;
    }
    
    // ---- minimum fsarchiver version required to restore
    dico_add_u64(d, 0, FSYSHEADKEY_MINFSAVERSION, FSA_VERSION_BUILD(0, 6, 4, 0));
            
    ext2fs_close(fs);
    
    return 0;
}
Пример #19
0
int
study_book(struct obj *spellbook, const struct nh_cmd_arg *arg)
{
    int booktype = spellbook->otyp;
    boolean confused = (Confusion != 0);
    boolean too_hard = FALSE;

    if (u.uoccupation_progress[tos_book] && !confused &&
        spellbook == u.utracked[tos_book] &&
        /* handle the sequence: start reading, get interrupted, have book
           become erased somehow, resume reading it */
        booktype != SPE_BLANK_PAPER) {
        if (turnstate.continue_message)
            pline("You continue your efforts to memorize the spell.");
    } else {
        /* Restarting reading the book */

        /* KMH -- Simplified this code */
        if (booktype == SPE_BLANK_PAPER) {
            pline("This spellbook is all blank.");
            makeknown(booktype);
            return 1;
        }
        switch (objects[booktype].oc_level) {
        case 1:
        case 2:
            u.uoccupation_progress[tos_book] = -objects[booktype].oc_delay;
            break;
        case 3:
        case 4:
            u.uoccupation_progress[tos_book] =
                -(objects[booktype].oc_level - 1) * objects[booktype].oc_delay;
            break;
        case 5:
        case 6:
            u.uoccupation_progress[tos_book] =
                -objects[booktype].oc_level * objects[booktype].oc_delay;
            break;
        case 7:
            u.uoccupation_progress[tos_book] = -8 * objects[booktype].oc_delay;
            break;
        default:
            impossible("Unknown spellbook level %d, book %d;",
                       objects[booktype].oc_level, booktype);
            return 0;
        }

        /* Books are often wiser than their readers (Rus.) */
        spellbook->in_use = TRUE;
        if (!spellbook->blessed && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) {
            if (spellbook->cursed) {
                too_hard = TRUE;
            } else {
                /* uncursed - chance to fail */
                int read_ability =
                    ACURR(A_INT) + 4 + u.ulevel / 2 -
                    2 * objects[booktype].oc_level +
                    ((ublindf && ublindf->otyp == LENSES) ? 2 : 0);
                /* only wizards know if a spell is too difficult */
                if (Role_if(PM_WIZARD) && read_ability < 20 && !confused) {
                    const char *qbuf;

                    qbuf = msgprintf("This spellbook is %sdifficult to "
                                     "comprehend. Continue?",
                                     (read_ability < 12 ? "very " : ""));
                    if (yn(qbuf) != 'y') {
                        spellbook->in_use = FALSE;
                        return 1;
                    }
                }
                /* it's up to random luck now */
                if (rnd(20) > read_ability) {
                    too_hard = TRUE;
                }
            }
        }

        if (too_hard) {
            boolean gone = cursed_book(spellbook);

            helpless(-u.uoccupation_progress[tos_book], hr_paralyzed,
                     "frozen by a spellbook", NULL);
            u.uoccupation_progress[tos_book] = 0;
            if (gone || !rn2(3)) {
                if (!gone)
                    pline("The spellbook crumbles to dust!");
                if (!objects[spellbook->otyp].oc_name_known &&
                    !objects[spellbook->otyp].oc_uname)
                    docall(spellbook);
                useup(spellbook);
            } else
                spellbook->in_use = FALSE;
            return 1;
        } else if (confused) {
            if (!confused_book(spellbook)) {
                spellbook->in_use = FALSE;
            }
            helpless(-u.uoccupation_progress[tos_book], hr_busy,
                     "absorbed in a spellbook",
                     "You're finally able to put the book down.");
            u.uoccupation_progress[tos_book] = 0;
            u.utracked[tos_book] = 0;
            return 1;
        }
        spellbook->in_use = FALSE;

        pline("You begin to %s the runes.",
              spellbook->otyp == SPE_BOOK_OF_THE_DEAD ? "recite" : "memorize");
    }

    u.utracked[tos_book] = spellbook;

    one_occupation_turn(learn, "studying", occ_book);

    return 1;
}
Пример #20
0
/* return 1 if action took 1 (or more) moves, 0 if error or aborted */
static int
doengrave_core(const struct nh_cmd_arg *arg, int auto_elbereth)
{
    boolean dengr = FALSE;      /* TRUE if we wipe out the current engraving */
    boolean doblind = FALSE;    /* TRUE if engraving blinds the player */
    boolean doknown = FALSE;    /* TRUE if we identify the stylus */
    boolean doknown_after = FALSE;      /* TRUE if we identify the stylus after
                                           successfully engraving. */
    boolean eow = FALSE;        /* TRUE if we are overwriting oep */
    boolean jello = FALSE;      /* TRUE if we are engraving in slime */
    boolean ptext = TRUE;       /* TRUE if we must prompt for engrave text */
    boolean teleengr = FALSE;   /* TRUE if we move the old engraving */
    boolean zapwand = FALSE;    /* TRUE if we remove a wand charge */
    xchar type = DUST;          /* Type of engraving made */
    const char *buf;            /* Buffer for final/poly engraving text */
    const char *ebuf;           /* Buffer for initial engraving text */
    const char *qbuf;           /* Buffer for query text */
    const char *post_engr_text; /* Text displayed after engraving prompt */
    const char *everb;          /* Present tense of engraving type */
    const char *eloc;           /* Where the engraving is (ie dust/floor/...) */
    const char *esp;            /* Iterator over ebuf; mostly handles spaces */
    char *sp;                   /* Ditto for mutable copies of ebuf */
    int len;                    /* # of nonspace chars of new engraving text */
    int maxelen;                /* Max allowable length of engraving text */
    int helpless_time;          /* Temporary for calculating helplessness */
    const char *helpless_endmsg;/* Temporary for helpless end message */
    struct engr *oep = engr_at(level, u.ux, u.uy);
    struct obj *otmp;

    /* The current engraving */
    const char *writer;

    buf = "";
    ebuf = "";
    post_engr_text = "";
    maxelen = 255; /* same value as in 3.4.3 */

    if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE)
        type = ENGR_BLOOD;

    /* Can the adventurer engrave at all? */

    if (Engulfed) {
        if (is_animal(u.ustuck->data)) {
            pline("What would you write?  \"Jonah was here\"?");
            return 0;
        } else if (is_whirly(u.ustuck->data)) {
            pline("You can't reach the %s.", surface(u.ux, u.uy));
            return 0;
        } else
            jello = TRUE;
    } else if (is_lava(level, u.ux, u.uy)) {
        pline("You can't write on the lava!");
        return 0;
    } else if (Underwater) {
        pline("You can't write underwater!");
        return 0;
    } else if (is_pool(level, u.ux, u.uy) ||
               IS_FOUNTAIN(level->locations[u.ux][u.uy].typ)) {
        pline("You can't write on the water!");
        return 0;
    }
    if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) /* in bubble */ ) {
        pline("You can't write in thin air!");
        return 0;
    }
    if (cantwield(youmonst.data)) {
        pline("You can't even hold anything!");
        return 0;
    }
    if (check_capacity(NULL))
        return 0;

    /* One may write with finger, or weapon, or wand, or..., or... Edited by
       GAN 10/20/86 so as not to change weapon wielded. */

    otmp = getargobj(arg, styluses, "write with");
    if (!otmp)
        return 0;       /* otmp == &zeroobj if fingers */

    if (otmp == &zeroobj)
        writer = makeplural(body_part(FINGER));
    else
        writer = xname(otmp);

    /* There's no reason you should be able to write with a wand while both
       your hands are tied up. */
    if (!freehand() && otmp != uwep && !otmp->owornmask) {
        pline("You have no free %s to write with!", body_part(HAND));
        return 0;
    }

    if (jello) {
        pline("You tickle %s with your %s.", mon_nam(u.ustuck), writer);
        pline("Your message dissolves...");
        return 0;
    }
    if (otmp->oclass != WAND_CLASS && !can_reach_floor()) {
        pline("You can't reach the %s!", surface(u.ux, u.uy));
        return 0;
    }
    if (IS_ALTAR(level->locations[u.ux][u.uy].typ)) {
        pline("You make a motion towards the altar with your %s.", writer);
        altar_wrath(u.ux, u.uy);
        return 0;
    }
    if (IS_GRAVE(level->locations[u.ux][u.uy].typ)) {
        if (otmp == &zeroobj) { /* using only finger */
            pline("You would only make a small smudge on the %s.",
                  surface(u.ux, u.uy));
            return 0;
        } else if (!level->locations[u.ux][u.uy].disturbed) {
            pline("You disturb the undead!");
            level->locations[u.ux][u.uy].disturbed = 1;
            makemon(&mons[PM_GHOUL], level, u.ux, u.uy, NO_MM_FLAGS);
            exercise(A_WIS, FALSE);
            return 1;
        }
    }

    /* SPFX for items */

    switch (otmp->oclass) {
    default:
    case AMULET_CLASS:
    case CHAIN_CLASS:
    case POTION_CLASS:
    case COIN_CLASS:
        break;

    case RING_CLASS:
        /* "diamond" rings and others should work */
    case GEM_CLASS:
        /* diamonds & other hard gems should work */
        if (objects[otmp->otyp].oc_tough) {
            type = ENGRAVE;
            break;
        }
        break;

    case ARMOR_CLASS:
        if (is_boots(otmp)) {
            type = DUST;
            break;
        }
        /* fall through */
        /* Objects too large to engrave with */
    case BALL_CLASS:
    case ROCK_CLASS:
        pline("You can't engrave with such a large object!");
        ptext = FALSE;
        break;

        /* Objects too silly to engrave with */
    case FOOD_CLASS:
    case SCROLL_CLASS:
    case SPBOOK_CLASS:
        pline("Your %s would get %s.", xname(otmp),
              is_ice(level, u.ux, u.uy) ? "all frosty" : "too dirty");
        ptext = FALSE;
        break;

    case RANDOM_CLASS: /* This should mean fingers */
        break;

        /* The charge is removed from the wand before prompting for the
           engraving text, because all kinds of setup decisions and
           pre-engraving messages are based upon knowing what type of engraving 
           the wand is going to do.  Also, the player will have potentially
           seen "You wrest .." message, and therefore will know they are using
           a charge. */
    case WAND_CLASS:
        if (zappable(otmp)) {
            check_unpaid(otmp);
            zapwand = TRUE;
            if (Levitation)
                ptext = FALSE;

            switch (otmp->otyp) {
                /* DUST wands */
            default:
                break;

                /* NODIR wands */
            case WAN_LIGHT:
            case WAN_SECRET_DOOR_DETECTION:
            case WAN_CREATE_MONSTER:
            case WAN_WISHING:
            case WAN_ENLIGHTENMENT:
                zapnodir(otmp);
                break;

                /* IMMEDIATE wands */
                /* If wand is "IMMEDIATE", remember to affect the previous
                   engraving even if turning to dust. */
            case WAN_STRIKING:
                post_engr_text =
                    "The wand unsuccessfully fights your attempt to write!";
                doknown_after = TRUE;
                break;
            case WAN_SLOW_MONSTER:
                if (!Blind) {
                    post_engr_text = msgprintf("The bugs on the %s slow down!",
                                               surface(u.ux, u.uy));
                    doknown_after = TRUE;
                }
                break;
            case WAN_SPEED_MONSTER:
                if (!Blind) {
                    post_engr_text = msgprintf("The bugs on the %s speed up!",
                                               surface(u.ux, u.uy));
                    doknown_after = TRUE;
                }
                break;
            case WAN_POLYMORPH:
                if (oep) {
                    if (!Blind) {
                        type = (xchar) 0;       /* random */
                        buf = random_engraving(rng_main);
                        doknown = TRUE;
                    }
                    dengr = TRUE;
                }
                break;
            case WAN_NOTHING:
            case WAN_UNDEAD_TURNING:
            case WAN_OPENING:
            case WAN_LOCKING:
            case WAN_PROBING:
                break;

                /* RAY wands */
            case WAN_MAGIC_MISSILE:
                ptext = TRUE;
                if (!Blind) {
                    post_engr_text = msgprintf(
                        "The %s is riddled by bullet holes!",
                        surface(u.ux, u.uy));
                    doknown_after = TRUE;
                }
                break;

                /* can't tell sleep from death - Eric Backus */
            case WAN_SLEEP:
            case WAN_DEATH:
                if (!Blind) {
                    post_engr_text = msgprintf(
                        "The bugs on the %s stop moving!", surface(u.ux, u.uy));
                }
                break;

            case WAN_COLD:
                if (!Blind) {
                    post_engr_text = "A few ice cubes drop from the wand.";
                    doknown_after = TRUE;
                }
                if (!oep || (oep->engr_type != BURN))
                    break;
            case WAN_CANCELLATION:
            case WAN_MAKE_INVISIBLE:
                if (oep && oep->engr_type != HEADSTONE) {
                    if (!Blind)
                        pline("The engraving on the %s vanishes!",
                              surface(u.ux, u.uy));
                    dengr = TRUE;
                }
                break;
            case WAN_TELEPORTATION:
                if (oep && oep->engr_type != HEADSTONE) {
                    if (!Blind)
                        pline("The engraving on the %s vanishes!",
                              surface(u.ux, u.uy));
                    teleengr = TRUE;
                }
                break;

                /* type = ENGRAVE wands */
            case WAN_DIGGING:
                ptext = TRUE;
                type = ENGRAVE;
                if (!objects[otmp->otyp].oc_name_known) {
                    if (flags.verbose)
                        pline("This %s is a wand of digging!", xname(otmp));
                    doknown = TRUE;
                }
                if (!Blind)
                    post_engr_text =
                        IS_GRAVE(level->locations[u.ux][u.uy].typ) ?
                        "Chips fly out from the headstone." :
                        is_ice(level, u.ux, u.uy) ?
                        "Ice chips fly up from the ice surface!" :
                        "Gravel flies up from the floor.";
                else
                    post_engr_text = "You hear drilling!";
                break;

                /* type = BURN wands */
            case WAN_FIRE:
                ptext = TRUE;
                type = BURN;
                if (!objects[otmp->otyp].oc_name_known) {
                    if (flags.verbose)
                        pline("This %s is a wand of fire!", xname(otmp));
                    doknown = TRUE;
                }
                post_engr_text = Blind ?
                    "You feel the wand heat up." :
                    "Flames fly from the wand.";
                break;
            case WAN_LIGHTNING:
                ptext = TRUE;
                type = BURN;
                if (!objects[otmp->otyp].oc_name_known) {
                    if (flags.verbose)
                        pline("This %s is a wand of lightning!", xname(otmp));
                    doknown = TRUE;
                }
                if (!Blind) {
                    post_engr_text = "Lightning arcs from the wand.";
                    doblind = TRUE;
                } else
                    post_engr_text = "You hear crackling!";
                break;
            
                /* type = MARK wands */
                /* type = ENGR_BLOOD wands */
            }
        } else /* end if zappable */ if (!can_reach_floor()) {
                pline("You can't reach the %s!", surface(u.ux, u.uy));
                /* If it's a wrestable wand, the player wasted a turn trying. */
                if (wrestable(otmp))
                    return 1;
                else
                    return 0;
            }
        break;
    
    case WEAPON_CLASS:
        if (is_blade(otmp)) {
            if ((int)otmp->spe > -3)
                type = ENGRAVE;
            else
                pline("Your %s too dull for engraving.", aobjnam(otmp, "are"));
        }
        break;

    case TOOL_CLASS:
        if (otmp == ublindf) {
            pline("That is a bit difficult to engrave with, don't you think?");
            return 0;
        }
        switch (otmp->otyp) {
        case MAGIC_MARKER:
            if (otmp->spe <= 0)
                pline("Your marker has dried out.");
            else
                type = MARK;
            break;
        case TOWEL:
            /* Can't really engrave with a towel */
            ptext = FALSE;
            if (oep)
                if ((oep->engr_type == DUST) || (oep->engr_type == ENGR_BLOOD)
                    || (oep->engr_type == MARK)) {
                    if (!Blind)
                        pline("You wipe out the message here.");
                    else
                        pline("Your %s %s %s.", xname(otmp),
                              otense(otmp, "get"),
                              is_ice(level, u.ux, u.uy) ? "frosty" : "dusty");
                    dengr = TRUE;
                } else
                    pline("Your %s can't wipe out this engraving.",
                          xname(otmp));
            else
                pline("Your %s %s %s.", xname(otmp), otense(otmp, "get"),
                      is_ice(level, u.ux, u.uy) ? "frosty" : "dusty");
            break;
        default:
            break;
        }
        break;

    case VENOM_CLASS:
    case ILLOBJ_CLASS:
        impossible("You're engraving with an illegal object!");
        break;
    }

    if (IS_GRAVE(level->locations[u.ux][u.uy].typ)) {
        if (type == ENGRAVE || type == 0)
            type = HEADSTONE;
        else {
            /* ensures the "cannot wipe out" case */
            type = DUST;
            dengr = FALSE;
            teleengr = FALSE;
            buf = "";
        }
    }

    /* End of implement setup */

    /* Identify stylus */
    if (doknown) {
        makeknown(otmp->otyp);
        more_experienced(0, 10);
    }

    if (teleengr) {
        rloc_engr(oep);
        oep = NULL;
    }

    if (dengr) {
        del_engr(oep, level);
        oep = NULL;
    }

    /* Something has changed the engraving here */
    if (*buf) {
        make_engr_at(level, u.ux, u.uy, buf, moves, type);
        pline("The engraving now reads: \"%s\".", buf);
        ptext = FALSE;
    }

    if (zapwand && (otmp->spe < 0)) {
        pline("%s %sturns to dust.", The(xname(otmp)),
              Blind ? "" : "glows violently, then ");
        if (!IS_GRAVE(level->locations[u.ux][u.uy].typ))
            pline("You are not going to get anywhere trying to write in the "
                  "%s with your dust.",
                  is_ice(level, u.ux, u.uy) ? "frost" : "dust");
        useup(otmp);
        ptext = FALSE;
    }

    if (!ptext) {       /* Early exit for some implements. */
        if (otmp->oclass == WAND_CLASS && !can_reach_floor())
            pline("You can't reach the %s!", surface(u.ux, u.uy));
        return 1;
    }

    /* Special effects should have deleted the current engraving (if possible)
       by now. */

    if (oep) {
        char c = 'n';

        /* Give player the choice to add to engraving. */

        if (type == HEADSTONE) {
            /* no choice, only append */
            c = 'y';
        } else if ((type == oep->engr_type) &&
                   (!Blind || (oep->engr_type == BURN) ||
                    (oep->engr_type == ENGRAVE))) {
            if (auto_elbereth)
                c = 'y';
            else
                c = yn_function("Do you want to add to the current engraving?",
                                ynqchars, 'y');
            if (c == 'q') {
                pline("Never mind.");
                return 0;
            }
        }

        if (c == 'n' || Blind) {

            if ((oep->engr_type == DUST) || (oep->engr_type == ENGR_BLOOD) ||
                (oep->engr_type == MARK)) {
                if (!Blind) {
                    pline("You wipe out the message that was %s here.",
                          ((oep->engr_type == DUST) ? "written in the dust" :
                           ((oep->engr_type == ENGR_BLOOD) ?
                            "scrawled in blood" : "written")));
                    del_engr(oep, level);
                    oep = NULL;
                } else
                    /* Don't delete engr until after we *know* we're engraving
                       */
                    eow = TRUE;
            } else if ((type == DUST) || (type == MARK) ||
                       (type == ENGR_BLOOD)) {
                pline("You cannot wipe out the message that is %s the %s here.",
                      oep->engr_type == BURN ? (is_ice(level, u.ux, u.uy) ?
                                                "melted into" : "burned into") :
                      "engraved in",
                      surface(u.ux, u.uy));
                return 1;
            } else if ((type != oep->engr_type) || (c == 'n')) {
                if (!Blind || can_reach_floor())
                    pline("You will overwrite the current message.");
                eow = TRUE;
            }
        }
    }

    eloc = surface(u.ux, u.uy);
    switch (type) {
    default:
        everb = (oep &&
                 !eow ? "add to the weird writing on" : "write strangely on");
        break;
    case DUST:
        everb = (oep && !eow ? "add to the writing in" : "write in");
        eloc = is_ice(level, u.ux, u.uy) ? "frost" : "dust";
        break;
    case HEADSTONE:
        everb = (oep && !eow ? "add to the epitaph on" : "engrave on");
        break;
    case ENGRAVE:
        everb = (oep && !eow ? "add to the engraving in" : "engrave in");
        break;
    case BURN:
        everb = (oep && !eow ? (is_ice(level, u.ux, u.uy) ?
                                "add to the text melted into" :
                                "add to the text burned into") :
                 (is_ice(level, u.ux, u.uy) ? "melt into" : "burn into"));
        break;
    case MARK:
        everb = (oep && !eow ? "add to the graffiti on" : "scribble on");
        break;
    case ENGR_BLOOD:
        everb = (oep && !eow ? "add to the scrawl on" : "scrawl on");
        break;
    }

    /* Tell adventurer what is going on */
    if (otmp != &zeroobj)
        pline("You %s the %s with %s.", everb, eloc, doname(otmp));
    else
        pline("You %s the %s with your %s.", everb, eloc,
              makeplural(body_part(FINGER)));

    /* Prompt for engraving! */
    qbuf = msgprintf("What do you want to %s the %s here?", everb, eloc);
    if (auto_elbereth)
        ebuf = "Elbereth";
    else
        ebuf = getarglin(arg, qbuf);

    /* Count the actual # of chars engraved not including spaces */
    len = strlen(ebuf);
    for (esp = ebuf; *esp; esp++)
        if (isspace(*esp))
            len -= 1;

    if (len == 0 || strchr(ebuf, '\033')) {
        if (zapwand) {
            if (!Blind)
                pline("%s, then %s.", Tobjnam(otmp, "glow"),
                      otense(otmp, "fade"));
            return 1;
        } else {
            pline("Never mind.");
            if (otmp && otmp->oclass == WAND_CLASS && wrestable(otmp))
                return 1;       /* disallow zero turn wrest */
            else
                return 0;
        }
    }

    /* A single `x' is the traditional signature of an illiterate person */
    if (len != 1 || (!strchr(ebuf, 'x') && !strchr(ebuf, 'X')))
        break_conduct(conduct_illiterate);

    /* Mix up engraving if surface or state of mind is unsound. Note: this
       won't add or remove any spaces. */

    char ebuf_copy[strlen(ebuf) + 1];
    strcpy(ebuf_copy, ebuf);
    for (sp = ebuf_copy; *sp; sp++) {
        if (isspace(*sp))
            continue;
        if (((type == DUST || type == ENGR_BLOOD) && !rn2(25)) ||
            (Blind && !rn2(11)) || (Confusion && !rn2(7)) ||
            (Stunned && !rn2(4)) || (Hallucination && !rn2(2)))
            *sp = ' ' + rnd(96 - 2);    /* ASCII '!' thru '~' (excludes ' ' and 
                                           DEL) */
    }

    /* Previous engraving is overwritten */
    if (eow) {
        del_engr(oep, level);
        oep = NULL;
    }

    /* Figure out how long it took to engrave, and if player has engraved too
       much. */
    helpless_time = len / 10;
    helpless_endmsg = NULL;
    switch (type) {
    default:
        helpless_endmsg = "You finish your weird engraving.";
        break;
    case DUST:
        helpless_endmsg = "You finish writing in the dust.";
        break;
    case HEADSTONE:
    case ENGRAVE:
        if ((otmp->oclass == WEAPON_CLASS) &&
            ((otmp->otyp != ATHAME) || otmp->cursed)) {
            helpless_time = len;
            maxelen = ((otmp->spe + 3) * 2) + 1;
            /* -2 = 3, -1 = 5, 0 = 7, +1 = 9, +2 = 11 Note: this does not allow 
               a +0 anything (except an athame) to engrave "Elbereth" all at
               once.  However, you could now engrave "Elb", then "ere", then
               "th". */
            pline("Your %s dull.", aobjnam(otmp, "get"));
            if (otmp->unpaid) {
                struct monst *shkp = shop_keeper(level, *u.ushops);

                if (shkp) {
                    pline("You damage it, you pay for it!");
                    bill_dummy_object(otmp);
                }
            }
            if (len > maxelen) {
                helpless_time = maxelen;
                otmp->spe = -3;
            } else if (len > 1)
                otmp->spe -= len >> 1;
            else
                otmp->spe -= 1; /* Prevent infinite engraving */
        } else if ((otmp->oclass == RING_CLASS) || (otmp->oclass == GEM_CLASS))
int decompress_block_generic(struct s_blockinfo *blkinfo)
{
    u64 checkorigsize;
    char *bufcomp=NULL;
    int res;
    
    // allocate memory for uncompressed data
    if ((bufcomp=malloc(blkinfo->blkrealsize))==NULL)
    {   errprintf("malloc(%ld) failed: cannot allocate memory for compressed block\n", (long)blkinfo->blkrealsize);
        return -1;
    }
    
    // check the block checksum
    if (fletcher32((u8*)blkinfo->blkdata, blkinfo->blkarsize)!=(blkinfo->blkarcsum))
    {   errprintf("block is corrupt at blockoffset=%ld, blksize=%ld\n", (long)blkinfo->blkoffset, (long)blkinfo->blkrealsize);
        memset(bufcomp, 0, blkinfo->blkrealsize);
    }
    else // data not corrupted, decompresses the block
    {
        if ((blkinfo->blkcryptalgo!=ENCRYPT_NONE) && (g_options.encryptalgo!=ENCRYPT_BLOWFISH))
        {   msgprintf(MSG_DEBUG1, "this archive has been encrypted, you have to provide a password "
                "on the command line using option '-c'\n");
            return -1;
        }
        
        char *bufcrypt=NULL;
        u64 clearsize;
        if (blkinfo->blkcryptalgo==ENCRYPT_BLOWFISH)
        {
            if ((bufcrypt=malloc(blkinfo->blkrealsize+8))==NULL)
            {   errprintf("malloc(%ld) failed: out of memory\n", (long)blkinfo->blkrealsize+8);
                return -1;
            }
            if ((res=crypto_blowfish(blkinfo->blkarsize, &clearsize, (u8*)blkinfo->blkdata, (u8*)bufcrypt, 
                g_options.encryptpass, strlen((char*)g_options.encryptpass), 0))!=0)
            {   errprintf("crypt_block_blowfish() failed\n");
                return -1;
            }
            if (clearsize!=blkinfo->blkcompsize)
            {   errprintf("clearsize does not match blkcompsize: clearsize=%ld and blkcompsize=%ld\n", 
                    (long)clearsize, (long)blkinfo->blkcompsize);
                return -1;
            }
            free(blkinfo->blkdata);
            blkinfo->blkdata=bufcrypt;
        }
        
        switch (blkinfo->blkcompalgo)
        {
            case COMPRESS_NONE:
                memcpy(bufcomp, blkinfo->blkdata, blkinfo->blkarsize);
                res=0;
                break;
#ifdef OPTION_LZO_SUPPORT
            case COMPRESS_LZO:
                if ((res=uncompress_block_lzo(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0)
                {   errprintf("uncompress_block_lzo()=%d failed: finalsize=%ld and checkorigsize=%ld\n", 
                        res, (long)blkinfo->blkarsize, (long)checkorigsize);
                    memset(bufcomp, 0, blkinfo->blkrealsize);
                    // TODO: inc(error_counter);
                }
                break;
#endif // OPTION_LZO_SUPPORT
            case COMPRESS_GZIP:
                if ((res=uncompress_block_gzip(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0)
                {   errprintf("uncompress_block_gzip()=%d failed: finalsize=%ld and checkorigsize=%ld\n", 
                        res, (long)blkinfo->blkarsize, (long)checkorigsize);
                    memset(bufcomp, 0, blkinfo->blkrealsize);
                    // TODO: inc(error_counter);
                }
                break;
            case COMPRESS_BZIP2:
                if ((res=uncompress_block_bzip2(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0)
                {   errprintf("uncompress_block_bzip2()=%d failed: finalsize=%ld and checkorigsize=%ld\n", 
                        res, (long)blkinfo->blkarsize, (long)checkorigsize);
                    memset(bufcomp, 0, blkinfo->blkrealsize);
                    // TODO: inc(error_counter);
                }
                break;
#ifdef OPTION_LZMA_SUPPORT
            case COMPRESS_LZMA:
                if ((res=uncompress_block_lzma(blkinfo->blkcompsize, &checkorigsize, (void*)bufcomp, blkinfo->blkrealsize, (u8*)blkinfo->blkdata))!=0)
                {   errprintf("uncompress_block_lzma()=%d failed: finalsize=%ld and checkorigsize=%ld\n", 
                        res, (long)blkinfo->blkarsize, (long)checkorigsize);
                    memset(bufcomp, 0, blkinfo->blkrealsize);
                    // TODO: inc(error_counter);
                }
                break;
#endif // OPTION_LZMA_SUPPORT
            default:
                errprintf("unsupported compression algorithm: %ld\n", (long)blkinfo->blkcompalgo);
                return -1;
        }
        free(blkinfo->blkdata); // free old buffer (with compressed data)
        blkinfo->blkdata=bufcomp; // pointer to new buffer with uncompressed data
    }
    
    return 0;
}
Пример #22
0
int
dowrite(struct obj *pen, const struct nh_cmd_arg *arg)
{
    struct obj *paper;
    const char *namebuf, *nm, *bp;
    struct obj *new_obj;
    int basecost, actualcost;
    int curseval;
    const char *qbuf;
    int first, last, i;
    boolean by_descr = FALSE, by_name = FALSE;
    const char *typeword;

    if (nohands(youmonst.data)) {
        pline(msgc_cancelled, "You need hands to be able to write!");
        return 0;
    } else if (slippery_fingers(&youmonst)) {
        pline(msgc_cancelled1, "%s from your %s.", Tobjnam(pen, "slip"),
              makeplural(body_part(FINGER)));
        unwield_silently(pen);
        dropx(pen);
        return 1;
    }

    /* get paper to write on */
    paper = getargobj(arg, write_on, "write on");
    if (!paper)
        return 0;

    typeword = (paper->oclass == SPBOOK_CLASS) ? "spellbook" : "scroll";
    if (Blind && !paper->dknown) {
        pline(msgc_cancelled1,
              "You don't know if that %s is blank or not!", typeword);
        return 1;
    }
    paper->dknown = 1;
    if (paper->otyp != SCR_BLANK_PAPER && paper->otyp != SPE_BLANK_PAPER) {
        pline(msgc_cancelled1, "That %s is not blank!", typeword);
        exercise(A_WIS, FALSE);
        return 1;
    }

    /* what to write */
    qbuf = msgprintf("What type of %s do you want to write?", typeword);
    namebuf = getarglin(arg, qbuf);
    namebuf = msgmungspaces(namebuf);   /* remove any excess whitespace */
    if (namebuf[0] == '\033' || !namebuf[0])
        return 1;
    nm = namebuf;
    if (!strncmpi(nm, "scroll ", 7))
        nm += 7;
    else if (!strncmpi(nm, "spellbook ", 10))
        nm += 10;
    if (!strncmpi(nm, "of ", 3))
        nm += 3;

    if ((bp = strstri(nm, " armour")) != 0)
        nm = msgcat_many(msgchop(nm, bp-nm), " armor", bp+7, NULL);

    first = bases[(int)paper->oclass];
    last = bases[(int)paper->oclass + 1] - 1;
    for (i = first; i <= last; i++) {
        /* extra shufflable descr not representing a real object */
        if (!OBJ_NAME(objects[i]))
            continue;

        if (!strcmpi(OBJ_NAME(objects[i]), nm))
            goto found;
        if (!strcmpi(OBJ_DESCR(objects[i]), nm)) {
            by_descr = TRUE;
            goto found;
        }
        if (objects[i].oc_uname &&
            !strcmpi(objects[i].oc_uname, nm)) {
            by_name = TRUE;
            goto found;
        }
    }

    pline(msgc_cancelled1, "There is no such %s!", typeword);
    return 1;
found:

    if (i == SCR_BLANK_PAPER || i == SPE_BLANK_PAPER) {
        pline(msgc_cancelled1, "You can't write that!");
        pline(msgc_cancelled1, "It's obscene!");
        return 1;
    } else if (i == SPE_BOOK_OF_THE_DEAD) {
        pline(msgc_cancelled1, "No mere dungeon adventurer could write that.");
        return 1;
    } else if ((by_descr || by_name) && paper->oclass == SPBOOK_CLASS &&
               !objects[i].oc_name_known) {
        /* can't write unknown spellbooks by description */
        pline(msgc_cancelled1,
              "Unfortunately you don't have enough information to go on.");
        return 1;
    }

    /* KMH, conduct */
    break_conduct(conduct_illiterate);

    new_obj = mksobj(level, i, FALSE, FALSE, rng_main);
    new_obj->bknown = (paper->bknown && pen->bknown);

    /* shk imposes a flat rate per use, not based on actual charges used */
    check_unpaid(pen);

    /* see if there's enough ink */
    basecost = cost(new_obj);
    if (pen->spe < basecost / 2) {
        pline(msgc_failcurse, "Your marker is too dry to write that!");
        obfree(new_obj, NULL);
        return 1;
    }

    /* we're really going to write now, so calculate cost

       no custom RNG used: too much influence from player actions */
    actualcost = rn1(basecost / 2, basecost / 2);
    curseval = bcsign(pen) + bcsign(paper);
    exercise(A_WIS, TRUE);
    /* dry out marker */
    if (pen->spe < actualcost) {
        pen->spe = 0;
        pline(msgc_itemloss, "Your marker dries out!");
        /* scrolls disappear, spellbooks don't */
        if (paper->oclass == SPBOOK_CLASS) {
            pline(msgc_failcurse,
                  "The spellbook is left unfinished and your writing fades.");
            update_inventory(); /* pen charges */
        } else {
            pline(msgc_failcurse, "The scroll is now useless and disappears!");
            useup(paper);
        }
        obfree(new_obj, NULL);
        return 1;
    }
    pen->spe -= actualcost;

    /* can't write if we don't know it - unless we're lucky */
    if (!(objects[new_obj->otyp].oc_name_known) &&
        (rnl(Role_if(PM_WIZARD) ? 3 : 15))) {
        pline(msgc_failrandom, "You %s to write that!",
              by_descr ? "fail" : "don't know how");
        /* scrolls disappear, spellbooks don't */
        if (paper->oclass == SPBOOK_CLASS) {
            pline_implied(msgc_failrandom,
                          "You write in your best handwriting:  "
                          "\"My Diary\", but it quickly fades.");
            update_inventory(); /* pen charges */
        } else {
            const char *written;
            if (by_descr) {
                written = OBJ_DESCR(objects[new_obj->otyp]);
                written = eroded_text(written,
                                      (6 + MAXULEV - youmonst.m_lev) / 6, 0);
            } else
                written = msgprintf("%s was here!", u.uplname);
            pline_implied(msgc_failrandom,
                          "You write \"%s\" and the scroll disappears.",
                          written);
            useup(paper);
        }
        obfree(new_obj, NULL);
        return 1;
    }

    /* useup old scroll / spellbook */
    useup(paper);

    /* success */
    if (new_obj->oclass == SPBOOK_CLASS) {
        /* acknowledge the change in the object's description... */
        pline(msgc_actionok, "The spellbook warps strangely, then turns %s.",
              OBJ_DESCR(objects[new_obj->otyp]));
    }
    new_obj->blessed = (curseval > 0);
    new_obj->cursed = (curseval < 0);
    hold_another_object(new_obj, "Oops!  %s out of your grasp!",
                        The(aobjnam(new_obj, "slip")), NULL);
    return 1;
}
Пример #23
0
/* called from check_special_room() when the player enters the temple room */
void
intemple(int roomno)
{
    struct monst *priest = findpriest((char)roomno);
    boolean tended = (priest != NULL);
    boolean sanctum, can_speak;
    xchar shrined;
    const char *msg1, *msg2;

    if (In_mines(&u.uz) && !historysearch("entered the Minetown temple", TRUE))
        historic_event(FALSE, TRUE, "entered the Minetown temple");

    if (!temple_occupied(u.urooms0)) {
        if (tended) {
            shrined = has_shrine(priest);
            sanctum = (priest->data == &mons[PM_HIGH_PRIEST] &&
                       (shrined & AM_SANCTUM));
            can_speak = (priest->mcanmove && !priest->msleeping &&
                         canhear());
            if (can_speak) {
                unsigned save_priest = priest->ispriest;

                /* don't reveal the altar's owner upon temple entry in the
                   endgame; for the Sanctum, the next message names Moloch so
                   suppress the "of Moloch" for him here too */
                if (sanctum && !Hallucination)
                    priest->ispriest = 0;
                pline("%s intones:",
                      canseemon(priest) ? Monnam(priest) : "A nearby voice");
                priest->ispriest = save_priest;
            }
            msg2 = 0;
            if (sanctum && CONST_EPRI(priest)->shralign == A_NONE) {
                if (priest->mpeaceful) {
                    msg1 = "Infidel, you have entered Moloch's Sanctum!";
                    msg2 = "Be gone!";
                    msethostility(priest, TRUE, TRUE);
                } else
                    msg1 = "You desecrate this place by your presence!";
            } else {
                msg1 = msgprintf("Pilgrim, you enter a %s place!",
                                 !shrined ? "desecrated" : "sacred");
            }
            if (can_speak) {
                verbalize("%s", msg1);
                if (msg2)
                    verbalize("%s", msg2);
            }
            if (!sanctum) {
                /* !tended -> !shrined */
                if (!shrined || !p_coaligned(priest) ||
                    u.ualign.record <= ALGN_SINNED)
                    pline("You have a%s forbidding feeling...",
                          (!shrined) ? "" : " strange");
                else
                    pline("You experience a strange sense of peace.");
            }
        } else {
            switch (rn2(3)) {
            case 0:
                pline("You have an eerie feeling...");
                break;
            case 1:
                pline("You feel like you are being watched.");
                break;
            default:
                pline("A shiver runs down your %s.", body_part(SPINE));
                break;
            }
            if (!rn2(5)) {
                struct monst *mtmp;

                if (!((mtmp = makemon(&mons[PM_GHOST], level, 
                                      u.ux, u.uy, NO_MM_FLAGS))))
                    return;
                if (!Blind || sensemon(mtmp))
                    pline("An enormous ghost appears next to you!");
                else
                    pline("You sense a presence close by!");
                msethostility(mtmp, TRUE, TRUE);
                if (flags.verbose)
                    pline("You are frightened to death, and unable to move.");
                helpless(3, hr_afraid, "frightened to death",
                         "You regain your composure.");
            }
        }
    }
}
Пример #24
0
int
doconsult(struct monst *oracl)
{
    int umoney = money_cnt(invent);
    int u_pay, minor_cost = 50, major_cost = 500 + 50 * u.ulevel;
    int add_xpts;
    const char *qbuf;

    /* TODO: Do we want this? The purpose seems to be specifically to prevent
       repeating an Oracle donation. */
    action_completed();

    if (!oracl) {
        pline("There is no one here to consult.");
        return 0;
    } else if (!oracl->mpeaceful) {
        pline("%s is not in the mood for conversation (believe it or not...)", Monnam(oracl));
        return 0;
    } else if (!umoney) {
        pline("You have no money.  There's no free lunch in wireless... and in being an oracle!");
        return 0;
    }

    qbuf = msgprintf("\"Would you mind talking for a little bit?\" (%d %s)",
                     minor_cost, currency(minor_cost));
    switch (ynq(qbuf)) {
    default:
    case 'q':
        return 0;
    case 'y':
        if (umoney < minor_cost) {
            pline("You don't even have enough money for that! There's no free lunch in wireless... and in being an oracle!");
            return 0;
        }
        u_pay = minor_cost;
        break;
    case 'n':
        if (umoney <= minor_cost ||     /* don't even ask */
            (oracle_cnt == 1 || oracle_flg < 0))
            return 0;
        qbuf = msgprintf("\"Oh! You'd like to sit and talk for a _long_ while?\" (%d %s)",
                         major_cost, currency(major_cost));
        if (yn(qbuf) != 'y')
            return 0;
        u_pay = (umoney < major_cost ? umoney : major_cost);

        break;
    }

    money2mon(oracl, u_pay);
    add_xpts = 0;       /* first oracle of each type gives experience points */
    if (u_pay == minor_cost) {
        outrumor(1, BY_ORACLE);
        if (!u.uevent.minor_oracle)
            add_xpts = u_pay / (u.uevent.major_oracle ? 25 : 10);
        /* 5 pts if very 1st, or 2 pts if major already done */
        u.uevent.minor_oracle = TRUE;
    } else {
        boolean cheapskate = u_pay < major_cost;

        outoracle(cheapskate, TRUE);
        if (!cheapskate && !u.uevent.major_oracle)
            add_xpts = u_pay / (u.uevent.minor_oracle ? 25 : 10);
        /* ~100 pts if very 1st, ~40 pts if minor already done */
        u.uevent.major_oracle = TRUE;
        historic_event(FALSE, "received advice from The Oracle.");
        exercise(A_WIS, !cheapskate);
    }
    if (add_xpts) {
        more_experienced(add_xpts, u_pay / 50);
        newexplevel();
    }
    return 1;
}
Пример #25
0
static void
disclose(int how, boolean taken, long umoney)
{
    char c = 0, defquery;
    const char *qbuf;
    boolean ask = should_query_disclose_options(&defquery);

    if (invent) {
        if (taken)
            qbuf = msgprintf("Do you want to see what you had when you %s?",
                             (how == QUIT) ? "quit" : "died");
        else
            /* This phrase is so fundamentally NetHack, I felt a huge sense of
               pride when I got to edit it, even though I was just changing it
               from a stack allocation to a string literal. Then I felt I should
               add a comment to it because it feels important enough to be
               dignified with one. So here it is. --AIS */
            qbuf = "Do you want your possessions identified?";

        if (!done_stopprint) {
            c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery;
            if (c == 'y') {
                struct obj *obj;

                for (obj = invent; obj; obj = obj->nobj) {
                    discover_object(obj->otyp, TRUE, FALSE, TRUE);
                    obj->known = obj->bknown = obj->dknown = obj->rknown = 1;
                }
                display_inventory(NULL, FALSE);
                container_contents(invent, TRUE, TRUE);
            }
            if (c == 'q')
                done_stopprint++;
        }
    }

    if (!done_stopprint) {
        c = ask ? yn_function("Do you want to see your attributes?", ynqchars,
                              defquery) : defquery;
        if (c == 'y')
            enlighten_mon(&youmonst, how > LAST_KILLER ? 1 : 2, 1); /* final */
        if (c == 'q')
            done_stopprint++;
    }

    if (!done_stopprint)
        list_vanquished(defquery, ask);

    if (!done_stopprint)
        list_genocided(defquery, ask);

    if (!done_stopprint) {
        c = ask ? yn_function("Do you want to see your conduct?", ynqchars,
                              defquery) : defquery;
        if (c == 'y')
            show_conduct(how > LAST_KILLER ? 1 : 2);
        if (c == 'q')
            done_stopprint++;
    }

    if (!done_stopprint) {
        c = ask ? yn_function("Do you want to see a breakdown of your score?",
                              ynqchars, defquery) : defquery;
        if (c == 'y')
            calc_score(how, TRUE, umoney);
        if (c == 'q')
            done_stopprint++;
    }
}
Пример #26
0
/* exclude_cookie is a hack used because we sometimes want to get rumors in a
 * context where messages such as "You swallowed the fortune!" that refer to
 * cookies should not appear.  This has no effect for true rumors since none
 * of them contain such references anyway.
 */
const char *
getrumor(int truth,     /* 1=true, -1=false, 0=either 3=potter (truier than true)*/
         boolean exclude_cookie, int *truth_out, enum rng rng)
{
    dlb *rumors;
    int tidbit, beginning;
    char *endp;
    int ltruth = 0;
    char line[BUFSZ]; /* for fgets */
    const char *rv = "";

    /* If this happens, we couldn't open the RUMORFILE. So synthesize a
       rumor just for the occasion :-) */
    if (true_rumor_size < 0L)
        return "";

    rumors = dlb_fopen(RUMORFILE, "r");

    if (rumors) {
        int count = 0;
        int adjtruth;

        do {
            if (true_rumor_size == 0L) {        /* if this is 1st outrumor() */
                init_rumors(rumors);
                if (true_rumor_size < 0L)       /* init failed */
                    return msgprintf("Error reading \"%.80s\".", RUMORFILE);
            }
            /* 
             *      input:      3    1    0   -1
             *       rn2 \ +1  4=P  2=T  1=T  0=F
             *       adj./ +0  3=P  1=T  0=F -1=F
             */
            switch (adjtruth = truth + rn2_on_rng(2, rng)) {
            case 4:    /* (might let a bogus input arg sneak thru) */
            case 3:
                beginning = potter_rumor_start;
                tidbit = rn2_on_rng(potter_rumor_size, rng);
                break;
            case 1:
                beginning = true_rumor_start;
                tidbit = rn2_on_rng(true_rumor_size, rng);
                break;
            case 0:    /* once here, 0 => false rather than "either" */
            case -1:
                beginning = false_rumor_start;
                tidbit = rn2_on_rng(false_rumor_size, rng);
                break;
            default:
                impossible("strange truth value for rumor");
                if (truth_out)
                    *truth_out = 0;
                return "Oops...";
            }
            dlb_fseek(rumors, beginning + tidbit, SEEK_SET);
            dlb_fgets(line, sizeof line, rumors);
            if (!dlb_fgets(line, sizeof line, rumors) ||
                ((adjtruth == 2 || adjtruth == 1) && dlb_ftell(rumors) > true_rumor_end)) {
                /* reached end of rumors -- go back to beginning */
                dlb_fseek(rumors, beginning, SEEK_SET);
                dlb_fgets(line, sizeof line, rumors);
            }
            else if (!dlb_fgets(line, sizeof line, rumors) ||
                        (adjtruth < 1 && dlb_ftell(rumors) > false_rumor_end)){
                dlb_fseek(rumors, beginning, SEEK_SET);
                dlb_fgets(line, sizeof line, rumors);
            }
            if ((endp = strchr(line, '\n')) != 0)
                *endp = 0;
            char decrypted_line[strlen(line) + 1];
            xcrypt(line, decrypted_line);
            rv = msg_from_string(decrypted_line);
        } while (count++ < 50 && exclude_cookie &&
                 (strstri(rv, "fortune") || strstri(rv, "pity")));
        dlb_fclose(rumors);
        if (count >= 50)
            impossible("Can't find non-cookie rumor?");
        else
            ltruth = (adjtruth > 0) ? 1 : -1;
    } else {
        pline("Can't open rumors file!");
        true_rumor_size = -1;   /* don't try to open it again */
        if (truth_out)
            *truth_out = 0;
    }
    if (truth_out)
        *truth_out = ltruth;
    return rv;
}
Пример #27
0
int btrfs_getinfo(cdico *d, char *devname)
{
    struct btrfs_super_block sb;
    char uuid[512];
    u16 temp32;
    int ret=0;
    int fd;
    
    if ((fd=open64(devname, O_RDONLY|O_LARGEFILE))<0)
    {   ret=-1;
        errprintf("cannot open(%s, O_RDONLY)\n", devname);
        goto btrfs_read_sb_return;
    }
    
    if (lseek(fd, BTRFS_SUPER_INFO_OFFSET, SEEK_SET)!=BTRFS_SUPER_INFO_OFFSET)
    {   ret=-2;
        errprintf("cannot lseek(fd, BTRFS_SUPER_INFO_OFFSET, SEEK_SET) on %s\n", devname);
        goto btrfs_read_sb_close;
    }
    
    if (read(fd, &sb, sizeof(sb))!=sizeof(sb))
    {   ret=-3;
        errprintf("cannot read the btrfs superblock on device [%s]\n", devname);
        goto btrfs_read_sb_close;
    }
    
    if (strncmp((char*)&sb.magic, BTRFS_MAGIC, sizeof(sb.magic))!=0)
    {   ret=-4;
        errprintf("magic different from expectations superblock on [%s]: magic=[%.8s], expected=[%.8s]\n", devname, (char*)&sb.magic, BTRFS_MAGIC);
        goto btrfs_read_sb_close;
    }
    
    // ---- label
    msgprintf(MSG_DEBUG1, "btrfs_label=[%s]\n", sb.label);
    dico_add_string(d, 0, FSYSHEADKEY_FSLABEL, (char*)sb.label);
    
    // ---- uuid
    /*if ((str=e2p_uuid2str(sb.dev_item.fsid))!=NULL)
        dico_add_string(d, 0, FSYSHEADKEY_FSUUID, str);*/
    memset(uuid, 0, sizeof(uuid));
    uuid_unparse_lower((u8*)sb.dev_item.fsid, uuid);
    dico_add_string(d, 0, FSYSHEADKEY_FSUUID, uuid);
    msgprintf(MSG_DEBUG1, "btrfs_uuid=[%s]\n", uuid);
    
    // ---- sector size
    temp32=le32_to_cpu(sb.sectorsize);
    dico_add_u64(d, 0, FSYSHEADKEY_FSBTRFSSECTORSIZE, temp32);
    msgprintf(MSG_DEBUG1, "btrfs_sectorsize=[%ld]\n", (long)temp32);
    
    // ---- filesystem features
    dico_add_u64(d, 0, FSYSHEADKEY_BTRFSFEATURECOMPAT, le64_to_cpu(sb.compat_flags));
    dico_add_u64(d, 0, FSYSHEADKEY_BTRFSFEATUREINCOMPAT, le64_to_cpu(sb.incompat_flags));
    dico_add_u64(d, 0, FSYSHEADKEY_BTRFSFEATUREROCOMPAT, le64_to_cpu(sb.compat_ro_flags));
    if (btrfs_check_compatibility(le64_to_cpu(sb.compat_flags), le64_to_cpu(sb.incompat_flags), le64_to_cpu(sb.compat_ro_flags))!=0)
    {   errprintf("this filesystem has features which are not supported by this fsarchiver version.\n");
        return -1;
    }
    
    // ---- minimum fsarchiver version required to restore
    dico_add_u64(d, 0, FSYSHEADKEY_MINFSAVERSION, FSA_VERSION_BUILD(0, 6, 4, 0));
    
btrfs_read_sb_close:
    close(fd);
btrfs_read_sb_return:
    return ret;
}
Пример #28
0
void *thread_reader_fct(void *args)
{
    char magic[FSA_SIZEOF_MAGIC];
    struct s_blockinfo blkinfo;
    u32 endofarchive=false;
    carchreader *ai=NULL;
    cdico *dico=NULL;
    int skipblock;
    u16 fsid;
    int sumok;
    int status;
    u64 errors;
    s64 lres;
    int res;
    
    // init
    errors=0;
    inc_secthreads();

    if ((ai=(carchreader *)args)==NULL)
    {   errprintf("ai is NULL\n");
        goto thread_reader_fct_error;
    }
    
    // open archive file
    if (archreader_volpath(ai)!=0)
    {   errprintf("archreader_volpath() failed\n");
        goto thread_reader_fct_error;
    }
    
    if (archreader_open(ai)!=0)
    {   errprintf("archreader_open(%s) failed\n", ai->basepath);
        goto thread_reader_fct_error;
    }
    
    // read volume header
    if (archreader_read_volheader(ai)!=0)
    {   errprintf("archio_read_volheader() failed\n");
        goto thread_reader_fct_error;
    }
    
    // ---- read main archive header
    if ((res=archreader_read_header(ai, magic, &dico, false, &fsid))!=FSAERR_SUCCESS)
    {   errprintf("archreader_read_header() failed to read the archive header\n");
        goto thread_reader_fct_error; // this header is required to continue
    }
    
    if (dico_get_u32(dico, 0, MAINHEADKEY_ARCHIVEID, &ai->archid)!=0)
    {   msgprintf(3, "cannot get archive-id from main header\n");
        goto thread_reader_fct_error;
    }
    
    if ((lres=queue_add_header(&g_queue, dico, magic, fsid))!=FSAERR_SUCCESS)
    {   errprintf("queue_add_header()=%ld=%s failed to add the archive header\n", (long)lres, error_int_to_string(lres));
        goto thread_reader_fct_error;
    }
    
    // read all other data from file (filesys-header, normal objects headers, ...)
    while (endofarchive==false && get_stopfillqueue()==false)
    {
        if ((res=archreader_read_header(ai, magic, &dico, true, &fsid))!=FSAERR_SUCCESS)
        {   dico_destroy(dico);
            msgprintf(MSG_STACK, "archreader_read_header() failed to read next header\n");
            if (res==OLDERR_MINOR) // header is corrupt or not what we expected
            {   errors++;
                msgprintf(MSG_DEBUG1, "OLDERR_MINOR\n");
                continue;
            }
            else // fatal error (eg: cannot read archive from disk)
            {
                msgprintf(MSG_DEBUG1, "!OLDERR_MINOR\n");
                goto thread_reader_fct_error;
            }
        }
        
        // read header and see if it's for archive management or higher level data
        if (strncmp(magic, FSA_MAGIC_VOLF, FSA_SIZEOF_MAGIC)==0) // header is "end of volume"
        {
            archreader_close(ai);
            
            // check the "end of archive" flag in header
            if (dico_get_u32(dico, 0, VOLUMEFOOTKEY_LASTVOL, &endofarchive)!=0)
            {   errprintf("cannot get compr from block-header\n");
                goto thread_reader_fct_error;
            }
            msgprintf(MSG_VERB2, "End of volume [%s]\n", ai->volpath);
            if (endofarchive!=true)
            {
                archreader_incvolume(ai, false);
                while (regfile_exists(ai->volpath)!=true)
                {
                    // wait until the queue is empty so that the main thread does not pollute the screen
                    while (queue_count(&g_queue)>0)
                        usleep(5000);
                    fflush(stdout);
                    fflush(stderr);
                    msgprintf(MSG_FORCE, "File [%s] is not found, please type the path to volume %ld:\n", ai->volpath, (long)ai->curvol);
                    fprintf(stdout, "New path:> ");
                    res=scanf("%256s", ai->volpath);
                }
                
                msgprintf(MSG_VERB2, "New volume is [%s]\n", ai->volpath);
                if (archreader_open(ai)!=0)
                {   msgprintf(MSG_STACK, "archreader_open() failed\n");
                    goto thread_reader_fct_error;
                }
                if (archreader_read_volheader(ai)!=0)
                {      msgprintf(MSG_STACK, "archio_read_volheader() failed\n");
                    goto thread_reader_fct_error;
                }
            }
            dico_destroy(dico);
        }
        else // high-level archive (not involved in volume management)
        {
            if (strncmp(magic, FSA_MAGIC_BLKH, FSA_SIZEOF_MAGIC)==0) // header starts a data block
            {
                skipblock=(g_fsbitmap[fsid]==0);
                //errprintf("DEBUG: skipblock=%d g_fsbitmap[fsid=%d]=%d\n", skipblock, (int)fsid, (int)g_fsbitmap[fsid]);
                if (archreader_read_block(ai, dico, skipblock, &sumok, &blkinfo)!=0)
                {   msgprintf(MSG_STACK, "archreader_read_block() failed\n");
                    goto thread_reader_fct_error;
                }
                
                if (skipblock==false)
                {
                    status=((sumok==true)?QITEM_STATUS_TODO:QITEM_STATUS_DONE);
                    if ((lres=queue_add_block(&g_queue, &blkinfo, status))!=FSAERR_SUCCESS)
                    {   if (lres!=FSAERR_NOTOPEN)
                            errprintf("queue_add_block()=%ld=%s failed\n", (long)lres, error_int_to_string(lres));
                        goto thread_reader_fct_error;
                    }
                    if (sumok==false) errors++;
                    dico_destroy(dico);
                }
            }
            else // another higher level header
            {
                // if it's a global header or a if this local header belongs to a filesystem that the main thread needs
                if (fsid==FSA_FILESYSID_NULL || g_fsbitmap[fsid]==1)
                {
                    if ((lres=queue_add_header(&g_queue, dico, magic, fsid))!=FSAERR_SUCCESS)
                    {   msgprintf(MSG_STACK, "queue_add_header()=%ld=%s failed\n", (long)lres, error_int_to_string(lres));
                        goto thread_reader_fct_error;
                    }
                }
                else // header not used: remove data strucutre in dynamic memory
                {
                    dico_destroy(dico);
                }
            }
        }
    }
    
thread_reader_fct_error:
    msgprintf(MSG_DEBUG1, "THREAD-READER: queue_set_end_of_queue(&g_queue, true)\n");
    queue_set_end_of_queue(&g_queue, true); // don't wait for more data from this thread
    dec_secthreads();
    msgprintf(MSG_DEBUG1, "THREAD-READER: exit\n");
    return NULL;
}
Пример #29
0
static int
domonnoise(struct monst *mtmp)
{
    const char *pline_msg = 0,  /* Monnam(mtmp) will be prepended */
        *verbl_msg = 0; /* verbalize() */
    const struct permonst *ptr = mtmp->data;

    /* presumably nearness checks have already been made */
    if (!canhear())
        return 0;
    if (is_silent(ptr))
        return 0;

    /* Make sure its your role's quest quardian; adjust if not */
    if (ptr->msound == MS_GUARDIAN && ptr != &pm_guardian) {
        int mndx = monsndx(ptr);

        ptr = &mons[genus(mndx, 1)];
    }

    /* be sure to do this before talking; the monster might teleport away, in
       which case we want to check its pre-teleport position */
    if (!canspotmon(mtmp))
        map_invisible(mtmp->mx, mtmp->my);

    switch (ptr->msound) {
    case MS_ORACLE:
        return doconsult(mtmp);
    case MS_PRIEST:
        priest_talk(mtmp);
        break;
    case MS_LEADER:
    case MS_NEMESIS:
    case MS_GUARDIAN:
        quest_chat(mtmp);
        break;
    case MS_SELL:      /* pitch, pay, total */
        shk_chat(mtmp);
        break;
    case MS_VAMPIRE:
        {
            /* vampire messages are varied by tameness, peacefulness, and time
               of night */
            boolean isnight = night();
            boolean kindred = (Upolyd &&
                               (u.umonnum == PM_VAMPIRE ||
                                u.umonnum == PM_VAMPIRE_LORD));
            boolean nightchild = (Upolyd &&
                                  (u.umonnum == PM_WOLF ||
                                   u.umonnum == PM_WINTER_WOLF ||
                                   u.umonnum == PM_WINTER_WOLF_CUB));
            const char *racenoun = (u.ufemale &&
                                    urace.individual.f) ? urace.
                individual.f : (urace.individual.m) ? urace.individual.
                m : urace.noun;

            if (mtmp->mtame) {
                if (kindred)
                    verbl_msg = msgprintf("Good %s to you Master%s",
                                          isnight ? "evening" : "day",
                                          isnight ? "!" :
                                          ".  Why do we not rest?");
                else
                    verbl_msg = msgcat(
                        nightchild ? "Child of the night, " : "",
                        midnight()? "I can stand this craving no longer!" :
                        isnight ?
                        "I beg you, help me satisfy this growing craving!" :
                        "I find myself growing a little weary.");
            } else if (mtmp->mpeaceful) {
                if (kindred && isnight)
                    verbl_msg = msgprintf("Good feeding %s!",
                                          u.ufemale ? "sister" : "brother");
                else if (nightchild && isnight)
                    verbl_msg = "How nice to hear you, child of the night!";
                else
                    verbl_msg = "I only drink... potions.";
            } else {
                int vampindex;

                static const char *const vampmsg[] = {
                    /* These first two (0 and 1) are specially handled below */
                    "I vant to suck your %s!",
                    "I vill come after %s without regret!",
                    /* other famous vampire quotes can follow here if desired */
                };
                if (kindred)
                    verbl_msg =
                        "This is my hunting ground that you dare to prowl!";
                else if (youmonst.data == &mons[PM_SILVER_DRAGON] ||
                         youmonst.data == &mons[PM_BABY_SILVER_DRAGON]) {
                    /* Silver dragons are silver in color, not made of silver */
                    verbl_msg = msgprintf(
                        "%s! Your silver sheen does not frighten me!",
                        youmonst.data ==
                        &mons[PM_SILVER_DRAGON] ? "Fool" : "Young Fool");
                } else {
                    vampindex = rn2(SIZE(vampmsg));
                    if (vampindex == 0) {
                        verbl_msg = msgprintf(
                            vampmsg[vampindex], body_part(BLOOD));
                    } else if (vampindex == 1) {
                        verbl_msg = msgprintf(
                            vampmsg[vampindex],
                            Upolyd ? an(mons[u.umonnum].mname) : an(racenoun));
                    } else
                        verbl_msg = vampmsg[vampindex];
                }
            }
        }
        break;
    case MS_WERE:
        if (flags.moonphase == FULL_MOON && (night() ^ !rn2(13))) {
            pline("%s throws back %s head and lets out a blood curdling %s!",
                  Monnam(mtmp), mhis(mtmp),
                  ptr == &mons[PM_HUMAN_WERERAT] ? "shriek" : "howl");
            wake_nearto(mtmp->mx, mtmp->my, 11 * 11);
        } else
            pline_msg =
                "whispers inaudibly.  All you can make out is \"moon\".";
        break;
    case MS_BARK:
        if (flags.moonphase == FULL_MOON && night()) {
            pline_msg = "howls.";
        } else if (mtmp->mpeaceful) {
            if (mtmp->mtame &&
                (mtmp->mconf || mtmp->mflee || mtmp->mtrapped ||
                 moves > EDOG(mtmp)->hungrytime || mtmp->mtame < 5))
                pline_msg = "whines.";
            else if (mtmp->mtame && EDOG(mtmp)->hungrytime > moves + 1000)
                pline_msg = "yips.";
            else {
                if (mtmp->data == &mons[PM_FOX])
                    pline_msg = whatthefoxsays();
                else if (mtmp->data != &mons[PM_DINGO])  /* dingos do not
                                                           actually bark */
                    pline_msg = "barks.";
            }
        } else {
            if (mtmp->data == &mons[PM_FOX])
                pline_msg = whatthefoxsays();
            else
                pline_msg = "growls.";
        }
        break;
    case MS_MEW:
        if (mtmp->mtame) {
            if (mtmp->mconf || mtmp->mflee || mtmp->mtrapped || mtmp->mtame < 5)
                pline_msg = "yowls.";
            else if (moves > EDOG(mtmp)->hungrytime)
                pline_msg = "meows.";
            else if (EDOG(mtmp)->hungrytime > moves + 1000)
                pline_msg = "purrs.";
            else
                pline_msg = "mews.";
            break;
        }       /* else FALLTHRU */
    case MS_GROWL:
        pline_msg = mtmp->mpeaceful ? "snarls." : "growls!";
        break;
    case MS_ROAR:
        pline_msg = mtmp->mpeaceful ? "snarls." : "roars!";
        break;
    case MS_SQEEK:
        pline_msg = "squeaks.";
        break;
    case MS_SQAWK:
        if (ptr == &mons[PM_RAVEN] && !mtmp->mpeaceful)
            verbl_msg = "Nevermore!";
        else
            pline_msg = "squawks.";
        break;
    case MS_HISS:
        if (!mtmp->mpeaceful)
            pline_msg = "hisses!";
        else
            return 0;   /* no sound */
        break;
    case MS_BUZZ:
        pline_msg = mtmp->mpeaceful ? "drones." : "buzzes angrily.";
        break;
    case MS_GRUNT:
        pline_msg = "grunts.";
        break;
    case MS_NEIGH:
        if (mtmp->mtame < 5)
            pline_msg = "neighs.";
        else if (moves > EDOG(mtmp)->hungrytime)
            pline_msg = "whinnies.";
        else
            pline_msg = "whickers.";
        break;
    case MS_WAIL:
        pline_msg = "wails mournfully.";
        break;
    case MS_GURGLE:
        pline_msg = "gurgles.";
        break;
    case MS_BURBLE:
        pline_msg = "burbles.";
        break;
    case MS_SHRIEK:
        pline_msg = "shrieks.";
        aggravate();
        break;
    case MS_IMITATE:
        pline_msg = "imitates you.";
        break;
    case MS_BONES:
        pline("%s rattles noisily.", Monnam(mtmp));
        pline("You freeze for a moment.");
        helpless(2, hr_afraid, "scared by rattling", NULL);
        break;
    case MS_LAUGH:
        {
            static const char *const laugh_msg[4] = {
                "giggles.", "chuckles.", "snickers.", "laughs.",
            };
            pline_msg = laugh_msg[rn2(4)];
        }
        break;
    case MS_MUMBLE:
        pline_msg = "mumbles incomprehensibly.";
        break;
    case MS_WISHGIVER:
        if (mtmp->mtame) {
            verbl_msg = "Sorry, I'm all out of wishes.";
        } else if (mtmp->mpeaceful) {
            if (ptr == &mons[PM_WATER_DEMON])
                pline_msg = "gurgles.";
            else
                verbl_msg = "I'm free!";
        } else
            verbl_msg = "This will teach you not to disturb me!";
        break;
    case MS_BOAST:     /* giants */
        if (!mtmp->mpeaceful) {
            switch (rn2(4)) {
            case 0:
                pline("%s boasts about %s gem collection.", Monnam(mtmp),
                      mhis(mtmp));
                break;
            case 1:
                pline_msg = "complains about a diet of mutton.";
                break;
            default:
                pline_msg = "shouts \"Fee Fie Foe Foo!\" and guffaws.";
                wake_nearto(mtmp->mx, mtmp->my, 7 * 7);
                break;
            }
            break;
        }
        /* else FALLTHRU */
    case MS_HUMANOID:
        if (!mtmp->mpeaceful) {
            if (In_endgame(&u.uz) && is_mplayer(ptr)) {
                mplayer_talk(mtmp);
                break;
            } else
                return 0;       /* no sound */
        }
        /* Generic peaceful humanoid behaviour. */
        if (mtmp->mflee)
            pline_msg = "wants nothing to do with you.";
        else if (mtmp->mhp < mtmp->mhpmax / 4)
            pline_msg = "moans.";
        else if (mtmp->mconf || mtmp->mstun)
            verbl_msg = !rn2(3) ? "Huh?" : rn2(2) ? "What?" : "Eh?";
        else if (!mtmp->mcansee)
            verbl_msg = "I can't see!";
        else if (mtmp->mtrapped) {
            struct trap *t = t_at(level, mtmp->mx, mtmp->my);

            if (t)
                t->tseen = 1;
            verbl_msg = "I'm trapped!";
        } else if (mtmp->mhp < mtmp->mhpmax / 2)
            pline_msg = "asks for a potion of healing.";
        else if (mtmp->mtame && !mtmp->isminion &&
                 moves > EDOG(mtmp)->hungrytime)
            verbl_msg = "I'm hungry.";
        /* Specific monsters' interests */
        else if (is_elf(ptr))
            pline_msg = "curses orcs.";
        else if (is_dwarf(ptr))
            pline_msg = "talks about mining.";
        else if (likes_magic(ptr))
            pline_msg = "talks about spellcraft.";
        else if (ptr->mlet == S_CENTAUR)
            pline_msg = "discusses hunting.";
        else
            switch (monsndx(ptr)) {
            case PM_HOBBIT:
                pline_msg =
                    (mtmp->mhpmax - mtmp->mhp >=
                     10) ? "complains about unpleasant dungeon conditions." :
                    "asks you about the One Ring.";
                break;
            case PM_ARCHEOLOGIST:
                pline_msg =
                    "describes a recent article in \"Spelunker Today\" "
                    "magazine.";
                break;
            case PM_TOURIST:
                verbl_msg = "Aloha.";
                break;
            case PM_PRISONER:
                verbl_msg = "Thank you for freeing me!";
                break;
            default:
                pline_msg = "discusses dungeon exploration.";
                break;
            }
        break;
    case MS_SEDUCE:
        if (ptr->mlet != S_NYMPH && flags.seduce_enabled &&
            could_seduce(mtmp, &youmonst, NULL) == 1) {
            doseduce(mtmp);
            break;
        }

        switch ((poly_gender() != (int)mtmp->female) ? rn2(3) : 0) {
        case 2:
            verbl_msg = "Hello, sailor.";
            break;
        case 1:
            pline_msg = "comes on to you.";
            break;
        default:
            pline_msg = "cajoles you.";
        }
        break;
    case MS_ARREST:
        if (mtmp->mpeaceful)
            verbalize("Just the facts, %s.", u.ufemale ? "Ma'am" : "Sir");
        else {
            static const char *const arrest_msg[3] = {
                "Anything you say can be used against you.",
                "You're under arrest!",
                "Stop in the name of the Law!",
            };
            verbl_msg = arrest_msg[rn2(3)];
        }
        break;
    case MS_BRIBE:
        if (mtmp->mpeaceful && !mtmp->mtame) {
            demon_talk(mtmp);
            break;
        }
        /* fall through */
    case MS_CUSS:
        if (!mtmp->mpeaceful)
            cuss(mtmp);
        break;
    case MS_SPELL:
        /* deliberately vague, since it's not actually casting any spell */
        pline_msg = "seems to mutter a cantrip.";
        break;
    case MS_NURSE:
        if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))
            verbl_msg = "Put that weapon away before you hurt someone!";
        else if (uarmc || (uarm && !uskin()) ||
                 uarmh || uarms || uarmg || uarmf)
            verbl_msg =
                Role_if(PM_HEALER) ?
                "Doc, I can't help you unless you cooperate." :
                "Please undress so I can examine you.";
        else if (uarmu)
            verbl_msg = "Take off your shirt, please.";
        else
            verbl_msg = "Relax, this won't hurt a bit.";
        break;
    case MS_GUARD:
        if (money_cnt(invent))
            verbl_msg = "Please drop that gold and follow me.";
        else
            verbl_msg = "Please follow me.";
        break;
    case MS_SOLDIER:
        {
            static const char *const soldier_foe_msg[3] = {
                "Resistance is useless!",
                "You're dog meat!",
                "Surrender!",
            }, *const soldier_pax_msg[3] = {
                "What lousy pay we're getting here!",
                "The food's not fit for Orcs!",
                "My feet hurt, I've been on them all day!",
            };
            verbl_msg = mtmp->mpeaceful ? soldier_pax_msg[rn2(3)]
                : soldier_foe_msg[rn2(3)];
        }
        break;
    case MS_RIDER:
        if (ptr == &mons[PM_DEATH] && !rn2(10))
            pline_msg = "is busy reading a copy of Sandman #8.";
        else
            verbl_msg = "Who do you think you are, War?";
        break;
    }

    if (pline_msg)
        pline("%s %s", Monnam(mtmp), pline_msg);
    else if (verbl_msg)
        verbalize("%s", verbl_msg);
    return 1;
}
Пример #30
0
/* returns 0 if something was detected          */
int
food_detect(struct obj *sobj, boolean * scr_known)
{
    struct obj *obj;
    struct monst *mtmp;
    int ct = 0, ctu = 0;
    boolean confused = (Confusion || (sobj && sobj->cursed)), stale;
    char oclass = confused ? POTION_CLASS : FOOD_CLASS;
    const char *what = confused ? "something" : "food";
    int uw = u.uinwater;

    stale = clear_stale_map(oclass, 0);

    for (obj = level->objlist; obj; obj = obj->nobj)
        if (o_in(obj, oclass)) {
            if (obj->ox == youmonst.mx && obj->oy == youmonst.my)
                ctu++;
            else
                ct++;
        }
    for (mtmp = level->monlist; mtmp && !ct; mtmp = mtmp->nmon) {
        /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */
        for (obj = mtmp->minvent; obj; obj = obj->nobj)
            if (o_in(obj, oclass)) {
                ct++;
                break;
            }
    }

    if (!ct && !ctu) {
        *scr_known = stale && !confused;
        if (stale) {
            doredraw();
            pline(msgc_notarget, "You sense a lack of %s nearby.", what);
            if (sobj && sobj->blessed) {
                if (!u.uedibility)
                    pline(msgc_statusgood, "Your %s starts to tingle.",
                          body_part(NOSE));
                u.uedibility = 1;
            }
        } else if (sobj) {
            const char *buf;

            buf = msgprintf("Your %s twitches%s.", body_part(NOSE),
                            (sobj->blessed &&
                             !u.uedibility) ? " then starts to tingle" : "");
            if (sobj->blessed && !u.uedibility) {
                /* prevent non-delivery of message */
                boolean savebeginner = flags.beginner;

                flags.beginner = FALSE;
                strange_feeling(sobj, buf);
                flags.beginner = savebeginner;
                u.uedibility = 1;
            } else
                strange_feeling(sobj, buf);
        }
        return !stale;
    } else if (!ct) {
        *scr_known = TRUE;
        pline(msgc_youdiscover, "You %s %s nearby.",
              sobj ? "smell" : "sense", what);
        if (sobj && sobj->blessed) {
            if (!u.uedibility)
                pline(msgc_statusgood, "Your %s starts to tingle.",
                      body_part(NOSE));
            u.uedibility = 1;
        }
    } else {
        struct obj *temp;

        *scr_known = TRUE;
        cls();
        u.uinwater = 0;
        for (obj = level->objlist; obj; obj = obj->nobj)
            if ((temp = o_in(obj, oclass)) != 0) {
                if (temp != obj) {
                    temp->ox = obj->ox;
                    temp->oy = obj->oy;
                }
                map_object(temp, 1, TRUE);
            }
        for (mtmp = level->monlist; mtmp; mtmp = mtmp->nmon)
            /* no DEADMONSTER(mtmp) check needed since dmons never have
               inventory */
            for (obj = mtmp->minvent; obj; obj = obj->nobj)
                if ((temp = o_in(obj, oclass)) != 0) {
                    temp->ox = mtmp->mx;
                    temp->oy = mtmp->my;
                    map_object(temp, 1, TRUE);
                    break;      /* skip rest of this monster's inventory */
                }
        newsym(youmonst.mx, youmonst.my);
        if (sobj) {
            if (sobj->blessed) {
                pline(u.uedibility ? msgc_youdiscover : msgc_statusgood,
                      "Your %s %s to tingle and you smell %s.", body_part(NOSE),
                      u.uedibility ? "continues" : "starts", what);
                u.uedibility = 1;
            } else
                pline(msgc_youdiscover, "Your %s tingles and you smell %s.",
                      body_part(NOSE), what);
        } else
            pline(msgc_youdiscover, "You sense %s.", what);
        win_pause_output(P_MAP);
        exercise(A_WIS, TRUE);
        doredraw();
        u.uinwater = uw;
        if (Underwater)
            under_water(2);
        if (u.uburied)
            under_ground(2);
    }
    return 0;
}