Пример #1
0
/* decide whether an artifact's special attacks apply against mtmp */
static int spec_applies(const struct artifact *weap, struct monst *mtmp)
{
	const struct permonst *ptr;
	boolean yours;

	if (!(weap->spfx & (SPFX_DBONUS | SPFX_ATTK)))
	    return weap->attk.adtyp == AD_PHYS;

	yours = (mtmp == &youmonst);
	ptr = mtmp->data;

	if (weap->spfx & SPFX_DMONS) {
	    return ptr == &mons[(int)weap->mtype];
	} else if (weap->spfx & SPFX_DCLAS) {
	    return weap->mtype == (unsigned long)ptr->mlet;
	} else if (weap->spfx & SPFX_DFLAG1) {
	    return (ptr->mflags1 & weap->mtype) != 0L;
	} else if (weap->spfx & SPFX_DFLAG2) {
	    return ((ptr->mflags2 & weap->mtype) || (yours &&
			((!Upolyd && (urace.selfmask & weap->mtype)) ||
			 ((weap->mtype & M2_WERE) && u.ulycn >= LOW_PM))));
	} else if (weap->spfx & SPFX_DALIGN) {
	    return yours ? (u.ualign.type != weap->alignment) :
			   (ptr->maligntyp == A_NONE ||
				sgn(ptr->maligntyp) != weap->alignment);
	} else if (weap->spfx & SPFX_ATTK) {
	    struct obj *defending_weapon = (yours ? uwep : MON_WEP(mtmp));

	    if (defending_weapon && defending_weapon->oartifact &&
		    defends((int)weap->attk.adtyp, defending_weapon))
		return FALSE;
	    switch(weap->attk.adtyp) {
		case AD_FIRE:
			return !(yours ? Fire_resistance : resists_fire(mtmp));
		case AD_COLD:
			return !(yours ? Cold_resistance : resists_cold(mtmp));
		case AD_ELEC:
			return !(yours ? Shock_resistance : resists_elec(mtmp));
		case AD_MAGM:
		case AD_STUN:
			return !(yours ? Antimagic : (rn2(100) < ptr->mr));
		case AD_DRST:
			return !(yours ? Poison_resistance : resists_poison(mtmp));
		case AD_DRLI:
			return !(yours ? Drain_resistance : resists_drli(mtmp));
		case AD_STON:
			return !(yours ? Stone_resistance : resists_ston(mtmp));
		default:	impossible("Weird weapon special attack.");
	    }
	}
	return 0;
}
Пример #2
0
/* Returns an object slot mask giving all the reasons why the given
   player/monster might have the given property, limited by "reasons", an object
   slot mask (W_EQUIP, INTRINSIC, and ANY_PROPERTY are the most likely values
   here, but you can specify slots individually if you like). */
unsigned
m_has_property(const struct monst *mon, enum youprop property,
               unsigned reasons, boolean even_if_blocked)
{
    unsigned rv = 0;
    struct obj *otmp;

    /* The general case for equipment */
    rv |= mworn_extrinsic(mon, property);

    if (mon == &youmonst) {
        /* Intrinsics */
        if (u.uintrinsic[property] & TIMEOUT)
            rv |= W_MASK(os_timeout);
        rv |= u.uintrinsic[property] & (INTRINSIC | I_SPECIAL);

        /* Birth options */
        if (property == BLINDED && flags.permablind)
            rv |= W_MASK(os_birthopt);
        if (property == HALLUC && flags.permahallu)
            rv |= W_MASK(os_birthopt);
        if (property == UNCHANGING && flags.polyinit_mnum != -1)
            rv |= W_MASK(os_birthopt);

    } else {
        /* Monster tempraries are boolean flags.

           TODO: Monsters with no eyes are not considered blind. This doesn't
           make much sense. However, changing it would be a major balance
           change (due to Elbereth), and so it has been left alone for now. */
        if (property == BLINDED && (!mon->mcansee || mon->mblinded))
            rv |= W_MASK(os_timeout);
        if (property == FAST && mon->mspeed == MFAST)
            rv |= (mon->permspeed == FAST ?
                   W_MASK(os_polyform) : W_MASK(os_outside));
        if (property == INVIS && mon->perminvis && !pm_invisible(mon->data))
            rv |= W_MASK(os_outside);
        if (property == STUNNED && mon->mstun)
            rv |= W_MASK(os_timeout);
        if (property == CONFUSION && mon->mconf)
            rv |= W_MASK(os_timeout);
    }


    /* Polyform / monster intrinsic */
    /* TODO: Change the monster data code into something that doesn't require a
       giant switch statement or ternary chain to get useful information from
       it. We use a ternary chain here because it cuts down on repetitive code
       and so is easier to read. */
    if (property == FIRE_RES     ? resists_fire(mon)                     :
        property == COLD_RES     ? resists_cold(mon)                     :
        property == SLEEP_RES    ? resists_sleep(mon)                    :
        property == DISINT_RES   ? resists_disint(mon)                   :
        property == SHOCK_RES    ? resists_elec(mon)                     :
        property == POISON_RES   ? resists_poison(mon)                   :
        property == DRAIN_RES    ? resists_drli(mon)                     :
        property == SICK_RES     ? mon->data->mlet == S_FUNGUS ||
                                   mon->data == &mons[PM_GHOUL]          :
        property == ANTIMAGIC    ? resists_magm(mon)                     :
        property == ACID_RES     ? resists_acid(mon)                     :
        property == STONE_RES    ? resists_ston(mon)                     :
        property == STUNNED      ? u.umonnum == PM_STALKER ||
                                   mon->data->mlet == S_BAT              :
        property == BLINDED      ? !haseyes(mon->data)                   :
        property == HALLUC       ? Upolyd && dmgtype(mon->data, AD_HALU) :
        property == SEE_INVIS    ? perceives(mon->data)                  :
        property == TELEPAT      ? telepathic(mon->data)                 :
        property == INFRAVISION  ? infravision(mon->data)                :
        /* Note: This one assumes that there's no way to permanently turn
           visible when you're in stalker form (i.e. mummy wrappings only). */
        property == INVIS        ? pm_invisible(mon->data)               :
        property == TELEPORT     ? can_teleport(mon->data)               :
        property == LEVITATION   ? is_floater(mon->data)                 :
        property == FLYING       ? is_flyer(mon->data)                   :
        property == SWIMMING     ? is_swimmer(mon->data)                 :
        property == PASSES_WALLS ? passes_walls(mon->data)               :
        property == REGENERATION ? regenerates(mon->data)                :
        property == REFLECTING   ? mon->data == &mons[PM_SILVER_DRAGON]  :
        property == TELEPORT_CONTROL  ? control_teleport(mon->data)      :
        property == MAGICAL_BREATHING ? amphibious(mon->data)            :
        0)
        rv |= W_MASK(os_polyform);

    if (mon == &youmonst) {
        /* External circumstances */
        if (property == BLINDED && u_helpless(hm_unconscious))
            rv |= W_MASK(os_circumstance);

        /* Riding */
        if (property == FLYING && u.usteed && is_flyer(u.usteed->data))
            rv |= W_MASK(os_saddle);
        if (property == SWIMMING && u.usteed && is_swimmer(u.usteed->data))
            rv |= W_MASK(os_saddle);
    }

    /* Overrides */
    if (!even_if_blocked) {
        if (property == BLINDED) {
            for (otmp = m_minvent(mon); otmp; otmp = otmp->nobj)
                if (otmp->oartifact == ART_EYES_OF_THE_OVERWORLD &&
                    otmp->owornmask & W_MASK(os_tool))
                    rv &= (unsigned)(W_MASK(os_circumstance) |
                                     W_MASK(os_birthopt));
        }

        if (property == WWALKING && Is_waterlevel(m_mz(mon)))
            rv &= (unsigned)(W_MASK(os_birthopt));
        if (mworn_blocked(mon, property))
            rv &= (unsigned)(W_MASK(os_birthopt));
    }

    return rv & reasons;
}
Пример #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;
    }
}