693 lines
23 KiB
C
693 lines
23 KiB
C
/* NetHack 3.6 steal.c $NHDT-Date: 1446713643 2015/11/05 08:54:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.65 $ */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "hack.h"
|
|
|
|
STATIC_PTR int NDECL(stealarm);
|
|
|
|
STATIC_DCL const char *FDECL(equipname, (struct obj *));
|
|
|
|
STATIC_OVL const char *
|
|
equipname(otmp)
|
|
register struct obj *otmp;
|
|
{
|
|
return ((otmp == uarmu)
|
|
? "shirt"
|
|
: (otmp == uarmf)
|
|
? "boots"
|
|
: (otmp == uarms)
|
|
? "shield"
|
|
: (otmp == uarmg)
|
|
? "gloves"
|
|
: (otmp == uarmc)
|
|
? cloak_simple_name(otmp)
|
|
: (otmp == uarmh)
|
|
? helm_simple_name(otmp)
|
|
: suit_simple_name(otmp));
|
|
}
|
|
|
|
/* proportional subset of gold; return value actually fits in an int */
|
|
long
|
|
somegold(lmoney)
|
|
long lmoney;
|
|
{
|
|
#ifdef LINT /* long conv. ok */
|
|
int igold = 0;
|
|
#else
|
|
int igold = (lmoney >= (long) LARGEST_INT) ? LARGEST_INT : (int) lmoney;
|
|
#endif
|
|
|
|
if (igold < 50)
|
|
; /* all gold */
|
|
else if (igold < 100)
|
|
igold = rn1(igold - 25 + 1, 25);
|
|
else if (igold < 500)
|
|
igold = rn1(igold - 50 + 1, 50);
|
|
else if (igold < 1000)
|
|
igold = rn1(igold - 100 + 1, 100);
|
|
else if (igold < 5000)
|
|
igold = rn1(igold - 500 + 1, 500);
|
|
else if (igold < 10000)
|
|
igold = rn1(igold - 1000 + 1, 1000);
|
|
else
|
|
igold = rn1(igold - 5000 + 1, 5000);
|
|
|
|
return (long) igold;
|
|
}
|
|
|
|
/*
|
|
* Find the first (and hopefully only) gold object in a chain.
|
|
* Used when leprechaun (or you as leprechaun) looks for
|
|
* someone else's gold. Returns a pointer so the gold may
|
|
* be seized without further searching.
|
|
* May search containers too.
|
|
* Deals in gold only, as leprechauns don't care for lesser coins.
|
|
*/
|
|
struct obj *
|
|
findgold(chain)
|
|
register struct obj *chain;
|
|
{
|
|
while (chain && chain->otyp != GOLD_PIECE)
|
|
chain = chain->nobj;
|
|
return chain;
|
|
}
|
|
|
|
/*
|
|
* Steal gold coins only. Leprechauns don't care for lesser coins.
|
|
*/
|
|
void
|
|
stealgold(mtmp)
|
|
register struct monst *mtmp;
|
|
{
|
|
register struct obj *fgold = g_at(u.ux, u.uy);
|
|
register struct obj *ygold;
|
|
register long tmp;
|
|
struct monst *who;
|
|
const char *whose, *what;
|
|
|
|
/* skip lesser coins on the floor */
|
|
while (fgold && fgold->otyp != GOLD_PIECE)
|
|
fgold = fgold->nexthere;
|
|
|
|
/* Do you have real gold? */
|
|
ygold = findgold(invent);
|
|
|
|
if (fgold && (!ygold || fgold->quan > ygold->quan || !rn2(5))) {
|
|
obj_extract_self(fgold);
|
|
add_to_minv(mtmp, fgold);
|
|
newsym(u.ux, u.uy);
|
|
if (u.usteed) {
|
|
who = u.usteed;
|
|
whose = s_suffix(y_monnam(who));
|
|
what = makeplural(mbodypart(who, FOOT));
|
|
} else {
|
|
who = &youmonst;
|
|
whose = "your";
|
|
what = makeplural(body_part(FOOT));
|
|
}
|
|
/* [ avoid "between your rear regions" :-] */
|
|
if (slithy(who->data))
|
|
what = "coils";
|
|
/* reduce "rear hooves/claws" to "hooves/claws" */
|
|
if (!strncmp(what, "rear ", 5))
|
|
what += 5;
|
|
pline("%s quickly snatches some gold from %s %s %s!", Monnam(mtmp),
|
|
(Levitation || Flying) ? "beneath" : "between", whose, what);
|
|
if (!ygold || !rn2(5)) {
|
|
if (!tele_restrict(mtmp))
|
|
(void) rloc(mtmp, TRUE);
|
|
monflee(mtmp, 0, FALSE, FALSE);
|
|
}
|
|
} else if (ygold) {
|
|
const int gold_price = objects[GOLD_PIECE].oc_cost;
|
|
|
|
tmp = (somegold(money_cnt(invent)) + gold_price - 1) / gold_price;
|
|
tmp = min(tmp, ygold->quan);
|
|
if (tmp < ygold->quan)
|
|
ygold = splitobj(ygold, tmp);
|
|
else
|
|
setnotworn(ygold);
|
|
freeinv(ygold);
|
|
add_to_minv(mtmp, ygold);
|
|
Your("purse feels lighter.");
|
|
if (!tele_restrict(mtmp))
|
|
(void) rloc(mtmp, TRUE);
|
|
monflee(mtmp, 0, FALSE, FALSE);
|
|
context.botl = 1;
|
|
}
|
|
}
|
|
|
|
/* steal armor after you finish taking it off */
|
|
unsigned int stealoid; /* object to be stolen */
|
|
unsigned int stealmid; /* monster doing the stealing */
|
|
|
|
STATIC_PTR int
|
|
stealarm(VOID_ARGS)
|
|
{
|
|
register struct monst *mtmp;
|
|
register struct obj *otmp;
|
|
|
|
for (otmp = invent; otmp; otmp = otmp->nobj) {
|
|
if (otmp->o_id == stealoid) {
|
|
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
|
|
if (mtmp->m_id == stealmid) {
|
|
if (DEADMONSTER(mtmp))
|
|
impossible("stealarm(): dead monster stealing");
|
|
if (!dmgtype(mtmp->data, AD_SITM)) /* polymorphed */
|
|
goto botm;
|
|
if (otmp->unpaid)
|
|
subfrombill(otmp, shop_keeper(*u.ushops));
|
|
freeinv(otmp);
|
|
pline("%s steals %s!", Monnam(mtmp), doname(otmp));
|
|
(void) mpickobj(mtmp, otmp); /* may free otmp */
|
|
/* Implies seduction, "you gladly hand over ..."
|
|
so we don't set mavenge bit here. */
|
|
monflee(mtmp, 0, FALSE, FALSE);
|
|
if (!tele_restrict(mtmp))
|
|
(void) rloc(mtmp, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
botm:
|
|
stealoid = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* An object you're wearing has been taken off by a monster (theft or
|
|
seduction). Also used if a worn item gets transformed (stone to flesh). */
|
|
void
|
|
remove_worn_item(obj, unchain_ball)
|
|
struct obj *obj;
|
|
boolean unchain_ball; /* whether to unpunish or just unwield */
|
|
{
|
|
if (donning(obj))
|
|
cancel_don();
|
|
if (!obj->owornmask)
|
|
return;
|
|
|
|
if (obj->owornmask & W_ARMOR) {
|
|
if (obj == uskin) {
|
|
impossible("Removing embedded scales?");
|
|
skinback(TRUE); /* uarm = uskin; uskin = 0; */
|
|
}
|
|
if (obj == uarm)
|
|
(void) Armor_off();
|
|
else if (obj == uarmc)
|
|
(void) Cloak_off();
|
|
else if (obj == uarmf)
|
|
(void) Boots_off();
|
|
else if (obj == uarmg)
|
|
(void) Gloves_off();
|
|
else if (obj == uarmh)
|
|
(void) Helmet_off();
|
|
else if (obj == uarms)
|
|
(void) Shield_off();
|
|
else if (obj == uarmu)
|
|
(void) Shirt_off();
|
|
/* catchall -- should never happen */
|
|
else
|
|
setworn((struct obj *) 0, obj->owornmask & W_ARMOR);
|
|
} else if (obj->owornmask & W_AMUL) {
|
|
Amulet_off();
|
|
} else if (obj->owornmask & W_RING) {
|
|
Ring_gone(obj);
|
|
} else if (obj->owornmask & W_TOOL) {
|
|
Blindf_off(obj);
|
|
} else if (obj->owornmask & W_WEAPON) {
|
|
if (obj == uwep)
|
|
uwepgone();
|
|
if (obj == uswapwep)
|
|
uswapwepgone();
|
|
if (obj == uquiver)
|
|
uqwepgone();
|
|
}
|
|
|
|
if (obj->owornmask & (W_BALL | W_CHAIN)) {
|
|
if (unchain_ball)
|
|
unpunish();
|
|
} else if (obj->owornmask) {
|
|
/* catchall */
|
|
setnotworn(obj);
|
|
}
|
|
}
|
|
|
|
/* Returns 1 when something was stolen (or at least, when N should flee now)
|
|
* Returns -1 if the monster died in the attempt
|
|
* Avoid stealing the object stealoid
|
|
* Nymphs and monkeys won't steal coins
|
|
*/
|
|
int
|
|
steal(mtmp, objnambuf)
|
|
struct monst *mtmp;
|
|
char *objnambuf;
|
|
{
|
|
struct obj *otmp;
|
|
int tmp, could_petrify, armordelay, olddelay, named = 0, retrycnt = 0;
|
|
boolean monkey_business, /* true iff an animal is doing the thievery */
|
|
was_doffing;
|
|
|
|
if (objnambuf)
|
|
*objnambuf = '\0';
|
|
/* the following is true if successful on first of two attacks. */
|
|
if (!monnear(mtmp, u.ux, u.uy))
|
|
return 0;
|
|
|
|
/* food being eaten might already be used up but will not have
|
|
been removed from inventory yet; we don't want to steal that,
|
|
so this will cause it to be removed now */
|
|
if (occupation)
|
|
(void) maybe_finished_meal(FALSE);
|
|
|
|
if (!invent || (inv_cnt(FALSE) == 1 && uskin)) {
|
|
nothing_to_steal:
|
|
/* Not even a thousand men in armor can strip a naked man. */
|
|
if (Blind)
|
|
pline("Somebody tries to rob you, but finds nothing to steal.");
|
|
else
|
|
pline("%s tries to rob you, but there is nothing to steal!",
|
|
Monnam(mtmp));
|
|
return 1; /* let her flee */
|
|
}
|
|
|
|
monkey_business = is_animal(mtmp->data);
|
|
if (monkey_business || uarmg) {
|
|
; /* skip ring special cases */
|
|
} else if (Adornment & LEFT_RING) {
|
|
otmp = uleft;
|
|
goto gotobj;
|
|
} else if (Adornment & RIGHT_RING) {
|
|
otmp = uright;
|
|
goto gotobj;
|
|
}
|
|
|
|
retry:
|
|
tmp = 0;
|
|
for (otmp = invent; otmp; otmp = otmp->nobj)
|
|
if ((!uarm || otmp != uarmc) && otmp != uskin
|
|
&& otmp->oclass != COIN_CLASS)
|
|
tmp += (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) ? 5 : 1;
|
|
if (!tmp)
|
|
goto nothing_to_steal;
|
|
tmp = rn2(tmp);
|
|
for (otmp = invent; otmp; otmp = otmp->nobj)
|
|
if ((!uarm || otmp != uarmc) && otmp != uskin
|
|
&& otmp->oclass != COIN_CLASS) {
|
|
tmp -= (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) ? 5 : 1;
|
|
if (tmp < 0)
|
|
break;
|
|
}
|
|
if (!otmp) {
|
|
impossible("Steal fails!");
|
|
return 0;
|
|
}
|
|
/* can't steal ring(s) while wearing gloves */
|
|
if ((otmp == uleft || otmp == uright) && uarmg)
|
|
otmp = uarmg;
|
|
/* can't steal gloves while wielding - so steal the wielded item. */
|
|
if (otmp == uarmg && uwep)
|
|
otmp = uwep;
|
|
/* can't steal armor while wearing cloak - so steal the cloak. */
|
|
else if (otmp == uarm && uarmc)
|
|
otmp = uarmc;
|
|
/* can't steal shirt while wearing cloak or suit */
|
|
else if (otmp == uarmu && uarmc)
|
|
otmp = uarmc;
|
|
else if (otmp == uarmu && uarm)
|
|
otmp = uarm;
|
|
|
|
gotobj:
|
|
if (otmp->o_id == stealoid)
|
|
return 0;
|
|
|
|
if (otmp->otyp == BOULDER && !throws_rocks(mtmp->data)) {
|
|
if (!retrycnt++)
|
|
goto retry;
|
|
goto cant_take;
|
|
}
|
|
/* animals can't overcome curse stickiness nor unlock chains */
|
|
if (monkey_business) {
|
|
boolean ostuck;
|
|
/* is the player prevented from voluntarily giving up this item?
|
|
(ignores loadstones; the !can_carry() check will catch those) */
|
|
if (otmp == uball)
|
|
ostuck = TRUE; /* effectively worn; curse is implicit */
|
|
else if (otmp == uquiver || (otmp == uswapwep && !u.twoweap))
|
|
ostuck = FALSE; /* not really worn; curse doesn't matter */
|
|
else
|
|
ostuck = ((otmp->cursed && otmp->owornmask)
|
|
/* nymphs can steal rings from under
|
|
cursed weapon but animals can't */
|
|
|| (otmp == uright && welded(uwep))
|
|
|| (otmp == uleft && welded(uwep) && bimanual(uwep)));
|
|
|
|
if (ostuck || can_carry(mtmp, otmp) == 0) {
|
|
static const char *const how[] = { "steal", "snatch", "grab",
|
|
"take" };
|
|
cant_take:
|
|
pline("%s tries to %s %s%s but gives up.", Monnam(mtmp),
|
|
how[rn2(SIZE(how))],
|
|
(otmp->owornmask & W_ARMOR) ? "your " : "",
|
|
(otmp->owornmask & W_ARMOR) ? equipname(otmp)
|
|
: yname(otmp));
|
|
/* the fewer items you have, the less likely the thief
|
|
is going to stick around to try again (0) instead of
|
|
running away (1) */
|
|
return !rn2(inv_cnt(FALSE) / 5 + 2);
|
|
}
|
|
}
|
|
|
|
if (otmp->otyp == LEASH && otmp->leashmon) {
|
|
if (monkey_business && otmp->cursed)
|
|
goto cant_take;
|
|
o_unleash(otmp);
|
|
}
|
|
|
|
was_doffing = doffing(otmp);
|
|
/* stop donning/doffing now so that afternmv won't be clobbered
|
|
below; stop_occupation doesn't handle donning/doffing */
|
|
olddelay = stop_donning(otmp);
|
|
/* you're going to notice the theft... */
|
|
stop_occupation();
|
|
|
|
if (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) {
|
|
switch (otmp->oclass) {
|
|
case TOOL_CLASS:
|
|
case AMULET_CLASS:
|
|
case RING_CLASS:
|
|
case FOOD_CLASS: /* meat ring */
|
|
remove_worn_item(otmp, TRUE);
|
|
break;
|
|
case ARMOR_CLASS:
|
|
armordelay = objects[otmp->otyp].oc_delay;
|
|
if (olddelay > 0 && olddelay < armordelay)
|
|
armordelay = olddelay;
|
|
if (monkey_business) {
|
|
/* animals usually don't have enough patience
|
|
to take off items which require extra time */
|
|
if (armordelay >= 1 && !olddelay && rn2(10))
|
|
goto cant_take;
|
|
remove_worn_item(otmp, TRUE);
|
|
break;
|
|
} else {
|
|
int curssv = otmp->cursed;
|
|
int slowly;
|
|
boolean seen = canspotmon(mtmp);
|
|
|
|
otmp->cursed = 0;
|
|
/* can't charm you without first waking you */
|
|
if (Unaware)
|
|
unmul((char *) 0);
|
|
slowly = (armordelay >= 1 || multi < 0);
|
|
if (flags.female)
|
|
pline("%s charms you. You gladly %s your %s.",
|
|
!seen ? "She" : Monnam(mtmp),
|
|
curssv ? "let her take"
|
|
: !slowly ? "hand over"
|
|
: was_doffing ? "continue removing"
|
|
: "start removing",
|
|
equipname(otmp));
|
|
else
|
|
pline("%s seduces you and %s off your %s.",
|
|
!seen ? "She" : Adjmonnam(mtmp, "beautiful"),
|
|
curssv
|
|
? "helps you to take"
|
|
: !slowly ? "you take"
|
|
: was_doffing ? "you continue taking"
|
|
: "you start taking",
|
|
equipname(otmp));
|
|
named++;
|
|
/* the following is to set multi for later on */
|
|
nomul(-armordelay);
|
|
multi_reason = "taking off clothes";
|
|
nomovemsg = 0;
|
|
remove_worn_item(otmp, TRUE);
|
|
otmp->cursed = curssv;
|
|
if (multi < 0) {
|
|
/*
|
|
multi = 0;
|
|
afternmv = 0;
|
|
*/
|
|
stealoid = otmp->o_id;
|
|
stealmid = mtmp->m_id;
|
|
afternmv = stealarm;
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
impossible("Tried to steal a strange worn thing. [%d]",
|
|
otmp->oclass);
|
|
}
|
|
} else if (otmp->owornmask)
|
|
remove_worn_item(otmp, TRUE);
|
|
|
|
/* do this before removing it from inventory */
|
|
if (objnambuf)
|
|
Strcpy(objnambuf, yname(otmp));
|
|
/* set mavenge bit so knights won't suffer an
|
|
* alignment penalty during retaliation;
|
|
*/
|
|
mtmp->mavenge = 1;
|
|
|
|
if (otmp->unpaid)
|
|
subfrombill(otmp, shop_keeper(*u.ushops));
|
|
freeinv(otmp);
|
|
pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp));
|
|
could_petrify =
|
|
(otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]));
|
|
(void) mpickobj(mtmp, otmp); /* may free otmp */
|
|
if (could_petrify && !(mtmp->misc_worn_check & W_ARMG)) {
|
|
minstapetrify(mtmp, TRUE);
|
|
return -1;
|
|
}
|
|
return (multi < 0) ? 0 : 1;
|
|
}
|
|
|
|
/* Returns 1 if otmp is free'd, 0 otherwise. */
|
|
int
|
|
mpickobj(mtmp, otmp)
|
|
register struct monst *mtmp;
|
|
register struct obj *otmp;
|
|
{
|
|
int freed_otmp;
|
|
boolean snuff_otmp = FALSE;
|
|
|
|
/* if monster is acquiring a thrown or kicked object, the throwing
|
|
or kicking code shouldn't continue to track and place it */
|
|
if (otmp == thrownobj)
|
|
thrownobj = 0;
|
|
else if (otmp == kickedobj)
|
|
kickedobj = 0;
|
|
/* don't want hidden light source inside the monster; assumes that
|
|
engulfers won't have external inventories; whirly monsters cause
|
|
the light to be extinguished rather than letting it shine thru */
|
|
if (obj_sheds_light(otmp) && attacktype(mtmp->data, AT_ENGL)) {
|
|
/* this is probably a burning object that you dropped or threw */
|
|
if (u.uswallow && mtmp == u.ustuck && !Blind)
|
|
pline("%s out.", Tobjnam(otmp, "go"));
|
|
snuff_otmp = TRUE;
|
|
}
|
|
/* for hero owned object on shop floor, mtmp is taking possession
|
|
and if it's eventually dropped in a shop, shk will claim it */
|
|
if (!mtmp->mtame)
|
|
otmp->no_charge = 0;
|
|
/* Must do carrying effects on object prior to add_to_minv() */
|
|
carry_obj_effects(otmp);
|
|
/* add_to_minv() might free otmp [if merged with something else],
|
|
so we have to call it after doing the object checks */
|
|
freed_otmp = add_to_minv(mtmp, otmp);
|
|
/* and we had to defer this until object is in mtmp's inventory */
|
|
if (snuff_otmp)
|
|
snuff_light_source(mtmp->mx, mtmp->my);
|
|
return freed_otmp;
|
|
}
|
|
|
|
void
|
|
stealamulet(mtmp)
|
|
struct monst *mtmp;
|
|
{
|
|
struct obj *otmp = (struct obj *) 0;
|
|
int real = 0, fake = 0;
|
|
|
|
/* select the artifact to steal */
|
|
if (u.uhave.amulet) {
|
|
real = AMULET_OF_YENDOR;
|
|
fake = FAKE_AMULET_OF_YENDOR;
|
|
} else if (u.uhave.questart) {
|
|
for (otmp = invent; otmp; otmp = otmp->nobj)
|
|
if (is_quest_artifact(otmp))
|
|
break;
|
|
if (!otmp)
|
|
return; /* should we panic instead? */
|
|
} else if (u.uhave.bell) {
|
|
real = BELL_OF_OPENING;
|
|
fake = BELL;
|
|
} else if (u.uhave.book) {
|
|
real = SPE_BOOK_OF_THE_DEAD;
|
|
} else if (u.uhave.menorah) {
|
|
real = CANDELABRUM_OF_INVOCATION;
|
|
} else
|
|
return; /* you have nothing of special interest */
|
|
|
|
if (!otmp) {
|
|
/* If we get here, real and fake have been set up. */
|
|
for (otmp = invent; otmp; otmp = otmp->nobj)
|
|
if (otmp->otyp == real || (otmp->otyp == fake && !mtmp->iswiz))
|
|
break;
|
|
}
|
|
|
|
if (otmp) { /* we have something to snatch */
|
|
if (otmp->owornmask)
|
|
remove_worn_item(otmp, TRUE);
|
|
if (otmp->unpaid)
|
|
subfrombill(otmp, shop_keeper(*u.ushops));
|
|
freeinv(otmp);
|
|
/* mpickobj wont merge otmp because none of the above things
|
|
to steal are mergable */
|
|
(void) mpickobj(mtmp, otmp); /* may merge and free otmp */
|
|
pline("%s stole %s!", Monnam(mtmp), doname(otmp));
|
|
if (can_teleport(mtmp->data) && !tele_restrict(mtmp))
|
|
(void) rloc(mtmp, TRUE);
|
|
}
|
|
}
|
|
|
|
/* when a mimic gets poked with something, it might take that thing
|
|
(at present, only implemented for when the hero does the poking) */
|
|
void
|
|
maybe_absorb_item(mon, obj, ochance, achance)
|
|
struct monst *mon;
|
|
struct obj *obj;
|
|
int ochance, achance; /* percent chance for ordinary item, artifact */
|
|
{
|
|
if (obj == uball || obj == uchain || obj->oclass == ROCK_CLASS
|
|
|| obj_resists(obj, 100 - ochance, 100 - achance)
|
|
|| !touch_artifact(obj, mon))
|
|
return;
|
|
|
|
if (carried(obj)) {
|
|
if (obj->owornmask)
|
|
remove_worn_item(obj, TRUE);
|
|
if (obj->unpaid)
|
|
subfrombill(obj, shop_keeper(*u.ushops));
|
|
if (cansee(mon->mx, mon->my)) {
|
|
const char *MonName = Monnam(mon);
|
|
|
|
/* mon might be invisible; avoid "It pulls ... and absorbs it!" */
|
|
if (!strcmp(MonName, "It"))
|
|
MonName = "Something";
|
|
pline("%s pulls %s away from you and absorbs %s!", MonName,
|
|
yname(obj), (obj->quan > 1L) ? "them" : "it");
|
|
} else {
|
|
const char *hand_s = body_part(HAND);
|
|
|
|
if (bimanual(obj))
|
|
hand_s = makeplural(hand_s);
|
|
pline("%s %s pulled from your %s!", upstart(yname(obj)),
|
|
otense(obj, "are"), hand_s);
|
|
}
|
|
freeinv(obj);
|
|
} else {
|
|
/* not carried; presumably thrown or kicked */
|
|
if (canspotmon(mon))
|
|
pline("%s absorbs %s!", Monnam(mon), yname(obj));
|
|
}
|
|
/* add to mon's inventory */
|
|
(void) mpickobj(mon, obj);
|
|
}
|
|
|
|
/* drop one object taken from a (possibly dead) monster's inventory */
|
|
void
|
|
mdrop_obj(mon, obj, verbosely)
|
|
struct monst *mon;
|
|
struct obj *obj;
|
|
boolean verbosely;
|
|
{
|
|
int omx = mon->mx, omy = mon->my;
|
|
boolean update_mon = FALSE;
|
|
|
|
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 = TRUE;
|
|
/* don't charge for an owned saddle on dead steed (provided
|
|
that the hero is within the same shop at the time) */
|
|
} else if (mon->mtame && (obj->owornmask & W_SADDLE) && !obj->unpaid
|
|
&& costly_spot(omx, omy)
|
|
/* being at costly_spot guarantees lev->roomno is not 0 */
|
|
&& index(in_rooms(u.ux, u.uy, SHOPBASE),
|
|
levl[omx][omy].roomno)) {
|
|
obj->no_charge = 1;
|
|
}
|
|
/* this should be done even if the monster has died */
|
|
if (obj->owornmask & W_WEP)
|
|
setmnotwielded(mon, obj);
|
|
obj->owornmask = 0L;
|
|
}
|
|
/* obj_no_longer_held(obj); -- done by place_object */
|
|
if (verbosely && cansee(omx, omy))
|
|
pline("%s drops %s.", Monnam(mon), distant_name(obj, doname));
|
|
if (!flooreffects(obj, omx, omy, "fall")) {
|
|
place_object(obj, omx, omy);
|
|
stackobj(obj);
|
|
}
|
|
/* do this last, after placing obj on floor; removing steed's saddle
|
|
throws rider, possibly inflicting fatal damage and producing bones */
|
|
if (update_mon)
|
|
update_mon_intrinsics(mon, obj, FALSE, TRUE);
|
|
}
|
|
|
|
/* some monsters bypass the normal rules for moving between levels or
|
|
even leaving the game entirely; when that happens, prevent them from
|
|
taking the Amulet or invocation tools with them */
|
|
void
|
|
mdrop_special_objs(mon)
|
|
struct monst *mon;
|
|
{
|
|
struct obj *obj, *otmp;
|
|
|
|
for (obj = mon->minvent; obj; obj = otmp) {
|
|
otmp = obj->nobj;
|
|
/* the Amulet, invocation tools, and Rider corpses resist even when
|
|
artifacts and ordinary objects are given 0% resistance chance */
|
|
if (obj_resists(obj, 0, 0)) {
|
|
obj_extract_self(obj);
|
|
mdrop_obj(mon, obj, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* release the objects the creature is carrying */
|
|
void
|
|
relobj(mtmp, show, is_pet)
|
|
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;
|
|
|
|
/* vault guard's gold goes away rather than be dropped... */
|
|
if (mtmp->isgd && (otmp = findgold(mtmp->minvent)) != 0) {
|
|
if (canspotmon(mtmp))
|
|
pline("%s gold %s.", s_suffix(Monnam(mtmp)),
|
|
canseemon(mtmp) ? "vanishes" : "seems to vanish");
|
|
obj_extract_self(otmp);
|
|
obfree(otmp, (struct obj *) 0);
|
|
} /* isgd && has gold */
|
|
|
|
while ((otmp = (is_pet ? droppables(mtmp) : mtmp->minvent)) != 0) {
|
|
obj_extract_self(otmp);
|
|
mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
|
|
}
|
|
|
|
if (show && cansee(omx, omy))
|
|
newsym(omx, omy);
|
|
}
|
|
|
|
/*steal.c*/
|