Esempio n. 1
0
File: worn.c Progetto: mbi/NitroHack
/* Wear the best object of each type that the monster has.  During creation,
 * the monster can put everything on at once; otherwise, wearing takes time.
 * This doesn't affect monster searching for objects--a monster may very well
 * search for objects it would not want to wear, because we don't want to
 * check which_armor() each round.
 *
 * We'll let monsters put on shirts and/or suits under worn cloaks, but
 * not shirts under worn suits.  This is somewhat arbitrary, but it's
 * too tedious to have them remove and later replace outer garments,
 * and preventing suits under cloaks makes it a little bit too easy for
 * players to influence what gets worn.  Putting on a shirt underneath
 * already worn body armor is too obviously buggy...
 */
void m_dowear(struct monst *mon, boolean creation)
{
#define RACE_EXCEPTION TRUE
	/* Note the restrictions here are the same as in dowear in do_wear.c
	 * except for the additional restriction on intelligence.  (Players
	 * are always intelligent, even if polymorphed).
	 */
	if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data))
		return;
	/* give mummies a chance to wear their wrappings
	 * and let skeletons wear their initial armor */
	if (mindless(mon->data) && (!creation ||
	    (mon->data->mlet != S_MUMMY && mon->data != &mons[PM_SKELETON])))
		return;

	m_dowear_type(mon, W_AMUL, creation, FALSE);
	/* can't put on shirt if already wearing suit */
	if (!cantweararm(mon->data) || (mon->misc_worn_check & W_ARM))
	    m_dowear_type(mon, W_ARMU, creation, FALSE);
	/* treating small as a special case allows
	   hobbits, gnomes, and kobolds to wear cloaks */
	if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL)
	    m_dowear_type(mon, W_ARMC, creation, FALSE);
	m_dowear_type(mon, W_ARMH, creation, FALSE);
	if (!MON_WEP(mon) || !bimanual(MON_WEP(mon)))
	    m_dowear_type(mon, W_ARMS, creation, FALSE);
	m_dowear_type(mon, W_ARMG, creation, FALSE);
	if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR)
	    m_dowear_type(mon, W_ARMF, creation, FALSE);
	if (!cantweararm(mon->data))
	    m_dowear_type(mon, W_ARM, creation, FALSE);
	else
	    m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION);
}
Esempio n. 2
0
/* release the objects the creature is carrying */
void
relobj(struct monst *mtmp, int show, boolean is_pet)
{       /* If true, pet should keep wielded/worn items */
    struct obj *otmp;
    int omx = mtmp->mx, omy = mtmp->my;
    struct obj *keepobj = 0;
    struct obj *wep = MON_WEP(mtmp), *hwep = attacktype(mtmp->data, AT_WEAP)
        ? select_hwep(mtmp) : (struct obj *)0, *proj =
        attacktype(mtmp->data, AT_WEAP)
        ? select_rwep(mtmp) : (struct obj *)0, *rwep;
    boolean item1 = FALSE, item2 = FALSE;

    rwep = attacktype(mtmp->data, AT_WEAP) ? propellor : &zeroobj;


    if (!is_pet || mindless(mtmp->data) || is_animal(mtmp->data))
        item1 = item2 = TRUE;
    if (!tunnels(mtmp->data) || !needspick(mtmp->data))
        item1 = TRUE;

    while ((otmp = mtmp->minvent) != 0) {
        obj_extract_self(otmp);
        /* special case: pick-axe and unicorn horn are non-worn */
        /* items that we also want pets to keep 1 of */
        /* (It is a coincidence that these can also be wielded.) */
        if (otmp->owornmask || otmp == wep || otmp == hwep || otmp == rwep ||
            otmp == proj ||
            would_prefer_hwep(mtmp, otmp) ||  /* cursed item in hand? */
            would_prefer_rwep(mtmp, otmp) || could_use_item(mtmp, otmp) ||
            ((!rwep || rwep == &zeroobj) &&
             (is_ammo(otmp) || is_launcher(otmp))) ||
            (rwep && rwep != &zeroobj && ammo_and_launcher(otmp, rwep)) ||
            ((!item1 && otmp->otyp == PICK_AXE) ||
             (!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) {
            if (is_pet) {       /* dont drop worn/wielded item */
                if (otmp->otyp == PICK_AXE)
                    item1 = TRUE;
                if (otmp->otyp == UNICORN_HORN && !otmp->cursed)
                    item2 = TRUE;
                otmp->nobj = keepobj;
                keepobj = otmp;
                continue;
            }
        }
        if (otmp == wep)
            setmnotwielded(mtmp, otmp);
        mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
    }

    /* put kept objects back */
    while ((otmp = keepobj) != NULL) {
        keepobj = otmp->nobj;
        add_to_minv(mtmp, otmp);
    }

    if (show & cansee(omx, omy))
        newsym(omx, omy);
}
Esempio n. 3
0
/*
 * See if a monst could use this item in an offensive or defensive capacity.
 */
boolean
could_use_item(struct monst *mtmp, struct obj *otmp)
{
    boolean can_use =
        /* make sure this is an intelligent monster */
        (mtmp && !is_animal(mtmp->data) && !mindless(mtmp->data) &&
         !nohands(mtmp->data) && otmp &&
         /* food */
         ((dogfood(mtmp, otmp) < APPORT) ||
          /* better weapons */
          (attacktype(mtmp->data, AT_WEAP) &&
           (otmp->oclass == WEAPON_CLASS || is_weptool(otmp)) &&
           (would_prefer_hwep(mtmp, otmp) || would_prefer_rwep(mtmp, otmp))) ||
          /* better armor */
          (otmp->oclass == ARMOR_CLASS && is_better_armor(mtmp, otmp)) ||
          /* useful amulets */
          otmp->otyp == AMULET_OF_LIFE_SAVING ||
          otmp->otyp == AMULET_OF_REFLECTION ||
          /* misc magic items that muse can use */
          otmp->otyp == SCR_TELEPORTATION || otmp->otyp == SCR_EARTH ||
          otmp->otyp == SCR_REMOVE_CURSE || otmp->otyp == WAN_DEATH ||
          otmp->otyp == WAN_DIGGING || otmp->otyp == WAN_FIRE ||
          otmp->otyp == WAN_COLD || otmp->otyp == WAN_LIGHTNING ||
          otmp->otyp == WAN_MAGIC_MISSILE || otmp->otyp == WAN_STRIKING ||
          otmp->otyp == WAN_TELEPORTATION || otmp->otyp == POT_HEALING ||
          otmp->otyp == POT_EXTRA_HEALING || otmp->otyp == POT_FULL_HEALING ||
          otmp->otyp == POT_PARALYSIS || otmp->otyp == POT_BLINDNESS ||
          otmp->otyp == POT_CONFUSION || otmp->otyp == POT_ACID ||
          otmp->otyp == FROST_HORN || otmp->otyp == FIRE_HORN ||
          otmp->otyp == UNICORN_HORN));

    if (can_use) {
        /* arbitrary - greedy monsters keep any item you can use */
        if (likes_gold(mtmp->data))
            return TRUE;

        if (otmp->oclass == ARMOR_CLASS) {
            return !is_better_armor(&youmonst, otmp);
        } else if (otmp->oclass == WAND_CLASS && otmp->spe <= 0)
            return FALSE;       /* used charges or was cancelled? */
        else {
            /* Check if you've got one. If you don't, don't hoard it. */
            register struct obj *otmp2;

            for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
                if (otmp->otyp == otmp2->otyp)
                    return TRUE;
        }
    }

    return FALSE;
}
Esempio n. 4
0
/* release the objects the creature is carrying */
// bool is_pet         /* If true, pet should keep wielded/worn items */
void relobj ( struct monst *mtmp, int show, bool is_pet) {
    struct obj *otmp;
    int omx = mtmp->mx, omy = mtmp->my;
    struct obj *keepobj = 0;
    struct obj *wep = MON_WEP(mtmp);
    bool item1 = false, item2 = false;

    if (!is_pet || mindless(mtmp->data) || is_animal(mtmp->data))
        item1 = item2 = true;
    if (!tunnels(mtmp->data) || !needspick(mtmp->data))
        item1 = true;

    while ((otmp = mtmp->minvent) != 0) {
        obj_extract_self(otmp);
        /* special case: pick-axe and unicorn horn are non-worn */
        /* items that we also want pets to keep 1 of */
        /* (It is a coincidence that these can also be wielded.) */
        if (otmp->owornmask || otmp == wep ||
                ((!item1 && otmp->otyp == PICK_AXE) ||
                 (!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) {
            if (is_pet) { /* dont drop worn/wielded item */
                if (otmp->otyp == PICK_AXE)
                    item1 = true;
                if (otmp->otyp == UNICORN_HORN && !otmp->cursed)
                    item2 = true;
                otmp->nobj = keepobj;
                keepobj = otmp;
                continue;
            }
        }
        mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
    }

    /* put kept objects back */
    while ((otmp = keepobj) != (struct obj *)0) {
        keepobj = otmp->nobj;
        (void) add_to_minv(mtmp, otmp);
    }
    if (mtmp->mgold) {
        long g = mtmp->mgold;
        (void) mkgold(g, omx, omy);
        if (is_pet && cansee(omx, omy) && flags.verbose) {
            message_monster_int(MSG_M_DROPS_X_GOLD_PIECES, mtmp, g);
        }
        mtmp->mgold = 0L;
    }

    if (show & cansee(omx, omy))
        newsym(omx, omy);
}
Esempio n. 5
0
/* release the objects the creature is carrying */
void relobj(struct monst *mtmp, int show, 
	    boolean is_pet) /* If true, pet should keep wielded/worn items */
{
	struct obj *otmp;
	int omx = mtmp->mx, omy = mtmp->my;
	struct obj *keepobj = 0;
	struct obj *wep = MON_WEP(mtmp);
	boolean item1 = FALSE, item2 = FALSE;

	if (!is_pet || mindless(mtmp->data) || is_animal(mtmp->data))
		item1 = item2 = TRUE;
	if (!tunnels(mtmp->data) || !needspick(mtmp->data))
		item1 = TRUE;

	while ((otmp = mtmp->minvent) != 0) {
		obj_extract_self(otmp);
		/* special case: pick-axe and unicorn horn are non-worn */
		/* items that we also want pets to keep 1 of */
		/* (It is a coincidence that these can also be wielded.) */
		if (otmp->owornmask || otmp == wep ||
		    ((!item1 && otmp->otyp == PICK_AXE) ||
		     (!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) {
			if (is_pet) { /* dont drop worn/wielded item */
				if (otmp->otyp == PICK_AXE)
					item1 = TRUE;
				if (otmp->otyp == UNICORN_HORN && !otmp->cursed)
					item2 = TRUE;
				otmp->nobj = keepobj;
				keepobj = otmp;
				continue;
			}
		}
		mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
	}

	/* put kept objects back */
	while ((otmp = keepobj) != NULL) {
	    keepobj = otmp->nobj;
	    add_to_minv(mtmp, otmp);
	}
	
	if (show & cansee(omx, omy))
		newsym(omx, omy);
}
Esempio n. 6
0
static struct obj *
DROPPABLES(struct monst *mon)
{
    struct obj *obj;
    struct obj *wep = MON_WEP(mon), *hwep = attacktype(mon->data, AT_WEAP)
        ? select_hwep(mon) : (struct obj *)0, *proj =
        attacktype(mon->data, AT_WEAP)
        ? select_rwep(mon) : (struct obj *)0, *rwep;
    boolean item1 = FALSE, item2 = FALSE;

    rwep = attacktype(mon->data, AT_WEAP) ? propellor : &zeroobj;

    if (is_animal(mon->data) || mindless(mon->data))
        item1 = item2 = TRUE;
    if (!tunnels(mon->data) || !needspick(mon->data))
        item1 = TRUE;
    for (obj = mon->minvent; obj; obj = obj->nobj) {
        if (!item1 && is_pick(obj) &&
            (obj->otyp != DWARVISH_MATTOCK || !which_armor(mon, W_ARMS))) {
            item1 = TRUE;
            continue;
        }
        if (!item2 && obj->otyp == UNICORN_HORN && !obj->cursed) {
            item2 = TRUE;
            continue;
        }
        if (!obj->owornmask && obj != wep && obj != rwep &&
            obj != proj && obj != hwep &&
            !would_prefer_hwep(mon, obj)  /* cursed item in hand?  */
            && !would_prefer_rwep(mon, obj)
            && ((rwep != &zeroobj) || (!is_ammo(obj) && !is_launcher(obj)))
            && (rwep == &zeroobj || !ammo_and_launcher(obj, rwep))
            && !could_use_item(mon, obj))
            return obj;
    }
    return NULL;
}
Esempio n. 7
0
/* Returns the bitwise OR of all MSENSE_ values that explain how "viewer" can
   see "viewee". &youmonst is accepted as either argument. If both arguments
   are the same, this tests if/how a monster/player can detect itself. */
unsigned
msensem(const struct monst *viewer, const struct monst *viewee)
{
    unsigned sensemethod = 0;

    /* sanity checks, so the caller doesn't have to */
    if (viewer != &youmonst)
        if (!onmap(viewer) || DEADMONSTER(viewer))
            return 0;
    if (viewee != &youmonst)
        if (!onmap(viewee) || DEADMONSTER(viewee))
            return 0;
    if (!level) {
        impossible("vision calculations during level creation");
        return 0;
    }

    /* TODO: once levels rewrite is done, this code can be simplified (and won't
       work in its present form). */
    d_level *sz = m_mz(viewer), *tz = m_mz(viewee);
    if (sz->dnum != tz->dnum || sz->dlevel != tz->dlevel)
        return 0;
    struct level *lev = level;
    if (viewer != &youmonst)
        lev = viewer->dlevel;

    int sx = m_mx(viewer), sy = m_my(viewer),
        tx = m_mx(viewee), ty = m_my(viewee);

    int distance = dist2(sx, sy, tx, ty);

    /* Special case: if either endpoint is an engulfing monster, then we want
       LOE to the square specifically, ignoring players on that square (because
       the edge of an engulfing monster blocks LOE to the player). */
    char **msensem_vizarray =
        (Engulfed && (viewer == u.ustuck || viewee == u.ustuck)) ?
        NULL : viz_array;

    /* Line of effect. clear_path is like couldsee(), but doesn't require the
       player to be at either endpoint. (If the player happens to be at one of
       the endpoints, it just calls couldsee() directly.) */
    boolean loe = clear_path(sx, sy, tx, ty, msensem_vizarray);

    /* A special case for many vision methods: water or the ground blocking
       vision. A hiding target is also included in these, because hiding is
       often a case of using an object, part of the floor, a cranny in the
       ceiling, etc., to block vision (and even when it isn't, it should block
       vision in the same cases). */
    boolean vertical_loe =
        !(m_mburied(viewer) || m_mburied(viewee) ||
          ((!!m_underwater(viewee)) ^ (!!m_underwater(viewer))) ||
          m_mundetected(viewee));

    boolean invisible = !!m_has_property(viewee, INVIS, ANY_PROPERTY, 0);

    /* For normal vision, one necessary condition is that the target must be
       adjacent or on a lit square (we assume there's just enough light in the
       dungeon that even in dark areas, adjacent squares are visible to normal
       vision). We test "lit" by testing that the square is either temporarily
       lit, or permanently lit. (We can't use the normal cansee() check because
       that doesn't work for squares outside the player's LOE, and it's possible
       that neither the viewer nor the viewee is the player.)

       TODO: templit off-level. That's very hard to implement because we don't
       run lighting calculations off-level. */
    boolean target_lit = distance <= 2 || (lev == level && templit(tx, ty)) ||
        lev->locations[tx][ty].lit;

    /* TODO: Maybe infravision (and perhaps even infravisibility) should be
       properties? */
    boolean infravision_ok = infravision(viewer->data) &&
        infravisible(viewee->data);

    boolean blinded = !!m_has_property(viewer, BLINDED, ANY_PROPERTY, 0);
    boolean see_invisible =
        !!m_has_property(viewer, SEE_INVIS, ANY_PROPERTY, 0);

    if (loe && vertical_loe && !blinded) {
        if (!invisible && target_lit)
            sensemethod |= MSENSE_VISION;
        if (!invisible && infravision_ok)
            sensemethod |= MSENSE_INFRAVISION;
        if (invisible && (target_lit || infravision_ok) && see_invisible)
            sensemethod |= MSENSE_SEEINVIS | MSENSEF_KNOWNINVIS;
    }

    /* Telepathy. The viewee needs a mind; the viewer needs either to be blind,
       or for the telepathy to be extrinsic and the viewer within BOLT_LIM. */
    if (!mindless(viewee->data) && !m_helpless(viewer, hm_unconscious)) {
        unsigned telepathy_reason =
            m_has_property(viewer, TELEPAT, ANY_PROPERTY, 0);
        if ((telepathy_reason && blinded) ||
            (telepathy_reason & (W_EQUIP | W_ARTIFACT) &&
             distance <= BOLT_LIM * BOLT_LIM))
            sensemethod |= MSENSE_TELEPATHY;
    }

    /* Astral vision. Like regular vision, but has a distance check rather than
       an LOE check. It's unclear whether this pierces blindness, because the
       only item that gives astral vision also gives blindness immunity; this
       code assumes not. */
    boolean xray = m_has_property(viewer, XRAY_VISION, ANY_PROPERTY, 0) &&
        (!invisible || see_invisible);
    if (vertical_loe && distance <= XRAY_RANGE * XRAY_RANGE && xray &&
        (target_lit || infravision_ok)) {
        sensemethod |= MSENSE_XRAY;
        if (invisible && see_invisible)
            sensemethod |= MSENSEF_KNOWNINVIS;
    }

    /* Ideally scent should work around corners, but not through walls. That's
       awkward to write, though, because it'd require pathfinding. */
    if (vertical_loe && loe && distance <= 5 && has_scent(viewer->data))
        sensemethod |= MSENSE_SCENT;

    /* Monster detection. All that is needed (apart from same-level, which was
       checked earlier) is the property itself. */
    if (m_has_property(viewer, DETECT_MONSTERS, ANY_PROPERTY, 0))
        sensemethod |= MSENSE_MONDETECT;

    /* Warning versus monster class. (Actually implemented as monster
       /race/.) */
    if (mworn_warntype(viewer) & viewee->data->mflags2)
        sensemethod |= MSENSE_WARNOFMON;

    /* Covetous sense. Note that the player can benefit from this too, e.g. a
       player in master lich form will be able to detect the Wizard of Yendor
       holding the Book of the Dead. */
    if (covetous_sense(viewer, viewee))
        sensemethod |= MSENSE_COVETOUS;

    /* Smell of gold, approximating 3.4.3 behaviour (which was previously in
       set_apparxy in monmove.c). Xorns can sense any monster with gold in their
       inventory. */
    if (viewer->data == &mons[PM_XORN] && money_cnt(m_minvent(viewee)))
        sensemethod |= MSENSE_GOLDSMELL;

    /* Warning. This partial-senses monsters that are hostile to the viewer, and
       have a level of 4 or greater, and a distance of 100 or less. */
    if (distance <= 100 && m_mlev(viewee) >= 4 &&
        m_has_property(viewer, WARNING, ANY_PROPERTY, 0) &&
        mm_aggression(viewee, viewer) & ALLOW_M)
        sensemethod |= MSENSE_WARNING;

    /* Deducing the existence of a long worm via seeing a segment.

       Based on the code that was formerly worm_known in worm.c, but expanded to
       handle monster viewing.

       Note: assumes that normal vision, possibly modified by astral vision and
       see invisible, is the only way to see a long worm tail. Infravision
       doesn't work (they're cold-blooded), and currently no other types of
       vision are implemented. Detection would find the head. */
    if (viewee->wormno && (!invisible || see_invisible) &&
        vertical_loe && !blinded) {
        struct wseg *curr = viewee->dlevel->wtails[viewee->wormno];

        while (curr) {
            boolean seg_dist = dist2(sx, sy, curr->wx, curr->wy);
            boolean seg_loe =
                clear_path(sx, sy, curr->wx, curr->wy, msensem_vizarray) ||
                (xray && seg_dist <= XRAY_RANGE * XRAY_RANGE);
            boolean seg_lit = seg_dist <= 2 ||
                (lev == level && templit(curr->wx, curr->wy)) ||
                lev->locations[curr->wx][curr->wy].lit;

            if (seg_loe && seg_lit)
                sensemethod |= MSENSE_WORM;

            curr = curr->nseg;
        }
    }

    /* Calculate known invisibility, because we have all the information to
       hand, and it's a complex calculation without it. We need to be able to
       see the monster's location with normal vision, but not the monster
       itself. Also don't include warning in this (because then, we can't match
       the monster to the message). */
    if (loe && vertical_loe && !blinded && sensemethod && target_lit &&
        !(sensemethod & (MSENSE_ANYVISION | MSENSE_WARNING)))
        sensemethod |= MSENSEF_KNOWNINVIS;

    /* If the target is in item form, it's not being seen properly. Any
       vision-style detection of the target is going to not see it as a
       monster. */
    if (m_helpless(viewee, 1 << hr_mimicking) &&
        (lev != level || !Protection_from_shape_changers) &&
        (sensemethod & MSENSE_ANYVISION)) {
        sensemethod &= ~MSENSE_ANYVISION;
        sensemethod |= MSENSE_ITEMMIMIC;
    }

    return sensemethod;
}