OSDN Git Service

update year to 2020
[jnethack/source.git] / src / steal.c
1 /* NetHack 3.6  steal.c $NHDT-Date: 1570566382 2019/10/08 20:26:22 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.75 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2012. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 #include "hack.h"
12
13 STATIC_PTR int NDECL(stealarm);
14
15 STATIC_DCL const char *FDECL(equipname, (struct obj *));
16
17 STATIC_OVL const char *
18 equipname(otmp)
19 register struct obj *otmp;
20 {
21     return ((otmp == uarmu)
22 /*JP
23                 ? "shirt"
24 */
25                 ? "\83V\83\83\83c"
26                 : (otmp == uarmf)
27 /*JP
28                       ? "boots"
29 */
30                       ? "\8cC"
31                       : (otmp == uarms)
32 /*JP
33                             ? "shield"
34 */
35                             ? "\8f\82"
36                             : (otmp == uarmg)
37 /*JP
38                                   ? "gloves"
39 */
40                                   ? "\8f¬\8eè"
41                                   : (otmp == uarmc)
42                                         ? cloak_simple_name(otmp)
43                                         : (otmp == uarmh)
44                                               ? helm_simple_name(otmp)
45                                               : suit_simple_name(otmp));
46 }
47
48 /* proportional subset of gold; return value actually fits in an int */
49 long
50 somegold(lmoney)
51 long lmoney;
52 {
53 #ifdef LINT /* long conv. ok */
54     int igold = 0;
55 #else
56     int igold = (lmoney >= (long) LARGEST_INT) ? LARGEST_INT : (int) lmoney;
57 #endif
58
59     if (igold < 50)
60         ; /* all gold */
61     else if (igold < 100)
62         igold = rn1(igold - 25 + 1, 25);
63     else if (igold < 500)
64         igold = rn1(igold - 50 + 1, 50);
65     else if (igold < 1000)
66         igold = rn1(igold - 100 + 1, 100);
67     else if (igold < 5000)
68         igold = rn1(igold - 500 + 1, 500);
69     else if (igold < 10000)
70         igold = rn1(igold - 1000 + 1, 1000);
71     else
72         igold = rn1(igold - 5000 + 1, 5000);
73
74     return (long) igold;
75 }
76
77 /*
78  * Find the first (and hopefully only) gold object in a chain.
79  * Used when leprechaun (or you as leprechaun) looks for
80  * someone else's gold.  Returns a pointer so the gold may
81  * be seized without further searching.
82  * May search containers too.
83  * Deals in gold only, as leprechauns don't care for lesser coins.
84 */
85 struct obj *
86 findgold(chain)
87 register struct obj *chain;
88 {
89     while (chain && chain->otyp != GOLD_PIECE)
90         chain = chain->nobj;
91     return chain;
92 }
93
94 /*
95  * Steal gold coins only.  Leprechauns don't care for lesser coins.
96 */
97 void
98 stealgold(mtmp)
99 register struct monst *mtmp;
100 {
101     register struct obj *fgold = g_at(u.ux, u.uy);
102     register struct obj *ygold;
103     register long tmp;
104 #if 0 /*JP*/
105     struct monst *who;
106     const char *whose, *what;
107 #endif
108
109     /* skip lesser coins on the floor */
110     while (fgold && fgold->otyp != GOLD_PIECE)
111         fgold = fgold->nexthere;
112
113     /* Do you have real gold? */
114     ygold = findgold(invent);
115
116     if (fgold && (!ygold || fgold->quan > ygold->quan || !rn2(5))) {
117         obj_extract_self(fgold);
118         add_to_minv(mtmp, fgold);
119         newsym(u.ux, u.uy);
120 #if 0 /*JP*/
121         if (u.usteed) {
122             who = u.usteed;
123             whose = s_suffix(y_monnam(who));
124             what = makeplural(mbodypart(who, FOOT));
125         } else {
126             who = &youmonst;
127             whose = "your";
128             what = makeplural(body_part(FOOT));
129         }
130         /* [ avoid "between your rear regions" :-] */
131         if (slithy(who->data))
132             what = "coils";
133         /* reduce "rear hooves/claws" to "hooves/claws" */
134         if (!strncmp(what, "rear ", 5))
135             what += 5;
136         pline("%s quickly snatches some gold from %s %s %s!", Monnam(mtmp),
137               (Levitation || Flying) ? "beneath" : "between", whose, what);
138 #else /*JP:\91«\82ª\96³\82­\82Ä\82à\81u\91«\8c³\81v\82Å\82æ\82µ\82Æ\82·\82é*/
139         pline("%s\82Í\91f\91\81\82­\82 \82È\82½\82Ì%s\82©\82ç\8bà\82ð\82Ð\82Á\82½\82­\82Á\82½\81I", Monnam(mtmp),
140               (Levitation || Flying) ? "\89º" : "\91«\8c³");
141 #endif
142         if (!ygold || !rn2(5)) {
143             if (!tele_restrict(mtmp))
144                 (void) rloc(mtmp, TRUE);
145             monflee(mtmp, 0, FALSE, FALSE);
146         }
147     } else if (ygold) {
148         const int gold_price = objects[GOLD_PIECE].oc_cost;
149
150         tmp = (somegold(money_cnt(invent)) + gold_price - 1) / gold_price;
151         tmp = min(tmp, ygold->quan);
152         if (tmp < ygold->quan)
153             ygold = splitobj(ygold, tmp);
154         else
155             setnotworn(ygold);
156         freeinv(ygold);
157         add_to_minv(mtmp, ygold);
158 /*JP
159         Your("purse feels lighter.");
160 */
161         Your("\8dà\95z\82Í\8cy\82­\82È\82Á\82½\81D");
162         if (!tele_restrict(mtmp))
163             (void) rloc(mtmp, TRUE);
164         monflee(mtmp, 0, FALSE, FALSE);
165         context.botl = 1;
166     }
167 }
168
169 /* steal armor after you finish taking it off */
170 unsigned int stealoid; /* object to be stolen */
171 unsigned int stealmid; /* monster doing the stealing */
172
173 STATIC_PTR int
174 stealarm(VOID_ARGS)
175 {
176     register struct monst *mtmp;
177     register struct obj *otmp;
178
179     for (otmp = invent; otmp; otmp = otmp->nobj) {
180         if (otmp->o_id == stealoid) {
181             for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
182                 if (mtmp->m_id == stealmid) {
183                     if (DEADMONSTER(mtmp))
184                         impossible("stealarm(): dead monster stealing");
185                     if (!dmgtype(mtmp->data, AD_SITM)) /* polymorphed */
186                         goto botm;
187                     if (otmp->unpaid)
188                         subfrombill(otmp, shop_keeper(*u.ushops));
189                     freeinv(otmp);
190 /*JP
191                     pline("%s steals %s!", Monnam(mtmp), doname(otmp));
192 */
193                     pline("%s\82Í%s\82ð\93\90\82ñ\82¾\81I", Monnam(mtmp), doname(otmp));
194                     (void) mpickobj(mtmp, otmp); /* may free otmp */
195                     /* Implies seduction, "you gladly hand over ..."
196                        so we don't set mavenge bit here. */
197                     monflee(mtmp, 0, FALSE, FALSE);
198                     if (!tele_restrict(mtmp))
199                         (void) rloc(mtmp, TRUE);
200                     break;
201                 }
202             }
203             break;
204         }
205     }
206  botm:
207     stealoid = 0;
208     return 0;
209 }
210
211 /* An object you're wearing has been taken off by a monster (theft or
212    seduction).  Also used if a worn item gets transformed (stone to flesh). */
213 void
214 remove_worn_item(obj, unchain_ball)
215 struct obj *obj;
216 boolean unchain_ball; /* whether to unpunish or just unwield */
217 {
218     if (donning(obj))
219         cancel_don();
220     if (!obj->owornmask)
221         return;
222
223     if (obj->owornmask & W_ARMOR) {
224         if (obj == uskin) {
225             impossible("Removing embedded scales?");
226             skinback(TRUE); /* uarm = uskin; uskin = 0; */
227         }
228         if (obj == uarm)
229             (void) Armor_off();
230         else if (obj == uarmc)
231             (void) Cloak_off();
232         else if (obj == uarmf)
233             (void) Boots_off();
234         else if (obj == uarmg)
235             (void) Gloves_off();
236         else if (obj == uarmh)
237             (void) Helmet_off();
238         else if (obj == uarms)
239             (void) Shield_off();
240         else if (obj == uarmu)
241             (void) Shirt_off();
242         /* catchall -- should never happen */
243         else
244             setworn((struct obj *) 0, obj->owornmask & W_ARMOR);
245     } else if (obj->owornmask & W_AMUL) {
246         Amulet_off();
247     } else if (obj->owornmask & W_RING) {
248         Ring_gone(obj);
249     } else if (obj->owornmask & W_TOOL) {
250         Blindf_off(obj);
251     } else if (obj->owornmask & W_WEAPONS) {
252         if (obj == uwep)
253             uwepgone();
254         if (obj == uswapwep)
255             uswapwepgone();
256         if (obj == uquiver)
257             uqwepgone();
258     }
259
260     if (obj->owornmask & (W_BALL | W_CHAIN)) {
261         if (unchain_ball)
262             unpunish();
263     } else if (obj->owornmask) {
264         /* catchall */
265         setnotworn(obj);
266     }
267 }
268
269 /* Returns 1 when something was stolen (or at least, when N should flee now)
270  * Returns -1 if the monster died in the attempt
271  * Avoid stealing the object stealoid
272  * Nymphs and monkeys won't steal coins
273  */
274 int
275 steal(mtmp, objnambuf)
276 struct monst *mtmp;
277 char *objnambuf;
278 {
279     struct obj *otmp;
280     int tmp, could_petrify, armordelay, olddelay, icnt,
281         named = 0, retrycnt = 0;
282     boolean monkey_business, /* true iff an animal is doing the thievery */
283             was_doffing, was_punished = Punished;
284
285     if (objnambuf)
286         *objnambuf = '\0';
287     /* the following is true if successful on first of two attacks. */
288     if (!monnear(mtmp, u.ux, u.uy))
289         return 0;
290
291     /* food being eaten might already be used up but will not have
292        been removed from inventory yet; we don't want to steal that,
293        so this will cause it to be removed now */
294     if (occupation)
295         (void) maybe_finished_meal(FALSE);
296
297     icnt = inv_cnt(FALSE); /* don't include gold */
298     if (!icnt || (icnt == 1 && uskin)) {
299  nothing_to_steal:
300         /* Not even a thousand men in armor can strip a naked man. */
301         if (Blind)
302 /*JP
303             pline("Somebody tries to rob you, but finds nothing to steal.");
304 */
305             pline("\92N\82©\82ª\82 \82È\82½\82©\82ç\93\90\82à\82¤\82Æ\82µ\82½\82ª\81C\93\90\82Þ\82à\82Ì\82ª\82È\82¢\82±\82Æ\82É\8bC\82ª\82Â\82¢\82½\81D");
306         else if (inv_cnt(TRUE) > inv_cnt(FALSE)) /* ('icnt' might be stale) */
307 /*JP
308             pline("%s tries to rob you, but isn't interested in gold.",
309 */
310             pline("%s\82Í\82 \82È\82½\82©\82ç\93\90\82à\82¤\82Æ\82µ\82½\82ª\81C\82¨\8bà\82É\82Í\8b»\96¡\82ª\82È\82¢\81D",
311                   Monnam(mtmp));
312         else
313 /*JP
314             pline("%s tries to rob you, but there is nothing to steal!",
315 */
316             pline("%s\82Í\82 \82È\82½\82©\82ç\93\90\82à\82¤\82Æ\82µ\82½\82ª\81C\93\90\82Þ\82à\82Ì\82ª\82È\82¢\82±\82Æ\82É\8bC\82ª\82Â\82¢\82½\81I",
317                   Monnam(mtmp));
318         return 1; /* let her flee */
319     }
320
321     monkey_business = is_animal(mtmp->data);
322     if (monkey_business || uarmg) {
323         ; /* skip ring special cases */
324     } else if (Adornment & LEFT_RING) {
325         otmp = uleft;
326         goto gotobj;
327     } else if (Adornment & RIGHT_RING) {
328         otmp = uright;
329         goto gotobj;
330     }
331
332  retry:
333     tmp = 0;
334     for (otmp = invent; otmp; otmp = otmp->nobj)
335         if ((!uarm || otmp != uarmc) && otmp != uskin
336             && otmp->oclass != COIN_CLASS)
337             tmp += (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) ? 5 : 1;
338     if (!tmp)
339         goto nothing_to_steal;
340     tmp = rn2(tmp);
341     for (otmp = invent; otmp; otmp = otmp->nobj)
342         if ((!uarm || otmp != uarmc) && otmp != uskin
343             && otmp->oclass != COIN_CLASS) {
344             tmp -= (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) ? 5 : 1;
345             if (tmp < 0)
346                 break;
347         }
348     if (!otmp) {
349         impossible("Steal fails!");
350         return 0;
351     }
352     /* can't steal ring(s) while wearing gloves */
353     if ((otmp == uleft || otmp == uright) && uarmg)
354         otmp = uarmg;
355     /* can't steal gloves while wielding - so steal the wielded item. */
356     if (otmp == uarmg && uwep)
357         otmp = uwep;
358     /* can't steal armor while wearing cloak - so steal the cloak. */
359     else if (otmp == uarm && uarmc)
360         otmp = uarmc;
361     /* can't steal shirt while wearing cloak or suit */
362     else if (otmp == uarmu && uarmc)
363         otmp = uarmc;
364     else if (otmp == uarmu && uarm)
365         otmp = uarm;
366
367  gotobj:
368     if (otmp->o_id == stealoid)
369         return 0;
370
371     if (otmp->otyp == BOULDER && !throws_rocks(mtmp->data)) {
372         if (!retrycnt++)
373             goto retry;
374         goto cant_take;
375     }
376     /* animals can't overcome curse stickiness nor unlock chains */
377     if (monkey_business) {
378         boolean ostuck;
379
380         /* is the player prevented from voluntarily giving up this item?
381            (ignores loadstones; the !can_carry() check will catch those) */
382         if (otmp == uball)
383             ostuck = TRUE; /* effectively worn; curse is implicit */
384         else if (otmp == uquiver || (otmp == uswapwep && !u.twoweap))
385             ostuck = FALSE; /* not really worn; curse doesn't matter */
386         else
387             ostuck = ((otmp->cursed && otmp->owornmask)
388                       /* nymphs can steal rings from under
389                          cursed weapon but animals can't */
390                       || (otmp == uright && welded(uwep))
391                       || (otmp == uleft && welded(uwep) && bimanual(uwep)));
392
393         if (ostuck || can_carry(mtmp, otmp) == 0) {
394 #if 0 /*JP*/
395             static const char *const how[] = { "steal", "snatch", "grab",
396                                                "take" };
397  cant_take:
398             pline("%s tries to %s %s%s but gives up.", Monnam(mtmp),
399                   how[rn2(SIZE(how))],
400                   (otmp->owornmask & W_ARMOR) ? "your " : "",
401                   (otmp->owornmask & W_ARMOR) ? equipname(otmp)
402                                               : yname(otmp));
403 #else
404         cant_take:
405             pline("%s\82Í%s\82ð\93\90\82à\82¤\82Æ\82µ\82½\82ª\92ú\82ß\82½\81D", Monnam(mtmp),
406                   (otmp->owornmask & W_ARMOR) ? equipname(otmp)
407                                               : yname(otmp));
408 #endif
409             /* the fewer items you have, the less likely the thief
410                is going to stick around to try again (0) instead of
411                running away (1) */
412             return !rn2(inv_cnt(FALSE) / 5 + 2);
413         }
414     }
415
416     if (otmp->otyp == LEASH && otmp->leashmon) {
417         if (monkey_business && otmp->cursed)
418             goto cant_take;
419         o_unleash(otmp);
420     }
421
422     was_doffing = doffing(otmp);
423     /* stop donning/doffing now so that afternmv won't be clobbered
424        below; stop_occupation doesn't handle donning/doffing */
425     olddelay = stop_donning(otmp);
426     /* you're going to notice the theft... */
427     stop_occupation();
428
429     if (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) {
430         switch (otmp->oclass) {
431         case TOOL_CLASS:
432         case AMULET_CLASS:
433         case RING_CLASS:
434         case FOOD_CLASS: /* meat ring */
435             remove_worn_item(otmp, TRUE);
436             break;
437         case ARMOR_CLASS:
438             armordelay = objects[otmp->otyp].oc_delay;
439             if (olddelay > 0 && olddelay < armordelay)
440                 armordelay = olddelay;
441             if (monkey_business) {
442                 /* animals usually don't have enough patience
443                    to take off items which require extra time */
444                 if (armordelay >= 1 && !olddelay && rn2(10))
445                     goto cant_take;
446                 remove_worn_item(otmp, TRUE);
447                 break;
448             } else {
449                 int curssv = otmp->cursed;
450                 int slowly;
451                 boolean seen = canspotmon(mtmp);
452
453                 otmp->cursed = 0;
454                 /* can't charm you without first waking you */
455                 if (Unaware)
456                     unmul((char *) 0);
457                 slowly = (armordelay >= 1 || multi < 0);
458                 if (flags.female)
459 #if 0 /*JP:T*/
460                     pline("%s charms you.  You gladly %s your %s.",
461                           !seen ? "She" : Monnam(mtmp),
462                           curssv ? "let her take"
463                                  : !slowly ? "hand over"
464                                            : was_doffing ? "continue removing"
465                                                          : "start removing",
466                           equipname(otmp));
467 #else
468                     pline("%s\82Í\82 \82È\82½\82ð\96£\97¹\82µ\82½\81D\82 \82È\82½\82Í\82æ\82ë\82±\82ñ\82Å%s\82ð%s\82½\81D",
469                           !seen ? "\94Þ\8f\97" : Monnam(mtmp),
470                           equipname(otmp),
471                           curssv ? "\82Í\82¸\82µ\82Ä\82à\82ç\82Á"
472                                  : !slowly ? "\82Í\82¸\82µ\82Ä\8eè\93n\82µ"
473                                            : was_doffing ? "\82Í\82¸\82µ\91±\82¯"
474                                                          : "\82Í\82¸\82µ\8en\82ß");
475 #endif
476                 else
477 #if 0 /*JP:T*/
478                     pline("%s seduces you and %s off your %s.",
479                           !seen ? "She" : Adjmonnam(mtmp, "beautiful"),
480                           curssv
481                               ? "helps you to take"
482                               : !slowly ? "you take"
483                                         : was_doffing ? "you continue taking"
484                                                       : "you start taking",
485                           equipname(otmp));
486 #else
487                     pline("%s\82Í\82 \82È\82½\82ð\97U\98f\82µ\82½\81D\82 \82È\82½\82Í%s\82ð%s\81D",
488                           !seen ? "\94Þ\8f\97" : Adjmonnam(mtmp, "\94ü\82µ\82¢"),
489                           equipname(otmp),
490                           curssv
491                               ? "\82Í\82¸\82µ\82Ä\82à\82ç\82Á"
492                               : !slowly ? "\82Í\82¸\82µ"
493                                         : was_doffing ? "\82Í\82¸\82µ\91±\82¯"
494                                                       : "\82Í\82¸\82µ\8en\82ß");
495 #endif
496                 named++;
497                 /* the following is to set multi for later on */
498                 nomul(-armordelay);
499 /*JP
500                 multi_reason = "taking off clothes";
501 */
502                 multi_reason = "\95\9e\82ð\92E\82¢\82Å\82¢\82é\8e\9e\82É";
503                 nomovemsg = 0;
504                 remove_worn_item(otmp, TRUE);
505                 otmp->cursed = curssv;
506                 if (multi < 0) {
507                     /*
508                     multi = 0;
509                     afternmv = 0;
510                     */
511                     stealoid = otmp->o_id;
512                     stealmid = mtmp->m_id;
513                     afternmv = stealarm;
514                     return 0;
515                 }
516             }
517             break;
518         default:
519             impossible("Tried to steal a strange worn thing. [%d]",
520                        otmp->oclass);
521         }
522     } else if (otmp->owornmask) /* weapon or ball&chain */
523         remove_worn_item(otmp, TRUE);
524
525     /* do this before removing it from inventory */
526     if (objnambuf)
527         Strcpy(objnambuf, yname(otmp));
528     /* usually set mavenge bit so knights won't suffer an alignment penalty
529        during retaliation; not applicable for removing attached iron ball */
530     if (!Conflict && !(was_punished && !Punished))
531         mtmp->mavenge = 1;
532
533     if (otmp->unpaid)
534         subfrombill(otmp, shop_keeper(*u.ushops));
535     freeinv(otmp);
536     /* if attached ball was taken, uball and uchain are now Null */
537 #if 0 /*JP:T*/
538     pline("%s%s stole %s.", named ? "She" : Monnam(mtmp),
539           (was_punished && !Punished) ? " removed your chain and" : "",
540           doname(otmp));
541 #else
542     pline("%s\82Í%s%s\82ð\93\90\82ñ\82¾\81D", named ? "\94Þ\8f\97" : Monnam(mtmp),
543           (was_punished && !Punished) ? "\82 \82È\82½\82Ì\8d½\82ð\82Í\82¸\82µ\82Ä" : "",
544           doname(otmp));
545 #endif
546     could_petrify = (otmp->otyp == CORPSE
547                      && touch_petrifies(&mons[otmp->corpsenm]));
548     (void) mpickobj(mtmp, otmp); /* may free otmp */
549     if (could_petrify && !(mtmp->misc_worn_check & W_ARMG)) {
550         minstapetrify(mtmp, TRUE);
551         return -1;
552     }
553     return (multi < 0) ? 0 : 1;
554 }
555
556 /* Returns 1 if otmp is free'd, 0 otherwise. */
557 int
558 mpickobj(mtmp, otmp)
559 register struct monst *mtmp;
560 register struct obj *otmp;
561 {
562     int freed_otmp;
563     boolean snuff_otmp = FALSE;
564
565     if (!otmp) {
566         impossible("monster (%s) taking or picking up nothing?",
567                    mtmp->data->mname);
568         return 1;
569     } else if (otmp == uball || otmp == uchain) {
570         impossible("monster (%s) taking or picking up attached %s (%s)?",
571                    mtmp->data->mname,
572                    (otmp == uchain) ? "chain" : "ball", simpleonames(otmp));
573         return 0;
574     }
575     /* if monster is acquiring a thrown or kicked object, the throwing
576        or kicking code shouldn't continue to track and place it */
577     if (otmp == thrownobj)
578         thrownobj = 0;
579     else if (otmp == kickedobj)
580         kickedobj = 0;
581     /* don't want hidden light source inside the monster; assumes that
582        engulfers won't have external inventories; whirly monsters cause
583        the light to be extinguished rather than letting it shine thru */
584     if (obj_sheds_light(otmp) && attacktype(mtmp->data, AT_ENGL)) {
585         /* this is probably a burning object that you dropped or threw */
586         if (u.uswallow && mtmp == u.ustuck && !Blind)
587 /*JP
588             pline("%s out.", Tobjnam(otmp, "go"));
589 */
590             pline("%s\82Í\94ò\82Ñ\82¾\82µ\82½\81D", xname(otmp));
591         snuff_otmp = TRUE;
592     }
593     /* for hero owned object on shop floor, mtmp is taking possession
594        and if it's eventually dropped in a shop, shk will claim it */
595     if (!mtmp->mtame)
596         otmp->no_charge = 0;
597     /* Must do carrying effects on object prior to add_to_minv() */
598     carry_obj_effects(otmp);
599     /* add_to_minv() might free otmp [if merged with something else],
600        so we have to call it after doing the object checks */
601     freed_otmp = add_to_minv(mtmp, otmp);
602     /* and we had to defer this until object is in mtmp's inventory */
603     if (snuff_otmp)
604         snuff_light_source(mtmp->mx, mtmp->my);
605     return freed_otmp;
606 }
607
608 /* called for AD_SAMU (the Wizard and quest nemeses) */
609 void
610 stealamulet(mtmp)
611 struct monst *mtmp;
612 {
613     char buf[BUFSZ];
614     struct obj *otmp = 0, *obj = 0;
615     int real = 0, fake = 0, n;
616
617     /* target every quest artifact, not just current role's;
618        if hero has more than one, choose randomly so that player
619        can't use inventory ordering to influence the theft */
620     for (n = 0, obj = invent; obj; obj = obj->nobj)
621         if (any_quest_artifact(obj))
622             ++n, otmp = obj;
623     if (n > 1) {
624         n = rnd(n);
625         for (otmp = invent; otmp; otmp = otmp->nobj)
626             if (any_quest_artifact(otmp) && !--n)
627                 break;
628     }
629
630     if (!otmp) {
631         /* if we didn't find any quest arifact, find another valuable item */
632         if (u.uhave.amulet) {
633             real = AMULET_OF_YENDOR;
634             fake = FAKE_AMULET_OF_YENDOR;
635         } else if (u.uhave.bell) {
636             real = BELL_OF_OPENING;
637             fake = BELL;
638         } else if (u.uhave.book) {
639             real = SPE_BOOK_OF_THE_DEAD;
640         } else if (u.uhave.menorah) {
641             real = CANDELABRUM_OF_INVOCATION;
642         } else
643             return; /* you have nothing of special interest */
644
645         /* If we get here, real and fake have been set up. */
646         for (n = 0, obj = invent; obj; obj = obj->nobj)
647             if (obj->otyp == real || (obj->otyp == fake && !mtmp->iswiz))
648                 ++n, otmp = obj;
649         if (n > 1) {
650             n = rnd(n);
651             for (otmp = invent; otmp; otmp = otmp->nobj)
652                 if ((otmp->otyp == real
653                      || (otmp->otyp == fake && !mtmp->iswiz)) && !--n)
654                     break;
655         }
656     }
657
658     if (otmp) { /* we have something to snatch */
659         /* take off outer gear if we're targetting [hypothetical]
660            quest artifact suit, shirt, gloves, or rings */
661         if ((otmp == uarm || otmp == uarmu) && uarmc)
662             remove_worn_item(uarmc, FALSE);
663         if (otmp == uarmu && uarm)
664             remove_worn_item(uarm, FALSE);
665         if ((otmp == uarmg || ((otmp == uright || otmp == uleft) && uarmg))
666             && uwep) {
667             /* gloves are about to be unworn; unwield weapon(s) first */
668             if (u.twoweap)    /* remove_worn_item(uswapwep) indirectly */
669                 remove_worn_item(uswapwep, FALSE); /* clears u.twoweap */
670             remove_worn_item(uwep, FALSE);
671         }
672         if ((otmp == uright || otmp == uleft) && uarmg)
673             /* calls Gloves_off() to handle wielded cockatrice corpse */
674             remove_worn_item(uarmg, FALSE);
675
676         /* finally, steal the target item */
677         if (otmp->owornmask)
678             remove_worn_item(otmp, TRUE);
679         if (otmp->unpaid)
680             subfrombill(otmp, shop_keeper(*u.ushops));
681         freeinv(otmp);
682         Strcpy(buf, doname(otmp));
683         (void) mpickobj(mtmp, otmp); /* could merge and free otmp but won't */
684 /*JP
685         pline("%s steals %s!", Monnam(mtmp), buf);
686 */
687         pline("%s\82Í%s\82ð\93\90\82ñ\82¾\81I", Monnam(mtmp), buf);
688         if (can_teleport(mtmp->data) && !tele_restrict(mtmp))
689             (void) rloc(mtmp, TRUE);
690     }
691 }
692
693 /* when a mimic gets poked with something, it might take that thing
694    (at present, only implemented for when the hero does the poking) */
695 void
696 maybe_absorb_item(mon, obj, ochance, achance)
697 struct monst *mon;
698 struct obj *obj;
699 int ochance, achance; /* percent chance for ordinary item, artifact */
700 {
701     if (obj == uball || obj == uchain || obj->oclass == ROCK_CLASS
702         || obj_resists(obj, 100 - ochance, 100 - achance)
703         || !touch_artifact(obj, mon))
704         return;
705
706     if (carried(obj)) {
707         if (obj->owornmask)
708             remove_worn_item(obj, TRUE);
709         if (obj->unpaid)
710             subfrombill(obj, shop_keeper(*u.ushops));
711         if (cansee(mon->mx, mon->my)) {
712             const char *MonName = Monnam(mon);
713
714 #if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\95s\97v*/
715             /* mon might be invisible; avoid "It pulls ... and absorbs it!" */
716             if (!strcmp(MonName, "It"))
717                 MonName = "Something";
718 #endif
719 #if 0 /*JP:T*/
720             pline("%s pulls %s away from you and absorbs %s!", MonName,
721                   yname(obj), (obj->quan > 1L) ? "them" : "it");
722 #else
723             pline("%s\82Í%s\82ð\88ø\82Á\82Ï\82è\8d\9e\82ñ\82Å\8bz\8eû\82µ\82½\81I", MonName,
724                   yname(obj));
725 #endif
726         } else {
727             const char *hand_s = body_part(HAND);
728
729             if (bimanual(obj))
730                 hand_s = makeplural(hand_s);
731 #if 0 /*JP:T*/
732             pline("%s %s pulled from your %s!", upstart(yname(obj)),
733                   otense(obj, "are"), hand_s);
734 #else
735             pline("%s\82Í\82 \82È\82½\82Ì%s\82©\82ç\88ø\82Á\82Ï\82è\8d\9e\82Ü\82ê\82½\81I", upstart(yname(obj)),
736                   hand_s);
737 #endif
738         }
739         freeinv(obj);
740     } else {
741         /* not carried; presumably thrown or kicked */
742         if (canspotmon(mon))
743 /*JP
744             pline("%s absorbs %s!", Monnam(mon), yname(obj));
745 */
746             pline("%s\82Í%s\82ð\8bz\8eû\82µ\82½\81I", Monnam(mon), yname(obj));
747     }
748     /* add to mon's inventory */
749     (void) mpickobj(mon, obj);
750 }
751
752 /* drop one object taken from a (possibly dead) monster's inventory */
753 void
754 mdrop_obj(mon, obj, verbosely)
755 struct monst *mon;
756 struct obj *obj;
757 boolean verbosely;
758 {
759     int omx = mon->mx, omy = mon->my;
760     boolean update_mon = FALSE;
761
762     if (obj->owornmask) {
763         /* perform worn item handling if the monster is still alive */
764         if (!DEADMONSTER(mon)) {
765             mon->misc_worn_check &= ~obj->owornmask;
766             update_mon = TRUE;
767
768         /* don't charge for an owned saddle on dead steed (provided
769            that the hero is within the same shop at the time) */
770         } else if (mon->mtame && (obj->owornmask & W_SADDLE) != 0L
771                    && !obj->unpaid && costly_spot(omx, omy)
772                    /* being at costly_spot guarantees lev->roomno is not 0 */
773                    && index(in_rooms(u.ux, u.uy, SHOPBASE),
774                             levl[omx][omy].roomno)) {
775             obj->no_charge = 1;
776         }
777         /* this should be done even if the monster has died */
778         if (obj->owornmask & W_WEP)
779             setmnotwielded(mon, obj);
780         obj->owornmask = 0L;
781     }
782     /* obj_no_longer_held(obj); -- done by place_object */
783     if (verbosely && cansee(omx, omy))
784 /*JP
785         pline("%s drops %s.", Monnam(mon), distant_name(obj, doname));
786 */
787         pline("%s\82Í%s\82ð\92u\82¢\82½\81D", Monnam(mon), distant_name(obj, doname));
788 /*JP
789     if (!flooreffects(obj, omx, omy, "fall")) {
790 */
791     if (!flooreffects(obj, omx, omy, "\97\8e\82¿\82é")) {
792         place_object(obj, omx, omy);
793         stackobj(obj);
794     }
795     /* do this last, after placing obj on floor; removing steed's saddle
796        throws rider, possibly inflicting fatal damage and producing bones */
797     if (update_mon)
798         update_mon_intrinsics(mon, obj, FALSE, TRUE);
799 }
800
801 /* some monsters bypass the normal rules for moving between levels or
802    even leaving the game entirely; when that happens, prevent them from
803    taking the Amulet, invocation items, or quest artifact with them */
804 void
805 mdrop_special_objs(mon)
806 struct monst *mon;
807 {
808     struct obj *obj, *otmp;
809
810     for (obj = mon->minvent; obj; obj = otmp) {
811         otmp = obj->nobj;
812         /* the Amulet, invocation tools, and Rider corpses resist even when
813            artifacts and ordinary objects are given 0% resistance chance;
814            current role's quest artifact is rescued too--quest artifacts
815            for the other roles are not */
816         if (obj_resists(obj, 0, 0) || is_quest_artifact(obj)) {
817             obj_extract_self(obj);
818             if (mon->mx) {
819                 mdrop_obj(mon, obj, FALSE);
820             } else { /* migrating monster not on map */
821                 if (obj->owornmask) {
822                     mon->misc_worn_check &= ~obj->owornmask;
823                     if (obj->owornmask & W_WEP)
824                         setmnotwielded(mon, obj);
825                     obj->owornmask = 0L;
826                 }
827                 rloco(obj);
828             }
829         }
830     }
831 }
832
833 /* release the objects the creature is carrying */
834 void
835 relobj(mtmp, show, is_pet)
836 struct monst *mtmp;
837 int show;
838 boolean is_pet; /* If true, pet should keep wielded/worn items */
839 {
840     struct obj *otmp;
841     int omx = mtmp->mx, omy = mtmp->my;
842
843     /* vault guard's gold goes away rather than be dropped... */
844     if (mtmp->isgd && (otmp = findgold(mtmp->minvent)) != 0) {
845         if (canspotmon(mtmp))
846 #if 0 /*JP:T*/
847             pline("%s gold %s.", s_suffix(Monnam(mtmp)),
848                   canseemon(mtmp) ? "vanishes" : "seems to vanish");
849 #else
850             pline("%s\82Ì\8bà\82Í\8fÁ\82¦\82½%s\81D", Monnam(mtmp),
851                   canseemon(mtmp) ? "" : "\82æ\82¤\82¾");
852 #endif
853         obj_extract_self(otmp);
854         obfree(otmp, (struct obj *) 0);
855     } /* isgd && has gold */
856
857     while ((otmp = (is_pet ? droppables(mtmp) : mtmp->minvent)) != 0) {
858         obj_extract_self(otmp);
859         mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
860     }
861
862     if (show && cansee(omx, omy))
863         newsym(omx, omy);
864 }
865
866 /*steal.c*/