1 /* SCCS Id: @(#)steal.c 3.4 2003/12/04 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 STATIC_PTR int NDECL(stealarm);
10 STATIC_DCL const char *FDECL(equipname, (struct obj *));
11 STATIC_DCL void FDECL(mdrop_obj, (struct monst *,struct obj *,BOOLEAN_P));
13 STATIC_OVL const char *
15 register struct obj *otmp;
19 (otmp == uarmu) ? "shirt" :
21 (otmp == uarmf) ? "boots" :
22 (otmp == uarms) ? "shield" :
23 (otmp == uarmg) ? "gloves" :
24 (otmp == uarmc) ? cloak_simple_name(otmp) :
25 (otmp == uarmh) ? "helmet" : "armor");
29 long /* actually returns something that fits in an int */
32 #ifdef LINT /* long conv. ok */
35 return (long)( (u.ugold < 100) ? u.ugold :
36 (u.ugold > 10000) ? rnd(10000) : rnd((int) u.ugold) );
42 register struct monst *mtmp;
44 register struct obj *gold = g_at(u.ux, u.uy);
47 if (gold && ( !u.ugold || gold->quan > u.ugold || !rn2(5))) {
48 mtmp->mgold += gold->quan;
51 pline("%s quickly snatches some gold from between your %s!",
52 Monnam(mtmp), makeplural(body_part(FOOT)));
53 if(!u.ugold || !rn2(5)) {
54 if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
55 /* do not set mtmp->mavenge here; gold on the floor is fair game */
56 monflee(mtmp, 0, FALSE, FALSE);
59 u.ugold -= (tmp = somegold());
60 Your("purse feels lighter.");
62 if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
64 monflee(mtmp, 0, FALSE, FALSE);
71 long /* actually returns something that fits in an int */
75 #ifdef LINT /* long conv. ok */
78 return (long)( (umoney < 100) ? umoney :
79 (umoney > 10000) ? rnd(10000) : rnd((int) umoney) );
84 Find the first (and hopefully only) gold object in a chain.
85 Used when leprechaun (or you as leprechaun) looks for
86 someone else's gold. Returns a pointer so the gold may
87 be seized without further searching.
88 May search containers too.
89 Deals in gold only, as leprechauns don't care for lesser coins.
93 register struct obj *chain;
95 while (chain && chain->otyp != GOLD_PIECE) chain = chain->nobj;
100 Steal gold coins only. Leprechauns don't care for lesser coins.
104 register struct monst *mtmp;
106 register struct obj *fgold = g_at(u.ux, u.uy);
107 register struct obj *ygold;
110 /* skip lesser coins on the floor */
111 while (fgold && fgold->otyp != GOLD_PIECE) fgold = fgold->nexthere;
113 /* Do you have real gold? */
114 ygold = findgold(invent);
116 if (fgold && ( !ygold || fgold->quan > ygold->quan || !rn2(5))) {
117 obj_extract_self(fgold);
118 add_to_minv(mtmp, fgold);
120 pline("%s quickly snatches some gold from between your %s!",
121 Monnam(mtmp), makeplural(body_part(FOOT)));
122 if(!ygold || !rn2(5)) {
123 if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
124 monflee(mtmp, 0, FALSE, FALSE);
127 const int gold_price = objects[GOLD_PIECE].oc_cost;
128 tmp = (somegold(money_cnt(invent)) + gold_price - 1) / gold_price;
129 tmp = min(tmp, ygold->quan);
130 if (tmp < ygold->quan) ygold = splitobj(ygold, tmp);
132 add_to_minv(mtmp, ygold);
133 Your("purse feels lighter.");
134 if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
135 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)) impossible("stealarm(): dead monster stealing");
156 if(!dmgtype(mtmp->data, AD_SITM)) /* polymorphed */
159 subfrombill(otmp, shop_keeper(*u.ushops));
161 pline("%s steals %s!", Monnam(mtmp), doname(otmp));
162 (void) mpickobj(mtmp,otmp); /* may free otmp */
163 /* Implies seduction, "you gladly hand over ..."
164 so we don't set mavenge bit here. */
165 monflee(mtmp, 0, FALSE, FALSE);
166 if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
177 /* An object you're wearing has been taken off by a monster (theft or
178 seduction). Also used if a worn item gets transformed (stone to flesh). */
180 remove_worn_item(obj, unchain_ball)
182 boolean unchain_ball; /* whether to unpunish or just unwield */
189 if (obj->owornmask & W_ARMOR) {
191 impossible("Removing embedded scales?");
192 skinback(TRUE); /* uarm = uskin; uskin = 0; */
194 if (obj == uarm) (void) Armor_off();
195 else if (obj == uarmc) (void) Cloak_off();
196 else if (obj == uarmf) (void) Boots_off();
197 else if (obj == uarmg) (void) Gloves_off();
198 else if (obj == uarmh) (void) Helmet_off();
199 else if (obj == uarms) (void) Shield_off();
201 else if (obj == uarmu) (void) Shirt_off();
203 /* catchall -- should never happen */
204 else setworn((struct obj *)0, obj->owornmask & W_ARMOR);
205 } else if (obj->owornmask & W_AMUL) {
207 } else if (obj->owornmask & W_RING) {
209 } else if (obj->owornmask & W_TOOL) {
211 } else if (obj->owornmask & (W_WEP|W_SWAPWEP|W_QUIVER)) {
220 if (obj->owornmask & (W_BALL|W_CHAIN)) {
221 if (unchain_ball) unpunish();
222 } else if (obj->owornmask) {
228 /* Returns 1 when something was stolen (or at least, when N should flee now)
229 * Returns -1 if the monster died in the attempt
230 * Avoid stealing the object stealoid
233 steal(mtmp, objnambuf)
238 int tmp, could_petrify, named = 0, armordelay;
239 boolean monkey_business; /* true iff an animal is doing the thievery */
241 if (objnambuf) *objnambuf = '\0';
242 /* the following is true if successful on first of two attacks. */
243 if(!monnear(mtmp, u.ux, u.uy)) return(0);
245 /* food being eaten might already be used up but will not have
246 been removed from inventory yet; we don't want to steal that,
247 so this will cause it to be removed now */
248 if (occupation) (void) maybe_finished_meal(FALSE);
250 if (!invent || (inv_cnt() == 1 && uskin)) {
252 /* Not even a thousand men in armor can strip a naked man. */
254 pline("Somebody tries to rob you, but finds nothing to steal.");
256 pline("%s tries to rob you, but there is nothing to steal!",
258 return(1); /* let her flee */
261 monkey_business = is_animal(mtmp->data);
262 if (monkey_business) {
263 ; /* skip ring special cases */
264 } else if (Adornment & LEFT_RING) {
267 } else if (Adornment & RIGHT_RING) {
273 for(otmp = invent; otmp; otmp = otmp->nobj)
274 if ((!uarm || otmp != uarmc) && otmp != uskin
275 #ifdef INVISIBLE_OBJECTS
276 && (!otmp->oinvis || perceives(mtmp->data))
279 tmp += ((otmp->owornmask &
280 (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1);
281 if (!tmp) goto nothing_to_steal;
283 for(otmp = invent; otmp; otmp = otmp->nobj)
284 if ((!uarm || otmp != uarmc) && otmp != uskin
285 #ifdef INVISIBLE_OBJECTS
286 && (!otmp->oinvis || perceives(mtmp->data))
289 if((tmp -= ((otmp->owornmask &
290 (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1)) < 0)
293 impossible("Steal fails!");
296 /* can't steal gloves while wielding - so steal the wielded item. */
297 if (otmp == uarmg && uwep)
299 /* can't steal armor while wearing cloak - so steal the cloak. */
300 else if(otmp == uarm && uarmc) otmp = uarmc;
302 else if(otmp == uarmu && uarmc) otmp = uarmc;
303 else if(otmp == uarmu && uarm) otmp = uarm;
306 if(otmp->o_id == stealoid) return(0);
308 /* animals can't overcome curse stickiness nor unlock chains */
309 if (monkey_business) {
311 /* is the player prevented from voluntarily giving up this item?
312 (ignores loadstones; the !can_carry() check will catch those) */
314 ostuck = TRUE; /* effectively worn; curse is implicit */
315 else if (otmp == uquiver || (otmp == uswapwep && !u.twoweap))
316 ostuck = FALSE; /* not really worn; curse doesn't matter */
318 ostuck = (otmp->cursed && otmp->owornmask);
320 if (ostuck || !can_carry(mtmp, otmp)) {
321 static const char * const how[] = { "steal","snatch","grab","take" };
323 pline("%s tries to %s your %s but gives up.",
324 Monnam(mtmp), how[rn2(SIZE(how))],
325 (otmp->owornmask & W_ARMOR) ? equipname(otmp) :
327 /* the fewer items you have, the less likely the thief
328 is going to stick around to try again (0) instead of
330 return !rn2(inv_cnt() / 5 + 2);
334 if (otmp->otyp == LEASH && otmp->leashmon) {
335 if (monkey_business && otmp->cursed) goto cant_take;
339 /* you're going to notice the theft... */
342 if((otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))){
343 switch(otmp->oclass) {
347 case FOOD_CLASS: /* meat ring */
348 remove_worn_item(otmp, TRUE);
351 armordelay = objects[otmp->otyp].oc_delay;
352 /* Stop putting on armor which has been stolen. */
354 remove_worn_item(otmp, TRUE);
356 } else if (monkey_business) {
357 /* animals usually don't have enough patience
358 to take off items which require extra time */
359 if (armordelay >= 1 && rn2(10)) goto cant_take;
360 remove_worn_item(otmp, TRUE);
363 int curssv = otmp->cursed;
365 boolean seen = canspotmon(mtmp);
368 /* can't charm you without first waking you */
369 if (multi < 0 && is_fainted()) unmul((char *)0);
370 slowly = (armordelay >= 1 || multi < 0);
372 pline("%s charms you. You gladly %s your %s.",
373 !seen ? "She" : Monnam(mtmp),
374 curssv ? "let her take" :
375 slowly ? "start removing" : "hand over",
378 pline("%s seduces you and %s off your %s.",
379 !seen ? "She" : Adjmonnam(mtmp, "beautiful"),
380 curssv ? "helps you to take" :
381 slowly ? "you start taking" : "you take",
384 /* the following is to set multi for later on */
386 remove_worn_item(otmp, TRUE);
387 otmp->cursed = curssv;
394 stealoid = otmp->o_id;
395 stealmid = mtmp->m_id;
402 impossible("Tried to steal a strange worn thing. [%d]",
406 else if (otmp->owornmask)
407 remove_worn_item(otmp, TRUE);
409 /* do this before removing it from inventory */
410 if (objnambuf) Strcpy(objnambuf, yname(otmp));
411 /* set mavenge bit so knights won't suffer an
412 * alignment penalty during retaliation;
417 pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp));
418 could_petrify = (otmp->otyp == CORPSE &&
419 touch_petrifies(&mons[otmp->corpsenm]));
420 (void) mpickobj(mtmp,otmp); /* may free otmp */
421 if (could_petrify && !(mtmp->misc_worn_check & W_ARMG)) {
422 minstapetrify(mtmp, TRUE);
425 return((multi < 0) ? 0 : 1);
431 /* Returns 1 if otmp is free'd, 0 otherwise. */
434 register struct monst *mtmp;
435 register struct obj *otmp;
440 if (otmp->oclass == COIN_CLASS) {
441 mtmp->mgold += otmp->quan;
442 obfree(otmp, (struct obj *)0);
446 boolean snuff_otmp = FALSE;
447 /* don't want hidden light source inside the monster; assumes that
448 engulfers won't have external inventories; whirly monsters cause
449 the light to be extinguished rather than letting it shine thru */
450 if (otmp->lamplit && /* hack to avoid function calls for most objs */
451 obj_sheds_light(otmp) &&
452 attacktype(mtmp->data, AT_ENGL)) {
453 /* this is probably a burning object that you dropped or threw */
454 if (u.uswallow && mtmp == u.ustuck && !Blind)
455 pline("%s out.", Tobjnam(otmp, "go"));
458 /* Must do carrying effects on object prior to add_to_minv() */
459 carry_obj_effects(otmp);
460 /* add_to_minv() might free otmp [if merged with something else],
461 so we have to call it after doing the object checks */
462 freed_otmp = add_to_minv(mtmp, otmp);
463 /* and we had to defer this until object is in mtmp's inventory */
464 if (snuff_otmp) snuff_light_source(mtmp->mx, mtmp->my);
478 struct obj *otmp = (struct obj *)0;
481 /* select the artifact to steal */
483 real = AMULET_OF_YENDOR;
484 fake = FAKE_AMULET_OF_YENDOR;
485 } else if(u.uhave.questart) {
486 for(otmp = invent; otmp; otmp = otmp->nobj)
487 if(is_quest_artifact(otmp)) break;
488 if (!otmp) return; /* should we panic instead? */
489 } else if(u.uhave.bell) {
490 real = BELL_OF_OPENING;
492 } else if(u.uhave.book) {
493 real = SPE_BOOK_OF_THE_DEAD;
494 } else if(u.uhave.menorah) {
495 real = CANDELABRUM_OF_INVOCATION;
496 } else return; /* you have nothing of special interest */
499 /* If we get here, real and fake have been set up. */
500 for(otmp = invent; otmp; otmp = otmp->nobj)
501 if(otmp->otyp == real || (otmp->otyp == fake && !mtmp->iswiz))
505 if (otmp) { /* we have something to snatch */
507 remove_worn_item(otmp, TRUE);
509 /* mpickobj wont merge otmp because none of the above things
510 to steal are mergable */
511 (void) mpickobj(mtmp,otmp); /* may merge and free otmp */
512 pline("%s stole %s!", Monnam(mtmp), doname(otmp));
513 if (can_teleport(mtmp->data) && !tele_restrict(mtmp))
514 (void) rloc(mtmp, FALSE);
521 /* drop one object taken from a (possibly dead) monster's inventory */
523 mdrop_obj(mon, obj, verbosely)
528 int omx = mon->mx, omy = mon->my;
530 if (obj->owornmask) {
531 /* perform worn item handling if the monster is still alive */
533 mon->misc_worn_check &= ~obj->owornmask;
534 update_mon_intrinsics(mon, obj, FALSE, TRUE);
535 /* obj_no_longer_held(obj); -- done by place_object */
536 if (obj->owornmask & W_WEP) setmnotwielded(mon, obj);
538 /* don't charge for an owned saddle on dead steed */
539 } else if (mon->mtame && (obj->owornmask & W_SADDLE) &&
540 !obj->unpaid && costly_spot(omx, omy)) {
546 if (verbosely && cansee(omx, omy))
547 pline("%s drops %s.", Monnam(mon), distant_name(obj, doname));
548 if (!flooreffects(obj, omx, omy, "fall")) {
549 place_object(obj, omx, omy);
554 /* some monsters bypass the normal rules for moving between levels or
555 even leaving the game entirely; when that happens, prevent them from
556 taking the Amulet or invocation tools with them */
558 mdrop_special_objs(mon)
561 struct obj *obj, *otmp;
563 for (obj = mon->minvent; obj; obj = otmp) {
565 /* the Amulet, invocation tools, and Rider corpses resist even when
566 artifacts and ordinary objects are given 0% resistance chance */
567 if (obj_resists(obj, 0, 0)) {
568 obj_extract_self(obj);
569 mdrop_obj(mon, obj, FALSE);
574 /* release the objects the creature is carrying */
576 relobj(mtmp,show,is_pet)
577 register struct monst *mtmp;
579 boolean is_pet; /* If true, pet should keep wielded/worn items */
581 register struct obj *otmp;
582 register int omx = mtmp->mx, omy = mtmp->my;
583 struct obj *keepobj = 0;
584 struct obj *wep = MON_WEP(mtmp);
585 boolean item1 = FALSE, item2 = FALSE;
587 if (!is_pet || mindless(mtmp->data) || is_animal(mtmp->data))
588 item1 = item2 = TRUE;
589 if (!tunnels(mtmp->data) || !needspick(mtmp->data))
592 while ((otmp = mtmp->minvent) != 0) {
593 obj_extract_self(otmp);
594 /* special case: pick-axe and unicorn horn are non-worn */
595 /* items that we also want pets to keep 1 of */
596 /* (It is a coincidence that these can also be wielded.) */
597 if (otmp->owornmask || otmp == wep ||
598 ((!item1 && otmp->otyp == PICK_AXE) ||
599 (!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) {
600 if (is_pet) { /* dont drop worn/wielded item */
601 if (otmp->otyp == PICK_AXE)
603 if (otmp->otyp == UNICORN_HORN && !otmp->cursed)
605 otmp->nobj = keepobj;
610 mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
613 /* put kept objects back */
614 while ((otmp = keepobj) != (struct obj *)0) {
615 keepobj = otmp->nobj;
616 (void) add_to_minv(mtmp, otmp);
620 register long g = mtmp->mgold;
621 (void) mkgold(g, omx, omy);
622 if (is_pet && cansee(omx, omy) && flags.verbose)
623 pline("%s drops %ld gold piece%s.", Monnam(mtmp),
629 if (show & cansee(omx, omy))