Example #1
0
/* Can we ride this monster?  Caller should also check can_saddle() */
boolean
can_ride(struct monst * mtmp)
{
    return (mtmp->mtame && humanoid(youmonst.data) && !verysmall(youmonst.data)
            && !bigmonst(youmonst.data) && (!Underwater ||
                                            is_swimmer(mtmp->data)));
}
Example #2
0
File: worn.c Project: 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);
}
/* true iff the type of monster pass through iron bars */
boolean
passes_bars(const struct permonst * mptr)
{
    return (boolean) (passes_walls(mptr) || amorphous(mptr) || is_whirly(mptr)
                      || verysmall(mptr) || (slithy(mptr) && !bigmonst(mptr)));
}
Example #4
0
File: worn.c Project: mbi/NitroHack
void mon_break_armor(struct monst *mon, boolean polyspot)
{
	struct obj *otmp;
	const struct permonst *mdat = mon->data;
	boolean vis = cansee(mon->mx, mon->my);
	boolean handless_or_tiny = (nohands(mdat) || verysmall(mdat));
	const char *pronoun = mhim(mon),
			*ppronoun = mhis(mon);

	if (breakarm(mdat)) {
	    if ((otmp = which_armor(mon, W_ARM)) != 0) {
		if ((Is_dragon_scales(otmp) &&
			mdat == Dragon_scales_to_pm(otmp)) ||
		    (Is_dragon_mail(otmp) && mdat == Dragon_mail_to_pm(otmp)))
		    ;	/* no message here;
			   "the dragon merges with his scaly armor" is odd
			   and the monster's previous form is already gone */
		else if (vis)
		    pline("%s breaks out of %s armor!", Monnam(mon), ppronoun);
		else
		    You_hear("a cracking sound.");
		m_useup(mon, otmp);
	    }
	    if ((otmp = which_armor(mon, W_ARMC)) != 0) {
		if (otmp->oartifact) {
		    if (vis)
			pline("%s %s falls off!", s_suffix(Monnam(mon)),
				cloak_simple_name(otmp));
		    if (polyspot) bypass_obj(otmp);
		    m_lose_armor(mon, otmp);
		} else {
		    if (vis)
			pline("%s %s tears apart!", s_suffix(Monnam(mon)),
				cloak_simple_name(otmp));
		    else
			You_hear("a ripping sound.");
		    m_useup(mon, otmp);
		}
	    }
	    if ((otmp = which_armor(mon, W_ARMU)) != 0) {
		if (vis)
		    pline("%s shirt rips to shreds!", s_suffix(Monnam(mon)));
		else
		    You_hear("a ripping sound.");
		m_useup(mon, otmp);
	    }
	} else if (sliparm(mdat)) {
	    if ((otmp = which_armor(mon, W_ARM)) != 0) {
		if (vis)
		    pline("%s armor falls around %s!",
				 s_suffix(Monnam(mon)), pronoun);
		else
		    You_hear("a thud.");
		if (polyspot) bypass_obj(otmp);
		m_lose_armor(mon, otmp);
	    }
	    if ((otmp = which_armor(mon, W_ARMC)) != 0) {
		if (vis) {
		    if (is_whirly(mon->data))
			pline("%s %s falls, unsupported!",
				     s_suffix(Monnam(mon)), cloak_simple_name(otmp));
		    else
			pline("%s shrinks out of %s %s!", Monnam(mon),
						ppronoun, cloak_simple_name(otmp));
		}
		if (polyspot) bypass_obj(otmp);
		m_lose_armor(mon, otmp);
	    }
	    if ((otmp = which_armor(mon, W_ARMU)) != 0) {
		if (vis) {
		    if (sliparm(mon->data))
			pline("%s seeps right through %s shirt!",
					Monnam(mon), ppronoun);
		    else
			pline("%s becomes much too small for %s shirt!",
					Monnam(mon), ppronoun);
		}
		if (polyspot) bypass_obj(otmp);
		m_lose_armor(mon, otmp);
	    }
	}
	if (handless_or_tiny) {
	    /* [caller needs to handle weapon checks] */
	    if ((otmp = which_armor(mon, W_ARMG)) != 0) {
		if (vis)
		    pline("%s drops %s gloves%s!", Monnam(mon), ppronoun,
					MON_WEP(mon) ? " and weapon" : "");
		if (polyspot) bypass_obj(otmp);
		m_lose_armor(mon, otmp);
	    }
	    if ((otmp = which_armor(mon, W_ARMS)) != 0) {
		if (vis)
		    pline("%s can no longer hold %s shield!", Monnam(mon),
								ppronoun);
		else
		    You_hear("a clank.");
		if (polyspot) bypass_obj(otmp);
		m_lose_armor(mon, otmp);
	    }
	}
	if (handless_or_tiny || has_horns(mdat)) {
	    if ((otmp = which_armor(mon, W_ARMH)) != 0 &&
		    /* flimsy test for horns matches polyself handling */
		    (handless_or_tiny || !is_flimsy(otmp))) {
		if (vis)
		    pline("%s helmet falls to the %s!",
			  s_suffix(Monnam(mon)), surface(mon->mx, mon->my));
		else
		    You_hear("a clank.");
		if (polyspot) bypass_obj(otmp);
		m_lose_armor(mon, otmp);
	    }
	}
	if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) {
	    if ((otmp = which_armor(mon, W_ARMF)) != 0) {
		if (vis) {
		    if (is_whirly(mon->data))
			pline("%s boots fall away!",
				       s_suffix(Monnam(mon)));
		    else pline("%s boots %s off %s feet!",
			s_suffix(Monnam(mon)),
			verysmall(mdat) ? "slide" : "are pushed", ppronoun);
		}
		if (polyspot) bypass_obj(otmp);
		m_lose_armor(mon, otmp);
	    }
	}
	if (!can_saddle(mon)) {
	    if ((otmp = which_armor(mon, W_SADDLE)) != 0) {
		if (polyspot) bypass_obj(otmp);
		m_lose_armor(mon, otmp);
		if (vis)
		    pline("%s saddle falls off.", s_suffix(Monnam(mon)));
	    }
	    if (mon == u.usteed)
		goto noride;
	} else if (mon == u.usteed && !can_ride(mon)) {
	noride:
	    pline("You can no longer ride %s.", mon_nam(mon));
	    if (touch_petrifies(u.usteed->data) &&
			!Stone_resistance && rnl(3)) {
		char buf[BUFSZ];

		pline("You touch %s.", mon_nam(u.usteed));
		sprintf(buf, "falling off %s",
				an(u.usteed->data->mname));
		instapetrify(buf);
	    }
	    dismount_steed(DISMOUNT_FELL);
	}
	return;
}
Example #5
0
struct obj *
mksobj(int otyp, boolean init, boolean artif)
{
    int mndx, tryct;
    struct obj *otmp;
    char let = objects[otyp].oc_class;

    otmp = newobj(0);
    *otmp = zeroobj;
    otmp->age = monstermoves;
    otmp->o_id = flags.ident++;
    if (!otmp->o_id) otmp->o_id = flags.ident++;	/* ident overflowed */
    otmp->quan = 1L;
    otmp->oclass = let;
    otmp->otyp = otyp;
    otmp->where = OBJ_FREE;
    otmp->dknown = index(dknowns, let) ? 0 : 1;
    if (otmp->otyp == AMULET_OF_YENDOR)
        otmp->orecursive = FALSE;
    if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD) ||
            otmp->otyp == SHIELD_OF_REFLECTION)
        otmp->dknown = 0;
    if (!objects[otmp->otyp].oc_uses_known)
        otmp->known = 1;
    if (is_rustprone(otmp) || is_corrodeable(otmp) || is_flammable(otmp))
        otmp->rknown = 1;
#ifdef INVISIBLE_OBJECTS
    otmp->oinvis = !rn2(1250);
#endif
    if (init) switch (let) {
        case WEAPON_CLASS:
            otmp->quan = is_multigen(otmp) ? (long) rn1(6,6) : 1L;
            if(!rn2(11)) {
                otmp->spe = rne(3);
                otmp->blessed = rn2(2);
            } else if(!rn2(10)) {
                curse(otmp);
                otmp->spe = -rne(3);
            } else	blessorcurse(otmp, 10);
            if (is_poisonable(otmp) && !rn2(100))
                otmp->opoisoned = 1;

            if (artif && !rn2(20))
                otmp = mk_artifact(otmp, (aligntyp)A_NONE);
            break;
        case FOOD_CLASS:
            otmp->odrained = 0;
            otmp->oeaten = 0;
            switch(otmp->otyp) {
            case CORPSE:
                /* possibly overridden by mkcorpstat() */
                tryct = 50;
                do otmp->corpsenm = undead_to_corpse(rndmonnum());
                while ((mvitals[otmp->corpsenm].mvflags & G_NOCORPSE) && (--tryct > 0));
                if (tryct == 0) {
                    /* perhaps rndmonnum() only wants to make G_NOCORPSE monsters on
                       this level; let's create an adventurer's corpse instead, then */
                    otmp->corpsenm = PM_HUMAN;
                }
                /* timer set below */
                break;
            case EGG:
                otmp->corpsenm = NON_PM;	/* generic egg */
                if (!rn2(3)) for (tryct = 200; tryct > 0; --tryct) {
                        mndx = can_be_hatched(rndmonnum());
                        if (mndx != NON_PM && !dead_species(mndx, TRUE)) {
                            otmp->corpsenm = mndx;		/* typed egg */
                            attach_egg_hatch_timeout(otmp);
                            break;
                        }
                    }
                break;
            case TIN:
                otmp->corpsenm = NON_PM;	/* empty (so far) */
                if (!rn2(6))
                    otmp->spe = 1;		/* spinach */
                else for (tryct = 200; tryct > 0; --tryct) {
                        mndx = undead_to_corpse(rndmonnum());
                        if (mons[mndx].cnutrit &&
                                !(mvitals[mndx].mvflags & G_NOCORPSE)) {
                            otmp->corpsenm = mndx;
                            break;
                        }
                    }
                blessorcurse(otmp, 10);
                break;
            case SLIME_MOLD:
                otmp->spe = current_fruit;
                break;
            case KELP_FROND:
                otmp->quan = (long) rnd(2);
                break;
            }
            if (otmp->otyp == CORPSE || otmp->otyp == MEAT_RING ||
                    otmp->otyp == KELP_FROND) break;
            /* fall into next case */

        case GEM_CLASS:
            if (otmp->otyp == LOADSTONE) curse(otmp);
            else if (otmp->otyp == ROCK) otmp->quan = (long) rn1(6,6);
            else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2L;
            else otmp->quan = 1L;
            break;
        case TOOL_CLASS:
            switch(otmp->otyp) {
            case TALLOW_CANDLE:
            case WAX_CANDLE:
                otmp->spe = 1;
                otmp->age = 20L * /* 400 or 200 */
                            (long)objects[otmp->otyp].oc_cost;
                otmp->lamplit = 0;
                otmp->quan = 1L +
                             (long)(rn2(2) ? rn2(7) : 0);
                blessorcurse(otmp, 5);
                break;
            case BRASS_LANTERN:
            case OIL_LAMP:
                otmp->spe = 1;
                otmp->age = (long) rn1(500,1000);
                otmp->lamplit = 0;
                blessorcurse(otmp, 5);
                break;
            case MAGIC_LAMP:
                otmp->spe = 1;
                otmp->lamplit = 0;
                blessorcurse(otmp, 2);
                break;
            case IRON_SAFE:
                otmp->olocked = 1;
            case CHEST:
            case LARGE_BOX:
                if (otmp->otyp != IRON_SAFE) {
                    otmp->olocked = !!(rn2(5));  /* clumsy tweak */
                }
                otmp->otrapped = !(rn2(10));
            case ICE_BOX:
            case SACK:
            case OILSKIN_SACK:
            case BAG_OF_HOLDING:
                mkbox_cnts(otmp);
                break;
#ifdef TOURIST
            case EXPENSIVE_CAMERA:
#endif
            case TINNING_KIT:
            case MAGIC_MARKER:
                otmp->spe = rn1(60,20);
                break;
            case CAN_OF_GREASE:
                otmp->spe = rnd(25);
                blessorcurse(otmp, 10);
                break;
            case CRYSTAL_BALL:
                otmp->spe = rnd(5);
                blessorcurse(otmp, 2);
                break;
            case HORN_OF_PLENTY:
            case BAG_OF_TRICKS:
                otmp->spe = rnd(20);
                break;
            case FIGURINE:	{
                int tryct2 = 0;
                do
                    otmp->corpsenm = rndmonnum();
                while(is_human(&mons[otmp->corpsenm])
                        && tryct2++ < 30);
                blessorcurse(otmp, 4);
                break;
            }
            case BELL_OF_OPENING:
                otmp->spe = 3;
                break;
            case MAGIC_FLUTE:
            case MAGIC_HARP:
            case FROST_HORN:
            case FIRE_HORN:
            case DRUM_OF_EARTHQUAKE:
                otmp->spe = rn1(5,4);
                break;
            }
            break;
        case AMULET_CLASS:
            if (otmp->otyp == AMULET_OF_YENDOR) flags.made_amulet = TRUE;
            if(rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION ||
                           otmp->otyp == AMULET_OF_CHANGE ||
                           otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) {
                curse(otmp);
            } else	blessorcurse(otmp, 10);
        case VENOM_CLASS:
        case CHAIN_CLASS:
        case BALL_CLASS:
            break;
        case POTION_CLASS:
            if (otmp->otyp == POT_OIL)
                otmp->age = MAX_OIL_IN_FLASK;	/* amount of oil */
            /* fall through */
        case SCROLL_CLASS:
#ifdef MAIL
            if (otmp->otyp != SCR_MAIL)
#endif
                blessorcurse(otmp, 4);
            break;
        case SPBOOK_CLASS:
            blessorcurse(otmp, 17);
            break;
        case ARMOR_CLASS:
            if(rn2(10) && (otmp->otyp == FUMBLE_BOOTS ||
                           otmp->otyp == LEVITATION_BOOTS ||
                           otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT ||
                           otmp->otyp == GAUNTLETS_OF_FUMBLING ||
                           otmp->otyp == TINFOIL_HAT ||
                           !rn2(11))) {
                curse(otmp);
                otmp->spe = -rne(3);
            } else if(!rn2(10)) {
                otmp->blessed = rn2(2);
                otmp->spe = rne(3);
            } else	blessorcurse(otmp, 10);
            if (artif && !rn2(40))
                otmp = mk_artifact(otmp, (aligntyp)A_NONE);
            /* simulate lacquered armor for samurai */
            if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL &&
                    (moves <= 1 || In_quest(&u.uz))) {
#ifdef UNIXPC
                /* optimizer bitfield bug */
                otmp->oerodeproof = 1;
                otmp->rknown = 1;
#else
                otmp->oerodeproof = otmp->rknown = 1;
#endif
            }
            break;
        case WAND_CLASS:
            if (otmp->otyp == WAN_WISHING) {
                otmp->spe = (rnf(2,3) ? 1 : rnf(1,2) ? 0 : 2);
                otmp->recharged = 1;
            } else {
                otmp->spe = rn1(5,
                                (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4);
                otmp->recharged = 0; /* used to control recharging */
            }
            blessorcurse(otmp, 17);
            break;
        case RING_CLASS:
            if(objects[otmp->otyp].oc_charged) {
                blessorcurse(otmp, 3);
                if(rn2(10)) {
                    if(rn2(10) && bcsign(otmp))
                        otmp->spe = bcsign(otmp) * rne(3);
                    else otmp->spe = rn2(2) ? rne(3) : -rne(3);
                }
                /* make useless +0 rings much less common */
                if (otmp->spe == 0) otmp->spe = rn2(4) - rn2(3);
                /* negative rings are usually cursed */
                if (otmp->spe < 0 && rn2(5)) curse(otmp);
            } else if(rn2(10) && (otmp->otyp == RIN_TELEPORTATION ||
                                  otmp->otyp == RIN_POLYMORPH ||
                                  otmp->otyp == RIN_AGGRAVATE_MONSTER ||
                                  otmp->otyp == RIN_HUNGER || !rn2(9))) {
                curse(otmp);
            }
            break;
        case ROCK_CLASS:
            switch (otmp->otyp) {
            case STATUE:
                /* possibly overridden by mkcorpstat() */
                otmp->corpsenm = rndmonnum();
                if (!verysmall(&mons[otmp->corpsenm]) &&
                        rn2(level_difficulty()/2 + 10) > 10)
                    (void) add_to_container(otmp,
                                            mkobj(SPBOOK_CLASS,FALSE));
            }
            break;
        case COIN_CLASS:
            break;	/* do nothing */
        default:
            warning("impossible mkobj %d, sym '%c'.", otmp->otyp,
                    objects[otmp->otyp].oc_class);
            return (struct obj *)0;
        }

    /* Some things must get done (timers) even if init = 0 */
    switch (otmp->otyp) {
    case CORPSE:
        start_corpse_timeout(otmp);
        break;
    }

    /* unique objects may have an associated artifact entry */
    if (objects[otyp].oc_unique && !otmp->oartifact)
        otmp = mk_artifact(otmp, (aligntyp)A_NONE);
    otmp->owt = weight(otmp);
    return(otmp);
}
Example #6
0
static void break_armor(void)
{
    struct obj *otmp;

    if (breakarm(youmonst.data)) {
	if ((otmp = uarm) != 0) {
		if (donning(otmp)) cancel_don();
		pline("You break out of your armor!");
		exercise(A_STR, FALSE);
		Armor_gone();
		useup(otmp);
	}
	if ((otmp = uarmc) != 0) {
	    if (otmp->oartifact) {
		pline("Your %s falls off!", cloak_simple_name(otmp));
		Cloak_off();
		dropx(otmp);
	    } else {
		pline("Your %s tears apart!", cloak_simple_name(otmp));
		Cloak_off();
		useup(otmp);
	    }
	}
	if (uarmu) {
		pline("Your shirt rips to shreds!");
		useup(uarmu);
	}
    } else if (sliparm(youmonst.data)) {
	if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) {
		if (donning(otmp)) cancel_don();
		pline("Your armor falls around you!");
		Armor_gone();
		dropx(otmp);
	}
	if ((otmp = uarmc) != 0) {
		if (is_whirly(youmonst.data))
			pline("Your %s falls, unsupported!", cloak_simple_name(otmp));
		else pline("You shrink out of your %s!", cloak_simple_name(otmp));
		Cloak_off();
		dropx(otmp);
	}
	if ((otmp = uarmu) != 0) {
		if (is_whirly(youmonst.data))
			pline("You seep right through your shirt!");
		else pline("You become much too small for your shirt!");
		setworn(NULL, otmp->owornmask & W_ARMU);
		dropx(otmp);
	}
    }
    if (has_horns(youmonst.data)) {
	if ((otmp = uarmh) != 0) {
	    if (is_flimsy(otmp) && !donning(otmp)) {
		char hornbuf[BUFSZ], yourbuf[BUFSZ];

		/* Future possiblities: This could damage/destroy helmet */
		sprintf(hornbuf, "horn%s", plur(num_horns(youmonst.data)));
		pline("Your %s %s through %s %s.", hornbuf, vtense(hornbuf, "pierce"),
		     shk_your(yourbuf, otmp), xname(otmp));
	    } else {
		if (donning(otmp)) cancel_don();
		pline("Your helmet falls to the %s!", surface(u.ux, u.uy));
		Helmet_off();
		dropx(otmp);
	    }
	}
    }
    if (nohands(youmonst.data) || verysmall(youmonst.data)) {
	if ((otmp = uarmg) != 0) {
	    if (donning(otmp)) cancel_don();
	    /* Drop weapon along with gloves */
	    pline("You drop your gloves%s!", uwep ? " and weapon" : "");
	    drop_weapon(0);
	    Gloves_off();
	    dropx(otmp);
	}
	if ((otmp = uarms) != 0) {
	    pline("You can no longer hold your shield!");
	    Shield_off();
	    dropx(otmp);
	}
	if ((otmp = uarmh) != 0) {
	    if (donning(otmp)) cancel_don();
	    pline("Your helmet falls to the %s!", surface(u.ux, u.uy));
	    Helmet_off();
	    dropx(otmp);
	}
    }
    if (nohands(youmonst.data) || verysmall(youmonst.data) ||
		slithy(youmonst.data) || youmonst.data->mlet == S_CENTAUR) {
	if ((otmp = uarmf) != 0) {
	    if (donning(otmp)) cancel_don();
	    if (is_whirly(youmonst.data))
		pline("Your boots fall away!");
	    else pline("Your boots %s off your feet!",
			verysmall(youmonst.data) ? "slide" : "are pushed");
	    Boots_off();
	    dropx(otmp);
	}
    }
}
Example #7
0
/* try to close a door */
int
doclose(const struct nh_cmd_arg *arg)
{
    struct rm *door;
    struct monst *mtmp;
    coord cc;
    schar dx, dy, dz;

    if (nohands(youmonst.data)) {
        pline(msgc_cancelled, "You can't close anything -- you have no hands!");
        return 0;
    }

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

    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;

    if ((cc.x == youmonst.mx) && (cc.y == youmonst.my)) {
        pline(msgc_cancelled1, "You are in the way!");
        return 1;
    }

    if ((mtmp = m_at(level, cc.x, cc.y)) && 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;
    }

    door = &level->locations[cc.x][cc.y];

    if (!IS_DOOR(door->typ)) {
        if (door->typ == DRAWBRIDGE_DOWN)
            pline(msgc_cancelled,
                  "There is no obvious way to close the drawbridge.");
        else
            pline(msgc_mispaste, "You %s no door there.",
                  Blind ? "feel" : "see");
        return 0;
    }

    if (door->doormask == D_NODOOR) {
        pline(msgc_cancelled, "This doorway has no door.");
        return 0;
    }

    if (obstructed(cc.x, cc.y, msgc_cancelled))
        return 0;

    if (door->doormask == D_BROKEN) {
        pline(msgc_cancelled, "This door is broken.");
        return 0;
    }

    if (door->doormask & (D_CLOSED | D_LOCKED)) {
        pline(msgc_cancelled, "This door is already closed.");
        return 0;
    }

    if (door->doormask == D_ISOPEN) {
        if (verysmall(youmonst.data) && !u.usteed) {
            pline(msgc_cancelled, "You're too small to push the door closed.");
            return 0;
        }
        if (u.usteed ||
            rn2(25) < (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3) {
            pline(msgc_actionok, "The door closes.");
            door->doormask = D_CLOSED;
            door->mem_door_l = 1;
            /* map_background here sets the mem_door flags correctly; and it's
               redundant to both feel_location and newsym with a door.
               Exception: if we remember an invisible monster on the door
               square, but in this case, we want to set the memory of a door
               there anyway because we know there's a door there because we
               just closed it, and in Nitro this doesn't clash with keeping the 
               I there. */
            map_background(cc.x, cc.y, TRUE);
            if (Blind)
                feel_location(cc.x, cc.y);   /* the hero knows she closed it */
            else
                newsym(cc.x, cc.y);
            block_point(cc.x, cc.y);    /* vision: no longer see there */
        } else {
            exercise(A_STR, TRUE);
            pline(msgc_failrandom, "The door resists!");
        }
    }

    return 1;
}
Example #8
0
/* try to open a door */
int
doopen(const struct nh_cmd_arg *arg)
{
    coord cc;
    struct rm *door;
    struct monst *mtmp;
    schar dx, dy, dz;

    if (nohands(youmonst.data)) {
        pline(msgc_cancelled, "You can't open, close, or unlock anything "
              "-- you have no hands!");
        return 0;
    }

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

    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;

    if ((cc.x == youmonst.mx) && (cc.y == youmonst.my))
        return 0;

    if ((mtmp = m_at(level, cc.x, cc.y)) && mtmp->m_ap_type == M_AP_FURNITURE &&
        (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) &&
        !Protection_from_shape_changers) {

        stumble_onto_mimic(mtmp, cc.x - youmonst.mx, cc.y - youmonst.my);
        return 1;
    }

    door = &level->locations[cc.x][cc.y];

    if (!IS_DOOR(door->typ)) {
        if (is_db_wall(cc.x, cc.y)) {
            pline(msgc_cancelled,
                  "There is no obvious way to open the drawbridge.");
            return 0;
        }
        pline(msgc_mispaste, "You %s no door there.", Blind ? "feel" : "see");
        return 0;
    }

    if (door->doormask == D_ISOPEN) {
        struct nh_cmd_arg newarg;
        arg_from_delta(dx, dy, dz, &newarg);
        return doclose(&newarg);
    }

    if (!(door->doormask & D_CLOSED)) {
        const char *mesg;

        switch (door->doormask) {
        case D_BROKEN:
            mesg = " is broken";
            break;
        case D_NODOOR:
            mesg = "way has no door";
            break;
        case D_ISOPEN:
            mesg = " is already open";
            break;
        default:
            if (last_command_was("open") && door->mem_door_l) {

                /* With the "open" command given explicitly (rather than
                   implicitly via doorbumping), unlock the door. */
                struct obj *bestpick = get_current_unlock_tool();
                struct nh_cmd_arg newarg;

                arg_from_delta(dx, dy, dz, &newarg);
                if (!bestpick)
                    pline(msgc_cancelled,
                          "You have nothing to unlock that with.");
                else if (!bestpick->lastused)
                    /* not msgc_controlhelp, or many players would get
                       no message */
                    pline(msgc_hint,
                          "Use an unlocking tool manually so I know "
                          "which one you want to use.");
                else
                    return pick_lock(bestpick, &newarg);
            }
            door->mem_door_l = 1;
            map_background(cc.x, cc.y, TRUE);
            mesg = " is locked";
            break;
        }
        pline(msgc_cancelled, "This door%s.", mesg);
        if (Blind)
            feel_location(cc.x, cc.y);
        return 0;
    }

    if (verysmall(youmonst.data)) {
        pline(msgc_cancelled, "You're too small to pull the door open.");
        return 0;
    }

    /* door is known to be CLOSED */
    if (rnl(20) < (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3) {
        pline(msgc_actionok, "The door opens.");
        if (door->doormask & D_TRAPPED) {
            b_trapped("door", FINGER);
            door->doormask = D_NODOOR;
            if (*in_rooms(level, cc.x, cc.y, SHOPBASE))
                add_damage(cc.x, cc.y, 0L);
        } else
            door->doormask = D_ISOPEN;
        if (Blind)
            feel_location(cc.x, cc.y);  /* the hero knows she opened it */
        else
            newsym(cc.x, cc.y);
        unblock_point(cc.x, cc.y);      /* vision: new see through there */
    } else {
        exercise(A_STR, TRUE);
        door->mem_door_l = 1;
        map_background(cc.x, cc.y, TRUE);
        pline(msgc_failrandom, "The door resists!");
    }

    return 1;
}
Example #9
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 #10
0
/* Start riding, with the given monster */
boolean
mount_steed(struct monst * mtmp,        /* The animal */
            boolean force)
{   /* Quietly force this animal */
    struct obj *otmp;
    const struct permonst *ptr;

    /* Sanity checks */
    if (u.usteed) {
        pline("You are already riding %s.", mon_nam(u.usteed));
        return FALSE;
    }

    /* Is the player in the right form? */
    if (Hallucination && !force) {
        pline("Maybe you should find a designated driver.");
        return FALSE;
    }
    /* While riding Wounded_legs refers to the steed's, not the hero's legs.
       That opens up a potential abuse where the player can mount a steed, then
       dismount immediately to heal leg damage, because leg damage is always
       healed upon dismount (Wounded_legs context switch). By preventing a hero
       with Wounded_legs from mounting a steed, the potential for abuse is
       minimized, if not eliminated altogether. */
    if (Wounded_legs) {
        pline("Your %s are in no shape for riding.",
              makeplural(body_part(LEG)));
        if (force && wizard && yn("Heal your legs?") == 'y')
            LWounded_legs = RWounded_legs = 0;
        else
            return FALSE;
    }

    if (Upolyd &&
            (!humanoid(youmonst.data) || verysmall(youmonst.data) ||
             bigmonst(youmonst.data) || slithy(youmonst.data))) {
        pline("You won't fit on a saddle.");
        return FALSE;
    }
    if (!force && (near_capacity() > SLT_ENCUMBER)) {
        pline("You can't do that while carrying so much stuff.");
        return FALSE;
    }

    /* Can the player reach and see the monster? */
    if (!mtmp ||
            (!force &&
             ((Blind && !Blind_telepat) || mtmp->mundetected ||
              mtmp->m_ap_type == M_AP_FURNITURE ||
              mtmp->m_ap_type == M_AP_OBJECT))) {
        pline("I see nobody there.");
        return FALSE;
    }

    struct test_move_cache cache;
    init_test_move_cache(&cache);

    if (Engulfed || u.ustuck || u.utrap || Punished ||
            !test_move(u.ux, u.uy, mtmp->mx - u.ux, mtmp->my - u.uy, 0,
                       TEST_MOVE, &cache)) {
        if (Punished || !(Engulfed || u.ustuck || u.utrap))
            pline("You are unable to swing your %s over.", body_part(LEG));
        else
            pline("You are stuck here for now.");
        return FALSE;
    }

    /* Is this a valid monster? */
    otmp = which_armor(mtmp, os_saddle);
    if (!otmp) {
        pline("%s is not saddled.", Monnam(mtmp));
        return FALSE;
    }
    ptr = mtmp->data;
    if (touch_petrifies(ptr) && !Stone_resistance) {
        pline("You touch %s.", mon_nam(mtmp));
        instapetrify(killer_msg(STONING,
                                msgcat("attempting to ride ", an(mtmp->data->mname))));
    }
    if (!mtmp->mtame || mtmp->isminion) {
        pline("I think %s would mind.", mon_nam(mtmp));
        return FALSE;
    }
    if (mtmp->mtrapped) {
        struct trap *t = t_at(level, mtmp->mx, mtmp->my);

        pline("You can't mount %s while %s's trapped in %s.", mon_nam(mtmp),
              mhe(mtmp), t ? an(trapexplain[t->ttyp - 1]) : "ice");
        return FALSE;
    }

    if (!force && !Role_if(PM_KNIGHT) && !(--mtmp->mtame)) {
        /* no longer tame */
        newsym(mtmp->mx, mtmp->my);
        pline("%s resists%s!", Monnam(mtmp),
              mtmp->mleashed ? " and its leash comes off" : "");
        if (mtmp->mleashed)
            m_unleash(mtmp, FALSE);
        return FALSE;
    }
    if (!force && Underwater && !is_swimmer(ptr)) {
        pline("You can't ride that creature while under water.");
        return FALSE;
    }
    if (!can_saddle(mtmp) || !can_ride(mtmp)) {
        pline("You can't ride such a creature.");
        return 0;
    }

    /* Is the player impaired? */
    if (!force && !is_floater(ptr) && !is_flyer(ptr) && Levitation &&
            !Lev_at_will) {
        pline("You cannot reach %s.", mon_nam(mtmp));
        return FALSE;
    }
    if (!force && uarm && is_metallic(uarm) && greatest_erosion(uarm)) {
        pline("Your %s armor is too stiff to be able to mount %s.",
              uarm->oeroded ? "rusty" : "corroded", mon_nam(mtmp));
        return FALSE;
    }
    if (!force &&
            (Confusion || Fumbling || Glib || Wounded_legs || otmp->cursed ||
             ((u.ulevel + mtmp->mtame < rnd(MAXULEV / 2 + 5)) &&
              (!Role_if(PM_KNIGHT))))) {
        if (Levitation) {
            pline("%s slips away from you.", Monnam(mtmp));
            return FALSE;
        }
        pline("You slip while trying to get on %s.", mon_nam(mtmp));

        const char *buf = msgcat(
                              "slipped while mounting ",
                              /* "a saddled mumak" or "a saddled pony called Dobbin" */
                              x_monnam(mtmp, ARTICLE_A, NULL,
                                       SUPPRESS_IT | SUPPRESS_INVISIBLE |
                                       SUPPRESS_HALLUCINATION, TRUE));
        losehp(rn1(5, 10), buf);
        return FALSE;
    }

    /* Success */
    maybewakesteed(mtmp);
    if (!force) {
        if (Levitation && !is_floater(ptr) && !is_flyer(ptr))
            /* Must have Lev_at_will at this point */
            pline("%s magically floats up!", Monnam(mtmp));
        pline("You mount %s.", mon_nam(mtmp));
    }
    /* setuwep handles polearms differently when you're mounted */
    if (uwep && is_pole(uwep))
        u.bashmsg = TRUE;
    u.usteed = mtmp;
    remove_monster(level, mtmp->mx, mtmp->my);
    teleds(mtmp->mx, mtmp->my, TRUE);
    return TRUE;
}
Example #11
0
static void
break_armor (void)
{
    struct obj *otmp;

    if (breakarm(youmonst.data)) {
        if ((otmp = uarm) != 0) {
                if (donning(otmp)) cancel_don();
                You("break out of your armor!");
                exercise(A_STR, false);
                (void) Armor_gone();
                useup(otmp);
        }
        if ((otmp = uarmc) != 0) {
            if(otmp->oartifact) {
                Your("%s falls off!", cloak_simple_name(otmp));
                (void) Cloak_off();
                dropx(otmp);
            } else {
                Your("%s tears apart!", cloak_simple_name(otmp));
                (void) Cloak_off();
                useup(otmp);
            }
        }
        if (uarmu) {
                Your("shirt rips to shreds!");
                useup(uarmu);
        }
    } else if (sliparm(youmonst.data)) {
        if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) {
                if (donning(otmp)) cancel_don();
                Your("armor falls around you!");
                (void) Armor_gone();
                dropx(otmp);
        }
        if ((otmp = uarmc) != 0) {
                if (is_whirly(youmonst.data))
                        Your("%s falls, unsupported!", cloak_simple_name(otmp));
                else You("shrink out of your %s!", cloak_simple_name(otmp));
                (void) Cloak_off();
                dropx(otmp);
        }
        if ((otmp = uarmu) != 0) {
                if (is_whirly(youmonst.data))
                        You("seep right through your shirt!");
                else You("become much too small for your shirt!");
                setworn((struct obj *)0, otmp->owornmask & W_ARMU);
                dropx(otmp);
        }
    }
    if (has_horns(youmonst.data)) {
        if ((otmp = uarmh) != 0) {
            if (is_flimsy(otmp) && !donning(otmp)) {
                /* Future possiblities: This could damage/destroy helmet */
                message_object(MSG_YOUR_HORNS_PIERCE_O, otmp);
            } else {
                if (donning(otmp)) cancel_don();
                Your("helmet falls to the %s!", surface(u.ux, u.uy));
                (void) Helmet_off();
                dropx(otmp);
            }
        }
    }
    if (nohands(youmonst.data) || verysmall(youmonst.data)) {
        if ((otmp = uarmg) != 0) {
            if (donning(otmp)) cancel_don();
            /* Drop weapon along with gloves */
            You("drop your gloves%s!", uwep ? " and weapon" : "");
            drop_weapon(0);
            (void) Gloves_off();
            dropx(otmp);
        }
        if ((otmp = uarms) != 0) {
            You("can no longer hold your shield!");
            (void) Shield_off();
            dropx(otmp);
        }
        if ((otmp = uarmh) != 0) {
            if (donning(otmp)) cancel_don();
            Your("helmet falls to the %s!", surface(u.ux, u.uy));
            (void) Helmet_off();
            dropx(otmp);
        }
    }
    if (nohands(youmonst.data) || verysmall(youmonst.data) ||
                slithy(youmonst.data) || youmonst.data->mlet == S_CENTAUR) {
        if ((otmp = uarmf) != 0) {
            if (donning(otmp)) cancel_don();
            if (is_whirly(youmonst.data))
                Your("boots fall away!");
            else Your("boots %s off your feet!",
                        verysmall(youmonst.data) ? "slide" : "are pushed");
            (void) Boots_off();
            dropx(otmp);
        }
    }
}