Example #1
0
static boolean artifact_hit_drainlife(struct monst *magr, struct monst *mdef,
				      struct obj *otmp, int *dmgptr)
{
    boolean youattack = (magr == &youmonst);
    boolean youdefend = (mdef == &youmonst);
    boolean vis = (!youattack && magr && cansee(magr->mx, magr->my))
	|| (!youdefend && cansee(mdef->mx, mdef->my))
	|| (youattack && u.uswallow && mdef == u.ustuck && !Blind);
	
    if (!youdefend) {
	    if (vis) {
		if (otmp->oartifact == ART_STORMBRINGER)
		    pline("The %s blade draws the life from %s!",
			    hcolor("black"),
			    mon_nam(mdef));
		else
		    pline("%s draws the life from %s!",
			    The(distant_name(otmp, xname)),
			    mon_nam(mdef));
	    }
	    if (mdef->m_lev == 0) {
		*dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
	    } else {
		int drain = rnd(8);
		*dmgptr += drain;
		mdef->mhpmax -= drain;
		mdef->m_lev--;
		drain /= 2;
		if (drain) healup(drain, 0, FALSE, FALSE);
	    }
	    return vis;
    } else { /* youdefend */
	    int oldhpmax = u.uhpmax;

	    if (Blind)
		    pline("You feel an %s drain your life!",
			otmp->oartifact == ART_STORMBRINGER ?
			"unholy blade" : "object");
	    else if (otmp->oartifact == ART_STORMBRINGER)
		    pline("The %s blade drains your life!",
			    hcolor("black"));
	    else
		    pline("%s drains your life!",
			    The(distant_name(otmp, xname)));
	    losexp("life drainage");
	    if (magr && magr->mhp < magr->mhpmax) {
		magr->mhp += (oldhpmax - u.uhpmax)/2;
		if (magr->mhp > magr->mhpmax) magr->mhp = magr->mhpmax;
	    }
	    return TRUE;
    }
    return FALSE;
}
Example #2
0
static int describe_object(int x, int y, int votyp, char *buf)
{
    int num_objs = 0;
    struct obj *otmp;
    if (votyp == -1)
	return -1;
    
    otmp = vobj_at(x,y);
    
    if (!otmp || otmp->otyp != votyp) {
	if (votyp != STRANGE_OBJECT) {
	    otmp = mksobj(level, votyp, FALSE, FALSE);
	    if (otmp->oclass == COIN_CLASS)
		otmp->quan = 1L; /* to force pluralization off */
	    else if (otmp->otyp == SLIME_MOLD)
		otmp->spe = current_fruit;	/* give the fruit a type */
	    strcpy(buf, distant_name(otmp, xname));
	    dealloc_obj(otmp);
	    otmp = vobj_at(x,y); /* make sure we don't point to the temp obj any more */
	}
    } else
	strcpy(buf, distant_name(otmp, xname));
    
    if (level->locations[x][y].typ == STONE || level->locations[x][y].typ == SCORR)
	strcat(buf, " embedded in stone");
    else if (IS_WALL(level->locations[x][y].typ) || level->locations[x][y].typ == SDOOR)
	strcat(buf, " embedded in a wall");
    else if (closed_door(level, x,y))
	strcat(buf, " embedded in a door");
    else if (is_pool(level, x,y))
	strcat(buf, " in water");
    else if (is_lava(level, x,y))
	strcat(buf, " in molten lava");	/* [can this ever happen?] */
    
    if (!cansee(x, y))
	return -1; /* don't disclose the number of objects for location out of LOS */
    
    if (!otmp)
	/* There is no object here. Since the player sees one it must be a mimic */
	return 1;
    
    if (otmp->otyp != votyp)
	/* Hero sees something other than the actual top object. Probably a mimic */
	num_objs++;
    
    for ( ; otmp; otmp = otmp->nexthere)
	num_objs++;
    
    return num_objs;
}
Example #3
0
/* drop one object taken from a (possibly dead) monster's inventory */
static void mdrop_obj(struct monst *mon, struct obj *obj, boolean verbosely)
{
    int omx = mon->mx, omy = mon->my;

    if (obj->owornmask) {
	/* perform worn item handling if the monster is still alive */
	if (mon->mhp > 0) {
	    mon->misc_worn_check &= ~obj->owornmask;
	    update_mon_intrinsics(level, mon, obj, FALSE, TRUE);
	 /* obj_no_longer_held(obj); -- done by place_object */
	    if (obj->owornmask & W_WEP) setmnotwielded(mon, obj);
	/* don't charge for an owned saddle on dead steed */
	} else if (mon->mtame && (obj->owornmask & W_SADDLE) && 
		!obj->unpaid && costly_spot(omx, omy)) {
	    obj->no_charge = 1;
	}
	obj->owornmask = 0L;
    }
    if (verbosely && cansee(omx, omy))
	pline("%s drops %s.", Monnam(mon), distant_name(obj, doname));
    if (!flooreffects(obj, omx, omy, "fall")) {
	place_object(obj, level, omx, omy);
	stackobj(obj);
    }
}
Example #4
0
File: worn.c Project: mbi/NitroHack
static void m_dowear_type(struct monst *mon, long flag, boolean creation,
			  boolean racialexception)
{
	struct obj *old, *best, *obj;
	int m_delay = 0;
	int unseen = !canseemon(mon);
	char nambuf[BUFSZ];

	if (mon->mfrozen) return; /* probably putting previous item on */

	/* Get a copy of monster's name before altering its visibility */
	strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon));

	old = which_armor(mon, flag);
	if (old && old->cursed) return;
	if (old && flag == W_AMUL) return; /* no such thing as better amulets */
	best = old;

	for (obj = mon->minvent; obj; obj = obj->nobj) {
	    switch(flag) {
		case W_AMUL:
		    if (obj->oclass != AMULET_CLASS ||
			    (obj->otyp != AMULET_OF_LIFE_SAVING &&
				obj->otyp != AMULET_OF_REFLECTION))
			continue;
		    best = obj;
		    goto outer_break; /* no such thing as better amulets */
		case W_ARMU:
		    if (!is_shirt(obj)) continue;
		    break;
		case W_ARMC:
		    if (!is_cloak(obj)) continue;
		    break;
		case W_ARMH:
		    if (!is_helmet(obj)) continue;
		    /* (flimsy exception matches polyself handling) */
		    if (has_horns(mon->data) && !is_flimsy(obj)) continue;
		    break;
		case W_ARMS:
		    if (!is_shield(obj)) continue;
		    break;
		case W_ARMG:
		    if (!is_gloves(obj)) continue;
		    break;
		case W_ARMF:
		    if (!is_boots(obj)) continue;
		    break;
		case W_ARM:
		    if (!is_suit(obj)) continue;
		    if (racialexception && (racial_exception(mon, obj) < 1)) continue;
		    break;
	    }
	    if (obj->owornmask) continue;
	    /* I'd like to define a VISIBLE_ARM_BONUS which doesn't assume the
	     * monster knows obj->spe, but if I did that, a monster would keep
	     * switching forever between two -2 caps since when it took off one
	     * it would forget spe and once again think the object is better
	     * than what it already has.
	     */
	    if (best && (ARM_BONUS(best) + extra_pref(mon,best) >= ARM_BONUS(obj) + extra_pref(mon,obj)))
		continue;
	    best = obj;
	}
outer_break:
	if (!best || best == old) return;

	/* if wearing a cloak, account for the time spent removing
	   and re-wearing it when putting on a suit or shirt */
	if ((flag == W_ARM || flag == W_ARMU) && (mon->misc_worn_check & W_ARMC))
	    m_delay += 2;
	/* when upgrading a piece of armor, account for time spent
	   taking off current one */
	if (old)
	    m_delay += objects[old->otyp].oc_delay;

	if (old) /* do this first to avoid "(being worn)" */
	    old->owornmask = 0L;
	if (!creation) {
	    if (canseemon(mon)) {
		char buf[BUFSZ];

		if (old)
		    sprintf(buf, " removes %s and", distant_name(old, doname));
		else
		    buf[0] = '\0';
		pline("%s%s puts on %s.", Monnam(mon),
		      buf, distant_name(best,doname));
	    } /* can see it */
	    m_delay += objects[best->otyp].oc_delay;
	    mon->mfrozen = m_delay;
	    if (mon->mfrozen) mon->mcanmove = 0;
	}
	if (old)
	    update_mon_intrinsics(mon, old, FALSE, creation);
	mon->misc_worn_check |= flag;
	best->owornmask |= flag;
	update_mon_intrinsics(mon, best, TRUE, creation);
	/* if couldn't see it but now can, or vice versa, */
	if (!creation && (unseen ^ !canseemon(mon))) {
		if (mon->minvis && !See_invisible) {
			pline("Suddenly you cannot see %s.", nambuf);
			makeknown(best->otyp);
		} /* else if (!mon->minvis) pline("%s suddenly appears!", Amonnam(mon)); */
	}
}
Example #5
0
static int
describe_object(int x, int y, int votyp, char *buf, int known_embed,
                boolean *feature_described)
{
    int num_objs = 0;
    struct obj *otmp;
    int typ;

    *feature_described = FALSE;

    if (votyp == -1)
        return -1;

    otmp = vobj_at(x, y);

    if (!otmp || otmp->otyp != votyp) {
        /* We have a mimic. */
        if (votyp == STRANGE_OBJECT) {
            strcpy(buf, "strange object");
        } else {
            otmp = mktemp_sobj(level, votyp);
            otmp->corpsenm = PM_TENGU;
            /* (basic object only, no random features) */
            if (otmp->oclass == COIN_CLASS)
                otmp->quan = 1L;        /* to force pluralization off */
            else if (otmp->otyp == SLIME_MOLD)
                otmp->spe = gamestate.fruits.current;/* give the fruit a type */
            strcpy(buf, distant_name(otmp, xname));
            dealloc_obj(otmp);
            otmp = vobj_at(x, y);       /* make sure we don't point to the temp 
                                           obj any more */
        }
    } else
        strcpy(buf, distant_name(otmp, xname));

    typ = level->locations[x][y].typ;
    if (known_embed && IS_TREE(typ))
        strcat(buf, " stuck");
    else if (known_embed && (IS_ROCK(typ) || closed_door(level, x, y)))
        strcat(buf, " embedded");
    else if (IS_TREE(typ)) {
        strcat(buf, " stuck in a tree");
        *feature_described = TRUE;
    } else if (typ == STONE || typ == SCORR) {
        strcat(buf, " embedded in stone");
        *feature_described = TRUE;
    } else if (IS_WALL(typ) || typ == SDOOR) {
        strcat(buf, " embedded in a wall");
        *feature_described = TRUE;
    } else if (closed_door(level, x, y)) {
        strcat(buf, " embedded in a door");
        *feature_described = TRUE;
    } else if (is_pool(level, x, y)) {
        strcat(buf, " in water");
        *feature_described = TRUE;
    } else if (is_lava(level, x, y)) {
        strcat(buf, " in molten lava"); /* [can this ever happen?] */
        *feature_described = TRUE;
    }

    if (!cansee(x, y))
        return -1;      /* don't disclose the number of objects for location
                           out of LOS */

    if (!otmp)
        /* There is no object here. Since the player sees one it must be a
           mimic */
        return 1;

    if (otmp->otyp != votyp)
        /* Hero sees something other than the actual top object. Probably a
           mimic */
        num_objs++;

    for (; otmp; otmp = otmp->nexthere)
        num_objs++;

    return num_objs;
}
Example #6
0
/*
 * Move for priests and shopkeepers.  Called from shk_move() and pri_move().
 * Valid returns are  1: moved  0: didn't  -1: let m_move do it  -2: died.
 */
int
move_special(struct monst *mtmp, boolean in_his_shop, schar appr,
             boolean uondoor, boolean avoid, xchar omx, xchar omy, xchar gx,
             xchar gy)
{
    xchar nx, ny, nix, niy;
    schar i;
    schar chcnt, cnt;
    coord poss[9];
    long info[9];
    long allowflags;
    struct obj *ib = NULL;

    if (omx == gx && omy == gy)
        return 0;
    if (mtmp->mconf) {
        avoid = FALSE;
        appr = 0;
    }

    nix = omx;
    niy = omy;
    if (mtmp->isshk)
        allowflags = ALLOW_SSM;
    else
        allowflags = ALLOW_SSM | ALLOW_SANCT;
    if (passes_walls(mtmp->data))
        allowflags |= (ALLOW_ROCK | ALLOW_WALL);
    if (throws_rocks(mtmp->data))
        allowflags |= ALLOW_ROCK;
    if (tunnels(mtmp->data))
        allowflags |= ALLOW_DIG;
    if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
        allowflags |= OPENDOOR;
        if (m_carrying(mtmp, SKELETON_KEY))
            allowflags |= BUSTDOOR;
    }
    if (is_giant(mtmp->data))
        allowflags |= BUSTDOOR;
    cnt = mfndpos(mtmp, poss, info, allowflags);

    if (mtmp->isshk && avoid && uondoor) {    /* perhaps we cannot avoid him */
        for (i = 0; i < cnt; i++)
            if (!(info[i] & NOTONL))
                goto pick_move;
        avoid = FALSE;
    }
#define GDIST(x,y)      (dist2(x,y,gx,gy))
pick_move:
    chcnt = 0;
    for (i = 0; i < cnt; i++) {
        nx = poss[i].x;
        ny = poss[i].y;
        if (IS_ROOM(level->locations[nx][ny].typ) ||
            (mtmp->isshk && (!in_his_shop || ESHK(mtmp)->following))) {
            if (avoid && (info[i] & NOTONL))
                continue;
            if ((!appr && !rn2(++chcnt)) ||
                (appr && GDIST(nx, ny) < GDIST(nix, niy))) {
                nix = nx;
                niy = ny;
            }
        }
    }
    if (mtmp->ispriest && avoid && nix == omx && niy == omy &&
        onlineu(omx, omy)) {
        /* might as well move closer as long it's going to stay lined up */
        avoid = FALSE;
        goto pick_move;
    }

    if (nix != omx || niy != omy) {
        remove_monster(level, omx, omy);
        place_monster(mtmp, nix, niy);
        newsym(nix, niy);
        if (mtmp->isshk && !in_his_shop && inhishop(mtmp))
            check_special_room(FALSE);
        if (ib) {
            if (cansee(mtmp->mx, mtmp->my))
                pline("%s picks up %s.", Monnam(mtmp),
                      distant_name(ib, doname));
            obj_extract_self(ib);
            mpickobj(mtmp, ib);
        }
        return 1;
    }
    return 0;
}
Example #7
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;
}