1 /* NetHack 3.6 steal.c $NHDT-Date: 1456618998 2016/02/28 00:23:18 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.67 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 STATIC_PTR
int NDECL(stealarm
);
9 STATIC_DCL
const char *FDECL(equipname
, (struct obj
*));
11 STATIC_OVL
const char *
13 register struct obj
*otmp
;
15 return ((otmp
== uarmu
)
24 ? cloak_simple_name(otmp
)
26 ? helm_simple_name(otmp
)
27 : suit_simple_name(otmp
));
30 /* proportional subset of gold; return value actually fits in an int */
35 #ifdef LINT /* long conv. ok */
38 int igold
= (lmoney
>= (long) LARGEST_INT
) ? LARGEST_INT
: (int) lmoney
;
44 igold
= rn1(igold
- 25 + 1, 25);
46 igold
= rn1(igold
- 50 + 1, 50);
47 else if (igold
< 1000)
48 igold
= rn1(igold
- 100 + 1, 100);
49 else if (igold
< 5000)
50 igold
= rn1(igold
- 500 + 1, 500);
51 else if (igold
< 10000)
52 igold
= rn1(igold
- 1000 + 1, 1000);
54 igold
= rn1(igold
- 5000 + 1, 5000);
60 * Find the first (and hopefully only) gold object in a chain.
61 * Used when leprechaun (or you as leprechaun) looks for
62 * someone else's gold. Returns a pointer so the gold may
63 * be seized without further searching.
64 * May search containers too.
65 * Deals in gold only, as leprechauns don't care for lesser coins.
69 register struct obj
*chain
;
71 while (chain
&& chain
->otyp
!= GOLD_PIECE
)
77 * Steal gold coins only. Leprechauns don't care for lesser coins.
81 register struct monst
*mtmp
;
83 register struct obj
*fgold
= g_at(u
.ux
, u
.uy
);
84 register struct obj
*ygold
;
87 const char *whose
, *what
;
89 /* skip lesser coins on the floor */
90 while (fgold
&& fgold
->otyp
!= GOLD_PIECE
)
91 fgold
= fgold
->nexthere
;
93 /* Do you have real gold? */
94 ygold
= findgold(invent
);
96 if (fgold
&& (!ygold
|| fgold
->quan
> ygold
->quan
|| !rn2(5))) {
97 obj_extract_self(fgold
);
98 add_to_minv(mtmp
, fgold
);
102 whose
= s_suffix(y_monnam(who
));
103 what
= makeplural(mbodypart(who
, FOOT
));
107 what
= makeplural(body_part(FOOT
));
109 /* [ avoid "between your rear regions" :-] */
110 if (slithy(who
->data
))
112 /* reduce "rear hooves/claws" to "hooves/claws" */
113 if (!strncmp(what
, "rear ", 5))
115 pline("%s quickly snatches some gold from %s %s %s!", Monnam(mtmp
),
116 (Levitation
|| Flying
) ? "beneath" : "between", whose
, what
);
117 if (!ygold
|| !rn2(5)) {
118 if (!tele_restrict(mtmp
))
119 (void) rloc(mtmp
, TRUE
);
120 monflee(mtmp
, 0, FALSE
, FALSE
);
123 const int gold_price
= objects
[GOLD_PIECE
].oc_cost
;
125 tmp
= (somegold(money_cnt(invent
)) + gold_price
- 1) / gold_price
;
126 tmp
= min(tmp
, ygold
->quan
);
127 if (tmp
< ygold
->quan
)
128 ygold
= splitobj(ygold
, tmp
);
132 add_to_minv(mtmp
, ygold
);
133 Your("purse feels lighter.");
134 if (!tele_restrict(mtmp
))
135 (void) rloc(mtmp
, TRUE
);
136 monflee(mtmp
, 0, FALSE
, FALSE
);
141 /* steal armor after you finish taking it off */
142 unsigned int stealoid
; /* object to be stolen */
143 unsigned int stealmid
; /* monster doing the stealing */
148 register struct monst
*mtmp
;
149 register struct obj
*otmp
;
151 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
152 if (otmp
->o_id
== stealoid
) {
153 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
) {
154 if (mtmp
->m_id
== stealmid
) {
155 if (DEADMONSTER(mtmp
))
156 impossible("stealarm(): dead monster stealing");
157 if (!dmgtype(mtmp
->data
, AD_SITM
)) /* polymorphed */
160 subfrombill(otmp
, shop_keeper(*u
.ushops
));
162 pline("%s steals %s!", Monnam(mtmp
), doname(otmp
));
163 (void) mpickobj(mtmp
, otmp
); /* may free otmp */
164 /* Implies seduction, "you gladly hand over ..."
165 so we don't set mavenge bit here. */
166 monflee(mtmp
, 0, FALSE
, FALSE
);
167 if (!tele_restrict(mtmp
))
168 (void) rloc(mtmp
, TRUE
);
180 /* An object you're wearing has been taken off by a monster (theft or
181 seduction). Also used if a worn item gets transformed (stone to flesh). */
183 remove_worn_item(obj
, unchain_ball
)
185 boolean unchain_ball
; /* whether to unpunish or just unwield */
192 if (obj
->owornmask
& W_ARMOR
) {
194 impossible("Removing embedded scales?");
195 skinback(TRUE
); /* uarm = uskin; uskin = 0; */
199 else if (obj
== uarmc
)
201 else if (obj
== uarmf
)
203 else if (obj
== uarmg
)
205 else if (obj
== uarmh
)
207 else if (obj
== uarms
)
209 else if (obj
== uarmu
)
211 /* catchall -- should never happen */
213 setworn((struct obj
*) 0, obj
->owornmask
& W_ARMOR
);
214 } else if (obj
->owornmask
& W_AMUL
) {
216 } else if (obj
->owornmask
& W_RING
) {
218 } else if (obj
->owornmask
& W_TOOL
) {
220 } else if (obj
->owornmask
& W_WEAPON
) {
229 if (obj
->owornmask
& (W_BALL
| W_CHAIN
)) {
232 } else if (obj
->owornmask
) {
238 /* Returns 1 when something was stolen (or at least, when N should flee now)
239 * Returns -1 if the monster died in the attempt
240 * Avoid stealing the object stealoid
241 * Nymphs and monkeys won't steal coins
244 steal(mtmp
, objnambuf
)
249 int tmp
, could_petrify
, armordelay
, olddelay
, named
= 0, retrycnt
= 0;
250 boolean monkey_business
, /* true iff an animal is doing the thievery */
255 /* the following is true if successful on first of two attacks. */
256 if (!monnear(mtmp
, u
.ux
, u
.uy
))
259 /* food being eaten might already be used up but will not have
260 been removed from inventory yet; we don't want to steal that,
261 so this will cause it to be removed now */
263 (void) maybe_finished_meal(FALSE
);
265 if (!invent
|| (inv_cnt(FALSE
) == 1 && uskin
)) {
267 /* Not even a thousand men in armor can strip a naked man. */
269 pline("Somebody tries to rob you, but finds nothing to steal.");
271 pline("%s tries to rob you, but there is nothing to steal!",
273 return 1; /* let her flee */
276 monkey_business
= is_animal(mtmp
->data
);
277 if (monkey_business
|| uarmg
) {
278 ; /* skip ring special cases */
279 } else if (Adornment
& LEFT_RING
) {
282 } else if (Adornment
& RIGHT_RING
) {
289 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
290 if ((!uarm
|| otmp
!= uarmc
) && otmp
!= uskin
291 && otmp
->oclass
!= COIN_CLASS
)
292 tmp
+= (otmp
->owornmask
& (W_ARMOR
| W_ACCESSORY
)) ? 5 : 1;
294 goto nothing_to_steal
;
296 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
297 if ((!uarm
|| otmp
!= uarmc
) && otmp
!= uskin
298 && otmp
->oclass
!= COIN_CLASS
) {
299 tmp
-= (otmp
->owornmask
& (W_ARMOR
| W_ACCESSORY
)) ? 5 : 1;
304 impossible("Steal fails!");
307 /* can't steal ring(s) while wearing gloves */
308 if ((otmp
== uleft
|| otmp
== uright
) && uarmg
)
310 /* can't steal gloves while wielding - so steal the wielded item. */
311 if (otmp
== uarmg
&& uwep
)
313 /* can't steal armor while wearing cloak - so steal the cloak. */
314 else if (otmp
== uarm
&& uarmc
)
316 /* can't steal shirt while wearing cloak or suit */
317 else if (otmp
== uarmu
&& uarmc
)
319 else if (otmp
== uarmu
&& uarm
)
323 if (otmp
->o_id
== stealoid
)
326 if (otmp
->otyp
== BOULDER
&& !throws_rocks(mtmp
->data
)) {
331 /* animals can't overcome curse stickiness nor unlock chains */
332 if (monkey_business
) {
334 /* is the player prevented from voluntarily giving up this item?
335 (ignores loadstones; the !can_carry() check will catch those) */
337 ostuck
= TRUE
; /* effectively worn; curse is implicit */
338 else if (otmp
== uquiver
|| (otmp
== uswapwep
&& !u
.twoweap
))
339 ostuck
= FALSE
; /* not really worn; curse doesn't matter */
341 ostuck
= ((otmp
->cursed
&& otmp
->owornmask
)
342 /* nymphs can steal rings from under
343 cursed weapon but animals can't */
344 || (otmp
== uright
&& welded(uwep
))
345 || (otmp
== uleft
&& welded(uwep
) && bimanual(uwep
)));
347 if (ostuck
|| can_carry(mtmp
, otmp
) == 0) {
348 static const char *const how
[] = { "steal", "snatch", "grab",
351 pline("%s tries to %s %s%s but gives up.", Monnam(mtmp
),
353 (otmp
->owornmask
& W_ARMOR
) ? "your " : "",
354 (otmp
->owornmask
& W_ARMOR
) ? equipname(otmp
)
356 /* the fewer items you have, the less likely the thief
357 is going to stick around to try again (0) instead of
359 return !rn2(inv_cnt(FALSE
) / 5 + 2);
363 if (otmp
->otyp
== LEASH
&& otmp
->leashmon
) {
364 if (monkey_business
&& otmp
->cursed
)
369 was_doffing
= doffing(otmp
);
370 /* stop donning/doffing now so that afternmv won't be clobbered
371 below; stop_occupation doesn't handle donning/doffing */
372 olddelay
= stop_donning(otmp
);
373 /* you're going to notice the theft... */
376 if (otmp
->owornmask
& (W_ARMOR
| W_ACCESSORY
)) {
377 switch (otmp
->oclass
) {
381 case FOOD_CLASS
: /* meat ring */
382 remove_worn_item(otmp
, TRUE
);
385 armordelay
= objects
[otmp
->otyp
].oc_delay
;
386 if (olddelay
> 0 && olddelay
< armordelay
)
387 armordelay
= olddelay
;
388 if (monkey_business
) {
389 /* animals usually don't have enough patience
390 to take off items which require extra time */
391 if (armordelay
>= 1 && !olddelay
&& rn2(10))
393 remove_worn_item(otmp
, TRUE
);
396 int curssv
= otmp
->cursed
;
398 boolean seen
= canspotmon(mtmp
);
401 /* can't charm you without first waking you */
404 slowly
= (armordelay
>= 1 || multi
< 0);
406 pline("%s charms you. You gladly %s your %s.",
407 !seen
? "She" : Monnam(mtmp
),
408 curssv
? "let her take"
409 : !slowly
? "hand over"
410 : was_doffing
? "continue removing"
414 pline("%s seduces you and %s off your %s.",
415 !seen
? "She" : Adjmonnam(mtmp
, "beautiful"),
417 ? "helps you to take"
418 : !slowly
? "you take"
419 : was_doffing
? "you continue taking"
420 : "you start taking",
423 /* the following is to set multi for later on */
425 multi_reason
= "taking off clothes";
427 remove_worn_item(otmp
, TRUE
);
428 otmp
->cursed
= curssv
;
434 stealoid
= otmp
->o_id
;
435 stealmid
= mtmp
->m_id
;
442 impossible("Tried to steal a strange worn thing. [%d]",
445 } else if (otmp
->owornmask
)
446 remove_worn_item(otmp
, TRUE
);
448 /* do this before removing it from inventory */
450 Strcpy(objnambuf
, yname(otmp
));
451 /* set mavenge bit so knights won't suffer an
452 * alignment penalty during retaliation;
457 subfrombill(otmp
, shop_keeper(*u
.ushops
));
459 pline("%s stole %s.", named
? "She" : Monnam(mtmp
), doname(otmp
));
461 (otmp
->otyp
== CORPSE
&& touch_petrifies(&mons
[otmp
->corpsenm
]));
462 (void) mpickobj(mtmp
, otmp
); /* may free otmp */
463 if (could_petrify
&& !(mtmp
->misc_worn_check
& W_ARMG
)) {
464 minstapetrify(mtmp
, TRUE
);
467 return (multi
< 0) ? 0 : 1;
470 /* Returns 1 if otmp is free'd, 0 otherwise. */
473 register struct monst
*mtmp
;
474 register struct obj
*otmp
;
477 boolean snuff_otmp
= FALSE
;
479 /* if monster is acquiring a thrown or kicked object, the throwing
480 or kicking code shouldn't continue to track and place it */
481 if (otmp
== thrownobj
)
483 else if (otmp
== kickedobj
)
485 /* don't want hidden light source inside the monster; assumes that
486 engulfers won't have external inventories; whirly monsters cause
487 the light to be extinguished rather than letting it shine thru */
488 if (obj_sheds_light(otmp
) && attacktype(mtmp
->data
, AT_ENGL
)) {
489 /* this is probably a burning object that you dropped or threw */
490 if (u
.uswallow
&& mtmp
== u
.ustuck
&& !Blind
)
491 pline("%s out.", Tobjnam(otmp
, "go"));
494 /* for hero owned object on shop floor, mtmp is taking possession
495 and if it's eventually dropped in a shop, shk will claim it */
498 /* Must do carrying effects on object prior to add_to_minv() */
499 carry_obj_effects(otmp
);
500 /* add_to_minv() might free otmp [if merged with something else],
501 so we have to call it after doing the object checks */
502 freed_otmp
= add_to_minv(mtmp
, otmp
);
503 /* and we had to defer this until object is in mtmp's inventory */
505 snuff_light_source(mtmp
->mx
, mtmp
->my
);
509 /* called for AD_SAMU (the Wizard and quest nemeses) */
515 struct obj
*otmp
= 0, *obj
= 0;
516 int real
= 0, fake
= 0, n
;
518 /* target every quest artifact, not just current role's;
519 if hero has more than one, choose randomly so that player
520 can't use inventory ordering to influence the theft */
521 for (n
= 0, obj
= invent
; obj
; obj
= obj
->nobj
)
522 if (any_quest_artifact(obj
))
526 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
527 if (any_quest_artifact(otmp
) && !--n
)
532 /* if we didn't find any quest arifact, find another valuable item */
533 if (u
.uhave
.amulet
) {
534 real
= AMULET_OF_YENDOR
;
535 fake
= FAKE_AMULET_OF_YENDOR
;
536 } else if (u
.uhave
.bell
) {
537 real
= BELL_OF_OPENING
;
539 } else if (u
.uhave
.book
) {
540 real
= SPE_BOOK_OF_THE_DEAD
;
541 } else if (u
.uhave
.menorah
) {
542 real
= CANDELABRUM_OF_INVOCATION
;
544 return; /* you have nothing of special interest */
546 /* If we get here, real and fake have been set up. */
547 for (n
= 0, obj
= invent
; obj
; obj
= obj
->nobj
)
548 if (obj
->otyp
== real
|| (obj
->otyp
== fake
&& !mtmp
->iswiz
))
552 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
553 if ((otmp
->otyp
== real
554 || (otmp
->otyp
== fake
&& !mtmp
->iswiz
)) && !--n
)
559 if (otmp
) { /* we have something to snatch */
560 /* take off outer gear if we're targetting [hypothetical]
561 quest artifact suit, shirt, gloves, or rings */
562 if ((otmp
== uarm
|| otmp
== uarmu
) && uarmc
)
564 if (otmp
== uarmu
&& uarm
)
566 if ((otmp
== uarmg
|| ((otmp
== uright
|| otmp
== uleft
) && uarmg
))
568 /* gloves are about to be unworn; unwield weapon(s) first */
570 uswapwepgone(); /* will clear u.twoweap */
573 if ((otmp
== uright
|| otmp
== uleft
) && uarmg
)
574 (void) Gloves_off(); /* handles wielded cockatrice corpse */
576 /* finally, steal the target item */
578 remove_worn_item(otmp
, TRUE
);
580 subfrombill(otmp
, shop_keeper(*u
.ushops
));
582 Strcpy(buf
, doname(otmp
));
583 (void) mpickobj(mtmp
, otmp
); /* could merge and free otmp but won't */
584 pline("%s steals %s!", Monnam(mtmp
), buf
);
585 if (can_teleport(mtmp
->data
) && !tele_restrict(mtmp
))
586 (void) rloc(mtmp
, TRUE
);
590 /* when a mimic gets poked with something, it might take that thing
591 (at present, only implemented for when the hero does the poking) */
593 maybe_absorb_item(mon
, obj
, ochance
, achance
)
596 int ochance
, achance
; /* percent chance for ordinary item, artifact */
598 if (obj
== uball
|| obj
== uchain
|| obj
->oclass
== ROCK_CLASS
599 || obj_resists(obj
, 100 - ochance
, 100 - achance
)
600 || !touch_artifact(obj
, mon
))
605 remove_worn_item(obj
, TRUE
);
607 subfrombill(obj
, shop_keeper(*u
.ushops
));
608 if (cansee(mon
->mx
, mon
->my
)) {
609 const char *MonName
= Monnam(mon
);
611 /* mon might be invisible; avoid "It pulls ... and absorbs it!" */
612 if (!strcmp(MonName
, "It"))
613 MonName
= "Something";
614 pline("%s pulls %s away from you and absorbs %s!", MonName
,
615 yname(obj
), (obj
->quan
> 1L) ? "them" : "it");
617 const char *hand_s
= body_part(HAND
);
620 hand_s
= makeplural(hand_s
);
621 pline("%s %s pulled from your %s!", upstart(yname(obj
)),
622 otense(obj
, "are"), hand_s
);
626 /* not carried; presumably thrown or kicked */
628 pline("%s absorbs %s!", Monnam(mon
), yname(obj
));
630 /* add to mon's inventory */
631 (void) mpickobj(mon
, obj
);
634 /* drop one object taken from a (possibly dead) monster's inventory */
636 mdrop_obj(mon
, obj
, verbosely
)
641 int omx
= mon
->mx
, omy
= mon
->my
;
642 boolean update_mon
= FALSE
;
644 if (obj
->owornmask
) {
645 /* perform worn item handling if the monster is still alive */
647 mon
->misc_worn_check
&= ~obj
->owornmask
;
650 /* don't charge for an owned saddle on dead steed (provided
651 that the hero is within the same shop at the time) */
652 } else if (mon
->mtame
&& (obj
->owornmask
& W_SADDLE
) != 0L
653 && !obj
->unpaid
&& costly_spot(omx
, omy
)
654 /* being at costly_spot guarantees lev->roomno is not 0 */
655 && index(in_rooms(u
.ux
, u
.uy
, SHOPBASE
),
656 levl
[omx
][omy
].roomno
)) {
659 /* this should be done even if the monster has died */
660 if (obj
->owornmask
& W_WEP
)
661 setmnotwielded(mon
, obj
);
664 /* obj_no_longer_held(obj); -- done by place_object */
665 if (verbosely
&& cansee(omx
, omy
))
666 pline("%s drops %s.", Monnam(mon
), distant_name(obj
, doname
));
667 if (!flooreffects(obj
, omx
, omy
, "fall")) {
668 place_object(obj
, omx
, omy
);
671 /* do this last, after placing obj on floor; removing steed's saddle
672 throws rider, possibly inflicting fatal damage and producing bones */
674 update_mon_intrinsics(mon
, obj
, FALSE
, TRUE
);
677 /* some monsters bypass the normal rules for moving between levels or
678 even leaving the game entirely; when that happens, prevent them from
679 taking the Amulet, invocation items, or quest artifact with them */
681 mdrop_special_objs(mon
)
684 struct obj
*obj
, *otmp
;
686 for (obj
= mon
->minvent
; obj
; obj
= otmp
) {
688 /* the Amulet, invocation tools, and Rider corpses resist even when
689 artifacts and ordinary objects are given 0% resistance chance;
690 current role's quest artifact is rescued too--quest artifacts
691 for the other roles are not */
692 if (obj_resists(obj
, 0, 0) || is_quest_artifact(obj
)) {
693 obj_extract_self(obj
);
694 mdrop_obj(mon
, obj
, FALSE
);
699 /* release the objects the creature is carrying */
701 relobj(mtmp
, show
, is_pet
)
704 boolean is_pet
; /* If true, pet should keep wielded/worn items */
707 int omx
= mtmp
->mx
, omy
= mtmp
->my
;
709 /* vault guard's gold goes away rather than be dropped... */
710 if (mtmp
->isgd
&& (otmp
= findgold(mtmp
->minvent
)) != 0) {
711 if (canspotmon(mtmp
))
712 pline("%s gold %s.", s_suffix(Monnam(mtmp
)),
713 canseemon(mtmp
) ? "vanishes" : "seems to vanish");
714 obj_extract_self(otmp
);
715 obfree(otmp
, (struct obj
*) 0);
716 } /* isgd && has gold */
718 while ((otmp
= (is_pet
? droppables(mtmp
) : mtmp
->minvent
)) != 0) {
719 obj_extract_self(otmp
);
720 mdrop_obj(mtmp
, otmp
, is_pet
&& flags
.verbose
);
723 if (show
&& cansee(omx
, omy
))