Пример #1
0
/* hero is hit by something other than a monster */
int
thitu(int tlev, int dam, struct obj *obj, const char *name)
{       /* if null, then format `obj' */
    const char *onm, *killer;
    boolean is_acid;

    /* TODO: credit the monster that fired the object with the kill */
    if (!name) {
        if (!obj)
            panic("thitu: name & obj both null?");
        name = (obj->quan > 1L) ? doname(obj) : mshot_xname(obj);
        killer = killer_msg_obj(DIED, obj);
    } else {
        killer = killer_msg(DIED, an(name));
    }
    onm = (obj && obj_is_pname(obj)) ? the(name) :
      (obj && obj->quan > 1L) ? name : an(name);
    is_acid = (obj && obj->otyp == ACID_VENOM);

    if (get_player_ac() + tlev <= rnd(20)) {
        if (Blind || !flags.verbose)
            pline("It misses.");
        else
            pline("You are almost hit by %s.", onm);
        return 0;
    } else {
        if (Blind || !flags.verbose)
            pline("You are hit!");
        else
            pline("You are hit by %s%s", onm, exclam(dam));

        if (obj && objects[obj->otyp].oc_material == SILVER &&
            hates_silver(youmonst.data)) {
            dam += rnd(20);
            pline("The silver sears your flesh!");
            exercise(A_CON, FALSE);
        }
        if (is_acid && Acid_resistance)
            pline("It doesn't seem to hurt you.");
        else {
            if (is_acid)
                pline("It burns!");
            if (Half_physical_damage)
                dam = (dam + 1) / 2;
            losehp(dam, killer);
            exercise(A_STR, FALSE);
        }
        return 1;
    }
}
Пример #2
0
/* an object launched by someone/thing other than player attacks a monster;
   return 1 if the object has stopped moving (hit or its range used up) */
int
ohitmon(struct monst *mtmp, /* accidental target */
        struct obj *otmp,   /* missile; might be destroyed by drop_throw */
        int range,  /* how much farther will object travel if it misses */
        /* Use -1 to signify to keep going even after hit, unless it's gone
           (used for rolling_boulder_traps) */
        boolean verbose) {  /* give message(s) even when you can't see what
                               happened */
    int damage, tmp;
    boolean vis, ismimic;
    int objgone = 1;

    ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER;
    vis = cansee(bhitpos.x, bhitpos.y);

    tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
    if (tmp < rnd(20)) {
        if (!ismimic) {
            if (vis)
                miss(distant_name(otmp, mshot_xname), mtmp);
            else if (verbose)
                pline("It is missed.");
        }
        if (!range) {   /* Last position; object drops */
            if (is_pole(otmp))
                return 1;

            drop_throw(otmp, 0, mtmp->mx, mtmp->my);
            return 1;
        }
    } else if (otmp->oclass == POTION_CLASS) {
        if (ismimic)
            seemimic(mtmp);
        mtmp->msleeping = 0;
        if (vis)
            otmp->dknown = 1;
        potionhit(mtmp, otmp, FALSE);
        return 1;
    } else {
        damage = dmgval(otmp, mtmp);

        if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
            damage = 0;
        if (otmp->otyp == VAMPIRE_BLOOD && resists_drli(mtmp))
            damage = 0;
        if (ismimic)
            seemimic(mtmp);
        mtmp->msleeping = 0;
        if (vis)
            hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
        else if (verbose)
            pline("%s is hit%s", Monnam(mtmp), exclam(damage));

        if (otmp->opoisoned && is_poisonable(otmp)) {
            if (resists_poison(mtmp)) {
                if (vis)
                    pline("The poison doesn't seem to affect %s.",
                          mon_nam(mtmp));
            } else {
                if (rn2(30)) {
                    damage += rnd(6);
                } else {
                    if (vis)
                        pline("The poison was deadly...");
                    damage = mtmp->mhp;
                }
            }
        }
        if (objects[otmp->otyp].oc_material == SILVER &&
            hates_silver(mtmp->data)) {
            if (vis)
                pline("The silver sears %s flesh!", s_suffix(mon_nam(mtmp)));
            else if (verbose)
                pline("Its flesh is seared!");
        }
        if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
            if (resists_acid(mtmp)) {
                if (vis || verbose)
                    pline("%s is unaffected.", Monnam(mtmp));
                damage = 0;
            } else {
                if (vis)
                    pline("The acid burns %s!", mon_nam(mtmp));
                else if (verbose)
                    pline("It is burned!");
            }
        }
        mtmp->mhp -= damage;
        if (mtmp->mhp < 1) {
            if (vis || verbose)
                pline("%s is %s!", Monnam(mtmp),
                      (nonliving(mtmp->data) || !canclassifymon(mtmp))
                      ? "destroyed" : "killed");
            /* don't blame hero for unknown rolling boulder trap */
            if (!flags.mon_moving &&
                (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped))
                xkilled(mtmp, 0);
            else
                mondied(mtmp);
        }

        if (can_blnd
            (NULL, mtmp,
             (uchar) (otmp->otyp == BLINDING_VENOM ? AT_SPIT : AT_WEAP),
             otmp)) {
            if (vis && mtmp->mcansee)
                pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
            mtmp->mcansee = 0;
            tmp = (int)mtmp->mblinded + rnd(25) + 20;
            if (tmp > 127)
                tmp = 127;
            mtmp->mblinded = tmp;
        }

        if (otmp->otyp == VAMPIRE_BLOOD) {
            if (!resists_drli(mtmp)) {
                int xtmp = dice(2, 6);
                if (vis)
                    pline("%s suddenly seems weaker!", Monnam(mtmp));
                mtmp->mhpmax -= xtmp;
                if ((mtmp->mhp -= xtmp) <= 0 || !mtmp->m_lev) {
                    if (vis)
                        pline("%s dies!", Monnam(mtmp));
                    xkilled(mtmp, 0);
                } else
                    mtmp->m_lev--;
            }
            obfree(otmp, NULL);
            return 1;
        }

        if (is_pole(otmp))
            return 1;

        objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y);
        if (!objgone && range == -1) {  /* special case */
            obj_extract_self(otmp);     /* free it for motion again */
            return 0;
        }
        return 1;
    }
    return 0;
}
Пример #3
0
/* fungi will eat even tainted food */
int
dogfood(const struct monst *mon, struct obj *obj)
{
    boolean carni = carnivorous(mon->data);
    boolean herbi = herbivorous(mon->data);
    const struct permonst *fptr = &mons[obj->corpsenm];
    boolean starving;

    if (is_quest_artifact(obj) || obj_resists(obj, 0, 95))
        return obj->cursed ? TABU : APPORT;

    switch (obj->oclass) {
    case FOOD_CLASS:
        if (obj->otyp == CORPSE &&
            ((touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon))
             || is_rider(fptr)))
            return TABU;

        /* Ghouls only eat old corpses... yum! */
        if (mon->data == &mons[PM_GHOUL])
            return (obj->otyp == CORPSE &&
                    peek_at_iced_corpse_age(obj) + 50L <=
                    moves) ? DOGFOOD : TABU;

        if (!carni && !herbi)
            return obj->cursed ? UNDEF : APPORT;

        /* a starving pet will eat almost anything */
        starving = (mon->mtame && !mon->isminion &&
                    CONST_EDOG(mon)->mhpmax_penalty);

        switch (obj->otyp) {
        case TRIPE_RATION:
        case MEATBALL:
        case MEAT_RING:
        case MEAT_STICK:
        case HUGE_CHUNK_OF_MEAT:
            return carni ? DOGFOOD : MANFOOD;
        case EGG:
            if (touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon))
                return POISON;
            return carni ? CADAVER : MANFOOD;
        case CORPSE:
            if ((peek_at_iced_corpse_age(obj) + 50L <= moves &&
                 obj->corpsenm != PM_LIZARD && obj->corpsenm != PM_LICHEN &&
                 mon->data->mlet != S_FUNGUS) ||
                (acidic(&mons[obj->corpsenm]) && !resists_acid(mon)) ||
                (poisonous(&mons[obj->corpsenm]) && !resists_poison(mon)))
                return POISON;
            else if (vegan(fptr))
                return herbi ? CADAVER : MANFOOD;
            else
                return carni ? CADAVER : MANFOOD;
        case CLOVE_OF_GARLIC:
            return (is_undead(mon->data) ? TABU
                    : ((herbi || starving) ? ACCFOOD : MANFOOD));
        case TIN:
            return metallivorous(mon->data) ? ACCFOOD : MANFOOD;
        case APPLE:
        case CARROT:
            return herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD;
        case BANANA:
            return ((mon->data->mlet ==
                     S_YETI) ? DOGFOOD : ((herbi ||
                                           starving) ? ACCFOOD : MANFOOD));

        case K_RATION:
        case C_RATION:
        case CRAM_RATION:
        case LEMBAS_WAFER:
        case FOOD_RATION:
            if (is_human(mon->data) || is_elf(mon->data) || is_dwarf(mon->data)
                || is_gnome(mon->data) || is_orc(mon->data))
                return ACCFOOD;

        default:
            if (starving)
                return ACCFOOD;
            return (obj->otyp >
                    SLIME_MOLD ? (carni ? ACCFOOD : MANFOOD) :
                    (herbi ? ACCFOOD : MANFOOD));
        }
    default:
        if (obj->otyp == AMULET_OF_STRANGULATION ||
            obj->otyp == RIN_SLOW_DIGESTION)
            return TABU;
        if (hates_silver(mon->data) && objects[obj->otyp].oc_material == SILVER)
            return TABU;
        if (mon->data == &mons[PM_GELATINOUS_CUBE] && is_organic(obj))
            return ACCFOOD;
        if (metallivorous(mon->data) && is_metallic(obj) &&
            (is_rustprone(obj) || mon->data != &mons[PM_RUST_MONSTER])) {
            /* Non-rustproofed ferrous based metals are preferred. */
            return (is_rustprone(obj) && !obj->oerodeproof) ? DOGFOOD : ACCFOOD;
        }
        if (!obj->cursed && obj->oclass != BALL_CLASS &&
            obj->oclass != CHAIN_CLASS)
            return APPORT;
        /* fall into next case */
    case ROCK_CLASS:
        return UNDEF;
    }
}